本节摘要:损失函数把"这次输出与正确答案差多少"折算成一个数,训练的全部目标就是把它压小。分类任务的标准配置是 softmax 加交叉熵:softmax 把分数变成概率分布,交叉熵惩罚"正确类的概率不够高"。本节手算一组完整数值对齐框架结果,并交代回归任务的均方误差与标签平滑这个常用微调件。
流水线输出的是十个类别的分数,比如猫 2.0、狗 1.0、鸟 0.1。分数不是概率——它们可能为负、加起来也不为一。质检台要做的第一件事是把分数换成可比较的概率,第二件事是给"概率分布与正确答案的距离"定一个可优化的量。这两步的公式各只有一行,但值得把每个数都亲手算一遍——算过一次,以后看到损失曲线异常才有排查的底气。
阅读完本节,你应当能够:
softmax 对每个分数取指数再归一化:正的差距被放大、全体非负、总和归一。指数的底是自然常数 e,一笔账看得清清楚楚:
import torch logits = torch.tensor([2.0, 1.0, 0.1]) # 某个三分类头的原始输出 probs = torch.softmax(logits, dim=0) print([round(v, 4) for v in probs.tolist()]) # [0.659, 0.2424, 0.0986]
手工复核:e 的 2.0 次方约 7.389,1.0 次方约 2.718,0.1 次方约 1.105,合计 11.212;7.389 除以 11.212 得 0.659,后两个依次 0.242 与 0.099。分数 2.0 与 1.0 只差 1.0,概率上却拉开了 0.66 对 0.24——指数放大差距,这是 softmax 的性格。顺带一提数值安全:分数很大时指数会溢出,框架内部统一先减去最大值再算,结果不变,这属于框架替你踩过的坑。
质检的标准是正确答案的独热向量(猫为 1,其余为 0)。交叉熵定义为负的、按正确类概率取对数:损失 = −ln(正确类的概率)。接着上例,若正确答案是猫:损失 = −ln(0.659) ≈ 0.417。概率越接近 1 损失越贴近零;若模型把猫认成狗(猫的概率 0.242),损失跳到 −ln(0.242) ≈ 1.418——错得越离谱,罚得越重,且是对数级地重。
target = torch.tensor([0]) # 正确类别:猫(索引 0) ce = torch.nn.functional.cross_entropy(logits.unsqueeze(0), target) print(round(ce.item(), 4)) # 0.4170,与手算一致 wrong_target = torch.tensor([1]) # 假如正确答案其实是狗 print(round(torch.nn.functional.cross_entropy( logits.unsqueeze(0), wrong_target).item(), 4)) # 1.4170
为什么不用更直观的均方误差去拟合概率?梯度形状说了算:交叉熵配 softmax 时,误差对分数的梯度恰好是"预测概率减真实概率",错多少传多少,干净利落;均方误差的梯度里叠了一个 softmax 的雅可比,正确类概率接近零时梯度也接近零——错得最狠的地方反而最不使劲。分类选交叉熵不是品味,是算术。
不同任务的量具不同:回归用均方误差或 L1;多标签(一张图可同时有猫和狗)用对每个标签独立的二元交叉熵;类别严重不平衡时给损失加权,稀有类错一次罚得更重。微调件里最常用的是标签平滑:把独热目标的 1 改成 0.9、剩下的 0.1 摊给其他类,防着模型把训练集的噪声也背到满分——那正是过拟合的前奏。
K = 3 smooth = torch.full((K,), 0.1 / (K - 1)) # 其余类各 0.05 smooth[0] = 0.9 # 正确类 0.9 print(smooth.tolist()) # [0.9, 0.05, 0.05] log_probs = torch.log_softmax(logits, dim=0) loss_ls = -(smooth * log_probs).sum() print("平滑后损失:", round(loss_ls.item(), 4)) # 0.5028,略高于 0.4170
平滑把"满分执念"换成了"九分留余地",损失的下限不再是零——这个细节常被误读为"损失怎么降不下去",其实是量具换了刻度。
问:交叉熵能降到零吗?答:理论上要正确类概率精确等于一,softmax 永远给不出,实践中训练后期损失在零点零几徘徊属正常。问:多标签任务为什么不能用 softmax 加交叉熵?答:softmax 把各类概率互相挤压、总和归一,隐含"类别互斥"假设;多标签的类别彼此独立,要用逐标签独立的二元交叉熵。问:Focal Loss 是做什么的?答:在交叉熵前乘一个"降低易样本权重"的因子,把训练火力集中到难样本上,检测任务里常见,属于加权思想的精细化。
⚠️ 常见坑:把交叉熵直接喂给已经做过 softmax 的概率——等于连做两次,损失值会小得反常且训练停滞。用框架的 cross_entropy 时,入口应该是原始分数。
合格线能打分了,还差把打出的差距送回每个参数手里的管道。下一节走反向传播:误差如何倒流。