import torch
import torch.nn.functional as F
import numpy as np
# 随机新建3个样例数据,每个样例数据包含4个属性特征
input = torch.randn(3,4)
tensor([[ 0.0054, -0.8030, -0.5758, -0.6518],
[-0.5518, 0.3904, 0.5296, 0.4973],
[ 0.1608, 0.5822, 0.9536, -0.3173]])
使用softmax对数据进行处理:
F.softmax(input, dim=1)
dim=1
表示跨列操作,行数不变。输出结果:
tensor([[0.3963, 0.1766, 0.2216, 0.2054],
[0.1067, 0.2738, 0.3147, 0.3047],
[0.1868, 0.2847, 0.4127, 0.1158]])
每一行元素相加为1.
使用log_softmax
进行处理:
F.log_softmax(input, dim=1)
输出结果:
tensor([[-0.9255, -1.7339, -1.5067, -1.5827],
[-2.2375, -1.2953, -1.1561, -1.1883],
[-1.6778, -1.2564, -0.8850, -2.1558]])
log_softmax
相当于对softmax
做了log
操作,下面进行验证:
# 首先将tensor类型转为numpy类型
np_data = F.softmax(input, dim=1).data.numpy()
np.log(np_data)
输出结果为:
array([[-0.9255125 , -1.7338518 , -1.5066911 , -1.5826656 ],
[-2.2374916 , -1.2952974 , -1.1560525 , -1.1883242 ],
[-1.6778362 , -1.2563533 , -0.88496906, -2.155847 ]],
dtype=float32)
可以看出与log_softmax
的结果一致,log_softmax
就是对softmax
的结果做了log
。
softmax
将数值压缩至0~1
,而log_softmax
将数据压缩至负无穷~0
NLLLoss
的结果就是把上面的输出与Label
对应的那个值拿出来,再去掉负号,再求均值。
NLLLoss
的输入是一个log_softmax
和一个目标label
。
假设我们的数据正确的label是[0,2,3]
,第一行取第0个元素,第二行取第2个,第三行取第3个,去掉负号,得到[0.9255125,1.1560525,2.155847]
,然后求平均,结果是:(0.9255125+1.1560525 + 2.155847)/3=1.4124706666666667
下面使用NLLLoss函数验证一下:
target = torch.tensor([0,2,3])
loss = F.nll_loss(F.log_softmax(input, dim=1),target)
得到loss=tensor(1.4125)
结果一致。
交叉熵的计算公式为:
c r o s s e n t r o p y = − ∑ k = 1 N ( p k ∗ l o g q k ) cross_entropy=-\sum_{k=1}^N(p_k*log q_k) crossentropy=−k=1∑N(pk∗logqk)
其中 p p p表示真实值,在这个公式中是one-hot
形式; q q q是预测值,在这里假设已经是经过 s o f t m a x softmax softmax后的结果了。
仔细观察可以知道,因为 p p p的元素不是0就是1,而且又是乘法,所以很自然地我们如果知道1所对应的index,那么就不用做其他无意义的运算了。所以在pytorch代码中target不是以one-hot形式表示的,而是直接用scalar表示。所以交叉熵的公式(m表示真实类别)可变形为:
c r o s s _ e n t r o p y = − ∑ k = 1 N ( p k ∗ l o g q k ) = − ∑ k = 1 N q m cross\_entropy=-\sum_{k=1}^N(p_k*log q_k)=-\sum_{k=1}^Nq_m cross_entropy=−k=1∑N(pk∗logqk)=−k=1∑Nqm
仔细看看,是不是就是等同于log_softmax和nll_loss两个步骤。
CrossEntropyLoss就是把以上Softmax–Log–NLLLoss合并成一步,我们用刚刚随机出来的input直接验证一下结果是不是1.4125
:
F.cross_entropy(input,target)
输出结果为tensor(1.4125)
,结果一致