PPL 是什么:把模型困惑度理解成平均岔路数

用 Qwen2.5-7B 的 llama-perplexity 实测结果,讲清 PPL、交叉熵和量化质量评估之间的关系。

PPL 是什么:把模型困惑度理解成平均岔路数

今天 Day 10 跑了第一份 llama-perplexity 结果:

Qwen2.5-7B-Instruct-Q4_K_M
WikiText-2 validation
ctx=512, chunks=16
Final estimate: PPL = 6.8790 +/- 0.30335

看到 PPL=6.8790 最容易产生一个问题:

这到底好不好?它在说模型错了 6.879 次吗?

不是。

这篇只讲一个直觉:PPL 可以先理解成模型预测下一个 token 时的“平均有效岔路数”。

如果 PPL=8,人话是:

模型在这个评测语料上,每一步预测正确下一个 token 的平均不确定性,
大致相当于在 8 个同样可能的 token 里选。

这个说法不是严格描述每一个位置都有 8 个候选,而是一个很好用的等价直觉。真实文本里,有的位置很容易,有的位置很难;PPL 把这些难度压成一个数。

1. 先用考试题理解:越不确定,PPL 越高

想象一个选择题考试,每题都有一个正确答案。

如果你每题都很确定,给正确答案很高概率:

正确答案概率 ≈ 1.0

那你的困惑度接近:

PPL ≈ 1

这表示几乎没有岔路:模型基本知道下一个 token 应该是什么。

如果你每题都在 8 个选项之间平均瞎猜:

每个选项概率 = 1/8
正确答案概率 = 1/8

那困惑度就是:

PPL = 8

这就是“平均岔路数”的来源。

LLM 的下一个 token 预测也是类似的题目。每一步,模型面对整个 vocab,比如 Qwen2.5 的输出词表行数大约是 15 万级,然后给每个 token 一个概率。评测时,我们已经知道真实文本的下一个 token 是什么,于是只看一件事:

模型给真实下一个 token 分了多高概率?

分得越高,模型越不困惑。分得越低,模型越困惑。

2. 最小数学地基:概率、log、交叉熵、PPL

先不要怕公式。这里只需要四个小概念。

2.1 概率:模型押中了多少信心

假设真实下一个 token 是 学习

模型可能输出这样的概率:

P("学习") = 0.50
P("工作") = 0.20
P("模型") = 0.10
...

这表示模型给正确答案 学习 的信心是 50%。

另一个模型可能是:

P("学习") = 0.05
P("工作") = 0.20
P("模型") = 0.18
...

这时它虽然不一定“输出错”,但它对真实答案的信心很低。PPL 惩罚的就是这种低信心。

2.2 负 log:把“低概率”变成“高惩罚”

交叉熵里会出现 -log(p)

先看几个数:

p = 1.00  -> -ln(p) = 0.000
p = 0.50  -> -ln(p) = 0.693
p = 0.25  -> -ln(p) = 1.386
p = 0.125 -> -ln(p) = 2.079

你不需要先背自然对数,只要抓住方向:

正确答案概率越低,-log(p) 越大,惩罚越重。

为什么不用 1 - p 这么简单的惩罚?因为语言模型是连乘问题。一篇文本里每个 token 的概率要连起来,很多小概率相乘会变成极小的数字。log 可以把连乘变成求和,计算更稳定,也更容易平均。

2.3 交叉熵:平均每一步有多意外

如果一段文本有 N 个 token,模型每一步都给真实 token 一个概率:

p1, p2, p3, ..., pN

交叉熵就是:

cross_entropy = - (log(p1) + log(p2) + ... + log(pN)) / N

人话:

平均每一步,真实答案让模型有多意外。

越意外,交叉熵越高。

2.4 PPL:把交叉熵还原成“有效岔路数”

PPL 是 perplexity,通常这样算:

PPL = exp(cross_entropy)

也就是把交叉熵从 log 空间还原回来。

如果:

cross_entropy = ln(8)

那么:

PPL = exp(ln(8)) = 8

所以 PPL=8 可以读成:

平均不确定性约等于每步在 8 个同样可能的候选里选。

更严格一点,它等价于正确 token 概率倒数的几何平均:

PPL = (1 / p1 * 1 / p2 * ... * 1 / pN)^(1/N)

如果这句看着绕,就记前面那句:平均有效岔路数

3. 一个三步小例子:为什么不是简单平均

假设只有 3 个 token 要预测,模型给真实 token 的概率分别是:

