~/blog/dgx-spark-gemma4-12b-omni-nvfp4-weight-only

DGX Spark · part 36

[Benchmark] Gemma 4 12B omni 上 DGX Spark:weight-only NVFP4 贏 W4A4,還保住多模態

2026-06-043 分鐘閱讀#dgx-spark#gb10#gemma-4#nvfp4English
cat --toc

TL;DR

我在 DGX Spark GB10 上量化了 Google 剛出的 omni Gemma 4 12B(同一顆吃文字 + 圖片 + 語音 + 影片),用 vLLM 測 throughput。結論:weight-only NVFP4(W4A16)是贏家 —— 7.7GB、24.9 tok/s,四種模態全都還能用。 直覺會選的全 NVFP4(W4A4)其實一無所獲:沒比較快(23.9 vs 24.9,差在誤差範圍內),還把圖片/語音/影片弄壞 —— 因為它的 activation 量化是用文字校準的,把分布外的多模態 embedding 夾爆了。FP8 在中間,15.9 tok/s / 13GB。還有一個坑:在純 transformers 裡每種量化都「比 BF16 慢」(沒 native kernel),真正的加速只有上 vLLM 才看得到。

白話版

Gemma 4 12B 是一顆能讀文字、圖片、語音、影片的模型。量化會讓檔案變小,在對的 runtime 上也會變快。意外的是:最激進的 4-bit 設定(權重 activation 都量化)反而把圖片/語音/影片的理解弄壞,而且根本沒比較快。只量化權重的版本檔案更小、速度持平、能力全保住。所以對多模態模型,不要量太兇反而贏


數字:NVFP4 weight-only 是贏家

同一台 DGX Spark(GB10、sm_121a、頻寬 273 GB/s),vLLM 0.22.1 native,單流 decode、warm、EN+ZH:

格式檔案tok/svs BF16Omni
BF1623 GB7.7
FP8 dynamic13 GB15.92.1×
NVFP4 W4A47.7 GB23.93.1×❌ 壞掉
NVFP4 W4A16(weight-only)7.7 GB24.93.2×

weight-only 那版檔案最小、速度跟 W4A4 持平,而且是唯一一個還保住多模態的 4-bit 版本。直覺選的全 W4A4 —— 速度上一點便宜都沒佔到,還把多模態整個賠掉。多那一層 activation 量化,在這裡是純虧。

為什麼 W4A4 會把 omni 弄壞

NVFP4 W4A4 把權重 activation 都壓到 4-bit。activation 的 scale 是跑一次校準算出來的 —— 而我跟大家做 LLM 一樣,用文字校準(UltraChat)。

坑就在這。當你餵一張圖或一段語音,那個 encoder-free 的 projector 會把原始的 patch / waveform embedding 送進語言模型。這些 activation 的分布跟文字不一樣。用文字校出來的 4-bit activation 範圍會把它們夾掉,模型就崩了:我實測下來,圖片跟影片回空白、語音吐出一堆不相關的字,但純文字完全正常。

關鍵線索是語音:它壞了,可是語音 projector 本身是留 BF16 的。所以兇手不是被量化的 projector,是 text tower 的 activation 量化,對多模態 activation 來說整個是分布外。

weight-only NVFP4(W4A16)沒有 activation 量化 —— activation 留 BF16 —— 所以沒有校準對不上的問題。圖片、語音、影片全都回來了:

  • 圖片:「錄音室裡兩隻貓,戴著耳機,牆上有 'ON AIR' 霓虹燈,專業麥克風,筆電。」
  • 語音:把一段 LibriSpeech 轉成文字 —— "Mr. Quilter is the apostle of the middle classes..."
  • 影片:「一個穿黑色緊身衣的女子走在夜晚的濕街上。」

而且 weight-only 在速度上一毛都不用付:在這種 bandwidth-bound 的 dense 模型上,W4A16 那條路(dequant 回 BF16)甚至小贏一點(24.9 對 23.9,算平手)。所以 W4A4 的 activation 量化在這裡換不到任何 throughput。這跟我在 Part 32 對 dense 模型測到的一致 —— 關鍵在頻寬,不是 FP4 ALU。

HF-eager 陷阱:用錯 runtime,量化看起來「更慢」

有個數字差點把我帶歪。同一份量化權重,改用純 transformers(HF eager)跑:

格式HF eager tok/svLLM native tok/s
BF167.37.7
FP85.315.9
NVFP4 W4A164.724.9

在 transformers 裡 NVFP4 是最慢的 —— 因為沒有 native FP4 kernel,每次 forward 都把權重拆回 BF16:量化的開銷全付了,頻寬的好處一個都沒拿到。換上 vLLM 的 native kernel,排序整個翻過來 —— NVFP4 變最快,同一份權重差 5 倍。永遠用你真的會拿去 serve 的 runtime 來測。

在 GB10 上 serve gemma4_unified:兩件必備

