采样不是玄学:从 logits 到 temperature、top-k、top-p
Day 10 我们用 llama-perplexity 看模型质量:模型对真实下一个 token 有多确定。
Day 11 换一个问题:
模型已经算出了下一个 token 的分数,推理程序到底怎么选出最后那个 token?
这就是采样。
很多人第一次接触采样参数,会把它们记成几句口号:
temperature 越高越有创造力
top-k 限制候选数量
top-p 限制概率范围
这些说法不算错,但太像菜单说明。真正要建立的是这条链路:
hidden state -> unembed -> logits -> softmax -> probability distribution -> sampling -> token
这篇只拆最后三步:logits 怎么变成概率,temperature 怎么改变概率分布,top-k/top-p 又怎么把候选 token 截掉。
1. 先用人话说:采样是在一堆候选里抽签
LLM 每生成一个 token,都不是直接吐出一句完整的话。
它每一步只做一件事:
给词表里每个 token 打一个分,然后选一个 token。
Qwen2.5 的词表是 15 万级。假设当前 prompt 是:
写一句关于秋天的诗。
模型可能觉得下一个 token 有这些候选:
秋 分数很高
金 分数也高
一 分数中等
猫 分数很低
GPU 分数极低
这些“分数”还不是概率。它们叫 logits。
你可以先把 logit 理解成:
模型在 softmax 之前给每个候选 token 的原始偏好分。
logit 越大,token 越可能被选中;但 logit 本身不要求加起来等于 1,也不一定在 0 到 1 之间。所以推理程序需要先把 logits 变成概率分布。
这个转换就是 softmax。
2. 最小数学地基:softmax 只做三件事
先不要背公式。softmax 做的事可以拆成三步:
第一步:把每个分数变成正数。
第二步:把所有正数加起来。
第三步:每个正数除以总和,得到概率。
举一个小例子。假设只有 3 个候选 token:
秋:4
金:2
猫:1
这些数字是 logits。
softmax 会先做指数变换。这里你不用深究自然底数,只要抓住一个直觉:指数会放大差距。
exp(4) ≈ 54.6
exp(2) ≈ 7.4
exp(1) ≈ 2.7
总和是:
54.6 + 7.4 + 2.7 = 64.7
所以概率大约是:
P(秋) = 54.6 / 64.7 ≈ 0.84
P(金) = 7.4 / 64.7 ≈ 0.11
P(猫) = 2.7 / 64.7 ≈ 0.04
这就是:
softmax(logits)
如果要写公式,就是:
P(token_i) = exp(logit_i) / sum(exp(logit_j))
公式里看起来吓人的东西,其实就是“先变正数,再求总和,再除以总和”。
3. temperature:不是创造力旋钮,而是分数差距缩放器
采样里的 temperature 进入 softmax 的位置是这里:
softmax(logits / T)
也就是说,它不是在 softmax 之后改概率,而是在 softmax 之前改 logits。
继续用刚才的例子:
秋:4
金:2
猫:1
如果 T = 1,不改变原始分数:
4, 2, 1
如果 T = 0.5,每个 logit 都除以 0.5,相当于乘以 2:
8, 4, 2
最高分和其他分数的差距被拉大了。softmax 后,第一名会更接近赢家通吃。
如果 T = 2:
2, 1, 0.5
分数差距被压小了。softmax 后,第二名、第三名更有机会被抽到。
所以 temperature 的真实含义是:
T 小:放大 logit 差距,输出更确定、更保守。
T 大:压扁 logit 差距,输出更随机、更发散。
两个极端尤其重要:
T -> 0
最高 logit 会压倒其他 token,softmax 退化成近似 argmax,也就是贪心选择。
T -> ∞
所有 logit 除以一个极大的数,都接近 0。softmax 看到的候选几乎没有差距,于是退化成接近均匀分布。
这就是 W2-Q4 的核心。
4. top-k:固定只看前 k 名
temperature 改的是概率分布的形状。
top-k 做的是另一件事:先按概率排序,然后只保留前 k 个候选。
假设 softmax 后是:
秋:0.50
金:0.20
叶:0.10
风:0.08
猫:0.04
GPU:0.01
其他:0.07
如果 top-k = 3,就只保留:
秋、金、叶
后面的候选直接被砍掉。然后在保留下来的候选里重新归一化,再采样。
所以 top-k 的特点是:
候选数量固定,概率门槛不固定。
不管第一名有多强,或者分布有多平,top-k=10 都只看前 10 个。
5. top-p:保留“累计概率够 p”的最小集合
top-p 也叫 nucleus sampling。它不是固定保留几个 token,而是看累计概率。
还是这个分布:
秋:0.50
金:0.20
叶:0.10
风:0.08
猫:0.04
GPU:0.01
其他:0.07
如果 top-p = 0.8,从最高概率开始累加:
秋:0.50
金:0.20 -> 累计 0.70
叶:0.10 -> 累计 0.80
保留到 叶 就够了。
如果分布很尖,第一名一个 token 就有 0.85,那么 top-p=0.8 可能只保留一个 token。
如果分布很平,前十个 token 加起来才 0.5,那么它就会继续保留更多候选。
所以 top-p 的特点是:
概率质量固定,候选数量自适应。
一句话区分:
top-k 按名次截断,top-p 按累计概率截断。
6. 用这次实验看参数行为
这次实验用同一个 prompt:
写一句关于秋天的诗。
固定 seed:
--seed 42
模型是:
Qwen2.5-7B-Instruct-Q4_K_M.gguf
结果如下:
| 配置 | 输出 |
|---|---|
temp=0 | 秋风送爽叶纷飞,金黄铺满小径辉。 |
temp=0.7 | 秋风送爽叶纷飞,黄金满地映斜晖。 |
temp=1.5 | 秋风送爽叶纷飞,黄金遍地映斜晖。 |
temp=1.0 top-k=10 | 秋风送爽叶纷飞,黄金满地映斜晖。 |
temp=1.0 top-p=0.3 | 秋风送爽叶纷飞,金黄铺满小径辉。 |
这组结果有三个值得抓住的点。
第一,固定 --seed 42 后,同一组采样配置可以复现。实验里 temp=1.5 跑了两次,输出都是:
秋风送爽叶纷飞,黄金遍地映斜晖。
这说明采样虽然是随机过程,但随机数生成器有固定种子时,路径可以复现。这对实验很重要,否则你很难判断输出变化来自参数,还是来自随机性。
第二,这个 prompt 约束很强,所以高温没有让输出彻底跑偏。
你看到的变化主要发生在这些近义位置:
金黄 / 黄金
铺满 / 满地 / 遍地
小径辉 / 映斜晖
这说明 temperature 不是简单的“胡说八道开关”。它只是让低一些的候选更有机会被抽到。如果 prompt 很窄、模型对下一步很确定,即使提高温度,输出也可能只在高概率近义表达里摆动。
第三,top-p=0.3 很保守。
它的输出回到了:
秋风送爽叶纷飞,金黄铺满小径辉。
这和 temp=0 一样。一个合理推断是:这个位置上的概率分布比较尖,前几个 token 已经占了很大概率质量。top-p=0.3 把尾部候选砍掉后,采样空间变得很窄,所以结果接近贪心。
7. 一个终端坑:不要在 > 里面输入下一条命令
这次实验里还有一个容易踩的坑。
llama-cli 启动后会进入交互模式,提示符长这样:
>
如果你在这个提示符后面输入:
llama-cli -m $M -p "$PROMPT" -n 64 --temp 0.7 --seed 42
它不会执行 shell 命令。
它会把这整行当成用户输入,让模型解释这条命令。所以那次输出变成了:
看起来你是在使用 `llama-cli` 工具来生成文本……
这条结果不能算采样实验结果。
正确做法是先退出交互:
/exit
或者 Ctrl+C,回到 shell 后再运行下一条命令。
8. 和推理主线对上
把这篇放回 Week 01-02 的主线,采样发生在最后一步:
tokenize
-> embed
-> N 层 Transformer
-> unembed 得到 logits
-> sample 得到下一个 token
前面几天我们拆过 attention、KV cache、prefill/decode、PPL。它们解决的是不同问题:
attention / FFN:怎么算出当前 hidden state
KV cache:怎么避免重复算历史 token
prefill / decode:不同阶段的性能瓶颈
PPL:模型给真实 token 的概率质量高不高
sampling:从概率分布里怎么选最终输出 token
所以采样不是模型质量本身。
同一个模型、同一个 prompt、同一份 logits,用不同采样策略,可能得到不同输出。temperature、top-k、top-p 调的是“选择策略”,不是模型参数。
9. 最后把 W2-Q4 背后的答案压缩成三句话
第一句:
temperature 作用在 softmax 前面的 logits 上:softmax(logits / T)。
第二句:
T -> 0 时接近贪心 argmax;T -> ∞ 时接近均匀随机。
第三句:
top-k 固定保留前 k 个 token;top-p 保留累计概率达到 p 的最小 token 集合。
如果这三句话能不看资料说出来,W2-Q4 就过了。
10. 自测
- 为什么
temperature=0通常比temperature=1.5更稳定? - 如果一个位置第一名 token 的概率已经是 0.92,
top-p=0.9可能保留几个 token? top-k=10和top-p=0.9哪个候选数量固定?- 为什么这次高温输出没有明显跑偏,只是在近义词之间变化?
答不上来就回到第 3、4、5 节重看。采样这件事一旦想清楚,后面看服务端推理的“输出稳定性”“幻觉控制”“多样性”和“benchmark 是否可复现”,都会少很多雾。