pytorch中多分类问题中最常用的损失函数应该就是CrossEntropyLoss了,传闻该函数结合了LogSoftmax和NLLLoss两个函数,那么这个函数到底是什么来头呢?本文来一探究竟。

交叉熵的定义

交叉熵刻画的是实际输出的分布与期望分布的距离:如果模型输出的结果的分布和期望的分布越相似,那么交叉熵就越小。交叉熵的定义公式为python计算模糊交叉熵 pytorch的交叉熵函数_交叉熵损失函数,其中python计算模糊交叉熵 pytorch的交叉熵函数_损失函数_02表示python计算模糊交叉熵 pytorch的交叉熵函数_损失函数_03的维度;更一般地,假设python计算模糊交叉熵 pytorch的交叉熵函数_交叉熵损失函数_04为期望分布,python计算模糊交叉熵 pytorch的交叉熵函数_Loss_05为输出的分布,则python计算模糊交叉熵 pytorch的交叉熵函数_交叉熵损失函数_04python计算模糊交叉熵 pytorch的交叉熵函数_Loss_05的交叉熵就是:python计算模糊交叉熵 pytorch的交叉熵函数_python计算模糊交叉熵_08

举个栗子,假设在一个三分类问题中,一条数据的真实标签为python计算模糊交叉熵 pytorch的交叉熵函数_python计算模糊交叉熵_09,而模型A的预测概率为python计算模糊交叉熵 pytorch的交叉熵函数_Loss_10,模型B的预测概率为python计算模糊交叉熵 pytorch的交叉熵函数_pytorch_11那么模型A的输出对应的交叉熵为python计算模糊交叉熵 pytorch的交叉熵函数_损失函数_12,而模型B的输出的交叉熵为python计算模糊交叉熵 pytorch的交叉熵函数_Loss_13,可见即使两个模型都能够预测正确,但是模型A的交叉熵更小,而更小的交叉熵也意味着模型A的预测概率分布与真实的概率分布更相似。

Pytorch中的CrossEntropyLoss

根据定义,Pytorch中的CrossEntropyLoss是将Softmax-log-NLLoss合并到一块的结果,也就是说CrossEntropyLoss就是我们前面所讨论的交叉熵,为什么这么说呢?看下面的推导:

python计算模糊交叉熵 pytorch的交叉熵函数_损失函数_14

假设一个10分类的神经网络,那么在输出层就应该有10个节点。在Pytorch中如果使用CrossEntropyLoss,这10个节点的后面将不再需要softmax,因为CrossEntropyLoss已经包含了softmax这一部分。softmax的公式为python计算模糊交叉熵 pytorch的交叉熵函数_交叉熵损失函数_15,其能够将十个节点的输出进行处理使得python计算模糊交叉熵 pytorch的交叉熵函数_损失函数_16,也就是对10个节点的输出做了一个变换,且使得其大小关系不变。

在得到softmax的结果之后再将概率值取log,并且执行后面剩下的求和计算。也就是说NLLLOSS的结果就是把取log得到的结果和真实的标签相乘并求和,之后再求均值并取反(求当前mini-batch的均值)。

结合Pytorch文档测试

来看看Pytorch文档中对CrossEntropyLoss的定义

python计算模糊交叉熵 pytorch的交叉熵函数_交叉熵损失函数_17


python计算模糊交叉熵 pytorch的交叉熵函数_pytorch_18


运行下面的代码:

import torch
import torch.nn as nn
import numpy as np

loss = nn.CrossEntropyLoss()

x_input = torch.randn(3, 3)
y = torch.tensor([1,2,0])
print('x_input = ', x_input)
print('y = ', y)

softmax_func = nn.Softmax(dim=1)
softmax_output = softmax_func(x_input)
print('softmax_output = ', softmax_output)

log_output = torch.log(softmax_output)
print('log_output = ', log_output)

nllloss = nn.NLLLoss()
nllloss_output = nllloss(log_output, y)
print('nlloss_output = ', nllloss_output)

print('crossentropyloss = ', loss(x_input, y))

得到输出为:

x_input =  tensor([[ 0.1650,  1.7421,  0.1270],
        [-0.1254, -0.7676, -0.1373],
        [ 1.3294, -0.0838, -1.2392]])
y =  tensor([1, 2, 0])
softmax_output =  tensor([[0.1470, 0.7115, 0.1415],
        [0.3977, 0.2093, 0.3930],
        [0.7576, 0.1844, 0.0581]])
log_output =  tensor([[-1.9174, -0.3404, -1.9554],
        [-0.9220, -1.5642, -0.9339],
        [-0.2777, -1.6908, -2.8462]])
nlloss_output =  tensor(0.5173)
crossentropyloss =  tensor(0.5173)

可以看到使用softmax-log-nllloss得到的结果和直接使用CrossEntropyLoss得到的结果是完全一样的。

再去看一下NLLLoss损失函数的官方定义:

python计算模糊交叉熵 pytorch的交叉熵函数_交叉熵损失函数_19

参考资料: