對應原題(Common ‧ Inference, Serving and GPU Performance)

  • What is speculative decoding? Why is output quality preserved, and when does it not help?
    — Asked at: NVIDIA, Together AI

論文:Leviathan et al., Fast Inference from Transformers via Speculative Decoding (ICML 2023);
Chen et al., Accelerating Large Language Model Decoding with Speculative Sampling (DeepMind, 2023)。

🎯 什麼情境該想到我

當你「單一使用者覺得吐字太慢,但又不能換小模型犧牲品質」的時候。這是少數能同時滿足「更快」和「輸出分布完全不變」的技術。

⚙️ 怎麼用(機制)

動機:免費的算力

Prefill 與 Decode 算過:batch 1 的 decode,H100 有 99.7% 的算力在空轉,全部時間在讀權重。

關鍵觀察:

一次 forward 驗證 1 個 token 和驗證 5 個 token,成本幾乎一樣——因為兩者都要把整份權重讀一遍(分母固定)。

那何不先猜幾個,再一次驗證?

流程

狀態:已生成 "台北的天氣"

1. Draft(小模型,自迴歸跑 γ=4 步,很快)
      猜:" 今天" " 很" " 好" "。"
      同時記下每步的分布 q(·)

2. Verify(大模型,★ 一次 forward 跑完 5 個位置)
      輸入 "台北的天氣 今天 很 好 。"
      得到 5 組分布 p(·)   ← 因為 causal mask,每個位置看到的都只有它前面的

3. 逐一判定接受 / 拒絕
      接受 " 今天" " 很"  →  在 " 好" 處拒絕
      →  從修正分布重新採一個 token,例如 " 熱"

4. 結果:這一輪拿到 3 個 token(" 今天" " 很" " 熱"),只花了 1 次大模型 forward

第 2 步是整件事的關鍵:驗證 γ 個猜測只需要一次大模型前向,因為 causal attention 讓每個位置天然只看得到它之前的內容。

★ 為什麼品質完全不變(必考的證明)

用的是 modified rejection sampling。設 target 分布 、draft 分布 ,draft 猜了 :

  • (draft 比 target 更不看好它)→ 必定接受
  • (draft 太樂觀)→ 以 的機率接受

拒絕時,從修正後的殘差分布重新採樣:

可以證明:這樣得到的 token 分布嚴格等於 。

直覺:接受的部分覆蓋了 的質量,拒絕後重採補上 超出 的那一塊 ,兩者相加剛好還原 。

★ 所以它是「數學上精確」,不是「近似」。 這和量化、蒸餾、換小模型完全不同性質——那些都要拿品質換速度,這個不用。

而且拒絕時也至少拿到 1 個 token(重採的那個),所以永遠不會比原本慢(以步數計)。

greedy()時退化成更簡單的規則:draft 猜的和 target 的 argmax 相同就接受,不同就採用 target 的。

期望加速

設每個 token 的接受率為 ,一輪猜 個,則每輪期望產出:

的期望產出
0.94.1
0.83.4
0.72.8
0.51.9
0.31.4

扣掉 draft 本身的成本 (相對 target 的比例),實際加速 ≈ 。

所以 draft 模型必須又準又便宜。 若 draft 是 target 的 1/10 成本、,分母是 1.4—— 時加速約 2.4×。

也有最佳值:猜太多,後面的接受率是 指數衰減,白算。 通常 3–8。

主要變體

方法怎麼產生猜測特點
標準 speculative獨立的小模型(如 Llama-70B 配 Llama-8B)要有同 tokenizer 的小模型
Medusa在原模型上加多個預測頭,平行預測位置 +1、+2、+3不用第二個模型;要訓練那些頭
EAGLE在特徵層(而非 token 層)做自迴歸預測接受率明顯較高;截至 2026-10 是實務常見選項(vLLM v0.31.0 內建 eagle/eagle3,TensorRT-LLM 內建 EAGLE 3;查證 2026-10-15)
★ Prompt lookup / n-gram直接從 prompt 或已生成內容裡抄匹配的 n-gram零模型、零訓練、零記憶體
Self-speculative同一個模型跳過部分層當 draft不用額外權重

★ Prompt lookup 值得特別記住:它完全不需要額外模型,只要在上下文裡找重複的 n-gram。
對「輸出大量重複輸入」的任務效果極佳——RAG 摘要與引用、程式碼編輯(大部分內容不變)、翻譯、結構化改寫。
這類場景是幾行程式碼就能拿到 2–3× 的加速,投報率極高。vLLM(method="ngram")與 TensorRT-LLM(NGramDecodingConfig)都內建(查證 2026-10-15)。

⚠️ 注意 / 什麼時候不適用(★ 這題的重點)

1. ★ 高 batch 下沒用,甚至更慢

這是最重要的一點。推測解碼消費的是閒置算力。

情境算力狀態結果
batch 1–4幾乎全閒加速明顯
batch 32+已接近 compute-bound增益急遽縮小
batch 很大完全 compute-bound變慢(驗證多算的那些 token 是純浪費)

→ 它是延遲優化,不是吞吐優化。 兩者在這裡直接衝突。
→ 生產系統常見做法:依當前 batch 大小動態開關(vLLM v0.31.0 可用 num_speculative_tokens_per_batch_size 依 batch 大小區間設定推測 token 數;查證 2026-10-15)。

2. 接受率會依任務劇烈變化

  • 高 :格式化輸出、程式碼樣板、複述、事實性短答
  • 低 :創意寫作、高 temperature、draft 沒見過的領域
    → 一定要在自己的流量上量 ,別用 benchmark 數字。

3. 高 temperature 會殺死接受率

越高分布越平, 和 越容易分歧。 時接受率最高。

4. draft 必須和 target 同 tokenizer

不同 tokenizer 就無法逐 token 對應。這大幅限制了 draft 的選擇(實務上多半得用同系列的小模型)。

5. 記憶體成本

多一個模型就多一份權重與 KV cache。在顯存已經吃緊時,這些顯存拿去加大 batch 可能更划算。

6. 實作正確性很難驗

接受規則寫錯不會報錯,只會讓輸出分布悄悄偏掉。
→ 驗證方法:固定 seed,比對「開啟推測解碼」與「關閉」的輸出。在 greedy 下必須逐 token 完全相同。這是上線前的必要檢查。

🧪 我實際套用的紀錄

  • 2026-09-20:從面試題庫展開。待辦:先試 prompt lookup(零成本),量自己場景的接受率。

🔗 相關