从 Softmax 到 Temperature:采样参数的直觉

大模型输出前的最后一步发生了什么?从 logits 到概率,再到 temperature 和 top-p,用一个可以拖动的小演示把采样参数讲清楚。

目录 · 4 节
  1. 模型输出的其实是 logits
  2. Softmax:把分数变成概率
  3. 用代码算一遍
  4. Temperature:给分布调「锐度」
  5. Top-p:只在「靠谱」的候选里抽
  6. 完整的采样流程
  7. 小结

调 API 的时候,temperaturetop_p 几乎是每个人都会碰到的两个参数。文档通常只说一句「值越高越随机」,但「随机」到底是怎么来的?这篇文章从模型输出的最后一步讲起,把温度采样背后的直觉拆开来看。

模型输出的其实是 logits

语言模型每生成一个 token,最后一层都会给词表里的每一个候选 token 打一个分,这个分叫 logit。它可以是任意实数,没有上下界,也不需要加起来等于 1。

假设词表只有 4 个 token,模型在某一步给出的 logits 是:

tokenlogit
3.0
2.0
1.0
0.2

分数越高,说明模型越倾向于选它,但我们还需要把它变成真正的概率分布,才能「按概率抽签」。

Softmax:把分数变成概率

Softmax 做的事情很简单:先对每个 logit 取指数,保证都是正数,再除以总和做归一化:

pi=ezijezjp_i = \frac{e^{z_i}}{\sum_{j} e^{z_j}}

其中 ziz_i 是第 ii 个 token 的 logit。指数函数会把差距放大:logit 只差 1,概率就差了 e2.72e \approx 2.72 倍。

0% 20% 40% 60% 80% 63.9% 23.5% 8.7% 3.9% 候选 token 概率 0% 20% 40% 60% 80% 63.9% 23.5% 8.7% 3.9% 候选 token 概率
图 1 · T = 1 时 4 个 token 的 softmax 概率

用代码算一遍

下面是一个不依赖任何库的实现。注意第 4–5 行:先减去最大值再取指数,是为了避免 exp 溢出,这在实际工程里几乎是必须的。

softmax.py
import math
def softmax(logits, temperature=1.0):
scaled = [z / temperature for z in logits]
m = max(scaled) # 数值稳定:减去最大值
exps = [math.exp(z - m) for z in scaled]
total = sum(exps)
return [e / total for e in exps]
print(softmax([3.0, 2.0, 1.0, 0.2], temperature=0.5))

Temperature:给分布调「锐度」

温度 TT 的作用发生在 softmax 之前:把所有 logits 都除以 TT

pi=ezi/Tjezj/Tp_i = \frac{e^{z_i / T}}{\sum_{j} e^{z_j / T}}
  • T<1T < 1:logits 之间的差距被放大,分布变「尖」,高分 token 几乎包揽所有概率;
  • T=1T = 1:就是原始的 softmax;
  • T>1T > 1:差距被压缩,分布变「平」,低分 token 也有机会被抽中。

光看公式不够直观,拖动下面的滑块试试(也可以用键盘的方向键):

交互演示

拖动滑块,观察 T 如何改变分布

1.0
  • logit 3.063.9%
  • logit 2.023.5%
  • logit 1.08.7%
  • logit 0.23.9%

T = 1.0:适中:保留主次,也有一点随机

把第一名的概率随温度的变化画出来,会看到一条单调下降的曲线:

  • 猫(logit 3.0)
  • 鱼(logit 0.2)
0% 25% 50% 75% 100% 0.2 0.5 1.0 1.5 2.0 3.0 温度 T 0% 25% 50% 75% 100% 0.2 0.5 1.0 1.5 2.0 3.0 温度 T
图 2 · 最高分与最低分 token 的概率随温度变化

Top-p:只在「靠谱」的候选里抽

温度调的是分布的形状,但无论怎么调,长尾里那几万个低概率 token 始终都有非零的概率。Top-p(也叫 nucleus sampling)的思路是:把 token 按概率从高到低排序,累加到总和刚好超过 pp 为止,只在这一小撮「核心」里重新归一化再抽样。

T=1T = 1p=0.9p = 0.9 为例:猫 63.9% + 狗 23.5% = 87.4%,还不到 0.9;再加上鸟 8.7% 就超过了,所以鱼被直接排除。

完整的采样流程

图 3 · 从 logits 到下一个 token 的采样流程

小结

  • logits 是模型给每个 token 打的原始分;softmax 把它变成概率。
  • temperature 在 softmax 之前缩放 logits,控制分布的尖锐程度。
  • top-p 在 softmax 之后截掉长尾,控制候选集合的大小。

下次再看到「值越高越随机」,你就知道它具体是在调哪一步了。