PyTorch 教程中的交叉熵计算

Cross Entropy Calculation in PyTorch tutorial

我正在阅读多 class class化问题的 Pytorch 教程。而且我发现 Pytorch 中 Loss 计算的行为让我很困惑。你能帮我解决这个问题吗?

用于class化的模型是这样的:

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16 * 5 * 5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

训练过程如下:

optimizer.zero_grad()
outputs = net(inputs)
loss = nn.CrossEntropyLoss(outputs, labels)
loss.backward()
optimizer.step()

我的问题是:Pytorch 中 Loss 计算的确切行为是什么?在每次迭代期间,nn.CrossEntropyLoss() 的输入有两部分:

  1. 模型的输出,它是一个 10 x 1 张量,其中有不同的值。这是一个没有归一化为概率的张量。
  2. 作为标量的标签,例如 1 或 2 或 3。

据我所知,交叉熵的计算通常用在两个张量之间,如:

  1. 目标为 [0,0,0,1],其中 1 是正确的 class
  2. 输出张量为[0.1,0.2,0.3,0.4],其中总和为1。

所以基于这个假设,这里的nn.CrossEntropyLoss()需要实现:

  1. 首先将输出张量归一化为可能性一
  2. 将标签编码为单热标签,如 2 in 5 class 为 [0,1,0,0,0]。长度必须与输出张量相同。
  3. 然后计算损失

请问这是nn.CrossEntropyLoss()的作用吗?或者我们是否需要在输入模型之前对真实标签进行一次性编码?

非常感谢您提前抽出时间!

nn.CrossEntropyLoss 首先应用 log-softmax (log(Softmax(x)) 获取对数概率,然后计算负对数似然,如文档中所述:

This criterion combines nn.LogSoftmax() and nn.NLLLoss() in one single class.

当使用one-hot编码目标时,交叉熵可以计算如下:

其中 y 是单热编码目标向量,ŷ 是每个 class 的概率向量。要获得概率,您可以将 softmax 应用于模型的输出。使用概率的对数,PyTorch只是将对数和softmax合并为一个操作nn.LogSoftmax(),为了数值稳定性。

由于 one-hot 向量中除一个外的所有值均为零,因此总和中只有一项不为零。因此给定实际的class,可以简化为:

只要知道class索引,就可以直接计算loss,比使用one-hot encoded target效率更高,因此nn.CrossEntropyLoss期望class 指数。

完整的计算在 nn.CrossEntropyLoss:

的文档中给出

The loss can be described as: