共计 1420 个字符,预计需要花费 4 分钟才能阅读完成。
信息论基础与 CE 推导
交叉熵(Cross-Entropy)本质是信息论的产物。要理解它,我们需要先明确三个概念:

-
信息熵:描述事件的不确定性,公式 $H(p)=-\sum p(x)\log p(x)$。比如抛硬币时,正面概率 0.5 的熵比 0.9 时更大。
-
KL 散度:衡量两个概率分布的差异,$D_{KL}(p||q)=\sum p(x)\log\frac{p(x)}{q(x)}$。注意它不对称,即 $D_{KL}(p||q) \neq D_{KL}(q||p)$。
-
交叉熵:可拆解为 $H(p,q)=H(p)+D_{KL}(p||q)$。当 p 是真实分布(one-hot 标签),$H(p)=0$,此时交叉熵等于 KL 散度。这就是分类任务中 CE 损失的理论依据。
CE vs MSE:为什么分类任务不用均方误差
- 梯度对比:
- MSE 的梯度包含 $(\hat{y}-y)\hat{y}(1-\hat{y})$,当预测值接近 0 / 1 时梯度消失
-
CE 的梯度简化为 $(\hat{y}-y)$,始终保持有效梯度
-
二分类示例:
假设真实标签 y =1,模型输出概率 0.01: - MSE 损失:$(1-0.01)^2=0.98$
- CE 损失:$-\log(0.01)=4.6$
CE 对错误预测的惩罚更严厉,更适合概率输出
代码实战:PyTorch 与 TensorFlow 实现
PyTorch 基础版
import torch.nn as nn
# 假设 3 分类任务,batch_size=2
logits = torch.randn(2, 3) # 未经 softmax 的模型输出
labels = torch.tensor([1, 2]) # 真实类别索引
loss_fn = nn.CrossEntropyLoss()
loss = loss_fn(logits, labels) # 内部自动做 log_softmax
处理类别不平衡(weight 参数)
class_weights = torch.tensor([0.2, 0.3, 0.5]) # 假设第 0 类样本少
loss_fn = nn.CrossEntropyLoss(weight=class_weights)
TensorFlow 实现
tf_loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
loss = tf_loss([1, 2], logits) # 标签不需要 one-hot
Label Smoothing 技术揭秘
传统 one-hot 标签会导致模型过度自信。标签平滑通过混合均匀分布来缓解:
- 原始标签:[0, 1, 0]
- 平滑后(ε=0.1):[0.05, 0.9, 0.05]
PyTorch 实现:
loss_fn = nn.CrossEntropyLoss(label_smoothing=0.1)
三大避坑指南
- log(0)问题:
- 总在 softmax 后加 epsilon(如 1e-8)
-
或直接使用
nn.CrossEntropyLoss(内部已处理) -
数值稳定性:
- 优先让模型输出 logits(未归一化),而非直接输出概率
-
使用
log_softmax而非分开计算 -
多标签任务:
- 普通 CE 要求单标签,多标签需改用
BCEWithLogitsLoss - 或对每个类别独立计算 CE
开放性问题
当类别数量极大时(如推荐系统中的百万级物品):
1. CE 计算涉及全体类别的 exp 求和,计算成本高昂
2. 改进方案包括:噪声对比估计(NCE)、分层 softmax、采样 softmax 等
你遇到过哪些 CE 损失的计算瓶颈?欢迎分享你的实战经验!
正文完
发表至: 未分类
近两天内
