导读
作为一名调包算法工程师,在调包的同时根据特定任务改改loss function是非常重要的,所以小老弟今天就基于Pytorch内置的函数,对损失函数做一个小总结。
Pytorch 的损失函数在torch.nn下,共19个(1.7.0版本)。
本篇包括L1损失、MSE损失、NLL损失、CROSSENTROPY损失、CTC损失和POISSONNLL损失,重点介绍后三个。
L1 Loss
torch.nn.L1Loss(size_average=None, reduce=None, reduction: str = 'mean')
也就是平均绝对误差,计算公式:
其中N是batch size:
参数解释
官方文档中size_average和reduce已经不推荐使用,统一用reduction。
reduction:三个值('none' | 'mean' | 'sum')默认为‘mean’,作用参考计算公式中说明。
特点
衡量两组连续型变量之间差距的最简单的公式,取绝对值是因为两个变量之间的差值有正有负,相加不至于抵消。
使用场景
回归问题;因为太过简单暴力,实际中不太用到这个损失函数。
MSE Loss
torch.nn.MSELoss(size_average=None, reduce=None, reduction: str = 'mean')
均方误差损失函数,计算公式:
参数解释
参数含义与L1 Loss中的一样。
特点
同样也是衡量两组连续型变量的差异,但做了平方计算,因此会对差异进行“放大”,比如两个数差值是0.1则平方后是0.01,而差值是10平方后则是100,相当于当模型做出的预测值与实际值差距越大,该损失函数所带来的惩罚越大。
使用场景
回归问题;常用的回归模型损失函数,但由于其平方计算的特性,对于离群点或者异常值较为敏感,同时容易出现梯度爆炸。
CROSSENTROPY Loss
torch.nn.CrossEntropyLoss(weight:Optional[torch.Tensor]=None, size_average=None, ignore_index: int = -100, reduce=None, reduction: str = 'me
即交叉熵损失函数,计算公式:
参数解释
weight:可选参数,权重,即类别权重,当类别数不平衡的时候可以使用,float型变量,必须对每个类别都设置一个权重。
ignore_index:指定一个类别值,该类别的数据将不会对loss计算有影响,也不会参与梯度计算,比如一共五个类[0,1,2,3,4],指定ignore_index=3, 则label=3的数据不会参与loss计算和梯度下降。
特点
实际上pytorch这里的交叉熵的实现方式和我们平时了解的交叉熵损失计算不太一样,为了方便理解,我们从头捋一下交叉熵损失。
首先来看什么是交叉熵,设p(x),q(x)分别是离散随机变量X的两个概率分布,其中p(x)是目标分布,p和q的交叉熵:
因此交叉熵损失可以写为:
我们训练一个模型完成分类任务,在计算loss的时候,p(x)是目标分布,假设三分类任务,三个类分别是:猫,猪,狗,某个样本的标签是猫,则此时的目标分布为:
通过预测,得到的三个类别的概率:
计算交叉熵:
可以看到,其实在计算交叉熵损失的时候,目标类别之外的都变成了0,所以交叉熵公式可以简化为:
这种形式是对应的是pytorch的交叉熵损失的实现方式,利用torch.nn.LogSoftmax和torch.nn.NLLLoss,也就是一个对数激活函数加负对数似然损失;softmax激活函数的用途很简单,我们在进行分类任务的时候,神经网络最后一层的输出节点数就是类别数,但这个数值并不是一个概率分布, softmax激活函数就是将几个值归一化为一个概率分布,logsoftmax则是在这个基础上再取个对数,如下图:
实际上pytorch的文档也表示的很清楚:
This criterion combines
nn.LogSoftmax() and nn.NLLLoss() in one single class.
使用场景
分类问题:包括多分类和二分类。
NLL Loss
torch.nn.NLLLoss(weight:Optional[torch.Tensor]=None, size_average=None, ignore_index: int = -100, reduce=None, reduction: str = 'mean')
特点
NLL是negative log likelihood的缩写,也就是负对数似然损失,计算公式可参考前面的CROSSENTROPY损失,不过这里要注意,NLLLOSS接受的输入必须是经过log_softmax处理的值,实际上就相当于前面的CROSSENTROPY,只是这里需要自己增加一个log_softmax层。
使用场景
分类问题:包括多分类和二分类。
CTC Loss
torch.nn.CTCLoss(blank: int = 0, reduction: str = 'mean', zero_infinity: bool = False)
特点
The Connectionist Temporal Classification loss.这个没找到中文名叫什么,它来自于CTC算法,主要用于处理序列标注问题中的输入与输出标签的对齐问题。
举个例子,比如我们训练一个词性标注模型,如下图,
输入和输出序列是天然对齐的,所以不需要进行任何处理,直接丢到模型里训练就行,但是如果是一个语音识别模型呢?如下图,
无法直接丢到模型进行训练,需要先进行对齐处理,而CTC算法则不需要进行对齐处理,详细介绍可以参考[1][2]两篇文章,比较复杂,这里就不展开介绍了
使用场景
序列预测场景中输入输出非对齐的情况。
POISSONNLL Loss
torch.nn.PoissonNLLLoss(log_input: bool = True, full: bool = False, size_average=None, eps: float = 1e-08, reduce=None, reduction: str = 'mean')
泊松负对数分布,用于目标服从泊松分布的负对数损失,计算公式如图,最后一项可以忽略或通过Stirling近似. 当目标值大于1时才进行近似,小于等于1的目标值,loss加上0。
特点
这个和前面的负对数似然损失其实关系并不大。首先泊松分布描述的是单位时间内随机事件发生的次数,泊松分布的参数λ是单位时间(或单位面积)内随机事件的平均发生次数:
比如我们可以统计并计算出某个车站每天的客流量,这个值就是栏目大,然后用P(k)就可以求某天实际为k人的概率。
对泊松分布求负对数:
对比上面公式,是不是有点像。所以其实这里的input就相当于栏目大,而target相当于k,这就是泊松负对数分布损失的导出了。
参数解释
log_input: 布尔值,可选参数。默认为True,为True时会对input取对数处理,即
full: 布尔值,可选参数。默认False 是否计算全部的loss,也就是前面讲的最后一项是否忽略和近似,如果采用斯特林公式近似,此为 target*log(target) - target+0.5∗log(2πtarget)
eps: 浮点数,当log_input = False时,用来防止计算log(0),而增加的一个修正项。即:loss(input,target)=input - target * log(input+eps)
size_average: 布尔值,可选参数,默认None,当reduce=True时有效。为True时,返回的loss为平均值;为False时,返回的各样本的loss之和。
reduce: 布尔值,返回值是否为标量,默认为True
使用场景
目标服从泊松分布。
参考资料
[1] Sequence ModelingWith CTC (https://distill.pub/2017/ctc/)
[2]CTC Algorithm Explained (https://xiaodu.io/ctc-explained/)
Ai小老弟
不积跬步,无以至千里