欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【深度学习】Softmax和交叉熵损失函数

程序员文章站 2022-03-16 19:26:57
...

前言

​ SoftMax和Sigmoid是搭建神经网络时常见的两种**函数。由于最近在做一个多分类的任务,使用到了Softmax函数,这里仅简单提一下Sigmoid,详细介绍Softmax函数。

Sigmoid

Sigmoid函数由下列公式定义
【深度学习】Softmax和交叉熵损失函数
Sigmoid函数的图形如S曲线
【深度学习】Softmax和交叉熵损失函数

SoftMax

Sigmoid函数由下列公式定义
【深度学习】Softmax和交叉熵损失函数
softmax 的作用是把 一个序列,变成概率
【深度学习】Softmax和交叉熵损失函数
softmax用于多分类过程中,它将多个神经元的输出,映射到(0,1)区间内,所有概率的和将等于1。

LogSoftMax

​ 在介绍完Softmax函数后,这里又出现了LogSoftMax函数,那么这个函数与Softmax函数有什么区别?它又有什么作用呢?

LogSigmoid函数由下列公式定义
【深度学习】Softmax和交叉熵损失函数
​ 由于使用SoftMax函数计算数值的稳定性不高,而且还有可能报 NaN的错误[2],因此一种可能的替代的方案是使用LogSoftMax(然后再求 exp)数值稳定定性比 softmax 好一些。
【深度学习】Softmax和交叉熵损失函数
​ 可以看到,LogSoftMax省了一个指数计算,省了一个除法,数值上相对稳定一些。

交叉熵损失函数

​ 交叉熵(cross entropy)是深度学习中常用的一个概念,一般用来求目标与预测值之间的差距。在介绍交叉熵损失函数之前,首先需要了解几个概念。

信息量

“太阳从东边升起”,这条信息陈述了一个事实,因为太阳肯定是从东边升起的,这是一句废话,信息量为0。

”2018年中国队成功进入世界杯“,从直觉上来看,这句话具有很大的信息量。因为中国队进入世界杯的不确定性因素很大,而这句话消除了进入世界杯的不确定性,所以按照定义,这句话的信息量很大。

根据上述可总结如下:信息量的大小与信息发生的概率成反比。概率越大,信息量越小。概率越小,信息量越大。

设某一事件发生的概率为P(x),其信息量表示为:

信息熵

信息熵也被称为熵,用来表示所有信息量的期望。

期望是试验中每次可能结果的概率乘以其结果的总和。

所以信息量的熵可表示为:
【深度学习】Softmax和交叉熵损失函数
使用明天的天气概率来计算其信息熵:
【深度学习】Softmax和交叉熵损失函数
H(X)=−(0.5∗log(0.5)+0.2∗log(0.2)+0.3∗log(0.3))*

相对熵(KL散度)

​ 如果对于同一个随机变量XXX有两个单独的概率分布P(x)和Q(x),则我们可以使用KL散度来衡量这两个概率分布之间的差异。公式如下:
【深度学习】Softmax和交叉熵损失函数
​ 在机器学习中,常常使用P(x)来表示样本的真实分布,Q(x)来表示模型所预测的分布,比如在一个三分类任务中(例如,猫狗马分类器),X1,X2,X3 分别代表猫,狗,马,例如一张猫的图片真实分布P(X)=[1,0,0],预测分布Q(X)=[0.7,0.2,0.1],计算KL散度:
【深度学习】Softmax和交叉熵损失函数
​ KL散度越小,表示P(x)的分布更加接近,可以通过反复训练Q(x)来使Q(x)的分布逼近P(x)。

交叉熵

首先将KL散度公式拆开:

H(p(x))表示信息熵,后者即为交叉熵,KL散度 = 交叉熵 - 信息熵

【深度学习】Softmax和交叉熵损失函数
交叉熵公式
【深度学习】Softmax和交叉熵损失函数
(上述公式中 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函数

​ 在上面我已经介绍了交叉熵损失函数的表达式,这里再给出:
【深度学习】Softmax和交叉熵损失函数
​ 其中 Pk 表示真实值,在这个公式中是one-hot形式; qk 是预测值,在这里假设已经是经过softmax后的结果了。仔细观

察可以知道,因为Pk 的元素不是0就是1,而且又是乘法,所以很自然地我们如果知道1所对应的index,那么就不用做其他无意义的运算了。所以在pytorch代码中target不是以one-hot形式表示的,而是直接用scalar表示。所以交叉熵的公式(m表示真实类别)可变形为:
【深度学习】Softmax和交叉熵损失函数
​ 仔细观察,其实CrossEntropyLoss就等同于LogsoftmaxNLLLoss两个步骤(把Softmax–Log–NLLLoss合并成一步)。其计算方式即为:
【深度学习】Softmax和交叉熵损失函数

# 使用交叉熵损失函数
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

相关标签: 深度学习