我应该在交叉熵之前应用 softmax 吗?

Liy*_*ang 3 cross-entropy pytorch

pytorch教程 ( https://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py ) 在 CIFAR 数据集上训练卷积神经网络 (CNN)。

    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 
Run Code Online (Sandbox Code Playgroud)

网络看起来不错,除了最后一层fc3,它预测属于 10 个类的概率,而没有 softmax。在计算交叉熵损失之前,我们不应该先应用 softmax 以确保 fc 层的输出介于 0 和 1 之间并求和吗?

我通过应用 softmax 并重新运行进行了测试,但准确度下降到了 35% 左右。这似乎违反直觉。解释是什么?

mr_*_*_mo 6

PyTorch 中的 CrossEntropyLoss 已经用 Softmax 实现了:

https://pytorch.org/docs/stable/nn.html#torch.nn.CrossEntropyLoss

该标准将 nn.LogSoftmax() 和 nn.NLLLoss() 组合在一个类中。

编辑:答案的第二部分的答案有点复杂。降低准确性可能有多种原因。从理论上讲,由于您添加的 softmax 层可以以合理的准确度预测正确答案,因此下一层应该能够通过保留最后两层之间具有同一性的最大值来做同样的事情。虽然 softmax 再次对那些有界输出(0 和 1 之间)进行归一化,但它可能会改变它们的分布方式,但仍然可以保留最大值,从而保留预测的类别。

然而,在实践中,情况略有不同。当你在输出层有一个双 softmax 时,你基本上改变了输出函数,它改变了传播到你的网络的梯度。由于其产生的梯度,具有交叉熵的 softmax 是首选的损失函数。您可以通过计算成本函数的梯度来向自己证明这一点,并说明每个“激活”(softmax)都在 0 和 1 之间。原始“后面”的附加 softmax 只是将梯度与值相乘在 0 和 1 之间,从而减小该值。这会影响权重的更新。也许它可以通过改变学习率来解决,但强烈不建议这样做。只需要一个 softmax 就完成了。
Michael Nielsen 的书,第 3 章对此进行了更深入的解释。