torch.nn 中分类损失的标准入口:吃 raw logits,内部融合 log_softmax 与 NLLLoss。本篇只讲 API 约定与工程用法,数学定义与数值例见 交叉熵损失。

输入约定:raw logits,不是概率

这个损失最大的坑不在参数,而在喂进去什么:未经 softmax 的 logits。内部实现等价于 log_softmax + NLLLoss 融合成单个 kernel,借 LogSumExp 保证数值稳定;数学定义已被完全封装,用户侧要锁死的是输入契约——pred 形状 (N, C),target 形状 (N,) 且为类别索引而非 one-hot(从 Keras 迁来的习惯最容易在这翻车):

import torch
import torch.nn as nn
 
logits = torch.randn(4, 3)           # (N, C):raw logits,未归一化
target = torch.tensor([0, 2, 1, 1])  # (N,):类别索引,不是 one-hot
 
loss = nn.CrossEntropyLoss()
print(loss(logits, target))          # 标量,默认 reduction='mean'

最经典的新手 bug

先手动 softmax 再传入。概率被归一化两次,反向传播要连乘两层 softmax 的 Jacobian,梯度被压扁,训练迟滞甚至停滞。网络最后一层 Linear 直接接损失,中间什么都不加。

高维输入与 ignore_index

二维之外,语义分割的输出是 (N, C, H, W),target 为 (N, H, W) 的逐像素类索引——此时 padding 像素必须剔出损失,否则填充区域会污染梯度。ignore_index 负责这件事,惯例取 -100:

logits = torch.randn(2, 5, 4, 4)         # (N, C, H, W):5 类分割输出
target = torch.randint(0, 5, (2, 4, 4))
target[:, :, -1, :] = -100               # 最后一行标记为 padding
 
loss = nn.CrossEntropyLoss(ignore_index=-100)
print(loss(logits, target))              # -100 像素不计入损失

padding 处理是一套组合拳:输入端 nn.Embedding 用 padding_idx 让填充 token 的向量恒为 0,损失端 ignore_index 把它剔出统计,两端各管一半。

面向真实数据的三个旋钮

默认参数对应均衡的 toy 数据;真实数据带来两个新问题——类别不平衡、one-bit 硬目标——外加工程上的聚合需求,正好对应三个参数。weight 给第 类损失乘 (稀有类 ),是类不平衡的初阶工具;label_smoothing 把目标从 one-hot 软化为 ,抑制过度自信;reduction 三态 mean(默认)/sum/none 决定聚合方式:

loss = nn.CrossEntropyLoss(
    weight=torch.tensor([1.0, 8.0, 1.0]),  # 第 2 类稀有,损失乘 8
    label_smoothing=0.1,                    # 目标软化,不再非 0 即 1
    reduction='none',                       # 返回 (N,) 逐样本损失
)
per_sample = loss(torch.randn(4, 3), torch.tensor([0, 2, 1, 1]))
print(per_sample.shape)                     # torch.Size([4])

三态里 'none' 是自定义场景的钥匙:加权聚合、OHEM 难例挖掘、跨 batch 的梯度累积,都要先拿到逐样本值再自己算——默认的 'mean' 会直接把这条路封死。

边界:什么时候不该用它

以上所有用法共用一个前提:类别互斥、每样本恰有一个正确答案。前提一塌就换工具——多标签场景(一个样本可同属多类)用 BCEWithLogitsLoss,每维独立 sigmoid、独立算 BCE,与互斥 softmax 是两条路;类不平衡走到深处,weight 的线性加权不够用,自然延伸到难例加权的 focal loss。

落到实践,损失函数 体系里这个模块的契约一句话锁死:输入给 logits、目标给索引、padding 给 -100,旋钮按数据状况加。