采样不是玄学:从 logits 到 temperature、top-k、top-p

用一次 llama-cli 采样实验讲清 logits、softmax、temperature、top-k 和 top-p 的真实作用。

采样不是玄学:从 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. 自测

  1. 为什么 temperature=0 通常比 temperature=1.5 更稳定?
  2. 如果一个位置第一名 token 的概率已经是 0.92,top-p=0.9 可能保留几个 token?
  3. top-k=10top-p=0.9 哪个候选数量固定?
  4. 为什么这次高温输出没有明显跑偏,只是在近义词之间变化?

答不上来就回到第 3、4、5 节重看。采样这件事一旦想清楚,后面看服务端推理的“输出稳定性”“幻觉控制”“多样性”和“benchmark 是否可复现”,都会少很多雾。