第 1 步:0.50
第 2 步:0.25
第 3 步:0.125

对应的倒数是:

2, 4, 8

如果粗暴做算术平均:

(2 + 4 + 8) / 3 = 4.67

但 PPL 用的是几何平均:

(2 * 4 * 8)^(1/3) = 4

为什么是几何平均?因为整段文本的概率是每一步概率相乘,不是相加:

0.50 * 0.25 * 0.125

乘法世界里,对应的平均方式就是几何平均。交叉熵里的 log,就是为了把这个乘法世界搬到加法世界里算。

4. 回到今天的实验:PPL=6.8790 怎么读

今天命令是:

llama-perplexity \
  -m ./models/Qwen2.5-7B-Instruct-Q4_K_M.gguf \
  -f ./data/wikitext-2-valid.txt \
  -ngl 99 \
  -c 512 \
  --chunks 16 \
  --no-warmup

语料是 WikiText-2 validation 的一个本地副本,来源是 PyTorch examples 里的 wikitext-2 数据文件:

https://raw.githubusercontent.com/pytorch/examples/main/word_language_model/data/wikitext-2/valid.txt

这次只跑了 16 个 chunks,所以它是 Day 10 的入门基线,不是完整排行榜评测。结果是:

Final estimate: PPL = 6.8790 +/- 0.30335

人话解释:

在这段 WikiText-2 validation 切片上,
这个 Q4_K_M 量化模型预测下一个 token 的平均不确定性,
大约相当于每步在 6.88 个同样可能的 token 里选。

它不是说模型每 6.88 个 token 错一次,也不是说模型每次真的只看 6.88 个候选。它说的是一种平均不确定性。

+/- 0.30335 是估计误差范围。因为只跑了有限 chunks,结果会有波动。跑更多 chunks、固定同一套评测设置,数字会更稳定。

5. 为什么量化实验常用 PPL 当质量标尺

量化的核心问题是:

模型变小、变快以后,质量掉了多少?

如果只看生成样例,会很不稳定。同一个 prompt,采样参数一变、随机种子一变,输出就会变。人肉读 20 段回答也很主观。

PPL 的价值在于它更可重复:

同一个模型
同一个 tokenizer
同一个评测语料
同一个 context length
同一个 perplexity 命令

在这些条件固定时,你可以比较:

FP16:    PPL = ?
Q8_0:    PPL = ?
Q5_K_M:  PPL = ?
Q4_K_M:  PPL = ?

如果 Q4_K_M 比 FP16 的 PPL 只高一点点,但模型小很多、decode 更快,那就是很好的速度/质量 tradeoff。

所以 PPL 是量化实验里常见的第一道质量门槛:

PPL 没明显变差 -> 量化大概率没有严重损伤 next-token 能力
PPL 明显变差   -> 量化可能把模型的语言建模能力打坏了

注意这只是“第一道门槛”,不是全部质量。

6. PPL 的边界:它能说明什么,不能说明什么

PPL 能比较的是:

模型对某个语料的 next-token prediction 有多好。

它很适合看:

同模型不同量化版本
同语料下的质量退化
同设置下的 checkpoint 对比

但它不能直接说明:

这个模型是不是更会聊天
这个模型是不是更安全
这个模型是不是更会写代码
这个模型是不是更懂中文用户意图

原因很简单:WikiText 这种语料测的是语言建模,不是指令遵循。一个模型 PPL 更低,通常表示它更会预测这类文本;但真实产品还关心对齐、推理、工具调用、长上下文、格式遵循和安全边界。

所以正确用法是:

PPL 用来做量化质量的基础体检;
任务评测和人工检查用来做真实能力诊断。

7. 最后用三句话记住

第一句:

PPL 是 exp(cross_entropy)。

第二句:

PPL=8 可以理解成平均每步有 8 条有效岔路。

第三句:

量化实验用 PPL,是因为它能在固定语料和设置下,稳定衡量 next-token 预测质量有没有明显退化。

如果下一次看到:

Q4_K_M PPL = 6.88
Q5_K_M PPL = 6.72
Q8_0   PPL = 6.65

你应该先问:

它们是不是同一个语料、同一个 tokenizer、同一个 context length、同一个评测命令?

如果不是,这些数字不能直接比。

自检

不看上文,试着回答三题:

  1. PPL=8 是不是“每 8 个 token 错一个”?为什么?
  2. 交叉熵和 PPL 的关系式是什么?
  3. 为什么 PPL 可以比较量化质量,但不能完全代表聊天体验?