DGX Spark · part 27
火箭起飛:Gemma 4 在 DGX Spark 跑出 670 tok/s 總吞吐(單流 108 tok/s)
❯ cat --toc
TL;DR
新技術讓本來的模型快 N 倍—不換模型、不換硬體、不重新訓練,光是換條更聰明的推論路徑就能拉吞吐。
2026-05-05 Google 發 Multi-Token Prediction drafter,vLLM PR #41745 同日進 preview docker。DGX Spark 上實測 Gemma 4 26B-A4B-it FP8(RedHatAI 量化版)+ Google 官方 drafter + γ=4 → 單 stream 108.78 tok/s(baseline 40.85 的 2.66×),8 路並行 aggregate 674 tok/s(per-user 仍有 84)。⚠️ 一個沒寫進文件的雷:drafter 不能配 base 主模型,必須配 -it(我先踩了一次,baseline 41 → MTP 25 tok/s,反向慢 38%)。
白話版:Google 給 Gemma 開了個外掛
Multi-Token Prediction(MTP) 是一種「投機解碼」技術—你用一個小很多的「草稿模型」(drafter)先猜接下來幾個字,然後讓主模型一次驗證全部猜的字。猜對的就直接用,猜錯的退回。如果 drafter 預測準確率高,主模型一次驗證等於同時產出多個 token,速度直接拉上去。
Google 在 2026-05-05 為 Gemma 4 全四個尺寸(E2B / E4B / 26B-A4B / 31B Dense)各發了一個搭配的 drafter,號稱 up to 3× 加速。
vLLM 同一天進了 PR #41745,由 Google 工程師 @lucianommartins 寫,當天就被 vLLM 核心 maintainer @benchislett APPROVED,7 個 CI 全 pass,從發布到可跑只花了幾小時。
我在 DGX Spark(GB10 / SM12.1,128 GB unified memory)上跑了一整天的對照組。最後單 stream 拿到 108.78 tok/s,比 Part 7 我那篇 52 tok/s 紀錄的 2.09×。中途還踩了一個沒寫進任何文件的雷,差點以為 MTP 在 DGX Spark 上不能用。
起因:站在巨人肩上
PR 開沒幾小時,有個社群成員 @hospedales 已經在 DGX Spark 上實測過—用 NVIDIA 官方 NVFP4 26B 主模型 + Google 官方 MTP drafter,跑出 1.84× 加速(baseline 23.2 tok/s → MTP γ=4 42.6 tok/s)。
他在跑的過程中抓到 PR 的兩個 bug 並寫了 patch(分散在第一則跟第二則 PR comment):
intermediate_size來源錯(gemma4_mtp.py:297): drafter 的 MLP intermediate_size 應該從text_config拿(8192),PR 第一版從頂層 config 拿(4096) → MLP 構造錯誤,weight load 直接 AssertionErrorquant_config過度傳遞(line 186/193/299): 量化主模型的quant_config被傳到 drafter 的 Linear 層,vLLM 把 drafter 用 4-bit 包裝開記憶體,但 drafter 是 BF16 → 形狀不合,load 失敗
兩個 patch 都已合進 PR 最新 head,但官方 docker preview image build 時間早於 hospedales 抓 bug,所以 image 裡的 gemma4_mtp.py 是舊版。要跑量化主模型(NVFP4 / FP8)+ MTP,必須把 PR 最新版檔案 bind-mount 進 docker 蓋掉。
→ 我們站在 hospedales + lucianommartins 鋪好的路上,加 FP8 instruction-tuned 路徑做第三組對照資料。
第一個雷:Drafter 配 base model 反而變慢
我手邊有一個 gemma4-26b-a4b-fp8(社群量化版),平常拿來跑。第一直覺直接套 MTP:
| Config | tok/s |
|---|---|
| FP8 base baseline | 41.25 ± 0.07 |
| FP8 base + MTP γ=2 | 25.37 ± 0.02 ❌ |
反向慢 38%。換 enforce_eager 模式同樣慢。同 prompt 重複跑 5 次 std 0.02—不是 noise,是穩定的 negative speedup。
困惑了 30 分鐘才想到去看 model config:
$ cat config.json | head
$ grep chat_template tokenizer_config.json
chat_template: NO
我那個 FP8 是 base model,不是 instruction-tuned。沒 chat template,沒過 RLHF。
Google drafter gemma-4-26B-A4B-it-assistant 的 model card 明確指定配 gemma-4-26B-A4B-it(-it 版主模型)。我推測:drafter 訓練在 -it 主模型的 logit 分布上,RLHF 過後的 logit 跟 base 不同,drafter 拿來預測 base model 的 next token 接受率必須極低(沒精確 instrument,但根據速度反推顯著低於 -it 版的水準)。
→ MTP 多做的 drafter forward + 驗證成本沒被攤掉,反而拖累整體速度。
這個雷沒寫在 Google 官方 blog 也沒寫在 HF 公告 —兩邊都假設讀者用 -it 主模型。實務上很多自架者(我本人就是)是 quantize 完 base 用,完全沒意識到 drafter 必須配 -it。
修法:抓 -it FP8 版本
HuggingFace 上 -it FP8 變體有好幾個,我選了 RedHatAI/gemma-4-26B-A4B-it-FP8-Dynamic。Red Hat AI 在 vLLM 圈是常見品牌,FP8 Dynamic 是 vLLM 原生支援格式。
換完之後馬上跑,baseline 從 41.25 變 40.85(同 stack,差距 in noise)。但加 MTP 之後:
| Config | tok/s | speedup |
|---|---|---|
| it-FP8 baseline | 40.85 ± 0.10 | 1.0× |
| it-FP8 + MTP γ=2 | 74.51 ± 0.95 | 1.82× |
| it-FP8 + MTP γ=4 | 108.78 ± 0.41 | 2.66× ✅ |
108 tok/s 達成。Drafter 配對是 silent killer,配對後速度直接翻倍多。
三個 target 對照矩陣
我跑了三組量化主模型對照,drafter 全部用 Google 官方 gemma-4-26B-A4B-it-assistant,γ=4(每步草稿 4 個 token):
| Target | -it / base? | Baseline | + MTP γ=4 | speedup |
|---|---|---|---|---|
| FP8 base(社群版) | base | 41.25 | 25.37 | 0.61× ❌ |
| NVFP4 it(NVIDIA 官方) | -it | 30.23 | 76.88 | 2.54× ✅ |
| FP8 it(RedHatAI) | -it | 40.85 | 108.78 | 2.66× ✅ |
FP8-it 比 NVFP4-it 快,跟 Part 19 結論一致—GB10 上 FP8 路徑比 NVFP4 路徑快(SM12.1 沒原生 FP4 compute,NVFP4 走 Marlin fallback)。MTP 加上去後速度差距還在,FP8-it 始終 ~30% 領先。
並行:單 box 8 路 user 撐 674 tok/s
單 stream 108 tok/s 已經很爽,但 production 場景多半是多人並行。再開兩組:
| concurrency | aggregate tok/s | per-request tok/s | 倍數 vs baseline |
|---|---|---|---|
| 1 | 108.78 ± 0.04 | 108.78 | 2.66× |
| 4 | 348.30 ± 0.82 | 87.08 | 8.53× |
| 8 | 674.28 ± 6.03 | 84.29 | 16.51× |
兩個欄位是看同一個現場的兩個角度:
- aggregate tok/s = 整台機器同一秒吐出的總 token 數(所有 user 加起來)。站在「機器主人 / 部署方」的角度看,衡量這台 box 撐得起多少流量、單位成本能餵幾張嘴。
- per-request tok/s = aggregate ÷ concurrency,單一 user 個人感受到的打字速度。站在「使用者」的角度看,體感是不是順、要不要等。
舉例 conc=8 那列:8 個 user 同時打,每人感受到的速度 ~84.29 tok/s,加總起來機器整體 8 × 84.29 ≈ 674.28 tok/s aggregate。
8 路並行,每個 user 還拿到 ~84 tok/s 個人速度(比原單 user baseline 40 tok/s 還快 2×)。8 個 user 同時打,個人感受還比沒 MTP 的單 user 快。
(沒跟 hospedales 的並行數字直接比—他發的是 peak aggregate generation,我們是 sustained avg,單位不一致沒辦法 like-for-like。)
內容驗證:無損嗎?
光看數字不夠,得確認 MTP 沒生垃圾文。同 prompt 同 seed 各跑一次比對:
Prompt: 「列出前 5 個質數,並用兩句話解釋每個為什麼是質數」
Baseline 輸出(48 tokens):
The first 5 prime numbers are 2, 3, 5, 7, and 11. Each of these numbers is prime because it is only divisible by 1 and itself.
MTP γ=4 輸出(54 tokens):
The first five prime numbers are 2, 3, 5, 7, and 11. These numbers are prime because they are greater than 1 and cannot be formed by multiplying any two smaller natural numbers.
兩邊質數答對(2, 3, 5, 7, 11),解釋都正確(可被 1 跟自己整除 / 大於 1 且不能由兩較小自然數相乘)。但語句不完全相同。
這是預期行為。vLLM 的投機解碼 測試 對 MTP 的實際 assertion 是:
MTP_SIMILARITY_RATE = 0.8—跑一批 prompt,至少 80% 的 prompt baseline 跟 MTP 輸出要完全一樣(prompt-level 不是 token-level)- GSM8K accuracy 不能掉(threshold 0.8)
也就是 prompt-level 容許少數 prompt 不完全一樣,但 quality benchmark 必須維持。Google 官方 blog 講「no quality loss」是談 quality 層面,不是 bit-level identical。
→ 語意無損,不是 bit-level 一致。一般使用沒問題,但別期望 deterministic 重現。
Credits / 我們站在誰的肩上
這篇實測能在 24 小時內完成,完全靠下面這些人/團隊已經做完的工作:
- Google Research / DeepMind —Multi-Token Prediction 技術 + drafter 模型發布
- @lucianommartins(Google 工程師)—vLLM PR #41745 作者,2026-05-05 開 PR,當天就有可運行版本
- @benchislett —vLLM 核心 maintainer,APPROVED PR within hours
- @hospedales —DGX Spark + NVFP4 路徑第一份實測(18:14 UTC)+ 抓出兩個 bug 寫 patch(19:57 UTC second comment)+ 發 PR comment 公開分享
- RedHatAI —
gemma-4-26B-A4B-it-FP8-Dynamic量化版本 - NVIDIA —
Gemma-4-26B-A4B-NVFP4量化版本(對照組之一) - vLLM team —preview docker image
gemma4-0505-arm64-cu130(arm64 = DGX Spark 架構)
我們的貢獻:把 FP8-it 路徑 + concurrent throughput 加進這個對照表,給 DGX Spark 自架者一份可以照抄的最佳組合(108 tok/s 單 stream / 674 tok/s 並行)。
限制 / 開放問題
- docker preview image 缺 GB10 MoE tuning config —log 會跳
Using default MoE config. Performance might be sub-optimal! Config file not found at .../E=128,N=704,device_name=NVIDIA_GB10,dtype=fp8_w8a8.json。我們 baseline 因此比自家 vllm-node-tf5 build 慢約 24%。等 vLLM upstream 補 GB10 config(或社群拿出 auto-tune)後,baseline 跟 MTP 數字應該都會再往上 - Part 20 NVFP4→FP8 Triton patch 沒疊上去 —我自家 SM12.1 編譯出來的
sm121_quant_bind.so是針對 vLLM 0.17 + torch 2.10+cu131 + Qwen 35B 路徑做的,跟這次 docker 的 torch 2.11+cu130 + Gemma 4 不相容(ABI mismatch)。要疊起來得從 vLLM main + PR cherry-pick 重 build,~30-60 min CUDA compile,先放下次 - Drafter 是 BF16 沒量化 —0.87 GB 對 128 GB unified 來說可忽略。社群還沒發 NVFP4 / FP8 drafter,出來再測
- MTP 不 deterministic —同 prompt 同 seed 重跑兩次,baseline 的兩次完全一樣,但加 MTP 兩次間有 token-level 微差(per PR test plan acceptable)
懶人包:兩條 command 跑起來
DGX Spark 自架 + 跑 Gemma 4 26B-A4B 的人,今天起 default 配置抄這個。
Step 1: 模型先抓好(只要做一次,放在 ~/models/)
huggingface-cli download RedHatAI/gemma-4-26B-A4B-it-FP8-Dynamic \
--local-dir ~/models/gemma4-26b-a4b-it-fp8
huggingface-cli download google/gemma-4-26B-A4B-it-assistant \
--local-dir ~/models/gemma4-26b-a4b-it-assistant
Step 2: 抓 patched gemma4_mtp.py(直接從 vLLM PR head SHA 拉 — GitHub raw URL pinned to commit,永久 immutable),再 docker run:
# 抓 patched 檔(包含 hospedales 兩個 bug fix,docker preview image 還沒包)
# URL 是 PR #41745 head SHA d8b3826,不會因 PR 後續 push 而變
wget https://raw.githubusercontent.com/vllm-project/vllm/d8b3826648da6b407f8c55457a2103be9aeb5d83/vllm/model_executor/models/gemma4_mtp.py \
-O /tmp/gemma4_mtp.py
# 起 vLLM
docker run -d --name gemma4-mtp \
--gpus all --ipc host --shm-size 64gb \
-p 8000:8000 \
-v ~/models:/models \
-v /tmp/gemma4_mtp.py:/usr/local/lib/python3.12/dist-packages/vllm/model_executor/models/gemma4_mtp.py:ro \
vllm/vllm-openai:gemma4-0505-arm64-cu130 \
--model /models/gemma4-26b-a4b-it-fp8 \
--speculative-config '{"method":"mtp","model":"/models/gemma4-26b-a4b-it-assistant","num_speculative_tokens":4}' \
--kv-cache-dtype fp8 \
--gpu-memory-utilization 0.85 \
--max-model-len 4096 \
--limit-mm-per-prompt '{"image":0,"audio":0,"video":0}'
跑起來 → 單 stream 108 tok/s / 8 路並行 674 tok/s aggregate(每 user 仍 ~84 tok/s)。
PR #41745 正式 merge + 下個官方 docker image 出來後,這個 bind-mount workaround 就不需要了 — 屆時只要拉新 image,連 wget 那行都可以拿掉。
沒驗 production 等級的 monitoring / retry / SLA 那層 — 那是部署架構問題,不是模型吞吐問題。
相關閱讀
- Part 7—Gemma 4 26B 在 DGX Spark 跑 52 tok/s NVFP4 紀錄 —這篇的前序紀錄
- Part 19—NVFP4 在 GB10 是陷阱:FP8 快 32% —為什麼這篇選 FP8 不選 NVFP4 path
- Part 20—NVFP4 → FP8 Triton patch —我自家 SM121 加速 patch(沒疊進這次測試,理由見限制段)
- Google blog: Accelerating Gemma 4 with MTP drafters
- vLLM PR #41745: Add Gemma4 MTP speculative decoding
- hospedales' DGX Spark NVFP4 first test + follow-up bug patch comment
常見問題
- Gemma 4 26B-A4B 在 DGX Spark 上加 MTP drafter 能跑多快?
- FP8 instruction-tuned 主模型 + Google 官方 MTP drafter + γ=4,單 stream 跑 108.78 ± 0.41 tok/s,baseline 40.85 tok/s 的 2.66×。8 路並行 aggregate 達 674.28 tok/s,每 user 仍有 84 tok/s。N=5 measurements,std 都 < 1%。
- 為什麼 base 版主模型加 MTP 反而變慢?
- Drafter 是 `gemma-4-26B-A4B-it-assistant`,Google 在 model card 明確說配 `gemma-4-26B-A4B-it`。我推測:drafter 訓練在 -it 主模型的 logit 分布上,配 base 版 logit 對不上,接受率極低(我沒精確 instrument,但根據速度反推必須極低)。drafter 額外 forward 的成本沒被攤掉,反而比 baseline 慢 38%(實測 41 → 25 tok/s)。Drafter 必須配 -it 主模型。
- vLLM 主分支已經支援這功能了嗎?
- PR #41745(lucianommartins,Google 工程師)2026-05-05 開,當天就被 vLLM 核心 maintainer benchislett APPROVED,7 個 CI 全 pass。截至 2026-05-06 PR 仍 open、未 merge,等待正式合併中。社群可以用 vLLM 官方發的 `vllm/vllm-openai:gemma4-0505-arm64-cu130` preview docker(arm64 = DGX Spark 架構)。本文做法是把 PR 最新版的 `gemma4_mtp.py` bind-mount 進 docker(因為 docker 用稍舊的 SHA,沒包含 hospedales 抓的兩個 patch)。
- MTP 是無損加速嗎?輸出會跟 baseline 一樣嗎?
- **語意無損,不是 bit-level 一致**。Google 官方說 no quality loss。vLLM PR 的測試門檻是 prompt-level 至少 80% 完全一樣(`MTP_SIMILARITY_RATE = 0.8`)+ GSM8K 準確率不掉。我實測同 prompt 同 seed,baseline 跟 MTP γ=4 都答出『前 5 個質數是 2, 3, 5, 7, 11』,解釋句構不同但兩邊都正確。FP8 量化路徑下投機解碼會引入 text-level 非確定性。