04

交叉熵与困惑度——怎么衡量预测的好坏

阅读约 8 分钟第 4/60 课

上一章节说到,训练语言模型时,每个位置都要计算模型的预测「有多差」,然后根据这个数字调整参数。

但「多差」不能是一个模糊的感觉。机器需要一个精确的数字——这个数字必须满足两个条件:预测得好时它要小,预测得差时它要大;而且它必须是可以用数学推导出调整方向的(否则机器不知道旋钮该往哪边转)。

满足这两个条件的数字叫做交叉熵。它是整条训练的核心指标。

从一道选择题开始

想象你在做一道四选一的选择题。正确答案是 B。

情况一:你学得很好,你觉得 B 的可能性是 90%,A 是 5%,C 是 3%,D 是 2%。

情况二:你完全没复习,毫无头绪,四个选项各给 25%。

情况三:你学偏了,你非常确信答案是 A(90%),B 你只给了 3%。

哪种情况最糟糕?

直觉上很清楚:第三种最差——不仅错了,还错得很有信心,几乎完全排除了正确答案。第二种居中——虽然没信心,但至少没有把正确答案排除掉。第一种最好——正确答案得到了最高的概率。

交叉熵就是把这个直觉翻译成数字的工具。

交叉熵的公式

公式只有一行:

交叉熵 = −log(模型给正确答案的概率)

这里的 log 是自然对数。如果你没有接触过对数也不要紧——你只需要知道它的效果。让我们把三种情况都算出来:

情况 给正确答案(B)的概率 −log(概率) 好坏
情况一 90% 0.105 很好
情况二 25% 1.386 一般
情况三 3% 3.507 很差

数字越小越好。 给正确答案的概率越高,交叉熵越低。

如果你想自己验算,可以用 Python:

import math

print(-math.log(0.90))  # 输出 0.105
print(-math.log(0.25))  # 输出 1.386
print(-math.log(0.03))  # 输出 3.507

math.log 算的就是自然对数。前面加一个负号,让「好」对应小数字、「差」对应大数字。

为什么用 log 而不是直接用概率

你可能会想:直接用「正确答案的概率」来衡量不好吗?概率越高越好,概率越低越差,也很直观。为什么要多此一举取一个 log?

第一个原因:让乘法变成加法。

一段文本有很多个位置。如果你要衡量模型对整段文本的预测能力,需要把每个位置的概率乘起来。比如一段 100 个词的文本,假设每个位置正确答案的概率都是 0.1,那整段文本的联合概率就是:

0.1 × 0.1 × 0.1 × …(100 个 0.1 相乘)= 10 的 −100 次方

这个数字小到计算机无法精确存储——它会变成 0,丢失所有信息。

取 log 之后,乘法变成了加法:

log(0.1) + log(0.1) + … = 100 × log(0.1) = −230

−230 是一个普通的数字,计算机处理起来毫无压力。这就是为什么在实际训练中,几乎所有的概率计算都在 log 空间进行。

第二个原因:惩罚的轻重更合理。

看两个对比:

把正确答案的概率从 50% 降到 10%——交叉熵从 0.69 升到 2.30,增加了 1.61。 把正确答案的概率从 10% 降到 1%——交叉熵从 2.30 升到 4.61,增加了 2.31。

同样是降了 40 个百分点(50→10)和 9 个百分点(10→1),后者的交叉熵增长反而更大。为什么?因为从 10% 降到 1%,意味着模型几乎完全排除了正确答案——这是一种更严重的错误,应该受到更重的惩罚。

如果直接用概率,这两种降低在惩罚上的区别不够明显。log 放大了低概率区域的梯度,迫使模型优先避免「对正确答案给出极低概率」这种灾难性错误。

困惑度:交叉熵的翻译

交叉熵是 3.36。这到底意味着什么?好还是不好?跟什么比?

困惑度(perplexity)把交叉熵翻译成一个更直观的数字:

困惑度 = e 的交叉熵次方

e 约等于 2.718,是自然对数的底数。困惑度的含义可以这样理解:模型在每个位置相当于在多少个选项中平均地猜。

如果困惑度是 1,意味着模型每次都 100% 确信且 100% 正确——它在 1 个选项里「猜」,当然不会错。

如果困惑度是 10,意味着模型的不确定性相当于每次在 10 个等概率的选项中选一个。

如果困惑度是 100,那就是在 100 个选项中猜。

用一张表来展示 Sophia 训练过程中这个数字的变化:

训练阶段 交叉熵 困惑度 相当于
训练开始(参数随机) 11.39 ≈ 88,000 在近九万个词里随机猜
训练中期 5.5 ≈ 245 在 245 个词里猜
训练结束 3.36 ≈ 29 在 29 个词里猜

训练开始时,Sophia 的参数全是随机的,她对语言一无所知。面对每个位置,她就像面对一张九万个选项的选择题在随机涂答题卡。

训练结束时,她的困惑度降到了 29。她已经学会了语言的大部分规律——哪些词常跟在哪些词后面,什么样的句子是通顺的——虽然她在每个位置仍然面对约 29 个合理的选择(语言本身就有模糊性,很多位置确实有不止一种合理的接法),但她已经能把候选范围从九万缩小到三十。

在训练中,Loss 就是交叉熵

在语言模型训练的语境中,有好几个词指的是同一件事:

  • Loss(损失)
  • Training loss(训练损失)
  • Cross-entropy(交叉熵)

当你看到技术报告里说「train loss 从 11.39 降到 3.36」,它说的就是平均交叉熵从 11.39 降到了 3.36。

Loss 是训练的罗盘。训练程序每走一步(处理一批数据、调整一次参数),都会计算当前的 loss。如果 loss 在稳定下降,说明训练在正常进行——模型在变好。如果 loss 突然跳上去,说明出了问题——可能是学习率太大导致参数跳过了好的位置,或者数据有异常。如果 loss 不再下降了,说明模型已经从当前的数据中学到了它能学到的一切。

Sophia 的训练曲线从 11.39 平滑地降到 3.36,中间没有跳变、没有中断。这条曲线覆盖了 200 亿个 token——每一个 token 都在让她对语言的理解加深一点,直到最后。

回顾:训练的完整循环

到这里,你已经知道了训练语言模型的完整框架。让我们把前四个章节串起来:

1. 文本进来(第 03 章节)
   ↓
2. 模型预测下一个词的概率分布(第 03 章节)
   ↓
3. 交叉熵衡量预测有多差(本章节)
   ↓
4. 学习算法根据交叉熵调整参数(第 01 章节)
   ↓
5. 回到第 1 步,换下一段文本

这个循环重复 200 亿次,就是预训练。

但这里有一个还没回答的问题:文本到底是怎么「进来」的?模型只能处理数字,而文本是由汉字、英文字母、标点符号组成的。一个汉字在机器眼里是什么?一句话怎么变成一串数字?

这是下一个单元的问题。