你训练一个识图模型,给它看一张猫的图,它吐出一组概率:猫 70%、狗 20%、鸟 10%。猫的概率最高,看上去学得不错。但问题来了——你怎么用一个数告诉模型「你这次预测得离正确答案还差多远」?模型只会顺着这个数去调整自己,这个数给得不合适,它就学歪了。
把「预测」和「真相」的差距压成一个数,正是交叉熵(Cross-Entropy)干的事。它是几乎所有分类任务(图像识别、文本分类、语音转文字……)的标准损失函数,和 softmax 是一对黄金搭档。
先把预测和真相都看成一份「概率预算单」。真相很干脆:这张图 100% 是猫,所以真实分布是把所有预算都给猫、其余给 0;预测那份则分散在猫狗鸟三类上。交叉熵就是量这两份单子「差多大」的尺子——预测越像真相,分数越低;越偏离,分数越高。
先从信息熵说起:一个分布「有多确定」
交叉熵的前置概念是信息熵(information entropy)。铺垫一下,因为它和交叉熵只差一个字母。
气象局预报明天的天气,可能有三种表态:
- 「100% 下雨」——完全确定
- 「50% 下雨」——拿不准
- 「33% 下雨」——更不确定
一个分布越集中(概率堆在一个选项上),就越确定;越平均(概率分散到各选项),就越乱。信息熵就是量化这种「不确定程度」的数:
符号解读:
:一个概率分布,共 个类别,每个 是第 类的概率,全部加起来等于 1 :第 类在分布里占的概率 :对数函数(深度学习里通常取自然对数 )。当 时 是负数 - 前面的负号:把
的负数翻成正数,让最终结果非负 - 求和
:把每个类别的贡献加起来
通俗理解:分布越平均,
图 1:信息熵量化分布的「不确定性」——越集中 H 越小(确定),越平均 H 越大(乱)。
交叉熵:拿预测去「量」真相
交叉熵只把信息熵公式里的一个字符换掉:把「分布自己描述自己」的
符号解读:
:真实分布里第 类的概率(真相) :预测分布里第 类的概率(模型的猜测) :模型给第 类的「确信程度」—— 越接近 1, 越接近 0; 越接近 0, 越趋向负无穷 - 用
加权求和:真相越看重哪几类( 大),就重点看模型在那几类上预测得准不准( 大不大)
通俗理解:真相觉得重要的类别,模型也得给够概率;模型把真相看重的类预测得越准,交叉熵越小。一个关键性质:
图 2:交叉熵把信息熵公式里 log 内的「自己 pᵢ」换成「预测 qᵢ」——用预测描述真相。
分类里的简化:one-hot 标签让公式缩成一行
分类任务的真实标签通常是 one-hot(独热)编码:正确类别概率为 1,其余全为 0。比如真相是「猫」,三类问题里
把这个
也就是说,one-hot 标签下,交叉熵 = 模型给正确类预测的概率取负对数。模型给正确类的概率越高(
图 3:−log q 的曲线——正确类概率越接近 0,惩罚越陡(q=0 时趋于无穷大)。
计算示例:两个模型比一比
还是识别一张猫的图,真相是猫,所以
| 模型 | 交叉熵损失 | |||
|---|---|---|---|---|
| 模型 A | 0.7 | 0.2 | 0.1 | |
| 模型 B | 0.3 | 0.4 | 0.3 |
模型 A 给猫的概率高(0.7),损失小(0.357);模型 B 给猫的概率低(0.3),损失大(1.204)。
自检:两个损失都非负 ✓;给正确类概率越高、损失越小 ✓;若
和 Softmax 是黄金搭档:梯度干净成
分类模型的输出层通常长这样:网络先吐一组原始得分(logits
softmax + 交叉熵组合后,损失对原始得分
也就是预测概率减真实标签(
比如真相是猫(
正因为推导简洁、数值稳定、训练信号直接,PyTorch 把这两步合成一个 API:nn.CrossEntropyLoss(内部先做 softmax 再算交叉熵)。你喂它原始 logits,它自动处理一切。一个常见坑:如果模型 forward 里已经手动加了 softmax,再喂给 CrossEntropyLoss 等于做了两次 softmax,模型会学坏。
图 4:softmax + 交叉熵组合后,损失对原始得分的梯度干净成 ŷ − y,反向传播信号直接。
和 MSE 对比:为什么分类任务不用 MSE
均方误差
- 梯度饱和,学得慢(最致命):分类模型最后一层通常套 softmax 或 sigmoid,这俩函数在输出接近 0 或 1 时曲线很平(梯度趋近 0)。MSE 配合它们时,损失对参数的梯度里会乘上这个接近 0 的因子,导致模型尤其在预测严重偏离时反而学不动——而那恰恰是最该使劲学的时候。交叉熵和 softmax 组合后梯度是
,不带这条「平尾巴」,训练信号一路通畅。 - 概率语义不匹配:MSE 衡量的是「数值差」,但分类预测的是概率。把正确类的概率从 0.01 提到 0.1,和从 0.9 提到 0.99,难度和意义都不同——前者是「从几乎全错到开始摸到边」,后者是「从很对到更对」。交叉熵里的
正好捕捉这种「概率越接近 0,惩罚越陡」的非线性代价。 - 优化曲面更友好:MSE 配合 sigmoid/softmax 会让损失曲面多出局部最小,优化容易卡住;交叉熵配合 softmax 的曲面更光滑,容易收敛到好解。
一句话:MSE 适合「预测一个数」,交叉熵适合「预测一个概率分布」——分类任务输出的是分布,所以选交叉熵。
完整代码
下面这段代码训练一个 3 分类小模型(4 维特征 → 猫 / 狗 / 鸟),演示 nn.CrossEntropyLoss 怎么用、怎么对上公式。整体流程:搭网络(吐 logits)→ 备假数据 → 训练多轮(CrossEntropyLoss 内部 softmax + 交叉熵算损失 → 反向 → 更新)→ 测试看学会没。带着这个地图读下面的逐行注释:
import torch
import torch.nn as nn
# ===== 任务:4 维特征 → 3 分类(猫 / 狗 / 鸟)=====
class Classifier(nn.Module): # nn.Module:所有神经网络模块的基类,自定义网络都继承它
def __init__(self, in_dim, num_classes):
super().__init__()
# 全连接层:把输入特征映射到 num_classes 个原始得分(logits)
self.fc = nn.Linear(in_dim, num_classes)
def forward(self, x):
# 关键坑:这里故意不加 softmax!
# 因为 nn.CrossEntropyLoss 内部会先 softmax 再算交叉熵,
# 这里再加一次等于做了两次 softmax,模型会学坏。
return self.fc(x) # 输出 logits z(对应公式里的 z)
torch.manual_seed(42) # 固定随机种子,让每次运行结果一样(可复现)
model = Classifier(in_dim=4, num_classes=3)
# CrossEntropyLoss = softmax + 交叉熵 H(p, q),喂整数标签时内部自动转 one-hot
loss_fn = nn.CrossEntropyLoss()
opt = torch.optim.SGD(model.parameters(), lr=0.1) # SGD 优化器,lr 是步长
# ===== 假数据:3 个样本,标签分别是猫(0)、狗(1)、鸟(2) =====
x = torch.randn(3, 4) # torch.randn:生成标准正态分布随机数当假特征
y = torch.tensor([0, 1, 2]) # 真实类别编号(0/1/2);CrossEntropyLoss 直接收这种整数标签
# ===== 训练 60 轮,看损失怎么降 =====
for epoch in range(60):
logits = model(x) # 前向:得到 logits(没加 softmax)
loss = loss_fn(logits, y) # 算交叉熵:内部先 softmax 得 q̂,再按 -log q̂_正确类 求平均
opt.zero_grad() # 清空上一轮的梯度
loss.backward() # 反向传播:自动算每个参数的梯度(梯度结论就是 ŷ − y)
opt.step() # 优化器走一步:用梯度更新参数
# ===== 测试:看模型对训练样本的预测概率 =====
with torch.no_grad(): # 推理阶段不需要算梯度,关掉省内存
logits = model(x)
probs = torch.softmax(logits, dim=1) # 手动套 softmax 看概率;dim=1 表示按行归一化(每行和为 1)
preds = probs.argmax(dim=1) # argmax:挑每行最大值的序号作为预测类别
print(f"预测概率:\n{probs}")
print(f"预测类别: {preds.tolist()}(标准答案 [0, 1, 2])")
print(f"训练结束 loss: {loss.item():.4f}")运行后你会看到:随训练轮次推进 loss 逐渐下降,最终 preds 接近 [0, 1, 2](三个样本都分对了),probs 每行最大的那个都落在正确类别上——CrossEntropyLoss 配合 softmax 真的驱动模型学会了这个 3 分类任务。
小结
一句话浓缩:交叉熵是衡量「预测概率分布」与「真实标签分布」差异的尺子;one-hot 标签下它退化成「正确类概率的负对数」,和 softmax 组合后梯度干净成 nn.CrossEntropyLoss,就知道它内部正悄悄做 softmax + 交叉熵,用一把「概率的尺子」量出模型离真相还差多远。
参考资料
- Softmax Regression — Dive into Deep Learning(李沐等,经典教材,从最大似然推出交叉熵) https://d2l.ai/chapter_linear-classification/softmax-regression.html
- A Gentle Introduction to Cross-Entropy for Machine Learning — Machine Learning Mastery(从信息熵讲到交叉熵的入门长文) https://machinelearningmastery.com/cross-entropy-for-machine-learning/
- 深度学习——Softmax 与交叉熵:从原理到梯度推导 - 博客园(含
梯度的完整推导) https://www.cnblogs.com/smartljy/p/18819629