PyTorch中的loss函数源码通常可以在torch.nn.functional模块中找到。这些函数接受模型的输出和真实标签作为输入,并计算出模型预测的误差,从而帮助优化器调整模型参数。下面是一些常见的loss函数及其对应的任务类型:

  1. 二分类任务(Binary Classification):

二分类任务只有两个类别,如判断一张图片是猫还是狗。常用的损失函数有:

  • (1)BCELoss(Binary Cross Entropy Loss):二分类交叉熵损失函数,适合输出为概率值的情况。

  • (2)BCEWithLogitsLoss:结合sigmoid函数和二分类交叉熵损失函数的一种损失函数,适合输出的是未经过sigmoid函数处理的原始值的情况。

  • (3)Focal Loss:对于类别不平衡问题较严重的二分类任务,可以采用Focal Loss,来关注分类错误样本中难分类的样本,加大难分类样本的损失权重,从而提升准确率。

  1. 多分类任务(Multi-class Classification):

多分类任务有多个互斥的类别,如图像分类任务中的1000个类别。常用的损失函数有:

  • (1)CrossEntropyLoss:交叉熵损失函数,适合输出为类别概率分布的情况。

  • (2)NLLLoss(Negative Log Likelihood Loss):负对数似然损失函数,适合输出为类别标签的情况。

  1. 目标检测任务(Object Detection):

目标检测任务常用的损失函数是Focal Loss和SSD Loss。Focal Loss是针对目标检测任务中的类别不平衡问题而设计的一种损失函数,SSD Loss则是一种结合置信度和位置回归的损失函数。

  • (1)Focal Loss: 针对目标检测任务中的类别不平衡问题而设计的一种损失函数。
  • (2)SSD Loss则是一种结合置信度和位置回归的损失函数。
  1. 图像分割任务(Image Segmentation):

图像分割任务常用的损失函数是交叉熵损失函和Dice Loss,其中Dice Loss是一种适合于像素级别的分割任务的损失函数。

  • (1)CrossEntropyLoss :多分类交叉熵损失函数(用于像素级别的分类任务)。
  • (2)Dice Loss是一种适合于像素级别的分割任务的损失函数。
  1. 回归任务(Regression):

回归任务常用的损失函数包括:

  • (1)MSELoss(Mean Square Error Loss):均方误差损失函数。

  • (2)L1Loss:平均绝对误差损失函数。

  • (3)SmoothL1Loss:平滑L1损失函数,对离群值更加稳健。

注意:以上列出的loss函数不是绝对的分类,对于不同的任务类型,也可以使用其他的loss函数。

二分类任务

BCELoss

BCELoss(Binary Cross Entropy Loss)是二分类任务中最常用的loss函数之一,适用于输出只有两个类别的模型。它的公式如下:

BCELoss ( x , y ) = − 1 n ∑ i = 1 n [ y i log ⁡ x i + ( 1 − y i ) log ⁡ ( 1 − x i ) ] \text{BCELoss}(x, y) = -\frac{1}{n} \sum_{i=1}^{n}\big[y_i\log x_i + (1-y_i)\log(1-x_i)\big] BCELoss(x,y)=n1i=1n[yilogxi+(1yi)log(1xi)]

其中 x x x表示模型经过sigmoid的输出, y y y表示真实标签(计算中需要转为float类型), n n n表示样本数。BCELoss可以看作是标准交叉熵损失的一个特例。

在Pytorch中,可以使用nn.BCELoss()来调用该函数。常用的参数如下:

  • weight:权重参数,用于对样本进行加权,可以根据数据集中各类别的比例来设定,比例较小的类别通常给予较高的权重。可选参数默认是None。

下面是一个使用nn.BCELoss()的示例代码:

import torch.nn as nn
import torch.nn.functional as F

loss_func = nn.BCELoss(weight=torch.tensor([0.2, 0.8])) # 2类别样本比例为0.2和0.8
output = model(data) # 模型经过sigmoid的输出
loss = loss_func(output, target.to(torch.float32)) # 计算损失

