Pytorch中分类loss总结

近期在学习pytorch时,发现分类算法在输出时不写激活层如softmax激活/sigmoid激活。并且pytorch文档中除了softmax激活/sigmoid激活外,还有logsoftmax/logsigmoid。以及torch的loss函数会把激活和损失计算都整合到一起计算,给的解释是为了获得更好的数值稳定性。为了弄清这一切,进行了以下探索。并将自己涉及的相关不清楚的部分进行了补充(可跳过)。

一分类的loss函数

理论上来说,可以用来衡量误差并且可微风的函数都可以用来作为损失函数来衡量误差,优化模型。以下列举了几个可用于分类的损失函数

  1. MSE Loss

均分误差mean squared error只给出定义:

loss=1Ni(yi-yi)2

pytorch实现softmax多分类_多项式

  1. 相对熵和交叉熵

(1)熵

熵在信息论中用来衡量某一随机时间的信息量。

HX=-ip(xi)log⁡p(xi)

pytorch实现softmax多分类_损失函数_02

(2)相对熵(K-L散度)

用来衡量两个分布之间的差异。

DKL=ip(xi)log⁡p(xi)q(xi)

pytorch实现softmax多分类_多项式_03

根据公式,当p,q的分布一致时,其相对熵为0。p一般是目标分布,q是预测分布。

(3)交叉熵

对相对熵公式变换:

DKL=ip(xi)log⁡p(xi)q(xi)

pytorch实现softmax多分类_多项式_03

ipxilogpxi-pxilogqxi

pytorch实现softmax多分类_似然函数_05

Hpx-ipxilogqxi

pytorch实现softmax多分类_损失函数_06

H(p(x))表示P的熵。为常数,所以仅使用后半部分就可以衡量来个分布的差异。也就是交叉熵:

 

CrossEntropy=-ipxilogqxi

pytorch实现softmax多分类_pytorch实现softmax多分类_07

二pytorch中的loss

1.BCEWithLogitsLoss

Torch官方文档给出的解释是,就是在sigmoid后接了BCELoss。通过将这些操作整合到一层,使用log-sum-exp strick的技巧可以获得更好的数值稳定性。等等,什么是log-sum-exp trick?

  1. log-sum-exp

这部分来自知乎回答,很通俗易懂。

pytorch实现softmax多分类_似然函数_08

总结下来就是,在计算log-sum-exp时,可能会存在数值上溢或者数值下溢的情况。为了避免这个情况在计算y=logiexi

pytorch实现softmax多分类_损失函数_09

时,使用以下方式计算。y=a+logiexi-a,其中a=max⁡(x)

pytorch实现softmax多分类_pytorch实现softmax多分类_10

这两种方式的计算结果是一样的,只是通过这种方式计算可以避免数值溢出。证明:

y=a+logiexi-a=a+logiexiea

pytorch实现softmax多分类_损失函数_11

a+logiexi-logea=logiexi

pytorch实现softmax多分类_损失函数_12

上面说清楚log-sum-exp trick后,那么在计算loss是怎么使用的呢。

为更好的举例,这里以交叉熵为例。我们知道模型的结果要经过softmax层后,输入损失函数计算loss。具体过程为。

softmaxy=exp⁡(yi)jexp⁡(yj)

pytorch实现softmax多分类_多项式_13

crossentropyy,y=-iyilogyi

pytorch实现softmax多分类_损失函数_14

-iyilogexp⁡(yi)jexp⁡(yj)

pytorch实现softmax多分类_似然函数_15

-i(yilogexp⁡(yi)-yilogjexp⁡(yj))

pytorch实现softmax多分类_pytorch实现softmax多分类_16

公式后半部分出现了log-sum-exp操作。可能会出现数值上溢或者下溢的问题。同时注意exp操作来自于softmax。log操作来自于loss函数。为了进行log-sum-exp trick,就要把这些操作放在一起计算,整合到一起无非两种方式。

1)把log计算放到激活函数中,所以pytorch中出现了logsigmoid,logsoftmax。那么在计算loss时,就要移除log运算,因为在激活时已经进行了log运算(例如后面要说的NLLLoss,看到过有些人在知乎提问为什么该损失函数中没有log计算)。

2)将exp操作放到loss函数计算中,一般会将整个激活函数统一到loss函数中计算。于是有了BCEWithLogitsLoss(将sigmoid和BCELoss整合到一起),CrossEntropyLoss(将logsoftmax和NLLLoss整合到一起)。

2.NLLLoss

Log似然函数或最大似然函数。

这部分来自于知乎和西瓜书。

  1. 极大似然估计

极大似然估计就是根据一堆观测结果,对模型的参数进行估计。注意:不是学习整个模型,仅仅是对模型的参数进行估计,这里要先假设模型的分布,仅仅估计该分布的参数。使得根据该分布产生该观测结果的概率最大。

最大似然估计的流程:

  1. 先假定其概率分布形式
  2. 定义最大观察概率
  3. 最大化观察概率求得概率分布的参数θ

举个栗子:栗子来自知乎:

pytorch实现softmax多分类_多项式_17

似然函数是关于模型参数θ的函数h(θ),用来衡量在当前参数θ的模型下,对已知样本集的似然(对已知样本集的解释情况)。

极大似然估计就是求解使得对已知样本集似然度最大的参数θ。

(2)似然损失函数

可参见夕小瑶的知乎:

可以将模型的predict作为参数,label作为已知样本集,使用似然函数来度量当前predict对label的解释程度。

多类模型的参数实际就是每一个类别发生的概率(两类的称之为二项分布,多类的成为多项式分布)。

以多项式分布为例,多项式分布的参数是属于每一个类别的概率(模型的预测值也是当前样本属于每一个类别的概率。所以可以用predict当做模型的参数,就是参数θ等于predict的单词观测多项式分布模型对当前样本label的似然。实际上就是实现了用似然函数来衡量两个分布的相似度,作为一种距离的度量,也就可以作为loss函数了)。

以上建模的对象是样本集合的条件概率分布p(y|x)。m个样本的集合是看做m个单次观察的多项式分布模型;而不是m次观察的多项式分布(m次观察的多项式分布,模型只有一个,所有的样本共有一套参数θ)。但在似然损失函数中,每个样本模型都用predict(相当于有m组模型参数)。

最大化似然函数等同于最小化负的似然函数。同时为了避免连乘下溢,使用log将连乘转化成累加。所以也叫作对数似然函数。待补充贝努利分布和多项式分布的计算,以及实际上对数似然函数等同于交叉熵损失函数。只是从不同的方面去解释。

三. 总结

logsoftmax/logsigmoid:正常的softmx/sigmoid激活后接log函数。

BCEWithLogitsLoss: 将sigmoid和BCELoss整合到一起

CrossEntropyLoss: 将logsoftmax和NLLLoss整合到一起

NLLLoss:移除了log运算的log似然损失函数。

目的:就是为了将log-sum-exp放在一起运算。然后使用log-sum-exp strick避免数值上溢/下溢。获得更好的数值稳定性。