【Loss总结】适用与弱监督语义分割中的各类loss
文章目录
- 【Loss总结】适用与弱监督语义分割中的各类loss
- 交叉熵损失
- 相对熵(KL散度)
- 交叉熵
- L1 Loss
- L2Loss
- SmoothL1Loss
- Dice loss
- 梯度分析
- 语义分割代码
交叉熵损失
交叉熵损失函数(CrossEntropy Loss),它是分类问题中经常使用的一种损失函数
在模型的输出层总会接一个softmax函数
交叉熵是信息论中的一个重要概念,主要用于度量两个概率分布间的差异性
构建理论:
- 信息是用来消除随机不确定性的东西
- 信息量的大小与信息发生的概率成反比。概率越大,信息量越小。概率越小,信息量越大
I(x)表示信息量,P(x)表示概率
I(x)为正值,因为log(P(x))为负值
信息熵
信息熵也被称为熵,用来表示所有信息量的期望
期望是试验中每次可能结果的概率乘以其结果的总和。
信息量的熵可表示为:
0-1分布问题
一件事情发生的概率为P(x) ,则另一件事情发生的概率为1-P(x)
相对熵(KL散度)
有两个单独的概率分布P ( x ) 和Q ( x ) ,则我们可以使用KL散度来衡量这两个概率分布之间的差异。
P ( x ) 来表示样本的真实分布,Q ( x ) 来表示模型所预测的分布
真实分布P ( X ) = [ 1 , 0 , 0 ] , 预测分布Q ( X ) = [ 0.7 , 0.2 , 0.1 ]
将对应的P,Q值进行代入
KL散度越小,表示P ( x ) 与Q ( x ) 的分布更加接近,可以通过反复训练Q ( x ) 来使Q ( x ) 的分布逼近P ( x ) 。
交叉熵
KL散度公式拆开:
前者H ( p ( x ) ) )表示信息熵,后者即为交叉熵,KL散度 = 交叉熵 - 信息熵
当KL散度完全一致(loss=1)DKL=1 · log1
交叉熵公式表示为:
输入数据与标签常常已经确定,那么真实概率分布P ( x ) 也就确定下来了,所以信息熵在这里就是一个常量
在线性回归问题中,常常使用MSE(Mean Squared Error)作为loss函数,而在分类问题中常常使用交叉熵作为loss函数。
其中一个batch的loss为
n表示预测的类别数(猫,狗 ,马)n=3,m表示样本数量(batch_size=16)m=16
L1 Loss
也就是L1 Loss了,它有几个别称:
- L1 范数损失
- 最小绝对值偏差(LAD)
- 最小绝对值误差(LAE)
MAE也是指L1 Loss损失函数
目标值 yi与模型输出f(xi)(估计值)做绝对值得到的误差。
应用场景:
- 回归任务
- 简单的模型
- 由于神经网络通常是解决复杂问题,所以很少使用。
公式: torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
创建一个绝对值误差损失函数
用法:reduction='mean','None','sum'
mean 对应(x, y)的均值,None 对应(x, y)的单独值,sum对应(x, y)的总值
L2Loss
也就是L2 Loss了,它有几个别称:
- L2 范数损失
- 最小均方值偏差(LSD)
- 最小均方值误差(LSE)
最常看到的MSE也是指L2 Loss损失函数,PyTorch中也将其命名为torch.nn.MSELoss
目标值 yi与模型输出f(xi)(估计值)做差然后平方得到的误差
应用场景:
-
回归任务
-
数值特征不大
-
问题维度不高
对离群点比较敏感,如果feature是unbounded的话,需要好好调整学习率,防止出现梯度爆炸的情况。l2正则会让特征的权重不过大,使得特征的权重比较平均。
SmoothL1Loss
简单来说就是平滑版的L1 Loss
SoothL1Loss的函数如下:
仔细观察可以看到,当预测值和ground truth差别较小的时候(绝对值差小于1),其实使用的是L2 Loss;而当差别大的时候,是L1 Loss的平移
SooothL1Loss其实是L2Loss和L1Loss的结合,它同时拥有L2 Loss和L1 Loss的部分优点。
优点:
- 当预测值和ground truth差别较小的时候(绝对值差小于1),梯度不至于太大。(损失函数相较L1 Loss比较圆滑)
- 当差别大的时候,梯度值足够小(较稳定,不容易梯度爆炸)。
应用:
- 回归
- 当特征中有较大的数值
- 适合大多数问题
Dice loss
dice loss 来自 dice coefficient,是一种用于评估两个样本的相似性的度量函数,取值范围在0到1之间,取值越大表示越相似
dice loss可以写为:
梯度分析
从dice loss的定义可以看出,dice loss 是一种区域相关的loss。意味着某像素点的loss以及梯度值不仅和该点的label以及预测值相关,和其他点的label以及预测值也相关,这点和ce (交叉熵cross entropy) loss 不同
从loss曲线和求导曲线对单点输出方式分析。然后对于多点输出的情况,利用模拟预测输出来分析其梯度
Dice Loss可以缓解样本中前景背景(面积)不平衡带来的消极影响,前景背景不平衡也就是说图像中大部分区域是不包含目标的,只有一小部分区域包含目标
语义分割代码
class DiceLoss(nn.Module):
def __init__(self, n_classes):
super(DiceLoss, self).__init__()
self.n_classes = n_classes # 物体的输入数量
# 没有问题,但是需要的是进行一个one_hot_的解码,来满足6个特征图
def _one_hot_encoder(self, input_tensor):
tensor_list = []
for i in range(self.n_classes):
temp_prob = input_tensor == i # * torch.ones_like(input_tensor)
tensor_list.append(temp_prob.unsqueeze(1))
output_tensor = torch.cat(tensor_list, dim=1)
return output_tensor.float()
def _dice_loss(self, score, target):
target = target.float()
smooth = 1e-5
intersect = torch.sum(score * target)
y_sum = torch.sum(target * target)
z_sum = torch.sum(score * score)
loss = (2 * intersect + smooth) / (z_sum + y_sum + smooth)
loss = 1 - loss
return loss
def forward(self, inputs, target, weight=None, softmax=False):
if softmax:
inputs = torch.softmax(inputs, dim=1) # 12, 6, 256, 256
target = self._one_hot_encoder(target) # [12, 6, 256, 256]
if weight is None:
weight = [1] * self.n_classes
assert inputs.size() == target.size(), 'predict {} & target {} shape do not match'.format(inputs.size(),
target.size())
class_wise_dice = []
loss = 0.0
for i in range(0, self.n_classes):
dice = self._dice_loss(inputs[:, i], target[:, i])
class_wise_dice.append(1.0 - dice.item())
loss += dice * weight[i]
return loss / self.n_classes