# 或者
output = torch.sigmoid(output)
loss = f.binary_cross_entropy(output, labels.float(), weight=torch.tensor([0.2, 0.8]))

BCEWithLogitsLoss

BCEWithLogitsLoss是对BCELoss的一种改进,它将sigmoid函数和BCELoss二元交叉熵合并在一起,可以提高数值稳定性。在Pytorch中,可以使用nn.BCEWithLogitsLoss()来调用该函数。常用的参数如下:

l o s s ( x , y ) = − w [ y ⋅ l o g ( σ ( x ) ) + ( 1 − y ) ⋅ l o g ( 1 − σ ( x ) ) ] + α 2 x 2 loss(x, y) = -w[y\cdot log(\sigma(x)) + (1-y)\cdot log(1-\sigma(x))] + \frac{\alpha}{2}x^2 loss(x,y)=w[ylog(σ(x))+(1y)log(1σ(x))]+2αx2

其中, x x x表示模型的预测值, y y y表示目标变量(二分类标签), α \alpha α是平衡正负样本数量的参数, w w w是权重。

  • weight:权重参数,同上。

下面是一个使用nn.BCEWithLogitsLoss()的示例代码:

import torch.nn as nn
import torch.nn.functional as F
loss_func = nn.BCEWithLogitsLoss(weight=torch.tensor([0.2, 0.8])) # 2类别样本比例为0.2和0.8
output = model(data) # 模型输出
loss = loss_func(output, target) # 计算损失

# output [B,C]  labels [B,C]
loss = f.binary_cross_entropy_with_logits(output, labels.float(), weight=torch.tensor([0.2, 0.8]))

Focal Loss

Focal Loss是一种解决类别不平衡问题的损失函数,特别适用于正负样本极其不平衡的情况下。在传统的交叉熵损失函数(Cross-Entropy Loss)中,分类错误的样本会被等同对待,这对于正负样本极其不平衡的情况显然不合适。Focal Loss通过动态调节每个样本的权重来缓解这个问题,使得模型更关注于那些难以分类的样本(即“难样本”),更加有效地进行训练。

Focal Loss的公式推导如下:

假设有 n n n个样本,其中 x i x_i xi表示第 i i i个样本的输入, y i y_i yi为它的真实标签, p i p_i pi为模型预测其为正样本的概率, p t p_t pt为样本实际为正样本的概率(即 p t = 1 p_t=1 pt=1 y i = 1 y_i=1 yi=1 p t = 0 p_t=0 pt=0 y i = 0 y_i=0 yi=0), α \alpha α为平衡因子, γ \gamma γ为难样本调节因子,那么Focal Loss的公式可以表示为:

F L ( p t ) = − α ( 1 − p t ) γ log ⁡ ( p t ) FL(p_t)=-\alpha(1-p_t)^\gamma\log{(p_t)} FL(pt)=α(1pt)γlog(pt)

其中, − log ⁡ ( p t ) -\log{(p_t)} log(pt)为交叉熵损失函数, ( 1 − p t ) γ (1-p_t)^\gamma (1pt)γ为难样本调节因子, α \alpha α为平衡因子,用来平衡正负样本的数量。

Focal Loss的应用场景包括但不限于:

  • 目标检测
  • 分割任务
  • 人脸识别
  • 不平衡数据集的分类任务

下面是使用PyTorch实现Focal Loss的代码示例:

import torch
import torch.nn as nn

class FocalLoss(nn.Module):
    def __init__(self, alpha=1, gamma=2, reduction='mean'):
        super(FocalLoss, self).__init__()
        self.alpha = alpha
        self.gamma = gamma
        self.reduction = reduction
    
    def forward(self, input, target):
        ce_loss = nn.CrossEntropyLoss(reduction='none')(input, target)  # 计算交叉熵损失
        pt = torch.exp(-ce_loss)  # 计算概率
        focal_loss = self.alpha * (1 - pt) ** self.gamma * ce_loss  # 计算Focal Loss
        
        if self.reduction == 'mean':
            return focal_loss.mean()
        elif self.reduction == 'sum':
            return focal_loss.sum()
        else:
            return focal_loss

