一、Focal Loss代碼
class FocalLoss(nn.Module): def __init__(self, gamma=2, alpha=0.25, size_average=True): super(FocalLoss, self).__init__() self.gamma = gamma self.alpha = alpha self.size_average = size_average def forward(self, input, target): if input.dim() > 2: input = input.view(input.size(0), input.size(1), -1) # N,C,H,W => N,C,H*W input = input.transpose(1, 2) # N,C,H*W => N,H*W,C input = input.contiguous().view(-1, input.size(2)) # N,H*W,C => N*H*W,C target = target.view(-1, 1) logpt = F.log_softmax(input) logpt = logpt.gather(1, target) logpt = logpt.view(-1) pt = logpt.data.exp() if self.alpha is not None: if self.alpha.type() != input.data.type(): self.alpha = self.alpha.type_as(input.data) at = self.alpha.gather(0, target.data.view(-1)) logpt = logpt * at loss = -1 * (1 - pt) ** self.gamma * logpt if self.size_average: return loss.mean() else: return loss.sum()
Focal Loss(FL)是一種針對類不平衡的分類問題的一種有效方法,成功的應用於目標檢測任務中,FL損失函數可通過調整$\gamma$和$\alpha$來適應不同類別正負樣本的分佈。下面將從多個方面詳細講解FL損失函數的基本原理、優點、缺點和改進方向。
二、Focal Loss實際並不好用
FL是一種比較新的損失函數,目前在一些高檔的目標檢測模型中得到了應用。但是,在實際應用中,FL有時候並不能很好的提高模型的性能。比如,FL存在一些缺點:
1. 當$\gamma$設定不合理時,可能會使訓練過程中模型的表現變得更差;
2. $\alpha$需要事先設定,不同的數據集需要不同的設定,這種設定需要基於模型的訓練數據的經驗,並不能很好的動態調整;
3. 精調每一個參數都比較複雜,特別是$\gamma$和$\alpha$的精細調整;
綜上所述,FL在實際應用中,並不是一種非常好的損失函數方法。
三、Focal Loss缺點
FL的主要缺點體現在如下幾個方面:
1. 不同數據集下的最佳損失函數參數需要重新調試;
# 想要從各個角度看到loss函數的效果 class FocalLoss(nn.Module): def __init__(self, alpha, gamma=2, reduction='mean'): super(FocalLoss, self).__init__() self.alpha = alpha self.gamma = gamma self.reduction = reduction def forward(self, inputs, targets): BCE_loss = F.binary_cross_entropy_with_logits(inputs, targets, reduce=False) pt = torch.exp(-BCE_loss) F_loss = (self.alpha * (1-pt)**self.gamma * BCE_loss).mean() if self.reduction == 'none': return F_loss elif self.reduction == 'sum': return F_loss.sum() else: return F_loss.mean()
2. 確定合理的$\gamma$並不容易;
3. 當類別數量較大時,缺少包容性和良好的可視化效果。
四、Focal Loss改進
1. Focal Loss With Label Smoothing(FL-LS):此方法考慮了標籤過度自信的問題,因此在目標檢測中提出了FL-LS方法,以降低標籤噪聲的影響。
class Focal_Loss_with_LS(nn.Module): def __init__(self, class_num, alpha=None, gamma=2, ls_epsilon=0.1): super(Focal_Loss_with_LS, self).__init__() self.alpha = alpha self.gamma = gamma self.ls_epsilon = ls_epsilon self.class_num = class_num def forward(self, inputs, targets): BCE_loss = F.binary_cross_entropy_with_logits(inputs, targets, reduce=False) p = F.sigmoid(inputs) p_smooth = (1 - self.ls_epsilon) * p + self.ls_epsilon / self.class_num pt = p * targets + (1 - p) * (1 - targets) pt_smooth = p_smooth * targets + (1 - p_smooth) * (1 - targets) FL_loss = - self.alpha * (1 - pt_smooth) ** self.gamma * torch.log(pt_smooth) F_loss = (FL_loss * (1 - pt) ** 2).mean() return F_loss
2. Focal Cosine Loss(FCOS):此方法針對第一個問題,採用了餘弦相似度來代替 softmax1。FCOS方法如下:
class FocalCosineLoss(nn.Module): def __init__(self, gamma=1.0, eps=1e-7): super(FocalCosineLoss, self).__init__() self.gamma = gamma self.eps = eps def forward(self, inputs, targets): cosine_loss = F.cosine_embedding_loss(inputs.view(-1), F.one_hot(targets, num_classes=inputs.size(-1)).float().view(-1, inputs.size(-1)), torch.tensor([1.0], device=inputs.device), reduction="none") sine_loss = F.sin_embedding_loss(inputs.view(-1), F.one_hot(targets, num_classes=inputs.size(-1)).float().view(-1, inputs.size(-1)), torch.tensor([1.0], device=inputs.device), reduction="none") one_hot = torch.zeros_like(inputs) one_hot.scatter_(1, targets.view(-1, 1).long(), 1) pt = (one_hot * inputs).sum(1) + self.eps focal_loss = -((1 - pt) ** self.gamma) * cosine_loss return focal_loss.mean()
3. Focal Loss with Dynamic Number of Objects(FL-DoN): FL-DoN是針對第三個問題的改進,其模型結構如下:
class FocalLoss(nn.Module): def __init__(self, gamma=2): super().__init__() self.gamma = gamma def forward(self, input, target, num_objs=None): target = target.type(input.type()).unsqueeze(1) logpt = F.logsigmoid(input * (target * 2 - 1)) pt = logpt.exp() if num_objs is not None: # dynamic focal loss alpha = num_objs / num_objs.mean() alpha = alpha.unsqueeze(-1) at = (target * alpha + (1 - target) * (1 - alpha)) f_loss = -at * ((1 - pt) ** self.gamma) * logpt else: f_loss = -((1 - pt) ** self.gamma) * logpt return f_loss.mean()
五、Focal Loss函數
Focal Loss函數可視化如圖所示:
def focal_loss(p, t, alpha = 0.25, gamma = 2.0): t = t.view(-1, 1) p = p.view(-1, 1) alpha_t = alpha*(2.0*t-1.0) modulating_factor = (1.0-p).pow(gamma) FL = -1.0 * alpha_t * modulating_factor * p.log()-(1.0-alpha_t) * modulating_factor * (1.0-p).log() return FL.mean()
六、Focal Loss損失函數選取
在多個數據集上對比使用不同的損失函數,如交叉熵損失函數(CE)、平衡交叉熵(BCE)、focal損失函數(FL)和Direct Cross Entropy (CEDE)損失函數4種常用的損失函數,實驗結果顯示 FL損失函數具有最佳性能。
七、小結
總的來說,FL是一種解決類不平衡問題的有效方法,但是由於其固有的限制,實際使用中可能會遇到瓶頸。因此,研究改進FL的方法和更有效的替代方法是值得我們繼續深入研究的問題。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/154693.html