交叉熵与负对数似然:今天真正弄懂
先记住:一句话定义 + 一句记忆口诀
交叉熵和负对数似然,本质是在问一句话:模型给正确答案的概率有多高,越高损失越小,越低损失越大。
记忆口诀:
“先 softmax 成概率,再取真类的负 log。”
更短一点:
“真类概率越大,loss 越小。”
一、生活类比
假设你在做一道选择题。
题目是:这段音频是谁在说话?
正确答案是:说话人 B。
模型给出预测:
A:0.10 B:0.70 C:0.20
模型把 70% 的信心给了正确答案 B。 这还不错,所以损失不大。
如果模型给出:
A:0.80 B:0.01 C:0.19
它只给正确答案 B 1% 的信心。 这很糟糕,所以损失很大。
交叉熵就是这样打分:
不是只看“猜没猜对”。 而是看“你给正确答案的信心有多足”。
二、必要公式
分类任务里,交叉熵常写成:
\[ H(y, p) = - \sum_{i=1}^{C} y_i \log(p_i) \]
逐个解释:
- \(C\):类别数。比如 3 个说话人,就是 \(C=3\)。
- \(i\):第几个类别。
- \(y_i\):真实标签的 one-hot 表示。
- 如果正确类是 B,则 \(y=[0,1,0]\)。
- \(p_i\):模型预测第 \(i\) 类的概率。
- 例如 \(p=[0.1,0.7,0.2]\)。
- \(\log\):对数,通常是自然对数。
- 前面的负号 \(-\):因为概率小于 1 时,\(\log(p)\) 是负数,加负号后变成正的损失。
如果标签是 one-hot,上面的公式会简化。
例如正确类是第 \(k\) 类:
\[ H(y,p) = -\log(p_k) \]
这就是负对数似然:
\[ NLL = -\log(p_{\text{true}}) \]
逐个解释:
- \(p_{\text{true}}\):模型分给真实类别的概率。
- \(-\log(\cdot)\):把“概率越大越好”变成“损失越小越好”。
三、看几个数字
如果模型给正确类的概率是:
\[ p_{\text{true}}=0.9 \]
损失是:
\[ -\log(0.9) \approx 0.105 \]
很小。
如果:
\[ p_{\text{true}}=0.1 \]
损失是:
\[ -\log(0.1) \approx 2.303 \]
很大。
如果:
\[ p_{\text{true}}=0.001 \]
损失是:
\[ -\log(0.001) \approx 6.908 \]
非常大。
所以它很“讨厌”模型对正确答案过度不自信。
四、它解决什么问题
它解决的是分类模型的训练问题。
模型输出一堆分数。 训练时需要告诉模型:
“你这次预测有多差?”
这个“差”的量,就是 loss。
对于分类任务,交叉熵特别合适,因为它关心:
- 正确类概率是否高。
- 错误类概率是否被压低。
- 模型有没有过度自信地选错。
没有它会怎样?
如果只用准确率:
- 准确率不可导,不能直接拿来反向传播。
- 它太粗糙。
- 0.51 猜对和 0.99 猜对,都算对。
- 0.49 猜错和 0.001 猜错,都算错。
- 训练信号不细。
交叉熵更细:
- 0.99 给正确类,奖励更大。
- 0.51 给正确类,虽然对了,但还不够稳。
- 0.001 给正确类,会被重罚。
这很适合神经网络学习。
五、主流用法
在 PyTorch 里,最常见的是:
loss_fn = torch.nn.CrossEntropyLoss()
loss = loss_fn(logits, labels)注意:
输入不是 softmax 后的概率。 输入是 logits。
logits 是模型最后一层输出的原始分数。
例如:
logits = [2.0, 5.0, 1.0]它还不是概率。 经过 softmax 后才是概率。
PyTorch 的 `CrossEntropyLoss` 内部大致做了两步:
CrossEntropyLoss = LogSoftmax + NLLLoss也就是:
- 先把 logits 变成 log 概率。
- 再取真实类别对应位置的负 log 概率。
学习资料建议:
- PyTorch CrossEntropyLoss 文档:适合重点看 logits、标签格式、reduction 参数。
- Dive into Deep Learning 的信息论章节:适合理解熵、交叉熵为什么和“不确定性”有关。
交叉熵一句话是什么?
CrossEntropyLoss 和 NLLLoss 的关系是什么?
为什么分类任务通常不用准确率直接训练?
一、发展流程:之前怎么做
早期做分类,常见想法是:
- 直接比较预测类别和真实类别。
- 看准确率。
- 或者用平方误差。
例如真实标签是 one-hot:
真实:[0, 1, 0]
预测:[0.2, 0.6, 0.2]可以用均方误差:
\[ MSE = \sum_i (y_i - p_i)^2 \]
这也能用。 但对分类问题不够自然。
因为分类的核心不是“数值离得多近”。 而是“给真实类别的概率有多大”。
二、为什么出现交叉熵
分类模型常把输出看成概率分布。
比如:
A: 0.1
B: 0.7
C: 0.2真实答案也可以看成一个分布:
A: 0
B: 1
C: 0训练目标就是:
让预测分布接近真实分布。
交叉熵正好衡量:
“如果真实分布是 y,但你用预测分布 p 来编码,会有多浪费。”
在深度学习里,可以简单理解成:
“模型给正确答案的概率越低,付出的代价越大。”
三、现在怎么用
现在它是分类任务的默认损失之一。
常见位置:
1. 图像分类 最后一层输出每个类别的 logits,然后接 CrossEntropyLoss。
2. 音频事件分类 输入一段声音,判断是咳嗽、笑声、音乐、噪声等。
3. 说话人识别 输入一段语音 embedding,分类到某个 speaker ID。
4. 视频动作分类 输入视频片段,输出动作类别,例如走路、坐下、挥手。
5. 语音识别或语言模型中的 token 预测 每个时间步预测下一个 token,通常也是交叉熵。
四、在音视频理解与说话人日志中的实际位置
- 音频分类
流程通常是:
音频 waveform
→ 特征,如 log-mel spectrogram
→ encoder
→ 分类头
→ logits
→ CrossEntropyLoss比如判断一段音频是不是:
speech / music / noise- 视频分类
流程通常是:
视频帧
→ video encoder
→ pooling
→ 分类头
→ logits
→ CrossEntropyLoss比如判断:
说话 / 沉默 / 转场 / 手势- 说话人识别
流程:
语音片段
→ speaker encoder
→ speaker embedding
→ linear classifier
→ speaker logits
→ CrossEntropyLoss训练时用 speaker ID 作为标签。 模型学会把同一个说话人的 embedding 拉到相似区域。
- 说话人日志 diarization
说话人日志常问:
“什么时候谁在说话?”
它可能包含多个子任务:
- 语音活动检测:这一帧有没有人说话。
- 说话人变化检测:这里是不是换人了。
- 说话人分类:这一段属于哪个已知说话人。
- 多说话人活动预测:某个时间段哪些人同时说话。
其中,只要任务被建成分类问题,就可能用交叉熵。
例如:
每一帧:speech / non-speech可以用二分类交叉熵。
如果是:
speaker A / speaker B / speaker C可以用多分类交叉熵。
但注意:真实 diarization 往往有重叠语音、未知说话人、聚类步骤。 不是所有环节都只是一个简单 CrossEntropyLoss。
五、与相近概念的区别
- 交叉熵 vs 负对数似然
在 one-hot 分类里,它们几乎是同一个东西。
交叉熵:
\[ -\sum_i y_i \log(p_i) \]
如果 \(y\) 是 one-hot,只剩真实类那一项:
\[ -\log(p_{\text{true}}) \]
这就是负对数似然。
简单说:
- 交叉熵:从两个分布的角度看。
- 负对数似然:从“真实答案的概率有多大”的角度看。
- 在普通多分类训练里,二者常常等价。
- CrossEntropyLoss vs NLLLoss
在 PyTorch 中:
- `CrossEntropyLoss` 接收 logits。
- `NLLLoss` 接收 log-probabilities。
也就是说:
CrossEntropyLoss(logits, labels)大致等价于:
NLLLoss(LogSoftmax(logits), labels)常见错误:
不要先 softmax 再传给 `CrossEntropyLoss`。 因为它内部已经会处理。
- 交叉熵 vs softmax
softmax 不是 loss。 softmax 是把 logits 转成概率的函数。
交叉熵是 loss。 它拿预测概率和真实标签算损失。
关系:
logits → softmax → probabilities → cross entropy但 PyTorch 的 `CrossEntropyLoss` 把 softmax/log-softmax 放在内部做了。
- 交叉熵 vs KL 散度
KL 散度衡量两个分布差多少:
\[ KL(y||p) \]
交叉熵和 KL 有关系:
\[ H(y,p)=H(y)+KL(y||p) \]
如果真实分布 \(y\) 固定,最小化交叉熵等价于最小化 KL。
但初学时先记:
- 交叉熵:训练分类器常用。
- KL:比较两个概率分布差异常用。
- 交叉熵 vs 均方误差
均方误差更适合回归。 例如预测年龄、温度、坐标。
交叉熵更适合分类。 例如预测类别、speaker ID、token ID。
六、当前局限
事实部分:
1. 它需要可靠标签。 标签错了,模型会被训练去相信错误答案。
2. 它容易鼓励过度自信。 模型可能给某类 0.999 的概率,但其实并不一定真的那么有把握。
3. 类别不平衡时会有问题。 如果“非语音”样本远多于“语音”样本,模型可能偏向多数类。
4. 对开放集不天然友好。 训练中只有 A、B、C 三个说话人,测试时来了未知说话人 D,普通交叉熵不会自动解决。
5. 对多标签任务要小心。 如果同一时间可能有多个说话人同时说话,普通多分类交叉熵不合适。 这时常用 binary cross entropy 处理每个说话人是否活跃。
七、未来可能作用
事实部分:
交叉熵现在仍是深度学习中最基础、最常用的训练目标之一。 在分类、token 预测、说话人识别、音频事件识别中仍然大量使用。
推测部分:
未来它可能继续作为基础损失存在。 但会更多和其他方法组合:
- 类别不平衡时,配合 class weight、focal loss 等。
- 标签不确定时,配合 label smoothing。
- 开放集说话人任务中,配合 metric learning 或聚类方法。
- 多模态模型中,配合对比学习、匹配损失等。
但这些是扩展。 基础还是那句话:
“让模型把概率放到正确答案上。”
- 1. 如果正确类别概率从 0.8 降到 0.2,交叉熵损失会变大还是变小?为什么?
- 2. PyTorch 的 CrossEntropyLoss 输入应该是 logits 还是 softmax 后的概率?标签应该是什么形状?
- 3. 在说话人日志中,什么时候适合用多分类交叉熵,什么时候更适合用 binary cross entropy?