其中,alpha为平衡因子,gamma为难样本调节因子,一般取值为2,reduction为损失函数的求和/求平均方式,默认为mean

多分类任务

CrossEntropyLoss

CrossEntropyLoss是多分类任务中最常用的loss函数之一,适用于输出多个类别的模型。它的公式如下:

CrossEntropyLoss ( x , y ) = − 1 n ∑ i = 1 n ∑ j = 1 C y i j log ⁡ x i j \text{CrossEntropyLoss}(x, y) = -\frac{1}{n} \sum_{i=1}^{n}\sum_{j=1}^{C} y_{ij} \log x_{ij} CrossEntropyLoss(x,y)=n1i=1nj=1Cyijlogxij

其中 x x x表示模型的输出, y y y表示真实标签, C C C表示类别数, n n n表示样本数。在Pytorch中,可以使用nn.CrossEntropyLoss()来调用该函数。常用的参数如下:

  • weight:权重参数,用于对样本进行加权,可以根据数据集中各类别的比例来设定,比例较小的类别通常给予较高的权重。

  • ignore_index:忽略某一类别,在分割任务中常用。

下面是一个使用nn.CrossEntropyLoss()的示例代码:

import torch.nn as nn
loss_func = nn.CrossEntropyLoss(weight=torch.tensor([0.2, 0.3, 0.5])) # 3类别样本比例为0.2、0.3和0.5
output = model(data) # 模型输出
loss = loss_func(output, target) # 计算损失

NLLLoss

NLLLoss(Negative Log Likelihood Loss)是CrossEntropyLoss的一种改进,在处理预测概率时更加灵活,可以用于带权重的多分类问题。它的公式如下:

NLLLoss ( x , y ) = − 1 n ∑ i = 1 n w i y i log ⁡ x i \text{NLLLoss}(x, y) = -\frac{1}{n} \sum_{i=1}^{n}w_i y_i \log x_i NLLLoss(x,y)=n1i=1nwiyilogxi

其中 x x x表示模型的输出, y y y表示真实标签, n n n表示样本数, w i w_i wi为样本 i i i的权重。在Pytorch中,可以使用nn.NLLLoss()来调用该函数。常用的参数如下:

  • weight:权重参数,用于对样本进行加权,可以根据数据集中各类别的比例来设定,比例较小的类别通常给予较高的权重。

下面是一个使用nn.NLLLoss()的示例代码:

import torch.nn as nn
loss_func = nn.NLLLoss(weight=torch.tensor([0.2, 0.3, 0.5])) # 3类别样本比例为0.2、0.3和0.5
output = model(data) # 模型输出
loss = loss_func(output, target) # 计算损失

Label Smoothing Loss

Label Smoothing Loss是一种用于减轻分类问题中过拟合现象的损失函数,其基本思想是将真实标签的概率分布进行平滑化处理,使得模型在训练时不会过于自信地预测某种类别,从而提高其泛化能力。

具体来说,Label Smoothing Loss将原本的one-hot标签 x x x转化为如下的平滑标签:

