DGX Spark · part 28
想用 MTP 加速 abliterated Gemma 4?vanilla draft 對不上被改過的 body
❯ cat --toc
- 衝突在哪:vanilla draft 跟 abliterated body 對不上
- 為什麼自量化
- 量化 recipe
- Smoke test 三模態
- 上路:vanilla / huihui 雙邊同 config 對照
- 證據 1:sweep `n=1..4`,看猜對機率掉到哪
- 自首:三個我塞進去的編造數字
- 1. Vanilla baseline 60 tok/s(第一稿,實測 39.4)
- 2. Vanilla per-position decay 92/85/78/70(第二稿,實際沒測)
- 3. Gemma 4 license「不是純 Apache 2.0」(第二稿,實際就是)
- 那 Part 27 的 108 tok/s 是哪裡來的?
- Per-position decay 把 mechanism 釘在數字上
- 對 hikari/kiriha use case 的建議
- 接下來:為 spec decode acceptance 優化的 abliteration
- 用法
- 相關
TL;DR
想用 MTP 加速 abliterated 版本的 Gemma 4?vanilla 官方 draft 是配 vanilla body 訓練的,body 被 abliterate 改過後 draft 跟不上 — n 越深複合 error 越大,猜對機率越低,vanilla draft 形同失效。
自量化 huihui-ai/Huihui-gemma-4-26B-A4B-it-abliterated 成 FP8-Dynamic ship 上 HF(2026-05-09 我在 HF 上沒找到此 base 其他 vLLM-loadable FP8 衍生)。同 config 對照:abliterated body 跟 vanilla baseline 完全一樣(39.4 vs 39.3 tok/s),n=1 上 MTP 加成也一樣;但 n=4 deep speculation 上 vanilla 過去做到 108 tok/s(Part 27 config),huihui 同 stack 只到 50。元兇推測是 per-position acceptance decay:huihui 每 step 衰減 ~22pp(65/43/29/21,vLLM /metrics 實讀)。⚠️ 寫 blog 兩稿我自己擺了三個 fabrication(60 tok/s baseline、92/85/78/70 vanilla decay、Gemma 4 license),都被 Codex 連續 attack 打掉。這篇是第三版,把坑老實寫進去當反面教材。
衝突在哪:vanilla draft 跟 abliterated body 對不上
先講結論再給證據。Speculative decoding(spec decode)三角:主模型 body、小 draft model、num_speculative_tokens=n(一次猜幾格)。draft 一次猜 n 個 token,body 一次性驗證,猜對的接受、猜錯的退回。
Google 釋出的 gemma-4-26B-A4B-it-assistant 是個 4-layer Gemma4Assistant,配 vanilla google/gemma-4-26B-A4B-it body 訓練。draft 模型學到的就是「vanilla body 在這個 hidden state 下,下一個 token 機率分布大概長這樣」。
但 abliteration 流派(huihui / TrevorJS / llmfan46 / Heretic ARA)做的事情,就是改 body 的 weight 讓 distribution shift — 拔掉 refusal direction 的代價是整個 hidden state 子空間的偏移。draft 看到的不再是它訓練時記得的 vanilla 分布,猜對機率自然下降。
更糟的是 autoregressive draft 的複合:
n=1→ draft 只猜下一格(從 body 真實 hidden state 出發),只吃一次 distribution mismatch。可以接受。n=4→ draft 猜 pos 0,然後用自己 pos 0 的 prediction 當 input 往 pos 1 推,再用 pos 1 推 pos 2…… 每滾一格疊一次 mismatch。n越深,猜對機率越低。
所以 deep speculation 在 abliterated body 上結構性失效:不是 draft 慢,是 draft 答案越來越離譜被 body 全 reject。下面整篇用測試把這個 mechanism 釘在數字上。
為什麼自量化
huihui-ai 是 abliteration 圈出量大的 publisher 之一,他們的 26B Gemma 4 BF16 在 HF 上 download 數量級數萬(2026-05-09 我這邊看 14188)。Quant 衍生(同樣是 2026-05-09 抓)的狀況:
| 格式 | 公開狀態 |
|---|---|
| BF16 原版 | ✅ huihui-ai 自己 |
| FP8-Dynamic(vLLM 用) | ❌ HF 上我搜不到 |
| NVFP4 | ✅ sakamakismile |
| GGUF(多家) | ✅ groxaxo / bullerwins / mradermacher / iamhsouna |
| MLX(Apple) | ✅ vanch007 |
| Q8_0 GGUF | ✅ puppert |
vLLM 用戶要跑這個 model 只剩兩條路:--quantization fp8 runtime 動態量化(實測 ~6× 慢),或自己預量化成 FP8 safetensors。GGUF 路徑能餵 llama.cpp / ollama / oobabooga textgen / LM Studio 等(NVFP4 路徑也有人放),但 vLLM 直接吃 GGUF 還在實驗階段、不適合生產 — 所以這個 base model 在 vLLM 圈的 FP8 niche 還沒人補,我們補。
量化 recipe
工具:llm-compressor + FP8_DYNAMIC scheme。Critical ignore list — re:.*router.* 必須在,MoE router weights 不能被量化,否則 expert dispatch 會崩(我們在自己測試時驗過)。
ignore = [
"re:.*router.*", # ← 關鍵,MoE router 不能量化
"lm_head",
"re:.*embed_tokens.*",
"re:.*norm.*", "re:.*layernorm.*", "re:.*layer_norm.*",
"re:.*rmsnorm.*", "re:.*rms_norm.*",
"re:.*conv1d.*", "re:.*linear_attn.*",
"re:visual.*", "re:model.visual.*",
"re:.*patch_embed.*", "re:.*vision.*", "re:.*image.*",
"re:.*video.*", "re:.*projector.*", "re:.*merger.*",
"re:.*mlp.gate$", "re:.*shared_expert_gate.*",
"re:.*embed_audio.*", "re:.*embed_vision.*",
"re:.*audio_tower.*", "re:.*audio_projector.*",
]
踩坑提醒:llm-compressor 穩定版 PyPI metadata 寫 transformers>=4.56.1,<=4.57.6,但 Gemma4ForConditionalGeneration 在 transformers v4.57.6 還沒進 — 我實測得用比這個 pin 更新的 transformers 分支(我這邊跑通的版本是 5.x 系列,具體 minor 看你 venv)。修法是 patch llmcompressor/entrypoints/utils.py 把 use_auth_token=... 拿掉(我在較新 transformers 分支上需要這樣改才跑通,新版 from_pretrained 是改用 token=...)。
GB10 上量化跑 2.9 分鐘(data-free pipeline,純 calibration + scale derivation,不需要訓練資料)。產出 27 GB FP8。
Smoke test 三模態
| 模態 | 結果 | 備註 |
|---|---|---|
| Text 英文 | ✅ haiku 語意正確 | 1.7 秒 |
| Text 繁體中文 | ✅ 80 tok 自嘲幽默,abliteration 還在 | 2.3 秒 |
| Vision(古風美女漢服圖) | ✅ 漢服、竹林、薄霧、低頭表情全描述對 | 2.8 秒 |
| Audio | N/A — Gemma 4 26B-A4B-it 架構本身 audio_config: null | 不是 quant 的鍋 |
上路:vanilla / huihui 雙邊同 config 對照
Part 27 我們紀錄過 vanilla Gemma 4 + MTP γ=4 達到 108.78 tok/s(N=5,std < 1%),baseline 40.85(2.66×)。Part 27 的 launch config 是 max_model_len=4096 + gpu_memory_utilization=0.85,但 acceptance 沒 publish 數字(只有 vLLM test 套件的 80% prompt-similarity gate,跟 token-level acceptance 是兩回事)。
今天為了 apples-to-apples 對照,我重新在同一台 GB10 上同 config 跑了 vanilla + huihui 兩邊 — 不直接拿 Part 27 數字當 vanilla 對照(quantization provenance 不同、bench 條件不同)。
| 項目 | 值 |
|---|---|
max_model_len | 8192(對照組)/ 65536(huihui 大 KV 嘗試) |
gpu_memory_utilization | 0.65 / 0.85 |
kv_cache_dtype | fp8 |
temperature | 0.7 |
tool_call_parser | gemma4 |
| MTP draft model | google/gemma-4-26B-A4B-it-assistant |
| vLLM image | vllm/vllm-openai:gemma4-0505-arm64-cu130 |
| MTP fix mod | mods/gemma4-mtp-fix-only(PR #41745 head 的 gemma4_mtp.py) |
| FP8 source | huihui 自量化(re:.*router.* ignore list 全配)/ vanilla 用 RedHatAI gemma-4-26B-A4B-it-FP8-Dynamic(ignore list 較精簡) |
⚠️ Confound 自首:vanilla 跟 huihui 的 FP8 量化路徑不一樣(不同 publisher、不同 ignore list)。Body baseline 兩邊都跑出 ~39 tok/s 是個強信號(quant pipeline 差異沒拉開速度差),但 per-position acceptance 跨兩邊比較時這條 confound 還在,讀者讀數字時要扣掉這個雜訊。
證據 1:sweep n=1..4,看猜對機率掉到哪
如果文章開頭的 mechanism 對,那 throughput 跟 acceptance 都應該隨 n 變大而走低 — n=1 只吃一次 mismatch,n=4 吃四次複合。
huihui FP8 throughput sweep(同 config,只變 n):
num_speculative_tokens | Throughput | Token-level acceptance | Pos-0 acceptance |
|---|---|---|---|
| 1 | 52.6 tok/s | 69% | — |
| 2 | 51.4 tok/s | 57% | 68% |
| 3 | 46.9 tok/s | 46% | 64% |
| 4 | 50.0 tok/s | 39% | 66% |
huihui 是 n=1 peak,n>1 都更慢,沒有 sweet spot。
bench methodology disclaimer:每個 cell 是 N=10 prompts × T=0.7 × batch=1,prompt 池固定但沒固定 seed,server 都跑過 1 個 warmup prompt 才開始計時。沒做 run-to-run repetition,所以 ±1-2 tok/s 的差距讀者要當 noise(不是「n=2 比 n=1 慢」這種小差距是統計顯著事件)。 acceptance 數字直接從 vLLM /metrics 的 vllm:spec_decode_num_accepted_tokens_per_pos_total 抓,跨 10 prompts 平均。
vanilla Gemma 4 對照(Part 27 已 published,N=5 std<1%):
| n | Throughput | Baseline | 倍率 |
|---|---|---|---|
| 4 | 108.78 tok/s | 40.85 | 2.66× |
(Part 27 launch config 是 max_model_len=4096 + gpu_mem=0.85,跟我今天 huihui 大 KV 嘗試的 65536/0.85 不完全一致,單純說「vanilla deep spec 上得去」這個結論方向沒問題,但拿來做點對點比較不算 apples-to-apples。Part 27 article 沒 publish token-level acceptance 數字,只有 vLLM test 套件的 80% prompt-similarity gate — 那個 80% 不是 acceptance 指標,我之前文章裡併寫成「~80% acceptance」是誤讀。)
vanilla 在 n=4 上仍能拉到兩倍以上,huihui 在 n=4 上反而慢於 n=1。
自首:三個我塞進去的編造數字
寫這篇兩稿過程,我自己塞了三個沒驗證的數字進去,都被 Codex 在 /debate attack 跟 Step 9 fact-check 抓回來。記下來當「LLM 寫技術文沒查就硬寫」的反面教材。
1. Vanilla baseline 60 tok/s(第一稿,實測 39.4)
第一稿沒實測 vanilla 在今天 config 下的 baseline,憑感覺寫「vanilla baseline 推估 ~60 tok/s」當對照,然後得出「huihui 39.3 vs vanilla 60 = 50% abliteration tax」的結論。Codex 動手讀 Part 27 .mdx 文件後指出 vanilla 同 config 的 baseline 沒人測過,我那 60 是憑空的。
實際補測 vanilla 同 config(max_model_len=8192、gpu_mem=0.65,小 KV 那組):
| baseline(no spec) | + MTP n=1 | |
|---|---|---|
| vanilla FP8 | 39.4 tok/s | 51.9 tok/s |
| huihui FP8 | 39.3 tok/s | 52.6 tok/s |
| Δ | 0.1(noise) | 0.7(noise) |
body 完全不收稅。「50% tax」假說整個錯,這也是整篇從 test-first 改成 mechanism-first framing 的觸發點。
2. Vanilla per-position decay 92/85/78/70(第二稿,實際沒測)
第二稿想對照 huihui 65/43/29/21,我寫了一組「vanilla 估 92/85/78/70」當對比 — 那是假設等比衰減 + 從 token-level 80% 反推的 numerology,不是 measure 出來的。Codex 第二輪 attack 直接抓出 Part 27 自己沒 publish per-position 數字,我那組「估」就是從幾何級數推回去的看似精確的編造。已拿掉,留下 hole 比留 fake precision 好。
3. Gemma 4 license「不是純 Apache 2.0」(第二稿,實際就是)
第二稿我又寫「Gemma 4 受 Gemma Terms of Use 約束、不是純 Apache 2.0」,Codex 第二輪 curl 打臉:
- Gemma terms 頁明寫:For Gemma 4 terms, see the Gemma 4 license
- Gemma 4 license 頁直接是 Apache License 2.0
- HF 官方 model card(
google/gemma-4-26B-A4B-it)frontmatter 寫license: apache-2.0
Gemma 1/2/3 走 ToU,Gemma 4 改成 Apache 2.0。HF release 用 apache-2.0 沒問題。
那 Part 27 的 108 tok/s 是哪裡來的?
主要差兩件事:num_speculative_tokens=4 + Part 27 自己的 launch config。
- Part 27 launch:
max_model_len=4096+gpu_memory_utilization=0.85+num_speculative_tokens=4 - 我今天小 KV 對照組(同 stack 跑 vanilla / huihui):
max_model_len=8192+gpu_mem=0.65+n=1時兩家都 ~52 tok/s - 我今天 huihui 大 KV 嘗試:
max_model_len=65536+gpu_mem=0.85+n=4→ 50 tok/s
vanilla 在 deep spec(n=4)上能拉到兩倍以上(52 → 108);但 huihui 在 deep spec 上不上去(52 → 50)。
關鍵變數是 num_speculative_tokens,不是 KV budget 大小。
Per-position decay 把 mechanism 釘在數字上
文章開頭講的「draft 每滾一格疊一次 distribution mismatch」,從 vLLM /metrics 的 vllm:spec_decode_num_accepted_tokens_per_pos_total 讀出來長這樣:
huihui per-position(n=4 大 KV,實讀):
pos 0: 65.6%
pos 1: 43.3% ← 衰減 22.3pp
pos 2: 29.2% ← 衰減 14.1pp
pos 3: 20.5% ← 衰減 8.7pp
每往後一格,draft 在自己上一個錯誤 prediction 上滾,猜對機率掉了 ~22pp。串到 pos 3 時 draft 真的是在亂猜了 — pos 3 acceptance 20% 等於 80% 的時候 body 直接 reject draft 那格、改用自己的 forward 結果。
Vanilla 這邊我沒實測 per-position,Part 27 也沒 publish。可以講的只有「vanilla n=4 上拉到 2.66× baseline,平均 acceptance 必須相對高(否則複合收益不會這麼大)」。配對比較我故意不做(理由見下面自首章節)。
對 hikari/kiriha use case 的建議
hikari + kiriha 主力 LLM 走 spec decode 加速時:
| 用法 | 推薦 |
|---|---|
| Chat / brainstorm(短回覆,低 latency 期望) | n=1(huihui 跟 vanilla 都 ~52 tok/s) |
| 長產生 / 寫作(throughput 重要) | vanilla n=4 = 108(快兩倍),但失去 abliteration |
| Abliterated + 不在乎 deep spec | huihui FP8 n=1,52 tok/s,自由 |
繁中重的 task(memory 紀錄 TMMLU+ paired Qwen 3.6 75% 對 Gemma 4 46% 差 29pp)還是留 Qwen 3.6 主力,Gemma 4 abliterated 適合英文 brainstorm + image gen prompt 寫作。
接下來:為 spec decode acceptance 優化的 abliteration
這次反而看到一條值得繼續試的路:abliteration 流派都在壓「refusal rate」,幾乎沒人在調「MTP acceptance」。huihui 的 abliteration 太重(自承「crude POC」),per-position decay 陡;p-e-w/Heretic + ARA 流派(llmfan46 用的)較輕但仍未針對 spec decode 調過。
下一步嘗試:用 Heretic + Optuna,target KLD ~0.025(比 llmfan46 的 0.0468 還低一半)、conservative hparams。實際開跑後從 trial 參數看到 Heretic 的 ARA 預設會同時動 attn.o_proj 跟 mlp.down_proj(我原本以為只動 attn.o_proj,trial output 打臉了),這個 footprint 對 MoE 架構的 expert path 影響待實測才知道。
這一段全是 hypothesis 不是承諾。我能合理猜的只有 baseline 不會壞(本篇已實測 abliteration 不影響 body 速度)。pos-0 acceptance / decay 斜率 / n=4 throughput 有沒有改善都要實測才知道,結果可能是改善、可能是沒改善、可能是反而更糟(Heretic ARA 流派沒人在「最大化 MTP acceptance」這個 objective 上跑過 Optuna)。
如果真的能把 decay 拉緩到讓 n=4 翻盤,會發一個小眾版 + 補 Part B;沒效就直接寫「這條路試過不行」 — 失敗也有資訊價值,把它寫出來才不浪費。
用法
pip install vllm # 注意:Gemma 4 MTP 要 PR #41745 之後才有,可能需要從 main build 或用 preview image
# 推薦:huihui FP8 + vanilla MTP n=1(+34% over no spec)
vllm serve coolthor/Huihui-gemma-4-26B-A4B-it-abliterated-FP8-Dynamic \
--speculative-config '{"method":"mtp","model":"google/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 \
--trust-remote-code
MTP 注意:Gemma 4 MTP 整合在 vLLM PR #41745(2026-05-06 merged)之後才完整。我自己用 eugr/spark-vllm-docker 的 vllm/vllm-openai:gemma4-0505-arm64-cu130 preview image,然後 bind-mount PR head 的 gemma4_mtp.py 進 container 蓋掉 image 內舊版本(這個 mod 是我 local 自己加在 mods/ 底下的,還沒 push 上 upstream)。踩過的坑:用 docker exec 跳過 recipe runner 會 silently 失去 mod,結果 spec decode acceptance 跑出 0% —— container 啟動後 md5sum gemma4_mtp.py 對照 PR head 是穩當的 sanity check。
相關
常見問題
- 在 GB10 上跑 huihui Gemma 4 abliterated FP8 會不會被收速度稅?
- 看 `num_speculative_tokens`。同 stack 同 config,abliterated body 的 baseline(no spec)39.3 tok/s,vanilla 量到 39.4 — 兩家在 noise 範圍內一樣。MTP n=1 也一樣:vanilla 51.9、huihui 52.6。差距只在 deep speculation 上開:n=4 大 KV config,vanilla 拉到 108(Part 27),huihui 卡 50,等於慢 54%。代價在 spec depth 不在 body。
- 為什麼 abliterated 在 deep spec 上吃不到加速?
- Per-position acceptance decay。從 vLLM `/metrics` 直讀,huihui n=4 每 step 衰減 22pp:pos 0 65.6%、pos 1 43.3%、pos 2 29.2%、pos 3 20.5%。複合下來把整體 speedup 砍半。MTP draft 模型 `google/gemma-4-26B-A4B-it-assistant` 是 train 在 vanilla body 的 distribution 上的;body 一被 abliteration 偏掉,drafter 自己用前一格 prediction 推下一格就越推越歪。Vanilla per-position 我沒實測,所以不做配對比較 — 前一稿亂編一組數字被打過。
- 這是 huihui abliterated 第一個 vLLM-loadable FP8 嗎?
- 2026-05-09 我在 HF 上沒找到 `huihui-ai/Huihui-gemma-4-26B-A4B-it-abliterated` 的其他 FP8 衍生。GGUF(多家)、MLX、NVFP4、Q8_0 都已有 publisher,FP8-Dynamic 是缺口我順手補。寫「第一個」會比我能證的強,所以就不寫。
- production 用 huihui FP8 推薦怎麼跑?
- 要 spec decode 就跑 `num_speculative_tokens=1`。和 vanilla MTP n=1 一樣 ~52 tok/s、69% pos-0 acceptance、abliteration 沒收稅。**不要往 n=2/3/4 加** — 這個 body 越深越慢。如果不在乎 spec decode,baseline 39 tok/s 兩邊一樣。繁中重的工作流還是建議留 Qwen 3.6 abliterated FP8 當主力(TMMLU+ 75% vs Gemma 4 46%)。