DGX Spark · part 29
在 DGX Spark 上 30 行 docker 拿 +34%:huihui Gemma 4 FP8 + vanilla MTP n=1 部署 recipe
❯ cat --toc
TL;DR
Part 28 是 mechanism 文,這篇是部署 recipe。abliterated Gemma 4 26B-A4B FP8 + 官方 vanilla MTP draft,在 DGX Spark 上 baseline 39.3 → 52.6 tok/s = +34%,不用重訓任何東西,30 行 docker 拿到。
唯一 trap 是 vLLM stable release 還沒包 PR #41745(Gemma 4 MTP integration),所以暫時要走 preview image + bind-mount PR head 的 gemma4_mtp.py。verifier 用我自量化的 coolthor/Huihui-gemma-4-26B-A4B-it-abliterated-FP8-Dynamic,draft 用 Google 官方 gemma-4-26B-A4B-it-assistant。
為什麼值得單寫一篇 recipe
Part 28 的 narrative 鎖在 mechanism — vanilla draft 是 train 在 vanilla body 的 distribution 上,body 一被 abliterate 偏掉,deep speculation(n=2/3/4)結構性失效。整篇圍繞「draft 跟不上 body」這個 bottleneck。
但 bottleneck 只在 deep speculation 上才咬。n=1 上 draft 只猜一格(從 body 真實 hidden state 出發),只吃一次 distribution mismatch,vanilla draft + abliterated body 跑得起來,Part 28 sweep 第一格就是 52.6 tok/s。
對只想要 inference 跑快一點、不打算自己 fine-tune drafter 的人,n=1 +34% 是免費午餐。這篇就是純 deploy 文,跳過 mechanism、直接給 recipe。
你會拿到什麼
| 模式 | tok/s | vs baseline | pos-0 acceptance |
|---|---|---|---|
| huihui FP8 baseline(no spec) | 39.3 | — | — |
| + vanilla MTP n=1 | 52.6 | +34% | 69% |
數據實測,設定細節 + 為什麼 n>1 不要碰見 Part 28。
Prereq checklist
- DGX Spark / ARM64 + GB10(sm_12.1,121 GB unified memory,273 GB/s bandwidth)
- Docker + nvidia-container-runtime
huggingface-cli裝好(這兩個 model 都 public/ungated,2026-05-14 我這邊抓不需要 token;但建議還是先login避免哪天 upstream 改 gated)- 約 30 GB free disk:huihui FP8 27 GB + Gemma 4 assistant draft ~1.7 GB
為什麼不能直接用 vLLM 穩定版
Gemma 4 MTP support 在 vLLM PR #41745 merged 2026-05-06 進 main。但目前最新 stable release 是 v0.20.2(2026-05-10),它是從 v0.20.1(5/04)切出來的 patch release(status: diverged, behind_by: 39),release notes 只 cherry-pick 4 個 bug-fix bullet:DeepSeek V4 sparse-attn × 2(MTP=1 hang + KV cache alloc)、gpt-oss MXFP4 + torch.compile × 1、Qwen3-VL deepstack × 1。完全沒有 PR #41745 的影子。
選項:
- 從
mainbuild vLLM(乾淨但要等 build) - 用 nightly image(隨 nightly 走,穩定性靠運氣)
- 用
eugr/spark-vllm-dockerpreview image + bind-mount PR head 的gemma4_mtp.py(本文採用,踩坑最少) - 等下一個 minor release(v0.21.x,還沒釋出)
Recipe
1. 抓兩個 model
huggingface-cli download coolthor/Huihui-gemma-4-26B-A4B-it-abliterated-FP8-Dynamic \
--local-dir ~/models/Huihui-gemma-4-26B-A4B-it-abliterated-fp8
huggingface-cli download google/gemma-4-26B-A4B-it-assistant \
--local-dir ~/models/gemma-4-26B-A4B-it-assistant
2. 抓 pinned commit 的 gemma4_mtp.py
mkdir -p ~/mods/gemma4-mtp-fix
# Pin 到 PR #41745 merge commit 27e0057a — 避免之後 main drift 把這份檔案改掉
curl -fsSL \
https://raw.githubusercontent.com/vllm-project/vllm/27e0057aeda6bc443069c20fdf2f3cc95ed892f3/vllm/model_executor/models/gemma4_mtp.py \
-o ~/mods/gemma4-mtp-fix/gemma4_mtp.py
md5sum ~/mods/gemma4-mtp-fix/gemma4_mtp.py
# 記下這個 md5,下面 sanity check 會對照
3. Docker run(bind-mount + serve config)
docker run --gpus all --rm --network host --name vllm_huihui --privileged --ipc=host \
-v $HOME/models:/models:ro \
-v $HOME/mods/gemma4-mtp-fix/gemma4_mtp.py:/usr/local/lib/python3.12/dist-packages/vllm/model_executor/models/gemma4_mtp.py:ro \
--entrypoint /bin/bash \
vllm/vllm-openai:gemma4-0505-arm64-cu130 \
-c 'vllm serve /models/Huihui-gemma-4-26B-A4B-it-abliterated-fp8 \
--served-model-name huihui-gemma4 \
--speculative-config "{\"method\":\"mtp\",\"model\":\"/models/gemma-4-26B-A4B-it-assistant\",\"num_speculative_tokens\":1}" \
--kv-cache-dtype fp8 \
--gpu-memory-utilization 0.65 \
--max-model-len 8192 \
--limit-mm-per-prompt "{\"image\":0,\"audio\":0,\"video\":0}" \
--enable-auto-tool-choice --tool-call-parser gemma4 \
--enable-prefix-caching \
--trust-remote-code \
--host 0.0.0.0 --port 8000'
為什麼是 n=1 — Part 28 sweep 過 n=1..4,只有 n=1 在 huihui body 上比 baseline 快。n=2/3/4 都更慢。
為什麼 gpu-memory-utilization=0.65 — 留 headroom 給 draft model + KV cache 緩衝。0.85 也跑得起來,但 n=1 用不到那麼大 KV budget。
4. Sanity check 三步
# (a) 確認 bind-mount 沒被吃掉 — md5 跟你下載的那個對得上
docker exec vllm_huihui md5sum /usr/local/lib/python3.12/dist-packages/vllm/model_executor/models/gemma4_mtp.py
# (b) 確認 server 起來、模型對
curl -s http://localhost:8000/v1/models | python3 -m json.tool
# (c) 發一個 request、看 /metrics 確認 spec decode 真的在跑
curl -s -X POST http://localhost:8000/v1/completions \
-H 'Content-Type: application/json' \
-d '{"model":"huihui-gemma4","prompt":"Write a haiku about an old API.","max_tokens":80,"temperature":0.7}' \
| python3 -m json.tool
curl -s http://localhost:8000/metrics | grep spec_decode_num_accepted_tokens
最後一條應該看到 vllm:spec_decode_num_accepted_tokens_per_pos_total{position="0"} 隨著 request 增加。如果完全沒 increment,通常是 (a) bind-mount 失敗 → md5 不對、或 (b) --speculative-config 拼錯 → 起來時 vLLM log 會有 warning。
什麼時候 n=1 不夠用 — 三個判斷點
- 想拉到 >52 tok/s:這條路天花板就是 52。要往 100+ 必須 deepen spec,而 deepen 在 abliterated body 上要重訓 drafter(Part 30 forthcoming 我們在跑 EAGLE-3 fine-tune)
- 繁中重 task:Gemma 4 TMMLU+ 46.30%,Qwen 3.6 35B-A3B 75.07%(見 TMMLU+ paired bench)。如果 task 是 BPS 紀錄、podcast 摘要、繁中 brainstorm,留 Qwen 3.6 主力,Gemma 4 適合英文 / image gen prompt 寫作
- 想吃 batch throughput:本 recipe 是 batch=1 latency 場景。生產 batch≥4 的設定要重調
gpu-memory-utilization+max-num-batched-tokens,不在本篇 scope
License 跟 attribution
- huihui FP8 release 繼承 Gemma 4 Apache 2.0(Gemma 4 license 頁、HF 官方 model card 都明寫)
- 上游 base:
huihui-ai/Huihui-gemma-4-26B-A4B-it-abliterated - vLLM PR:#41745
相關
常見問題
- 為什麼單寫一篇 recipe,不寫在 Part 28 裡?
- Part 28 是 mechanism 文(解釋為什麼 deep speculation 在 abliterated body 上會壞掉),narrative 鎖在「draft 跟不上 body」這個 bottleneck 上。這篇是純 deploy 文,讀者不需要懂 mechanism 也能拿到 +34%,讀完跑就有結果。兩篇互補不重疊。
- 升 vLLM v0.20.2(5/10 release)能直接拿到 +34% 嗎?
- 不能。PR #41745(Gemma 4 MTP integration)merged 2026-05-06 進 main branch,但 v0.20.2 是從 v0.20.1(5/4)分出來的 patch release,實測 compare `behind_by:39`、不含 #41745(release notes 是 4 bug-fix bullets:DeepSeek V4 sparse-attn ×2 / gpt-oss MXFP4 ×1 / Qwen3-VL deepstack ×1)。要嘛從 main build,要嘛用 preview image + bind-mount,要嘛等下一個 minor release。
- 為什麼不直接跑 num_speculative_tokens=4?
- 在 abliterated body 上 deep speculation 結構性失效(Part 28 細節)。huihui n=2/3/4 的 throughput **比 n=1 慢**,per-position acceptance 22pp/step 衰減。n=1 是 huihui 唯一 sweet spot,生產上不要往深開。
- 想再快怎麼辦?
- 兩條路:(a)走 vanilla Gemma 4 + MTP n=4 可以拉到 108 tok/s(Part 27),但失去 abliteration;(b)fine-tune EAGLE-3 drafter 對齊 abliterated body 的 distribution,目標是讓 n=4 在 abliterated 上也跑得起來。我們正在做 (b),結果出來會發 Part 30。