x i ‾ = { 1 − ϵ + ( 1 / K ) ϵ if  i = y ϵ / K otherwise \overline{x_i}=\begin{cases} 1-\epsilon+(1/K)\epsilon & \text{if } i=y \\ \epsilon/K & \text{otherwise} \end{cases} xi={1ϵ+(1/K)ϵϵ/Kif i=yotherwise

其中 K K K为类别数, ϵ \epsilon ϵ为平滑参数, y y y为真实类别的标签。

根据交叉熵的定义,可以得到Label Smoothing Loss的公式:

L LS = − ∑ i = 1 K x i ‾ log ⁡ ( p i ) L_{\text{LS}}=-\sum_{i=1}^{K}\overline{x_i}\log(p_i) LLS=i=1Kxilog(pi)

其中 p i p_i pi为模型预测的第 i i i个类别的概率。

Label Smoothing Loss可以应用于各种分类任务场景,但通常在存在过拟合风险的情况下效果更为显著。

以下是使用PyTorch实现Label Smoothing Loss的代码示例:

import torch.nn.functional as F

class LabelSmoothingLoss(nn.Module):
    def __init__(self, epsilon=0.1, reduction='mean'):
        super(LabelSmoothingLoss, self).__init__()
        self.epsilon = epsilon
        self.reduction = reduction

    def forward(self, logits, targets):
        K = logits.size(-1)
        log_probs = F.log_softmax(logits, dim=-1)
        targets = F.one_hot(targets, num_classes=K)

        targets = (1 - self.epsilon) * targets + self.epsilon / K
        loss = (-targets * log_probs).sum(dim=-1)

        if self.reduction == 'none':
            return loss
        elif self.reduction == 'mean':
            return loss.mean()
        elif self.reduction == 'sum':
            return loss.sum()

在使用时,只需要将LabelSmoothingLoss作为损失函数进行传参即可。

criterion = LabelSmoothingLoss(epsilon=0.1, reduction='mean')
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

for epoch in range(num_epochs):
    for images, labels in train_loader:
        images, labels = images.to(device), labels.to(device)
        optimizer.zero_grad()
        outputs = model(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

pytorch代码示例二:

import torch.nn as nn

class LabelSmoothingLoss(nn.Module):
    def __init__(self, smoothing=0.1):
        super(LabelSmoothingLoss, self).__init__()
        self.smoothing = smoothing

    def forward(self, predict, target):
        n_class = predict.size(1)
        log_pred = F.log_softmax(predict, dim=1)
        smooth_loss = -log_pred.mean(dim=1)
        nll_loss = F.nll_loss(log_pred, target)
        return (1 - self.smoothing) * nll_loss + self.smoothing * smooth_loss.mean()

其中,predict是模型的输出,target是真实标签,smoothing是平滑系数,默认为0.1。在forward方法中,我们首先计算log_softmax值,然后分别计算平滑损失和NLL loss,并将它们加权平均得到最终的loss。

检测任务

FocalLoss

Focal Loss(焦点损失函数)是一种针对不平衡数据集的损失函数,它在处理分类问题时能够提高较少样本的分类准确率。Focal Loss是由Lin等人在2017年提出的。在此之前,交叉熵损失函数是处理分类问题的最常见的损失函数。在不平衡数据集上,交叉熵损失函数容易受到多数类的干扰,从而降低较少类的分类准确率。

Focal Loss通过引入一个可调整的指数项来减轻多数类的影响。指数项对于容易分类的样本减少损失的贡献,同时对于难分类的样本增加损失的贡献,从而使网络更加关注难分类的样本。Focal Loss的公式如下:

F L ( p t ) = − α ( 1 − p t ) γ l o g ( p t ) FL(p_t) = -\alpha(1-p_t)^\gamma log(p_t) FL(pt)=α(1pt)γlog(pt)

其中, p t p_t pt表示网络预测的概率, γ \gamma γ是一个可调整的指数项,调节难分类样本的权重。当 γ = 0 \gamma=0 γ=0时,Focal Loss等价于交叉熵损失;当 γ > 0 \gamma>0 γ>0时,容易分类的样本的权重减少,难分类的样本的权重增加。

在pytorch中,实现Focal Loss的代码如下:

import torch
import torch.nn as nn
import torch.nn.functional as F

class FocalLoss(nn.Module):
    def __init__(self, gamma=2, alpha=None, size_average=True):
        super(FocalLoss, self).__init__()
        self.gamma = gamma
        self.alpha = alpha
        if isinstance(alpha, (float, int)): self.alpha = torch.Tensor([alpha, 1 - alpha])
        if isinstance(alpha, list): self.alpha = torch.Tensor(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()

其中,gamma是指数项,alpha是类别权重。如果不需要设置alpha,可以传入None。size_average表示是否对batch维度求平均值。

至此,Focal Loss的原理、公式和pytorch代码实现已经介绍完毕。

SSD Loss

SSD Loss是一种用于物体检测任务的损失函数,用于衡量模型对物体位置和类别的预测与真实值之间的差距。其原理及公式推导如下:

  1. Ground Truth Box与Default Box的匹配

在SSD中,每个预测框(Default Box)都与一个Ground Truth Box进行匹配,这样可以确定每个预测框应该预测哪个物体的位置和类别。匹配的过程分为两个步骤:

  • 首先,计算所有Default Box与Ground Truth Box的IoU值(交并比),确定每个Ground Truth Box应该与哪个Default Box匹配。具体来说,对于一个Ground Truth Box,我们选择与它IoU值最大的Default Box进行匹配(前提是这个IoU值大于一定阈值,比如0.5)。
  • 接下来,对于每个Default Box,如果它的IoU值与所有Ground Truth Box都小于一定阈值(比如0.5),那么就认为它不匹配任何Ground Truth Box,此时它的分类标签应该设为背景。
  1. 损失函数公式

通过上述匹配方法,可以得到每个Default Box的匹配Ground Truth Box的位置和类别。对于位置,我们可以使用Smooth L1 Loss(一种类似于MSE的损失函数)来计算位置误差:

L l o c = 1 N ∑ i ∈ P o s ∑ m ∈ { c x , c y , w , h } s m o o t h L 1 ( y i m − y ^ i m ) L_{loc} = \frac{1}{N} \sum_{i\in Pos} \sum_{m\in\{cx, cy, w, h\}}{smooth_{L1}(y_{i}^{m} - \hat{y}_{i}^{m})} Lloc=N1iPosm{cx,cy,w,h}smoothL1(yimy^im)

其中, N N N是匹配的Default Box总数, P o s Pos Pos是匹配的Positive Default Box(即匹配成功并且不是背景的Default Box)的集合, y i y_i yi是对应的Ground Truth Box的位置信息, y ^ i \hat{y}_i y^i是模型对应的预测值, s m o o t h L 1 ( x ) smooth_{L1}(x) smoothL1(x)为Smooth L1 Loss函数,公式如下:

s m o o t h L 1 ( x ) = { 0.5 x 2 , if  ∣ x ∣ < 1 ∣ x ∣ − 0.5 , otherwise smooth_{L1}(x)= \begin{cases} 0.5x^2,&\text{if}\ |x| < 1 \\ |x|-0.5,&\text{otherwise} \end{cases} smoothL1(x)={0.5x2,x0.5,if x<1otherwise

对于类别,我们可以使用Cross Entropy Loss来计算:

L c o n f = − 1 N ∑ i ∈ P o s ∑ j ∈ C y i j log ⁡ ( y ^ i j ) − 1 N ∑ i ∈ P o s ∑ j ∈ C ( 1 − y i j ) log ⁡ ( 1 − y ^ i j ) L_{conf} = -\frac{1}{N}\sum_{i\in Pos}\sum_{j\in C}y_{ij}\log(\hat{y}_{ij}) -\frac{1}{N}\sum_{i\in Pos}\sum_{j\in C}(1-y_{ij})\log(1-\hat{y}_{ij}) Lconf=N1iPosjCyijlog(y^ij)N1iPosjC(1yij)log(1y^ij)

其中, C C C是类别集合, y i j y_{ij} yij表示Default Box i i i是否属于类别 j j j(即Ground Truth Box的类别是否为 j j j), y ^ i j \hat{y}_{ij} y^ij表示模型对于Default Box i i i属于类别 j j j的预测概率。

最终的SSD Loss由这两个部分组成:

L = L l o c + α L c o n f L = L_{loc} + \alpha L_{conf} L=Lloc+αLconf

α \alpha α是一个用于平衡位置误差和类别误差的超参数,通常设置为1。

  1. Pytorch代码示例

以下是使用Pytorch实现SSD Loss的代码示例:

import torch.nn as nn
import torch.nn.functional as F

class SSDLoss(nn.Module):
    def __init__(self, num_classes, alpha=1.0):
        super(SSDLoss, self).__init__()
        self.num_classes = num_classes
        self.alpha = alpha
    
    def forward(self, loc_preds, conf_preds, loc_targets, conf_targets):
        # loc_preds: [batch_size, num_default_boxes, 4]
        # conf_preds: [batch_size, num_default_boxes, num_classes]
        # loc_targets: [batch_size, num_default_boxes, 4]
        # conf_targets: [batch_size, num_default_boxes, num_classes]
        pos_mask = conf_targets > 0  # 正样本的掩码
        num_pos = pos_mask.sum(dim=1, keepdim=True)  # 每个Default Box匹配的Positive Ground Truth Box数量
        smooth_l1 = nn.SmoothL1Loss(reduction='none')
        loss_loc = smooth_l1(loc_preds, loc_targets)
        loss_loc = (loss_loc * pos_mask).sum() / num_pos.sum()

        loss_conf = F.cross_entropy(conf_preds.view(-1, self.num_classes), 
                                    conf_targets.view(-1).long(), 
                                    reduction='none')
        loss_conf = loss_conf.view(conf_targets.size())
        loss_conf_pos = loss_conf[pos_mask]
        num_pos_per_img = num_pos.sum(dim=2, keepdim=True).float()
        loss_conf_pos_sum = loss_conf_pos.sum(dim=1)
        loss_conf_neg = loss_conf.sum(dim=1) - loss_conf_pos_sum
        num_neg = torch.clamp(num_pos_per_img * 3, max=pos_mask.size(1)-num_pos_per_img)
        loss_conf_neg, _ = torch.topk(loss_conf_neg, k=num_neg.int().item(), dim=1, largest=False)
        loss_conf = (loss_conf_pos_sum + loss_conf_neg.sum()) / num_pos_per_img.sum()
        
        return loss_loc + self.alpha * loss_conf

其中,loc_preds表示模型预测的位置信息,conf_preds表示模型预测的类别信息,loc_targets表示Ground Truth Box的位置信息,conf_targets表示Ground Truth Box的类别信息。在forward方法中,首先计算位置误差损失loss_loc,然后计算类别误差损失loss_conf。在计算loss_conf时,我们对所有Default Box计算Cross Entropy Loss,并根据Positive和Negative样本计算不同的损失。具体来说,我们将所有Positive样本的损失相加,并从Negative样本中选取与Positive样本数目相同的样本加入损失。选取的方法是取出所有Negative样本的loss,从小到大排序,保留最小的num_pos_per_img * 3个样本,num_pos_per_img表示每个图片中Positive样本的数量。最后将Positive样本和Negative样本的损失相加,除以Positive样本数量和图片数量的乘积作为最终的loss_conf。

SmoothL1Loss

SmoothL1Loss用于目标检测任务中的回归问题,其计算公式为:

l o s s ( x , y ) = { 0.5 ( x − y ) 2 i f   ∣ x − y ∣ < 1 ∣ x − y ∣ − 0.5 o t h e r w i s e loss(x, y) = \begin{cases} 0.5(x-y)^2 & if~|x-y| < 1 \\ |x-y|-0.5 & otherwise \\ \end{cases} loss(x,y)={0.5(xy)2xy0.5if xy<1otherwise

其中, x x x表示模型的预测值, y y y表示目标变量。

分割任务

Cross Entropy Loss

语义分割任务中,常用的loss函数是交叉熵损失函数(Cross Entropy Loss),计算公式如下:

L = − ∑ i = 1 N ∑ j = 1 C y i , j ⋅ log ⁡ ( y ^ i , j ) \begin{aligned} \mathcal{L} = -\sum_{i=1}^N \sum_{j=1}^C y_{i,j} \cdot \log(\hat{y}_{i,j}) \end{aligned} L=i=1Nj=1Cyi,jlog(y^i,j)

其中, N N N表示样本总数, C C C表示类别总数, y i , j y_{i,j} yi,j表示第i个样本的真实标签是否为类别j, y ^ i , j \hat{y}_{i,j} y^i,j表示模型对第i个样本是否属于类别j的预测结果。

源码示例:

import torch.nn.functional as F
criterion = F.cross_entropy(output, target, weight=torch.tensor([1, 2, 3, 4]))

Cross Entropy Loss可以通过weight参数调整不同类别的权重。

DiceLoss

除了Cross Entropy Loss之外,还常用的一个loss函数是Dice Loss,Dice Loss是一种常见的非sigmoid型的损失函数,也适用于多分类任务。Dice Loss通过计算模型预测结果与真实标签的交集与并集之间的差异来衡量模型的性能。Dice Loss的计算公式如下:

D i c e ( p , q ) = 2 ∣ p ∩ q ∣ ∣ p ∣ + ∣ q ∣ = 2 ∑ i = 1 N p i q i ∑ i = 1 N p i + ∑ i = 1 N q i \begin{aligned} Dice(p, q) = \frac{2 | p \cap q |}{| p | + | q |} = \frac{2\sum_{i=1}^{N}p_i q_i}{\sum_{i=1}^{N}p_i + \sum_{i=1}^{N}q_i} \end{aligned} Dice(p,q)=p+q2∣pq=i=1Npi+i=1Nqi2i=1Npiqi

其中, p p p表示模型的预测结果, q q q表示真实标签。

源码示例:

class DiceLoss(nn.Module):
    def __init__(self, weight=None, size_average=True):
        super(DiceLoss, self).__init__()
        self.size_average = size_average
        self.register_buffer('weight', weight)

    def forward(self, inputs, targets):
        self.num_classes = inputs.size(1)
        inputs_soft = F.softmax(inputs, dim=1)

        if self.weight is not None and targets.dim() == 4:
            weights = self.weight.repeat(targets.size(0), 1, targets.size(2), targets.size(3))
            inputs_soft = inputs_soft * weights

        dice = 0
        for i in range(1, self.num_classes):
            input_i = inputs_soft[:, i]
            target_i = (targets == i).float()
            intersection = (input_i * target_i).sum(dim=(2, 3))
            union = input_i.sum(dim=(2, 3)) + target_i.sum(dim=(2, 3))
            score_i = (2.0 * intersection / (union + 1e-7)).mean()
            dice += score_i

        loss = 1 - dice / float(self.num_classes - 1)
        return loss

Dice Loss可以通过weight参数调整不同类别的权重。

BCEWithLogitsLoss

BCEWithLogitsLoss也可以用于图像分割任务,其计算公式和二分类任务中的相同。

回归任务

MSELoss

MSELoss(Mean Squared Error Loss)是回归任务中最常用的loss函数之一。其计算公式如下:

l o s s ( x , y ) = 1 n ∑ i = 1 n ( x i − y i ) 2 loss(x, y) = \frac{1}{n}\sum_{i=1}^{n} (x_i - y_i)^2 loss(x,y)=n1i=1n(xiyi)2

其中, x x x表示模型的预测值, y y y表示目标变量(回归值), n n n表示样本数量。

import torch.nn.functional as F
criterion = F.mse_loss(pred, target, reduction='sum')

SmoothL1Loss

SmoothL1Loss也可以用于回归任务,其计算公式和检测任务中的相同。

总结:
本文介绍了常见的loss函数,并按照任务类型进行了分类,并给出了源码示例和参数解析。在实际使用过程中,需要根据任务类型和数据情况选用合适的loss函数,并合理设置参数以达到最佳的训练效果。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