重学语义分割之loss总结篇

本文详细介绍了语义分割中常见的四种损失函数:基于分布的交叉熵和加权交叉熵、基于区域的Dice Loss、IoU Loss和Generalized Dice Loss,以及Tversky Loss、Sensitivity-Specificity Loss;还包括边界导向的Hausdorff Distance Loss和Shape-aware Loss,以及复合的Combination Loss和Exponential Logarithmic Loss。这些损失函数的设计旨在解决类别不平衡、边界精确度和整体性能优化等问题。

目前遇到的loss大致可以分为四大类:基于分布的损失函数(Distribution-based),基于区域的损失函数(Region-based,),基于边界的损失函数(Boundary-based)和基于复合的损失函数(Compounded)。
参考文章:

  1. 语义分割中的 loss function 最全面汇总
  2. 一文看尽15种语义分割损失函数(含代码解析)
  3. 【损失函数合集】超详细的语义分割中的Loss大盘点
  4. 医学影像分割—Dice Loss
  5. Pytorch tversky损失函数
  6. 回归损失函数:Log-Cosh Loss
  7. MIDL 2019——Boundary loss代码
  8. 一票难求的MIDL 2019 Day 1-Boundary loss
  9. 【深度学习】医学图像分割损失函数简介
  10. JunMa11/SegLoss(推荐仓库)

一、基于分布的损失函数

1.1 cross entropy loss

像素级别的交叉熵损失函数可以说是图像语义分割任务的最常用损失函数,这种损失会逐个检查每个像素,将对每个像素类别的预测结果(概率分布向量,因此在多分类任务中,经常采用 softmax 激活函数将网络输出值进行“归一化”成概率分布)与我们的独热编码标签向量进行比较。
对于每个像素的损失为:
P i x e r L o s s = − ∑ c l a s s e s y t r u e l o g ( y p r e d ) PixerLoss = -\sum_{classes} {y_{true} log \left( y_{pred} \right)} PixerLoss=classesytruelog(ypred)

整个图像的损失就是对每个像素的损失求平均值。
特别注意的是,binary entropy loss 是针对类别只有两个的情况,简称 bce loss,损失函数公式为:
B C E L o s s = − y t r u e l o g ( y p r e d ) − ( 1 − y t r u e ) l o g ( 1 − y p r e d ) BCELoss = -y_{true} log \left( y_{pred} \right) - \left(1- y_{true} \right) log \left(1- y_{pred} \right) BCELoss=ytruelog(ypred)(1ytrue)log(1ypred)

代码实现:

  #二值交叉熵,这里输入要经过sigmoid处理
import torch
import torch.nn as nn
import torch.nn.functional as F
nn.BCELoss(F.sigmoid(input), target)
#多分类交叉熵, 用这个 loss 前面不需要加 Softmax 层
nn.CrossEntropyLoss(input, target)

1.2 weighted cross entropy loss

由于交叉熵损失会分别评估每个像素的类别预测,然后对所有像素的损失进行平均,因此我们实质上是在对图像中的每个像素进行平等地学习。如果多个类在图像中的分布不均衡,那么这可能导致训练过程由像素数量多的类所主导,即模型会主要学习数量多的类别样本的特征,并且学习出来的模型会更偏向将像素预测为该类别。
FCN论文和U-Net论文中针对这个问题,对输出概率分布向量中的每个值进行加权,即希望模型更加关注数量较少的样本,以缓解图像中存在的类别不均衡问题。比如对于二分类,正负样本比例为1: 99,此时模型将所有样本都预测为负样本,那么准确率仍有99%这么高,但其实该模型没有任何使用价值。
为了平衡这个差距,就对正样本和负样本的损失赋予不同的权重,带权重的二分类损失函数公式如下:
B C E L o s s = − p o s _ w e i g h t × y t r u e l o g ( y p r e d ) − ( 1 − y t r u e ) l o g ( 1 − y p r e d ) BCELoss = -{pos\_weight} \times y_{true} log \left( y_{pred} \right) - \left(1- y_{true} \right) log \left(1- y_{pred} \right) BCELoss=pos_weight×ytruelog(ypred)(1ytrue)log(1ypred)
p o s _ w e i g h t = n u m _ n e g n u m _ p o s {pos\_weight} = \frac{num\_neg}{num\_pos} pos_weight=num_posnum_neg
要减少假阴性样本的数量,可以增大 pos_weight;要减少假阳性样本的数量,可以减小 pos_weight。

