导读
AI小老弟:Pytorch的19个Loss Function(上)zhuanlan.zhihu.com
本篇包括KLDiv损失、BCE损失、对数BCE损失、MarginRanking损失、HingeEmbedding损失和MULTILABELMARGIN损失。
KLDiv Loss
torch.nn.KLDivLoss(size_average=None, reduce=None, reduction: str = 'mean', log_target: bool = False)
KL散度损失,即求模型输出和原始数据的KL散度,以此衡量两组数据分布之间的差异。
KL散度(Kullback–Leibler divergence),也叫相对熵,以离散随机变量X为例,X取值可能是x1,x2,…,xn,对应概率分布pi = P(X=xi),则X的熵是
如果有两个随机变量,即两个概率分布p(x),q(x),则其交叉熵为:
交叉熵可认为是对分布q(x)用分布p(x)来进行编码时所需要的信息量。
我们再来看p(x)对q(x) 的相对熵:
这个公式可以整理:
再来看pytorch文档中的计算公式:
好像不太一样xn没求log,实操一下:
这就比较清楚了,pytorch的KLDiv确实是按照他说明文档里的公式计算的,即没有对input求对数,因此如果想得到真正的KL散度,还需要对输入求一个对数。
参数解释
官方文档中提到size_average和reduce已经不推荐使用,统一用reduction。
reduction:四个值(none' | 'batchmean' | 'sum' | 'mean)默认为‘mean’,特别注意下'batchmean'和mean的区别,batchmean意思是除以batchsize求平均,而mean则是除以输入维度,因此mean算出来的并不是真正的KL散度值,不过说明文档也提到下个版本mean会调整为和batchmean一致。
log_target:布尔值:默认False, 指定Target是不是对数概率。
特点
注意默认计算公式和实际KL散度计算公式的区别。
使用场景
需要对两组数的分布进行比较的时候。
BCE Loss
torch.nn.BCELoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean')
均方误差损失函数。二分类任务时的交叉熵损失函数。target必须是0或1,input是概率分布。计算公式:
参数解释
weight:(Tensor, optional),每个batch里样本的类别权重,常用于类别不均衡问题。
reduction:三个值(‘none' | 'sum' | 'mean)默认为‘mean’,作用参考前文。
特点
文档中提到,如果输入,也就是xn为0或者1的时候,公式中求对数就会出现负无穷,所以这里给到解决方案是求对数的时候输出值限制为大于等于-100。
使用场景
二分类问题。
BCEWithLogits Loss
torch.nn.BCEWithLogitsLoss(weight: Optional[torch.Tensor] = None, size_average=None, reduce=None, reduction: str = 'mean', pos_weight: Optional[torch.Tensor] = None)
对数BCE损失,计算公式:
参数解释
相对于BCE多了pos_weight参数
pos_weight:(Tensor, optional) – 正样本权重,介绍看下面特点。
特点
该函数实际上与BCELoss相同,只是BCELoss的input,在计算之前需要先手动经过sigmoid映射到(0, 1)区间,而该函数将sigmoid与BCELoss整合到一起了。也就是先将输入经过sigmoid函数,然后计算BCE损失。文档中提到,通过把这两个操作都放到同一层, 可以充分利用log-sum-exp的trick来提高数值稳定性。
同时多了个参数pos_weight,这个参数的作用是通过给正样本添加一个权重,来权衡召回率(Recall)和精确度(Precision),上面的计算公式,为多标签分类的loss,c是标签数(c>1的时候为多标签二分类,c=1为单标签二分类),n是一个batch的样本数,pc是标签c的正样本权重,当pc>1,提高召回率,当pc<1,提高精确度。举例来说,数据集中某个标签下有100个正样本和300个负样本,所以pos_weight应该是300/100=3,这个时候计算出的loss相当于是300个正样本的效果,其实说白了就是在计算loss的时候给不平衡样本的正样本增加了权重。
使用场景
多标签的时候可以尝试看下效果。
MarginRanking Loss
torch.nn.MarginRankingLoss(margin: float = 0.0, size_average=None, reduce=None, reduction: str = 'mean')
边缘排序损失?不瞎翻译了,但是从ranking这个词可以知道这个损失函数肯定和排序有关系,先看计算公式:
特点
输入两个一维向量x1,x2(这个向量代表着一个batch中的全部样本输出的值,我们要比较的就是这个值)和一个一维的label向量y,如果y=1,则意味着输入的x1中的元素应该要排在x2前面,y=-1的时候反之。也就是说,需要比较或者排序的只有两个元素,y=1意味着第一个元素排在第二个前面。忽略margin,y=1时候,loss写为max(0,-(x1-x2)),当x1>x2时候,输出0,反之输出x2-x1。
参数解释
Margin:(float, optional),默认为0
其他参考前文所述
使用场景
这个loss平时见的不是很多,貌似在Gan中可以用。
HingeEmbedding Loss
torch.nn.HingeEmbeddingLoss(margin: float = 1.0, size_average=None, reduce=None, reduction: str = 'mean')
折页嵌入损失?hinge了解SVM的同学肯定很熟悉,embedding也是老朋友。但放在一块好像就不知道是什么了,官方文档里说是用来计算两个输入是否相似,特别是非线性的embedding和半监督的emdedding,比如,可以把两个向量的L1距离作为输入,也就是说这里的输入需要是两个向量的差异。我们接着看公式:
特点
输入是一个张量x和一个label张量y(1和-1组成),这里张量的尺寸没有任何限制。我们来分析下在什么时候loss是0, margin假设为默认值1,yn=1的时候,意味着前面提到的比较两个输入是否相似的label为相似,则xn=0,loss=0;y=-1的时候,意味着不能相似,公式变为max(0,1-xn),所以xn=1的时候,loss才等于0,注意,这里的xn为两个输入之间的距离,所以默认取值范围0-1。
参数解释
Margin:(float, optional),默认为0
其他参考前文所述
使用场景
比较非线性的embedding和半监督的emdedding的相似性问题。
MULTILABELMARGIN Loss
torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction: str = 'mean')
多标签MARGIN损失,多标签指的是,一个样本有多个标签,比如一篇文章,可以属于政策、财经两个类别(标签),计算公式:
x[y[j]] 表示 样本x所属类的输出值,x[i]表示不等于该类的输出值。
特点
这里注意的是,假定y=[2,4,0,-1,9],其中-1是一个占位符,该位置和后面的数字都会被认为不是正确的类。结合一个实例:
上面的y表示样本属于3,0两个类别,所以j=0,3,所以i=1,2,则: