Decoding⚓︎
Abstract
这篇笔记整理 language model 推理阶段的 token 选择问题,重点放在 greedy decoding、sampling、temperature、top-k 与 top-p 的作用边界。解码不改变模型参数,只决定模型已经给出的下一 token 分布如何被转成实际输出。
核心问题⚓︎
推理阶段反复执行的核心步骤只有一件事:给定当前上下文,模型输出下一 token 的条件分布,然后系统从这个分布里选出一个 token,追加到序列末尾,再进入下一轮。
因此,解码讨论的不是“模型学到了什么”,而是“模型已经给出一个分布之后,系统如何从里面做选择”。很多生成问题表面上看像是 decoding 参数设置不合适,实际上可能来自模型分布本身的质量不足。
生成质量通常可以拆成两部分:
- 模型分布本身是否可靠
- 推理阶段是否用合适的方式从这个分布里取样
前者决定上限,后者决定在这个上限附近偏向稳定、保守,还是偏向开放、多样。
解码过程⚓︎
对 decoder-only language model 而言,若当前上下文为 x_{1:t},模型输出下一个 token 的条件分布
解码器真正负责的是如何把这个分布变成一个离散选择结果。不同方法的差异,不在于模型前向过程是否改变,而在于最终选 token 的规则不同。
从这个角度看,greedy、sampling、top-k、top-p 都属于选择规则;temperature 则更接近在选择前先调整一次分布形状。
Greedy Decoding⚓︎
greedy decoding 在每一步都直接取当前概率最高的 token,也就是
它的特点是几乎没有额外策略,每一步都选择局部最优结果。
greedy 会沿着模型当前最确信的续写路径持续前进。这样做的优点是稳定、确定、可复现,尤其适合答案空间较窄、格式约束较强的任务。
但它也有明确边界。局部最优并不保证整段生成的全局效果最好。一旦某一步进入偏保守、偏重复、偏模板化的路径,后面每一步都会继续在这个上下文上做最保守的选择,结果就容易越来越单一。
可以概括为:
- 优点:稳定,噪声少,结果通常最可控
- 缺点:多样性差,容易过早锁死生成路径
Sampling⚓︎
sampling 不再固定取最大概率 token,而是把模型给出的分布当作采样分布,从中随机抽取一个 token。
这里的随机性不是脱离分布的任意选择,而是承认开放式生成任务往往本来就存在多条合理续写路径。模型已经把这些路径用概率分布表达出来,sampling 的作用是让系统不总是只走最高概率那一条。
因此,sampling 的意义不是“让模型更有创造力”,而是让分布中的次优但仍合理的候选有机会真正出现。
这也是为什么:
- 对封闭问答或结构化任务,过强 sampling 往往降低稳定性
- 对开放写作、续写、对话,完全不用 sampling 往往又显得过于僵硬
Temperature⚓︎
temperature 的作用是先改 logits 的相对尖锐程度,再进行采样。若原 logits 为 z,常见写法是
然后再对 \tilde{z} 做 softmax。
这里最容易混淆的一点是:temperature 调的是分布形状,不是直接切换“随机”或“非随机”两种模式。
- 当 T < 1 时,分布更尖锐,高概率 token 的优势被放大
- 当 T > 1 时,分布更平缓,尾部 token 更容易进入候选
- 当 T = 1 时,不额外缩放 logits
temperature 可以理解为对模型确信度差距的放大或压缩。模型原本已经认为某些 token 更可能出现,temperature 只是进一步强化或削弱这种差距。
Temperature = 0⚓︎
很多系统会把 temperature=0 近似成 greedy decoding,也就是直接取 argmax。这在工程上很常见,因为当 T \to 0 时,softmax 分布会越来越接近 one-hot。
但 temperature=0 更接近“尽量做确定性解码”,不等于“任何平台、任何时间、任何硬件上都严格逐 token 一致”。
出现差异的常见原因包括:
- 最大 logit 非唯一或极接近:若多个 token 分数几乎相同,tie-breaking、排序实现或浮点舍入都可能改变最终 argmax
- 浮点误差与并行归约差异:不同 kernel、不同硬件或不同并行路径会产生微小数值扰动,边界情况下足以改变选中的 token
- 服务系统实现细节变化:批处理方式、内核选择、推理优化策略、模型版本切换,都可能改变临界情况下的输出路径
- 自回归生成的放大效应:哪怕只在一个位置上出现不同 token,后续上下文也会改变,因此整段输出会继续分叉
因此,temperature=0 更准确的含义是最大程度接近 greedy 的工程选项,而不是绝对确定性承诺。
Top-k 与 Top-p⚓︎
如果直接在整个词表上做 sampling,理论上所有 token 都保留非零概率,但尾部里常常混有大量质量很差的候选。top-k 和 top-p 的核心作用,都是在采样前先做候选裁剪,把选择范围限制在更可信的子集里。
这个思路可以拆成两步:
- 先把明显不该选的尾部 token 去掉
- 再在剩下的候选里做采样
这样做的目的不是让输出更保守,而是减少低质量尾部 token 对结果的污染。
Top-k⚓︎
top-k 保留概率最高的前 k 个 token,其余 token 直接丢弃,然后在这 k 个候选中重新归一化并采样。
它的特点是边界很清楚:每一步最多只看固定数量的候选。实现简单,行为也比较容易预测。
但固定 k 也意味着它对不同分布形状缺乏自适应性:
- 如果当前分布很尖锐,保留很大的 k 可能没有必要
- 如果当前分布很平缓,过小的 k 又可能裁掉本来合理的候选
因此,top-k 的问题不在于方法本身,而在于它假设每一步都适合保留同样多的候选,这个假设并不总成立。
Top-p⚓︎
top-p 又叫 nucleus sampling。它不是固定保留多少个 token,而是按概率从高到低累加,选出累计概率刚刚达到阈值 p 的最小集合。
这意味着候选集大小会随当前分布自动变化:
- 分布很尖锐时,只需少量 token 就能达到阈值,候选集会很小
- 分布较平缓时,需要更多 token 才能达到阈值,候选集会更大
top-p 的关键特征在于,它试图让裁剪行为适应当前这一步到底有多不确定,因此通常比固定 top-k 更贴近分布本身的结构。
常见误区⚓︎
Greedy 不等于模型更准⚓︎
greedy 只是更保守,不代表它一定更正确。若模型最高概率 token 本身就是错的,那么 greedy 只会稳定地输出这个错误。
Sampling 不等于胡乱生成⚓︎
sampling 仍然受模型分布约束。随机性来自按概率抽样,不是脱离分布随意选 token。
Temperature 高不等于一定更有创造力⚓︎
temperature 升高只是让低概率候选更容易被采到。若模型尾部分布本身质量差,高 temperature 带来的可能不是创造性,而是漂移、重复和语义断裂。
Top-p 和 Top-k 不是替代模型能力⚓︎
这类裁剪方法只能控制输出风险,不能弥补模型本身缺乏知识、缺乏推理能力或分布校准不佳的问题。
生成退化⚓︎
开放式生成里常见的问题包括重复、跑题、局部语义断裂、风格漂移。这些现象通常不是单一参数直接导致的,而是多个因素共同作用:
- 模型分布本身质量不足
- 上下文已经逐步偏离高概率区域
- temperature 过高
- top-k 或 top-p 裁剪过宽,尾部噪声进入输出
- 小模型对长程约束和全局一致性的建模能力有限
- 边界情况下的数值路径差异被自回归过程放大
因此,调 decoding 参数更像是在已有分布上做折中:
- 更稳定,通常意味着更保守
- 更多样,通常意味着风险更高
这里没有独立于模型质量之外的万能参数组合。
要点⚓︎
- greedy 是每步都取当前最大概率 token,稳定但容易保守
- sampling 是按分布抽样,让多条合理路径有机会出现
- temperature 改的是分布尖锐程度,不是直接开关随机性
- top-k 与 top-p 都是在采样前裁剪候选,减少尾部低质量 token
- decoding 决定的是如何使用模型分布,不能替代模型本身的能力