首页 > 解决方案 > 我应该在交叉熵之前应用softmax吗?

问题描述

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 

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

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

标签: machine-learningpytorchcross-entropy

解决方案


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 章对此进行了更深入的解释。


推荐阅读