目标非独热编码时如何在PyTorch中计算两张量的正确交叉熵
PyTorch计算非独热标签交叉熵的解决方案
PyTorch中可以通过两种方式实现和TensorFlow CategoricalCrossentropy完全一致的多分类交叉熵计算,完美适配非独热的软标签场景:
方案1:使用内置CrossEntropyLoss(PyTorch ≥ 1.10)
PyTorch 1.10及以上版本的CrossEntropyLoss已经原生支持软标签输入,只要目标张量和输入张量形状一致、为浮点型概率分布即可直接使用。
注意:
CrossEntropyLoss默认要求输入为未经过softmax的网络原始输出logits,内部会自动完成log_softmax计算,数值稳定性比手动归一化更高。如果你的输入已经是归一化后的概率分布,可以配合NLLLoss使用。
示例代码(和你的测试用例参数一致):
import torch import torch.nn as nn from math import log a = torch.Tensor([0.1, 0.2, 0.7]) # 已归一化的预测概率 y = torch.Tensor([0.2, 0.2, 0.6]) # 非独热的目标分布 # 输入为已归一化概率的场景,转对数概率后用NLLLoss计算 loss_fn = nn.NLLLoss() log_a = torch.log(a).unsqueeze(0) # 补充batch维度 y = y.unsqueeze(0) loss = loss_fn(log_a, y) # 手动计算验证结果 y_ = -0.2* log(0.1) - 0.2 * log(0.2) - 0.6 * log(0.7) print(loss.item(), y_) # 输出:0.9964095950126648 0.9964095674488687,和TensorFlow计算结果完全一致
方案2:手动实现(兼容所有PyTorch版本)
如果你的PyTorch版本较低,或者需要自定义计算逻辑,直接按交叉熵公式实现即可,代码非常直观:
import torch a = torch.Tensor([0.1,0.2,0.7]) y = torch.Tensor([0.2,0.2,0.6]) # 按公式计算,求和/平均可根据你的reduction需求调整 loss = -torch.sum(y * torch.log(a)) print(loss.item()) # 输出0.9964095950126648,和预期值完全匹配
为什么BCELoss不符合要求
BCELoss是针对二分类/多标签分类场景设计的,该场景下不同类别之间不互斥,每个类别独立做二分类判断,因此公式中会包含-(1-yi)*log(1-pi)项;而多分类交叉熵要求所有类别概率和为1、类别互斥,仅需计算-yi*log(pi)的求和,因此BCELoss不适用于该场景。
内容的提问来源于stack exchange,提问作者Zhongzheng_11
相关产品推荐
相关产品推荐

