神经网络中NLLLoss和CrossEntropyLoss的快速理解

在很多论文中,我们看到loss有时候用的NLLLoss,有时候用的CrossEntropyLoss,这个主要的区别是什么?

如下:

cross_entropy_mean = F.nll_loss(log_preds, labels)

或者

loss = nn.NLLLoss()

很多人很难理解,不是求的交叉熵损损失吗?怎么返回的是nll_loss呢?

其实,NLLloss+log+softmax就是CrossEntropyLoss,而其中的NLLloss就是在做 交叉熵损失函数的最后一步 :预测结果的删除负号,然后求和。

我们下面看两个第一:
例子1

import torch
from torch import nn
#随机生成一个神经网络的最后一层,3行4列,那就是有4个标签
input = torch.randn(3,4)
#input的第一行设置为标签1,第二行为标签0,
label = torch.tensor([1,0,2])
#人工设置种子,不然每次计算loss不一样,我们通过固定种子就可以固定loss
torch.manual_seed(2)
#定义损失函数为NLLLoss
loss = nn.NLLLoss()
#定义log softmax函数,也就是将input中的每一行转化为带有负号的数字
m = nn.LogSoftmax(dim=1)
#计算损失,损失就是一个值。
loss_value = loss(m(input),label)
print(loss_value)

得到结果:

tensor(0.9703)

我们再看交叉熵损失怎么写的?

import torch
from torch import nn
#随机生成一个神经网络的最后一层,3行4列,那就是有4个标签
input = torch.randn(3,4)
#input的第一行设置为标签1,第二行为标签0,
label = torch.tensor([1,0,2])
#人工设置种子,不然每次计算loss不一样,我们通过固定种子就可以固定loss
torch.manual_seed(2)
#定义损失函数为NLLLoss
loss = nn.CrossEntropyLoss()
#计算损失,损失就是一个值。
loss_value = loss(input,label)
print(loss_value)

大家看到有没有什么区别没有?在CrossEntropyLoss()中我们删除了计算softmax的过程。一步到位。


例子二:(还是第一个例子,但是我们打印出变量进行分析)

import torch
from torch import nn
# NLLLoss+LogSoftmax
# logsoftmax=log(softmax(x))
m = nn.LogSoftmax(dim=1) #横向计算
loss = nn.NLLLoss()
# 3行5列的输入,即3个样本各包含5个特征,每个样本通过softmax产生5个输出
input = torch.randn(3, 5, requires_grad=True)
#这里的104就是标签,即input中的第一行的识别出来的标签为1,第二行的标签为0
target = torch.tensor([1, 0, 4]) 
# NLL将取输出矩阵中第0行的第1列、第1行的第0列、第2行的第4列加负号求和
output = loss(m(input), target)

我们打印出print(input)。

tensor([[ 0.3923, -0.2236, -0.3195, -1.2050,  1.0445],
        [-0.6332,  0.5731,  0.5409, -0.3919, -1.0427],
        [ 1.3186,  0.7476, -1.3265, -1.2413, -0.1028]], requires_grad=True)

我们打印出

mout = m(input)