【深度学习】Softmax和交叉熵损失函数
前言
SoftMax和Sigmoid是搭建神经网络时常见的两种**函数。由于最近在做一个多分类的任务,使用到了Softmax函数,这里仅简单提一下Sigmoid,详细介绍Softmax函数。
Sigmoid
Sigmoid函数由下列公式定义
Sigmoid函数的图形如S曲线
SoftMax
Sigmoid函数由下列公式定义
softmax 的作用是把 一个序列,变成概率。
softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,所有概率的和将等于1。
LogSoftMax
在介绍完Softmax函数后,这里又出现了LogSoftMax函数,那么这个函数与Softmax函数有什么区别?它又有什么作用呢?
LogSigmoid函数由下列公式定义
由于使用SoftMax函数计算数值的稳定性不高,而且还有可能报 NaN的错误[2],因此一种可能的替代的方案是使用LogSoftMax(然后再求 exp)数值稳定定性比 softmax 好一些。
可以看到,LogSoftMax省了一个指数计算,省了一个除法,数值上相对稳定一些。
交叉熵损失函数
交叉熵(cross entropy)是深度学习中常用的一个概念,一般用来求目标与预测值之间的差距。在介绍交叉熵损失函数之前,首先需要了解几个概念。
信息量
“太阳从东边升起”,这条信息陈述了一个事实,因为太阳肯定是从东边升起的,这是一句废话,信息量为0。
”2018年中国队成功进入世界杯“,从直觉上来看,这句话具有很大的信息量。因为中国队进入世界杯的不确定性因素很大,而这句话消除了进入世界杯的不确定性,所以按照定义,这句话的信息量很大。
根据上述可总结如下:信息量的大小与信息发生的概率成反比。概率越大,信息量越小。概率越小,信息量越大。
设某一事件发生的概率为P(x),其信息量表示为:
信息熵
信息熵也被称为熵,用来表示所有信息量的期望。
期望是试验中每次可能结果的概率乘以其结果的总和。
所以信息量的熵可表示为:
使用明天的天气概率来计算其信息熵:
H(X)=−(0.5∗log(0.5)+0.2∗log(0.2)+0.3∗log(0.3))*
相对熵(KL散度)
如果对于同一个随机变量XXX有两个单独的概率分布P(x)和Q(x),则我们可以使用KL散度来衡量这两个概率分布之间的差异。公式如下:
在机器学习中,常常使用P(x)来表示样本的真实分布,Q(x)来表示模型所预测的分布,比如在一个三分类任务中(例如,猫狗马分类器),X1,X2,X3 分别代表猫,狗,马,例如一张猫的图片真实分布P(X)=[1,0,0],预测分布Q(X)=[0.7,0.2,0.1],计算KL散度:
KL散度越小,表示P(x)的分布更加接近,可以通过反复训练Q(x)来使Q(x)的分布逼近P(x)。
交叉熵
首先将KL散度公式拆开:
H(p(x))表示信息熵,后者即为交叉熵,KL散度 = 交叉熵 - 信息熵
交叉熵公式
(上述公式中 q(xi) 即为SoftMax函数求出的值)
在机器学习训练网络时,输入数据与标签常常已经确定,那么真实概率分布P(x)也就确定下来了,所以信息熵在这里就是一个常量。由于KL散度的值表示真实概率分布P(x)与预测概率分布Q(x)之间的差异,值越小表示预测的结果越好,所以需要最小化KL散度,而交叉熵等于KL散度加上一个常量(信息熵),且公式相比KL散度更加容易计算,所以在机器学习中常常使用交叉熵损失函数来计算loss就行了[3]。
NLLLoss函数
最近在使用神经网络做图像的分类,使用到了pytorch框架,NLLLoss和CrossEntropyLoss两个函数设计到了交叉熵损失函数,而且这两个函数易为混淆,故这里特地记录下来,方便日后查阅。
吐槽一下,pytorch的官方文档写的极其简陋!
NLLLoss函数表达式:f(x,class)=−x[class]
例如:假设 x = [1,2,3],真实类别class = 2,那么f(x,class)=−x[2]=−3
NLLLoss函数的输入:
1. 是一个对数概率向量(先进行了SoftMax操作,对其进行-log操作,也就是LogSoftmax操作);
2. 一个目标标签;
NLLLoss函数的输出:
把上面的对数概率向量与Label对应的那个值拿出来,再去掉负号,再求均值。
import torch
import torch.nn as nn
# 使用NLLLoss损失函数
input = torch.randn(3, 3)
logsm = nn.LogSoftmax(dim=1) # LogSoftmax
NLLLloss = nn.NLLLoss() # 负对数似然损失函数
target = torch.tensor([0, 2, 1]) # 目标标签
result1 = NLLLloss(logsm(input), target)
print(input) # 打印模拟的张量元素
print(result1) # 打印使用NLLLoss损失函数结果
tensor([[ 0.1721, -0.8006, -0.8058],
[-0.0211, -0.7485, 0.3632],
[ 1.3830, 0.2733, 0.3185]]) # 模拟的张量元素
tensor(0.9618) # 使用NLLLoss损失函数计算的结果
我们可以验证一下NLLLoss函数的输出结果:
###验证NLLLoss损失的结果
print(logsm(input)) # 打印模拟的张量元素经过LogSoftmax后的结果
下面是对模拟的张量元素进行LogSoftmax后的结果
tensor([[-0.5620, -1.5347, -1.5399],
[-1.0824, -1.8098, -0.6981],
[-0.5155, -1.6253, -1.5801]]) # 经过LogSoftmax后的结果
经过计算:(1.5098+0.5208+1.2833) / 3 = 1.1046 与使用NLLLoss损失函数计算的结果相同。
注: NLLLoss函数不会为我们计算对数概率,适合最后一层是LogSoftmax函数的网络
CrossEntropyLoss函数
在上面我已经介绍了交叉熵损失函数的表达式,这里再给出:
其中 Pk 表示真实值,在这个公式中是one-hot形式; qk 是预测值,在这里假设已经是经过softmax后的结果了。仔细观
察可以知道,因为Pk 的元素不是0就是1,而且又是乘法,所以很自然地我们如果知道1所对应的index,那么就不用做其他无意义的运算了。所以在pytorch代码中target不是以one-hot形式表示的,而是直接用scalar表示。所以交叉熵的公式(m表示真实类别)可变形为:
仔细观察,其实CrossEntropyLoss就等同于Logsoftmax和NLLLoss两个步骤(把Softmax–Log–NLLLoss合并成一步)。其计算方式即为:
# 使用交叉熵损失函数
crossEntropyLoss = nn.CrossEntropyLoss() # 交叉熵损失函数
result2 = crossEntropyLoss(input, target)
print(result2)
tensor(0.9618) # 使用交叉熵损失函数计算的结果
可以发现,对模拟张量元素,经过LogSoftmax后输入到NLLLoss函数得到的结果与将模拟的张量元素直接输入到CrossEntropyLoss函数中的结果相同。
参考链接
[1] https://blog.csdn.net/uncle_ll/article/details/82778750
[2] https://www.zhihu.com/search?type=content&q=logsoftmax
[3] https://blog.csdn.net/b1055077005/article/details/100152102
[4] https://zhuanlan.zhihu.com/p/2572311
[5] https://www.cnblogs.com/marsggbo/p/10401215.html
推荐阅读
-
【深度学习学习笔记】3.LogisticRegression之一:实现sigmoid的交叉熵损失函数
-
【深度学习学习笔记】3.softmaxRegression:实现softmax的交叉熵损失函数
-
sigmoid和交叉熵损失函数
-
损失函数(MSE和交叉熵)
-
Python机器学习pytorch交叉熵损失函数的深刻理解
-
【Tensorflow与深度学习笔记day07】5.2. ANN网络分析+Mnist手写数字识别+one-hot编码+SoftMax回归+损失计算-交叉熵损失+实现神经网络模型+模型正确率评估
-
【深度学习】Softmax和交叉熵损失函数
-
Python机器学习pytorch交叉熵损失函数的深刻理解