交叉熵公式:
但是为什么下面给出的是
loss = 0.7437
而不是 loss = 0
(因为 1*log(1) = 0
)?
import torch
import torch.nn as nn
from torch.autograd import Variable
output = Variable(torch.FloatTensor([0,0,0,1])).view(1, -1)
target = Variable(torch.LongTensor([3]))
criterion = nn.CrossEntropyLoss()
loss = criterion(output, target)
print(loss) # 0.7437
在您的示例中,您将输出
[0, 0, 0, 1]
视为交叉熵数学定义所需的概率。 但 PyTorch 将它们视为输出,不需要求和为 1
,并且需要首先转换为使用 softmax 函数的概率。
所以
H(p, q)
变成:
H(p, softmax(output))
将输出
[0, 0, 0, 1]
转换为概率:
softmax([0, 0, 0, 1]) = [0.1749, 0.1749, 0.1749, 0.4754]
从何而来:
-log(0.4754) = 0.7437
您的理解是正确的,但 pytorch 不会以这种方式计算 交叉熵。 Pytorch 使用以下公式。
loss(x, class) = -log(exp(x[class]) / (\sum_j exp(x[j])))
= -x[class] + log(\sum_j exp(x[j]))
因为,在您的场景中,
x = [0, 0, 0, 1]
和class = 3
,如果您评估上述表达式,您将得到:
loss(x, class) = -1 + log(exp(0) + exp(0) + exp(0) + exp(1))
= 0.7437
Pytorch 考虑自然对数。
我想添加一个重要的注释,因为这常常会导致混乱。
Softmax 不是损失函数,也不是真正的激活函数。它有一个非常具体的任务:它用于多类分类,以标准化给定类的分数。通过这样做,我们得到每个类别的概率总和为 1。
Softmax 与 Cross-Entropy-Loss 结合来计算模型的损失。
不幸的是,由于这种组合非常常见,因此经常被缩写。有些人使用术语“Softmax-Loss”,而 PyTorch 仅将其称为“Cross-Entropy-Loss”。
nn.NLLLoss
的组合相当于使用
。该术语是 PyTorch 的特殊性,因为 事实上,nn.CrossEntropyLoss
[原文如此] 计算交叉熵,但以对数概率预测作为输入,其中nn.NLLoss
取分数(有时称为nn.CrossEntropyLoss
logits)。从技术上讲,是狄拉克分布(将所有质量放在目标上)与对数概率输入给出的预测分布之间的交叉熵。 使用 PyTorch 进行深度学习nn.NLLLoss
CrossEntropyLoss
Softmax
的input
张量,如下所示。 *
Softmax内部不用于具有 类索引 和 类概率的
target
张量:
import torch
from torch import nn
tensor1 = torch.tensor([0., 0., 0., 1.]).view(1, -1)
# ↑ ↑ ↑ ↑ tensor([[0., 0., 0., 1.]]) ↑ ↑ ↑ ↑
tensor2 = torch.tensor([3])
cel = nn.CrossEntropyLoss()
cel(input=tensor1, target=tensor2) # tensor(0.7437)
# ↓ ↓ ↓ ↓ ↓ Softmax ↓ ↓ ↓ ↓ ↓
# [softmax([0., 0., 0., 1.])]
# ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓ ↓
# [[0.1749, 0.1749, 0.1749, <0.4754>]] # 3 of `tensor2 = torch.tensor([3])`
# 0 1 2 ↑↑ 3 ↑↑ # Class indices
# ↓ ↓ ↓ ↓ ↓ ↓ Negative ln(Logarithmus Naturalis)
# -ln(0.4754)
# ↓ ↓ ↓ ↓
# 0.7437
# ↓ ↓ ↓ ↓ Sum
# 0.7437
# ↓ ↓ ↓ ↓ Mean
# 0.7437 / 1 = 0.7437