pytorch 自定义损失函数 nn.CrossEntropyLoss

Posted

技术标签:

【中文标题】pytorch 自定义损失函数 nn.CrossEntropyLoss【英文标题】:pytorch custom loss function nn.CrossEntropyLoss 【发布时间】:2021-11-13 00:54:21 【问题描述】:

在学习了autograd之后,我尝试自己制作损失函数。 这是我的损失

def myCEE(outputs,targets):
    exp=torch.exp(outputs)
    A=torch.log(torch.sum(exp,dim=1))
    
    hadamard=F.one_hot(targets, num_classes=10).float()*outputs
    B=torch.sum(hadamard, dim=1)
    return torch.sum(A-B)

我和 torch.nn.CrossEntropyLoss 比较

这里是结果

for i,j in train_dl:
    inputs=i
    targets=j
    break

outputs=model(inputs)

myCEE(outputs,targets) : tensor(147.5397, grad_fn=<SumBackward0>)
loss_func = nn.CrossEntropyLoss(reduction='sum')  : tensor(147.5397, grad_fn=<NllLossBackward>)

值相同。

我想,因为这些是不同的功能,所以 grad_fn 是不同的,它 不会造成任何问题。

但是发生了一些事情!

4 个 epoch 后,损失值变为nan

myCEE相反,nn.CrossEntropyLoss 学习进展顺利。

所以,不知道是不是我的功能有问题。

在阅读了一些关于nan 问题的帖子后,我在模型中堆叠了更多的卷积。

结果 39-epoch 的训练没有出错。

不过,我想知道 myCEE 和 nn.CrossEntropyLoss 之间的区别

【问题讨论】:

【参考方案1】:

torch.nn.CrossEntropyLoss 与您的实现不同,因为当使用数值较大的值时,它使用一种技巧来对抗指数的不稳定计算。给定 logits 输出l_1, ... l_j, ..., l_n,softmax 定义为:

softmax(l_i) = exp(l_i) / sum_j(exp(l_j))

诀窍是将分子和分母都乘以exp(-β)

softmax(l_i) = exp(l_i)*exp(-β) / [sum_j(exp(l_j))*exp(-β)]
             = exp(l_i-β) / sum_j(exp(l_j-β))

那么 log-softmax 归结为:

logsoftmax(l_i) = l_i - β - log[sum_j(exp(l_j-β))]

实际上β被选为最高的logit值β = max_j(l_j)

您可以在这个问题上阅读更多相关信息:Numerically Stable Softmax

【讨论】:

非常感谢!你回答的正是我好奇的问题。

以上是关于pytorch 自定义损失函数 nn.CrossEntropyLoss的主要内容,如果未能解决你的问题,请参考以下文章

PyTorch 运行自定义损失函数

Pyotorch自定义损失函数

如何在 PyTorch 中添加自定义定位损失函数?

PyTorch自定义损失函数实现

pytorch自定义多分类损失函数怎么反向传播

PyTorch 中自定义后向函数的损失 - 简单 MSE 示例中的爆炸损失