解码与采样策略详解
模型每一步输出的是词表上的概率分布,「如何从分布里选出下一个 token」就是解码策略。它直接决定生成的确定性、多样性与质量,是高频但容易被低估的考点——从 temperature 的数学含义到「推理模型为什么不建议贪心」,都能问出区分度。
从 logits 到 token
模型最后一层对每个位置输出词表大小的 logits 向量,经 softmax 得到概率分布,再由解码策略决定取哪个 token。temperature、top-k、top-p 全部作用在这一步——解码不改模型,只改「怎么选」。手撕实现见 手撕代码题解集。
确定性解码
贪心解码(Greedy)
每步取概率最大的 token。简单、快,但有两个问题:① 局部最优 ≠ 全局最优(第一步的高分词可能把后面带进死胡同);② 容易陷入重复循环(「的的的」「I'm sorry I'm sorry…」)。
束搜索(Beam Search)
每步保留整体对数概率最高的 B 条候选序列,最后输出整体最优。
- 适合翻译、摘要、ASR 等有「接近唯一正确答案」的任务;通常配长度惩罚(不然偏好短句,因为概率连乘越长越小)。
- 开放式生成中表现反而差——这是经典的文本退化(text degeneration)发现:人类语言并不总走高概率路径,而 beam search 强行最大化概率,产出枯燥、重复、套话化的文本。「高概率 ≠ 高质量」是解码部分最重要的认知。
随机采样
温度(Temperature)
softmax 前把 logits 除以 T:
$$p_i = \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)}$$
数学直觉:T<1 放大 logits 间的差距(强者愈强,趋近贪心);T>1 缩小差距(分布趋平,更随机)。T 改变的是分布形状,不改变排序。
Top-k 采样
只保留概率最高的 k 个 token 重新归一化采样。缺点是 k 固定:分布尖锐时 k=50 引入一堆垃圾候选,分布平坦时 k=50 又可能砍掉合理候选。
Top-p / 核采样(Nucleus Sampling)
保留「累积概率达到 p 的最小集合」。候选集大小随分布自适应——模型确定时候选少、犹豫时候选多,是对 top-k 缺陷的直接修复,目前最常用。
min-p 采样
以「最高概率 × 系数」为门槛过滤(如 min_p=0.1:概率不足最高者 10% 的全部丢弃)。相比 top-p 在高温度下更稳(top-p 在平坦分布下会放进很多低质量候选,min-p 始终锚定最高概率),近年在开源社区流行。
惩罚项(治复读)
| 参数 | 机制 | 特点 |
|---|---|---|
| repetition_penalty | 出现过的 token logits 除以惩罚系数(乘性) | 简单粗暴,过大会伤正常语法词 |
| frequency_penalty | 按出现次数线性扣减 logits | 出现越多扣越狠 |
| presence_penalty | 只要出现过就扣固定值(一次性) | 鼓励引入新话题 |
| no_repeat_ngram | 禁止重复生成 n-gram | 硬约束,可能误伤合理重复(人名、术语) |
进阶解码
- 对比解码(Contrastive Decoding):用「大模型 logits − 小模型 logits」选词,把小模型也会犯的低级倾向(重复、套话)减掉。
- 投机解码(Speculative Decoding):小模型起草、大模型并行验证,输出分布与大模型完全一致——是加速手段而非质量手段,详见 推理优化与部署。
- 约束解码(Constrained Decoding):用 FSM/语法(Outlines、XGrammar 等)在每步把非法 token 的概率置零,强制输出符合 JSON Schema/正则——结构化输出与 Function Calling 的底层保障,见 结构化输出详解。
- 采样级 scaling:Best-of-N(采 N 个答案用 RM 选最优)、Self-Consistency(多条 CoT 投票)——把解码采样变成「推理时计算换质量」的手段,与推理模型一脉相承,见 推理模型与慢思考。
推理模型的解码设置(新考点)
长 CoT 推理模型对解码参数敏感且与直觉相反:
- 不建议 T=0/贪心:长推理链里贪心容易陷入重复循环,且推理需要一定探索性;DeepSeek-R1 官方推荐 T≈0.6 + top-p 0.95。
- 复读惩罚要谨慎:推理过程天然会重复关键数字与中间结论,惩罚过强会破坏推理。
- 评测推理模型时常用「多次采样取 pass@k / 多数投票」而不是单次贪心。
参数怎么调(实战速记)
| 场景 | 建议 |
|---|---|
| 事实问答 / 抽取 / 分类 | T 0~0.3,追求确定可复现 |
| 代码生成 | T 0~0.4;要多候选时 T 0.8 采 N 个跑测试筛 |
| 翻译 / 摘要 | 低温度或 beam search(+长度惩罚) |
| 创意写作 / 头脑风暴 | T 0.7~1.0 + top-p 0.9(或 min-p 0.05~0.1) |
| 结构化输出 / FC | 低温度 + 约束解码 |
| 长 CoT 推理模型 | T 0.5~0.7 + top-p 0.95,避免贪心 |
另外:评测/回归对比时固定解码配置与随机种子,否则分数波动会淹没真实差异。
高频追问
Q:temperature 和 top-p 能一起用吗? 能,且常一起用:temperature 先调分布形状,top-p 再截断长尾。但不建议两个都设激进值(如 T=1.5 + p=0.99),交互效果难预测;调参时固定一个、动另一个。
Q:为什么开放式生成不用 Beam Search? 文本退化问题:beam search 最大化序列概率,而高概率文本往往「常见、安全、重复」,与人类语言的自然多样性背离。开放式生成要的是「合理且多样」,采样类方法更合适。
Q:温度为 0 一定完全可复现吗? 不一定。T→0 等价贪心,但 GPU 浮点运算的非确定性(并行归约顺序)、动态批处理(同 batch 里其他请求影响计算切分)都可能造成微小差异。严格复现需固定种子 + 确定性后端 + 固定批处理。
Q:top-k、top-p、min-p 三者怎么选? top-k 固定候选数量(最不自适应);top-p 固定累积概率(随分布自适应,默认主流);min-p 锚定最高概率的比例(高温度下最稳)。新项目默认 top-p;想用高温度保创造性又怕崩,试 min-p。
Q:frequency_penalty 和 presence_penalty 区别? frequency 按出现次数累计扣分(治高频复读),presence 出现过就扣固定一次(鼓励换话题、不管重复多少次)。复读循环用 frequency,内容单调用 presence。
Q:为什么推理模型官方不建议贪心解码? 长推理链放大了贪心的重复陷阱(一旦进入循环没有随机性能跳出);且 RL 训练时模型是在采样条件下优化的,贪心解码偏离训练分布。适度温度既防循环又保留探索性。
Q:生成总是重复怎么办? 按优先级排查:① 是否用了贪心/超低温度 → 提高 T 或换采样;② 加 frequency_penalty 或 no_repeat_ngram;③ prompt/模板是否本身诱导重复;④ 微调模型则检查训练数据是否有大量重复模式。