我正在阅读多类分类问题的 Pytorch 教程。而且我发现 Pytorch 中 Loss 计算的行为让我很困惑。你能帮我解决这个问题吗?
用于分类的模型是这样的:
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 中损失计算的确切行为是什么?在每次迭代中,nn.CrossEntropyLoss() 的输入有两部分:
- 模型的输出,它是一个 10 x 1 张量,其中包含不同的值。这是一个没有归一化为概率的张量。
- 作为标量的标签,例如 1 或 2 或 3。
据我所知,交叉熵的计算通常用于两个张量之间,例如:
- 目标为 [0,0,0,1],其中 1 是正确的类别
- 输出张量为 [0.1,0.2,0.3,0.4],其中总和为 1。
所以基于这个假设,这里的nn.CrossEntropyLoss()需要实现:
- 首先将输出张量归一化为可能性一。
- 将标签编码为单热标签,例如 5 类中的 2 个 [0,1,0,0,0]。长度必须与输出张量相同。
- 然后计算损失。
请问这是 nn.CrossEntropyLoss() 的作用吗?或者我们是否需要在输入模型之前对真实标签进行一次性编码?
非常感谢您提前抽出时间!
最佳答案
nn.CrossEntropyLoss
首先应用 log-softmax (log(Softmax(x)
) 获取对数概率,然后计算负对数似然,如文档中所述:
This criterion combines
nn.LogSoftmax()
andnn.NLLLoss()
in one single class.
当使用 one-hot 编码目标时,交叉熵可以计算如下:
其中 y 是单热编码目标向量,ŷ 是每个类别的概率向量。要获得概率,您可以将 softmax 应用于模型的输出。使用概率的对数,PyTorch 只是将对数和 softmax 合并为一个操作 nn.LogSoftmax()
, 为了数值稳定性。
由于 one-hot 向量中除 1 之外的所有值均为零,因此总和中只有一项为非零。因此给定实际类,可以简化为:
只要知道类别索引,就可以直接计算损失,这比使用单热编码目标更有效,因此 nn.CrossEntropyLoss
期望类索引。
完整的计算在 nn.CrossEntropyLoss
的文档中给出。 :
关于machine-learning - PyTorch 教程中的交叉熵计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62161194/