Gemma 4 12B 是個新架構(gemma4_unifiedGemma4UnifiedForConditionalGeneration)。要在 DGX Spark 上 serve,有兩個不明顯的條件:

  1. 要有含 native class 的 vLLM build(大約 0.22.x / main)。舊版會 fallback 到 vLLM 的 generic transformers backend,在注意力的 output projection 那步直接崩 —— 因為 Gemma 4 的注意力是非對稱的:head_dim 256 × 16 heads = 4096,跟 hidden 3840 不一樣(它是 GQA,8 個 KV head)。generic backend 預設了對稱的情況,就把投影的形狀切錯了。
  2. VLLM_ATTENTION_BACKEND=TRITON_ATTN —— 這個 backend 才處理得了那個非對稱注意力。
VLLM_ATTENTION_BACKEND=TRITON_ATTN \
vllm serve coolthor/gemma-4-12B-it-NVFP4A16 --max-model-len 4096

(提醒:vLLM 現在的 generic 多模態 wrapper 只吃 image,所以完整的 audio/video serving 還在等上游 —— 但四種模態都能用 transformers 跑。)

真正能在 vLLM 上載入的量化 recipe

這部分很龜毛又沒文件。vLLM 的 native gemma4_unified 會量化特定一組模組,如果你 checkpoint 裡哪些層有量化、哪些沒量化跟它對不起來,它就載不進來。能動的 recipe:

QuantizationModifier(targets="Linear", scheme="NVFP4A16",
    ignore=["lm_head", "re:.*embedding_projection.*"])

白話:量化 text tower 加上視覺的 patch_dense;lm_head兩個 embedding_projection(視覺 + 語音)留 BF16。這跟 vLLM 怎麼建這顆模型一致 —— patch_dense 是帶 quant config 建的 ColumnParallelLinear,projector 則是純 BF16 linear。(另外:用 llmcompressor 的 basic pipeline,不要用 sequential —— sequential 的 tracer 在這個新架構上會撞 UserDict 錯誤。)

模型

兩個都在 Hub 上,Apache 2.0,omni 完整:

TL;DR

  • 在 DGX Spark GB10 上,Gemma 4 12B omni weight-only NVFP4 贏:7.7GB、24.9 tok/s(BF16 的 3.2 倍)、四種模態全保住。
  • W4A4 是個坑(對多模態模型)—— 沒比較快,還把圖片/語音/影片弄壞(文字校準的 activation 量化對多模態 embedding 是分布外)。
  • HF eager 會騙你 —— 在那裡量化看起來更慢;真正的加速要 vLLM 的 native kernel(差 5 倍)。
  • 要 serve:有 native Gemma4Unified 的 vLLM + TRITON_ATTN

本系列其他篇:Part 32 — NVFP4 是壓縮,不是 FP4 核心Part 33 — NVFP4 W4A4 在 MoE 上贏 FP8Part 34 — NVFP4 把影片模型縮小卻沒變快Part 26 — Nemotron Omni 在 GB10 上看影片

常見問題

多模態 LLM 要用 NVFP4 W4A4 還是 weight-only W4A16?
omni 模型用 weight-only NVFP4(W4A16)。在 DGX Spark GB10 上跑 Gemma 4 12B,W4A16 是 24.9 tok/s 而且圖片/語音/影片都正常;全 W4A4(權重+activation 都 4-bit)沒比較快(23.9 tok/s,在誤差範圍內),卻把多模態弄壞了。W4A4 的 activation scale 是用文字校準的,圖片/語音的 embedding 落在分布外,就被夾掉了。
Gemma 4 12B 在 DGX Spark GB10 上量化後多快?
vLLM 0.22.1 下單流 decode:BF16 7.7 tok/s(23GB)、FP8 dynamic 15.9 tok/s(13GB)、NVFP4 weight-only 24.9 tok/s(7.7GB)。NVFP4 是 BF16 的 3.2 倍。但同一份量化權重在純 transformers(HF eager)反而比 BF16 慢 —— 因為那裡沒有 native FP4/FP8 kernel,速度優勢只有上 vLLM 才看得到。
為什麼 NVFP4 在 Hugging Face transformers 裡看起來比 BF16 慢?
transformers 沒有 native FP4/FP8 kernel,所以每次 forward 都把權重拆回 BF16 再算 —— 純開銷、拿不到頻寬帶來的好處。HF eager 下 NVFP4 量到 4.7 tok/s(最慢)。上 vLLM 的 native kernel,同一份權重變 24.9 tok/s(最快)。一樣的權重差 5 倍,所以一定要用你實際 serve 的 runtime 來測。
Gemma 4(gemma4_unified)怎麼在 vLLM 上跑起來?
要用有 native Gemma4UnifiedForConditionalGeneration class 的 vLLM build(大約 0.22.x / main),並設 VLLM_ATTENTION_BACKEND=TRITON_ATTN。Gemma 4 的注意力是非對稱的(head_dim 256 × 16 heads = 4096,跟 hidden 3840 不一樣,是 GQA 8 個 KV head),TRITON_ATTN 是能正確處理這個的 backend。舊版 vLLM 會 fallback 到 transformers backend,在注意力投影那步直接崩。