Top-K 采样

Top-K Sampling

Top-K 采样是大模型生成的一种解码策略:每一步只从概率最高的前 K 个候选 Token 里做随机采样,过滤掉长尾低概率选项,减少输出胡说八道同时保留多样性。

详细解释

Top-K 采样(Top-K Sampling)Top-P(核采样) 并列,是大模型 解码 阶段最常见的两种随机采样策略之一。

模型每一步生成下一个 Token 时,其实会对词表中每一个 Token 输出一个概率(比如 GPT-3.5 词表 100K,每一步就是 100K 个概率值)。如果纯贪婪(Greedy)解码,每次都取概率最大的那个——结果呆板、重复、像机器人。如果对全部 100K 都随机采样,长尾里大量奇怪的词(如生僻字、错拼、乱码)被抽中概率飙升——输出容易”放飞自我”。

Top-K 的做法很直觉:

先把词表按概率从大到小排序,只保留前 K 个,把剩下的全部概率置 0,然后把这 K 个的概率归一化后再采样。

K 的取值:一般取 10(比较确定)、40(OpenAI 旧默认)、50(平衡),极端场景可以取 1(等于 Greedy)或 100 以上(非常发散)。现在主流 SDK 里 Top-K 默认往往关闭(由 Top-P 接管),两者可以叠加生效。

与 Temperature、Top-P 的关系(采样三件套)

策略控制目标典型值什么时候开
Temperature概率分布”尖锐度”,T→0 越贪婪,T→∞ 越均匀0.0 – 2.0每次必设,默认 0.7–1.0
Top-P累计概率门槛,保留候选到累计概率 ≥ p 为止0.0 – 1.0,默认 0.9–1.0和 Temperature 配合
Top-K候选数量上限,不管概率多少最多 K 个1 – 100,常用 10/40/50想”硬卡上限”防止抽到完全无关词

三者叠加顺序(按主流框架实现)

  1. 先过 Temperature 对 logits 做缩放;
  2. 再过 Top-K 截断长尾;
  3. 剩下的 Token 再过 Top-P 截断累计概率尾部;
  4. 最终的小集合做加权采样。

实践建议:如果你已经设了合理的 Top-P(比如 0.9),Top-K 可以不设(或设一个非常大的 K,如 1000 等价于关闭),两者作用重叠,容易过度收敛。唯元智创 对所有接入方的默认参数是 temperature=1.0, top_p=1.0, top_k=0(关闭),推荐你只改 temperature,需要更严格再叠 Top-K。

示例:K=3 时采样过程(假设词表共 5 个候选)

Token原始概率Top-K=3 后(保留前 3)归一化后实际采样概率
“今天”0.600.60 ✅0.60 / (0.60+0.25+0.10) = 0.632
“明天”0.250.25 ✅0.263
“昨天”0.100.10 ✅0.105
“前天”0.04❌ 被截为 00
“去年”0.01❌ 被截为 00

没有 Top-K 时,“前天”和”去年”虽然概率低,但仍可能被抽中——尤其在 Temperature 很高的情况下。Top-K 相当于给了个硬性数量门槛。

常见问题

Top-K 和 Top-P 我应该用哪个?
大多数场景只设 Top-P(0.9)+ Temperature(0.7–1.0)就够,因为 Top-P 是”按概率质量动态选 K”,在分布尖锐时自动候选少、分布平缓时自动候选多。Top-K 更适合你需要确定性数量约束的场景:比如希望下一步最多 40 个可能的词,不管它们概率分布什么样。两者可以一起开,效果是”双重保险”。
为什么 OpenAI 的 Python SDK 里没有 top_k 参数?
OpenAI 官方 Chat API 暴露的采样参数是 temperature + top_p 两个,没有暴露 Top-K。Top-K 在开源推理框架(vLLM、SGLang、HuggingFace generate)里常见。像 唯元智创 这类聚合平台如果接了开源模型供应商,会在兼容层把 Top-K 透传给底层。
固定 Seed 之后 Top-K 采样的输出能复现吗?
同一个推理后端 + 相同参数下可以。但跨供应商、跨 SDK 版本、甚至同一供应商负载变化导致 批处理大小 不同时,Top-K 的采样路径可能因浮点精度或底层实现差异而有细微漂移,Seed 只能保证”大概率一致”不能保证 100% 字节级一致。