Pytorch中分类loss总结
近期在学习pytorch时,发现分类算法在输出时不写**层如softmax**/sigmoid**。并且pytorch文档中除了softmax**/sigmoid**外,还有logsoftmax/logsigmoid。以及torch的loss函数会把**和损失计算都整合到一起计算,给的解释是为了获得更好的数值稳定性。为了弄清这一切,进行了以下探索。并将自己涉及的相关不清楚的部分进行了补充(可跳过)。
一分类的loss函数
理论上来说,可以用来衡量误差并且可微风的函数都可以用来作为损失函数来衡量误差,优化模型。以下列举了几个可用于分类的损失函数
1.MSE Loss
均分误差mean squared error只给出定义:
2.相对熵和交叉熵
2.1熵
熵在信息论中用来衡量某一随机时间的信息量。
2.2相对熵(K-L散度)
用来衡量两个分布之间的差异。
根据公式,当p,q的分布一致时,其相对熵为0。p一般是目标分布,q是预测分布。
2.3交叉熵
对相对熵公式变换:
H(p(x))表示P的熵。为常数,所以仅使用后半部分就可以衡量来个分布的差异。也就是交叉熵:
二 pytorch中的loss
1.BCEWithLogitsLoss
Torch官方文档给出的解释是,就是在sigmoid后接了BCELoss。通过将这些操作整合到一层,使用log-sum-exp strick的技巧可以获得更好的数值稳定性。等等,什么是log-sum-exp trick?
2.1log-sum-exp
这部分来自知乎回答,很通俗易懂。
总结下来就是,在计算log-sum-exp时,可能会存在数值上溢或者数值下溢的情况。为了避免这个情况在计算时,使用以下方式计算。
这两种方式的计算结果是一样的,只是通过这种方式计算可以避免数值溢出。证明:
上面说清楚log-sum-exp trick后,那么在计算loss是怎么使用的呢。
为更好的举例,这里以交叉熵为例。我们知道模型的结果要经过softmax层后,输入损失函数计算loss。具体过程为。
公式后半部分出现了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似然函数或最大似然函数。
这部分来自于知乎和西瓜书。
2.1极大似然估计
极大似然估计就是根据一堆观测结果,对模型的参数进行估计。注意:不是学习整个模型,仅仅是对模型的参数进行估计,这里要先假设模型的分布,仅仅估计该分布的参数。使得根据该分布产生该观测结果的概率最大。
最大似然估计的流程:
- 先假定其概率分布形式
- 定义最大观察概率
- 最大化观察概率求得概率分布的参数θ
举个栗子:栗子来自知乎:
明白了什么是最大似然函数,那么为什么似然函数可以作为损失函数呢
2.2似然损失函数
可以这样考虑,我们将当前样本的label作为当前的观测值。模型预测值作为参数θ。那么模型预测出什么样的结果,才会让当前观察结果出现的概率最大呢。似然函数可以通过观察概率的大小来评估当前θ的好坏,那么也可以用来评估在某label下的模型预测值的好坏(好绕)。通过最大化似然函数可以找到最优模型预测值。最大化似然函数等同于最小化负的似然函数。同时为了避免连乘下溢,使用log将连乘转化成累加。所以也叫作对数似然函数。待补充贝努利分布和多项式分布的计算,以及实际上对数似然函数等同于交叉熵损失函数。只是从不同的方面去解释。
三. 总结
logsoftmax/logsigmoid | 正常的softmx/sigmoid**后接log函数。 |
BCEWithLogitsLoss | 将sigmoid和BCELoss整合到一起 |
CrossEntropyLoss | 将logsoftmax和NLLLoss整合到一起 |
NLLLoss | 移除了log运算的log似然损失函数。 |
目的:就是为了将log-sum-exp放在一起运算。然后使用log-sum-exp strick避免数值上溢/下溢。获得更好的数值稳定性。