技术博客

采样策略的概率视角:top-k 与 top-p 的尾部行为对比

第 24 / 147 篇 · 2025-10-14 · ai · 采样top-ktop-p

softmax 给出完整分布 $p$,采样本该是直接从 $p$ 里抽一个 token。实际部署里几乎没有谁真的这么做——原始分布的尾部又长又脏,低频 token 合计占着几个百分点的概率,却贡献了绝大多数的语法错误和跑题。截断(truncation)就是先把分布砍掉再归一化,top-k 和 top-p 是两种选保留集合的规则。它们都是同一个数学对象的实例:

$$ q(x)=\frac{p(x)\cdot\mathbb{1}[x\in S]}{\sum_{x'\in S}p(x')}, $$

区别只在集合 $S$ 怎么定。规则不同,砍掉的是分布的不同部位,行为差异也就出来了。

top-k:固定名额的粗放

top-k 按概率排序取前 $k$ 个。$k=1$ 退化成贪心,$k=|V|$ 退回原始采样。问题在 $k$ 是常数,而分布的"有效支持集"是变化的。看两个极端:

分布尖锐时(比如代码补全,下一 token 几乎确定是 )),第 2 到第 $k$ 名的概率加起来可能不到 $10^{-4}$,留着它们只是把噪声请回采样池。一个几乎确定的分布,被强制混进 $k-1$ 个无关选项。

分布平坦时(开放式续写,下一个词有十几个都讲得通),前 $k$ 名可能只覆盖总质量的 60%,剩下 40% 被整体扔掉,归一化后每个保留 token 的概率被等比例放大 1.67 倍——截断把分布的形状扭向头部,多样性被人为压扁。

固定的 $k$ 在两种情形下都做错事:该小的时候它大,该大的时候它小。根源是它只数名次,不看质量。

top-p:按质量配额自适应

nucleus 采样(Holtzman et al., 2020, ICLR)把规则换成:取最小的集合 $S_p$,使累积概率达到阈值 $p$,

$$ S_p=\{x_{(1)},\dots,x_{(m)}\},\qquad \sum_{i=1}^{m}p(x_{(i)})\ge p,\qquad \sum_{i=1}^{m-1}p(x_{(i)})< p, $$

下标 $(i)$ 表示按概率降序排列。$p=0.9$ 就是"保留能解释 90% 概率质量的那些 token"。集合大小 $m$ 由分布自己决定:尖锐分布时 $m$ 自动收缩到 1 附近,平坦分布时 $m$ 自动扩展到几十。这正是 top-k 缺的那个自适应维度。

论文里的实验证据很直白:人在开放式续写上的续写,nucleus 采样的输出与人类的困惑度最接近,而 top-k 和纯采样都有系统偏差——纯采样太低(分布太散),top-k 在 $k$ 大时也偏低。截断规则的目标不是"采样更随机",而是让采出来的分布形状贴近人写作时的不确定性。

尾部行为的定量对比

把排序后的概率看成一条衰减曲线 $p_{(1)}\ge p_{(2)}\ge\dots$,两条规则在曲线上留下不同的切口。top-k 在横轴(名次)$k$ 处垂直切:曲线衰减慢(平坦)时切口以下的面积大,砍掉的质量多;曲线衰减快时切口以下的面积小,但保留区里的尾部相对质量反而高。top-p 在纵轴(累积概率)$p$ 处水平切:无论曲线什么形状,切口以下恒为 $1-p$ 的质量。top-k 控制的是集合的大小,top-p 控制的是被丢弃的质量——后者才是和"风险预算"直接对应的量。

还有一个细节:top-p 天然保证归一化温和。由于丢弃质量恒为 $1-p\approx0.1$,重归一化的放大因子 $1/p\approx1.11$ 也是常数;top-k 的放大因子 $1/\sum_{i\le k}p_{(i)}$ 随分布形状剧烈波动,等于把"该不该冒险"这个决策埋进了一个隐式变量里。

工程上为什么总是三个一起用

实际采样管线几乎是固定搭配:temperature $T$ → top-k → top-p → 从最终的 $q$ 采样。顺序有讲究:先用温度重塑分布形状($p_i^{1/T}$ 再归一化,$T<1$ 压平尾部、$T>1$ 抹平差异),再做硬截断截掉重塑后仍然危险的长尾,最后归一化采样。OpenAI 的 API 文档明确说 top-k 在 top-p 之前过滤,HuggingFace 的 LogitsWarper 管线也是这个次序——先宽后窄,每一步都在上一步的结果上操作。

截断还有一个工程学副产品:softmax 分母只需要在保留集上算,排序 + 前缀和之后,cdf 反查采样(找第一个累积概率超过均匀随机数的 token)是 $O(m)$ 的,不需要碰完整词表。

排序概率曲线上的两种切口:垂直切名次 vs 水平切质量 top-k:垂直切(名次=k) top-p:水平切(累积=p) k=4 保留区 尾部 p=0.9 累积曲线 切口以下恒为 1−p 分布尖锐时 p 的切口自动左移(m→1);分布平坦时自动右扩(m 增大)

已知缺陷与补丁

top-p 不是终点。一个是多样性坍缩问题:多个研究观察到 nucleus 采样在长生成里多样性仍系统性低于人类文本,$p$ 调大只是延期。另一个是截断与温度的耦合:$T$ 先抬高了尾部,$p=0.9$ 划进去的候选就变多,两个超参互相掺水,调参时很难归因。后来的改进多沿两条线走:一条是均匀化(如典型采样,typical sampling,按信息量 $-\ln p(x)$ 截断而不是按概率),一条是把截断做成可学习或自适应(如根据上下文动态调 $p$)。typing 场景的实践更干脆——很多代码补全系统直接 $T\approx0$ 加很小的 top-k,宁可牺牲多样性换正确率,因为这类任务的评价函数里"错一个 token 就是全错"。

选择规则时可以问一句话:你要控制的是候选数量还是风险预算?前者对应 top-k,后者对应 top-p。开放式生成赌的是分布形状说不准,该留多大集合让分布自己报数,所以 nucleus 成了默认;有明确评价函数的任务,风险预算可以直接算出来,top-k 或干脆贪心反而更诚实。