temperature、top-k、top-p、beam search
分别怎么做?有什么区别?
先弄清楚:每个概念是什么
- Temperature \(T\)
- softmax 之前把 logits 除以 \(T\),像调"胆子"。\(T\) 小只敢说最可能的词,\(T\) 大敢说冷门词。
- Greedy / beam search
- greedy 每步拿概率最高的词;beam search 每步保留 \(B\) 个累计 log prob 最高的 prefix。
- Top-k
- 只在概率前 \(k\) 名里抽签,其余置 0,再 renormalize。
- Top-p(nucleus)
- 从高到低累加概率,到 \(\ge p\) 就停,留下的集合叫 nucleus。
- Degeneration
- 开放生成里,greedy / beam 的高概率文本平淡,一个短语重复过一次就更容易再重复。按原分布 sample 又会抽到 tail 里的怪词。截断 tail 是折中。
30 秒回答
Greedy and beam search are deterministic. Beam search keeps the B best prefixes by total log probability; it suits translation but gives bland, repetitive text in open-ended generation, so there we sample. Temperature divides the logits by T before the softmax: below 1 sharpens the distribution, above 1 flattens it, near 0 is greedy. It reshapes but never removes tokens. Top-k and top-p cut off the unreliable tail and renormalize: top-k keeps a fixed k tokens, top-p keeps the smallest set whose cumulative probability reaches p, so the set adapts to the model's confidence. In practice, temperature first, then top-p.
关键公式
\(T = 0.5\) 是把原概率平方再归一化,\(T = 2\) 是开根号。截断后:
\[ P'(x) = \frac{P(x)}{\sum_{x'\in V} P(x')}\ \ (x \in V),\quad \text{else } 0 \]\(V\) 是 top-k 的前 \(k\) 个,或 top-p 中累计 \(\ge p\) 的最短前缀。beam search 的打分:
\[ \text{score}(y_{1:t}) = \sum_{s=1}^{t} \log p(y_s \mid y_{<s}) \]手算例子
"I'd like a cup of ___",logits \(z = \ln(10, 6, 3, 1) \approx (2.30, 1.79, 1.10, 0)\)。T = 1 时概率就是 (10, 6, 3, 1) / 20;T = 0.5 用 (100, 36, 9, 1) / 146;T = 2 用 (3.16, 2.45, 1.73, 1) / 8.34:
| T | coffee | tea | water | milk | top-p = 0.9 留下 |
|---|---|---|---|---|---|
| 0.5 | 0.685 | 0.247 | 0.062 | 0.007 | 2 个(0.685 + 0.247 = 0.932) |
| 1 | 0.50 | 0.30 | 0.15 | 0.05 | 3 个(0.95) |
| 2 | 0.379 | 0.294 | 0.208 | 0.120 | 4 个(前 3 个只到 0.88) |
- top-k = 2:每一行都只留 coffee、tea。T = 1 时 renormalize 成 0.5 / 0.8 = 0.625 和 0.375。
- top-p = 0.9:留下 2 → 3 → 4 个,分布越平留得越多。
- temperature 只改形状:milk 在哪一行都不是 0。
手撕代码(NumPy)
def sample(logits, T=1.0, k=None, p=None, rng=np.random):
z = logits / T # temperature
probs = np.exp(z - z.max())
probs /= probs.sum() # softmax
idx = np.argsort(-probs) # 按概率降序
keep = len(idx) if k is None else k # top-k
if p is not None: # top-p:累计 ≥ p 的最短前缀
cum = np.cumsum(probs[idx])
keep = min(keep, np.searchsorted(cum, p) + 1)
idx = idx[:keep]
q = probs[idx] / probs[idx].sum() # renormalize
return rng.choice(idx, p=q)
必答点
- temperature:softmax\((z/T)\);\(T<1\) 变尖,\(T>1\) 变平,\(T\to0\) = greedy;只改形状,不截断
- top-k:固定 \(k\) 个;分布尖时混进烂词,分布平时又砍掉好词
- top-p:累计 \(\ge p\) 的最小集合,大小自适应;\(p\) 常取 0.9–0.95
- greedy / beam:deterministic,适合翻译;开放生成容易重复
- 常组合使用:先 temperature,再 top-k / top-p
追问
temperature 和 top-k 有什么区别?(Office Copilot 原题)
temperature 改整个分布的形状,所有 token 都还有概率。top-k 只砍掉 tail,留下的 token 比例不变,所以两者常叠加。
举个 beam search 比 greedy 好的例子?
第一步 A 0.5、B 0.4;A 后面最好的词 0.4,B 后面 0.9。greedy 走 A 得 0.5 × 0.4 = 0.20;beam(B = 2)留着 B,找到 0.4 × 0.9 = 0.36。
beam search 为什么偏爱短句?
每多一个 token 就多加一个负的 log prob,长句吃亏,所以要加 length penalty。原始 Transformer 用 beam size 4、\(\alpha = 0.6\)。
参数怎么选?
要准确(代码、事实问答)用低 \(T\) 或 greedy,随机性越大 hallucination 风险越高。要多样(写作、brainstorm)用 \(T\) 接近 1 配 top-p。
来源Holtzman et al. 2020(nucleus sampling) Abstract(p.1)、§3.1–3.3 eq. 2–4(pp.4–6)、Fig. 4(p.5)、§5.2(p.9)· Fan et al. 2018 §5.4(pp.5–6,top-k)· Vaswani et al. 2017 §6.1(p.8)· Huang et al. 2023 §3.3.1(p.11)