nn.crossentropyloss底层融合logsoftmax与nllloss,需输入raw logits而非概率;输入须为(n,c)形状logits,标签须为(n,)形状int64类索引;仅推理时在torch.no_grad下用torch.softmax解释结果。

nn.CrossEntropyLoss 自带 Softmax,是因为它底层直接融合了 LogSoftmax 和 nn.NLLLoss,不是“加了个 Softmax”,而是用数值稳定的 fused kernel 一次性完成 logits → log-probabilities → loss 的全过程。你传进去的必须是 raw logits(任意实数),不能是概率或 softmax 输出。
训练时显式调用 torch.softmax 会怎样
会导致双 softmax:一次是你写的 torch.softmax(x, dim=1),另一次是 nn.CrossEntropyLoss 内部再做一遍。结果不是“多归一化一次”那么简单——概率被过度挤压,logits 经过两次指数+归一后梯度极小,loss 突然飙升甚至变成 nan。
- 典型错误写法:
x = self.fc(x); x = torch.softmax(x, dim=1); loss = criterion(x, target) - 正确写法:
x = self.fc(x); loss = criterion(x, target)(中间不插任何激活) - 验证方法:打印
x.max()和x.min(),如果值域在[0, 1]且每行和 ≈ 1,说明你误加了 softmax
nn.CrossEntropyLoss 对输入和标签的格式要求很严格
它不吃概率,只认 logits;也不吃 one-hot 标签,只认 class index。这两个点出错,loss 可能看起来“正常下降”,但模型根本不学。
-
input形状必须是(N, C)(N 个样本,C 个类别),值为未归一化的原始分数 -
target形状必须是(N,),每个元素是int64类型,取值范围为[0, C-1] - 如果 dataloader 返回的是 one-hot label(如
torch.Size([N, C])),得先转:target = target.argmax(dim=1) - 千万别用
torch.nn.functional.one_hot去构造 target——nn.CrossEntropyLoss会直接报错或静默失败
什么时候真需要手动调用 torch.softmax
只在 inference 阶段,且仅用于解释性目的:比如可视化预测置信度、做阈值过滤、导出人类可读结果。此时必须确保:
- 在
with torch.no_grad():下调用,避免污染计算图 - 用的是
torch.softmax(logits, dim=1),不是log_softmax - 绝对不要把它写进
model.forward()主干路径——否则训练/推理行为不一致,TorchScript 或 ONNX 导出可能失败 - 部署时若需固定输出概率,应单独封装 inference wrapper,而非修改模型结构
最常被忽略的其实是三件事:logits 分布是否合理、target 类型是否为 torch.long、grad norm 是否随 epoch 缓慢下降。别光盯着 loss 曲线——它可能骗人。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











