Focal Loss損失函數詳解

一、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

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-16 14:13
下一篇 2024-11-16 14:14

相關推薦

  • Python中引入上一級目錄中函數

    Python中經常需要調用其他文件夾中的模塊或函數,其中一個常見的操作是引入上一級目錄中的函數。在此,我們將從多個角度詳細解釋如何在Python中引入上一級目錄的函數。 一、加入環…

    編程 2025-04-29
  • Python中capitalize函數的使用

    在Python的字符串操作中,capitalize函數常常被用到,這個函數可以使字符串中的第一個單詞首字母大寫,其餘字母小寫。在本文中,我們將從以下幾個方面對capitalize函…

    編程 2025-04-29
  • Python中set函數的作用

    Python中set函數是一個有用的數據類型,可以被用於許多編程場景中。在這篇文章中,我們將學習Python中set函數的多個方面,從而深入了解這個函數在Python中的用途。 一…

    編程 2025-04-29
  • 單片機打印函數

    單片機打印是指通過串口或並口將一些數據打印到終端設備上。在單片機應用中,打印非常重要。正確的打印數據可以讓我們知道單片機運行的狀態,方便我們進行調試;錯誤的打印數據可以幫助我們快速…

    編程 2025-04-29
  • 三角函數用英語怎麼說

    三角函數,即三角比函數,是指在一個銳角三角形中某一角的對邊、鄰邊之比。在數學中,三角函數包括正弦、餘弦、正切等,它們在數學、物理、工程和計算機等領域都得到了廣泛的應用。 一、正弦函…

    編程 2025-04-29
  • Python3定義函數參數類型

    Python是一門動態類型語言,不需要在定義變量時顯示的指定變量類型,但是Python3中提供了函數參數類型的聲明功能,在函數定義時明確定義參數類型。在函數的形參後面加上冒號(:)…

    編程 2025-04-29
  • Python實現計算階乘的函數

    本文將介紹如何使用Python定義函數fact(n),計算n的階乘。 一、什麼是階乘 階乘指從1乘到指定數之間所有整數的乘積。如:5! = 5 * 4 * 3 * 2 * 1 = …

    編程 2025-04-29
  • Python定義函數判斷奇偶數

    本文將從多個方面詳細闡述Python定義函數判斷奇偶數的方法,並提供完整的代碼示例。 一、初步了解Python函數 在介紹Python如何定義函數判斷奇偶數之前,我們先來了解一下P…

    編程 2025-04-29
  • 分段函數Python

    本文將從以下幾個方面詳細闡述Python中的分段函數,包括函數基本定義、調用示例、圖像繪製、函數優化和應用實例。 一、函數基本定義 分段函數又稱為條件函數,指一條直線段或曲線段,由…

    編程 2025-04-29
  • Python函數名稱相同參數不同:多態

    Python是一門面向對象的編程語言,它強烈支持多態性 一、什麼是多態多態是面向對象三大特性中的一種,它指的是:相同的函數名稱可以有不同的實現方式。也就是說,不同的對象調用同名方法…

    編程 2025-04-29

發表回復

登錄後才能評論