1.3 focal loss

Focal loss是在目标检测领域提出来的。其目的是关注难例(也就是给难分类的样本较大的权重)。对于正样本,使预测概率大的样本(简单样本)得到的loss变小,而预测概率小的样本(难例)loss变得大,从而加强对难例的关注度。
对于较难学习的样本,将 bce loss 修改为:
− ( 1 − y p r e d ) γ × y t r u e l o g ( y p r e d ) − y p r e d γ ( 1 − y t r u e ) l o g ( 1 − y p r e d ) -\left(1- y_{pred} \right)^\gamma \times y_{true} log \left( y_{pred} \right) - y_{pred}^\gamma \left(1- y_{true} \right) log \left(1- y_{pred} \right) (1ypred)γ×ytruelog(ypred)ypredγ(1ytrue)log(1ypred)
其中的 γ \gamma γ通常设置为2。
举个例子,预测一个正样本,如果预测结果为0.95,这是一个容易学习的样本,有 ( 1 − 0.95 ) 2 = 0.0025 \left(1- 0.95 \right)^2=0.0025 (10.95)2=0.0025 ,损失直接减少为原来的1/400。而如果预测结果为0.5,这是一个难学习的样本,有 ( 1 − 0.5 ) 2 = 0.25 \left(1- 0.5 \right)^2=0.25 (10.5)2=0.25 ,损失减小为原来的1/4,虽然也在减小,但是相对来说,减小的程度小得多。所以通过这种修改,就可以使模型更加专注于学习难学习的样本。

而将这个修改和对正负样本不均衡的修改(即加权系数)合并在一起,就是focal loss:
− α ( 1 − y p r e d ) γ × y t r u e l o g ( y p r e d ) − ( 1 − α ) y p r e d γ ( 1 − y t r u e ) l o g ( 1 − y p r e d ) -\alpha \left(1- y_{pred} \right)^\gamma \times y_{true} log \left( y_{pred} \right) -\left(1- \alpha \right) y_{pred}^\gamma \left(1- y_{true} \right) log \left(1- y_{pred} \right) α(1ypred)γ×ytruelog(ypred)(1α)ypredγ(1ytrue)log(1ypred)

下面是多分类的focla loss的代码实现:

class FocalLoss(nn.Module):
   """
   copy from: https://github.com/Hsuxu/Loss_ToolBox-PyTorch/blob/master/FocalLoss/FocalLoss.py
   This is a implementation of Focal Loss with smooth label cross entropy supported which is proposed in
   'Focal Loss for Dense Object Detection. (https://arxiv.org/abs/1708.02002)'
       Focal_Loss= -1*alpha*(1-pt)*log(pt)
   :param num_class:
   :param alpha: (tensor) 3D or 4D the scalar factor for this criterion
   :param gamma: (float,double) gamma > 0 reduces the relative loss for well-classified examples (p>0.5) putting more
                   focus on hard misclassified example
   :param smooth: (float,double) smooth value when cross entropy
   :param balance_index: (int) balance class index, should be specific when alpha is float
   :param size_average: (bool, optional) By default, the losses are averaged over each loss element in the batch.
   """

   def __init__(self, apply_nonlin=None, alpha=None, gamma=2, balance_index=0, smooth=1e-5, size_average=True):
       super(FocalLoss, self).__init__()
       self.apply_nonlin = apply_nonlin
       self.alpha = alpha
       self.gamma = gamma
       self.balance_index = balance_index
       self.smooth = smooth
       self.size_average = size_average

       if self.smooth is not None:
           if self.smooth < 0 or self.smooth > 1.0:
               raise ValueError('smooth value should be in [0,1]')

   def forward(self, logit, target):
       if self.apply_nonlin is not None:
           logit = self.apply_nonlin(logit)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值