~/blog/part2-qwen-122b-14-toks-gdn-kernel-gap

Qwen3.5-122B on DGX Spark · part 1

[vLLM] Qwen3.5-122B 跑起來了。但只有 14 tok/s。

2026-03-192 分鐘閱讀#dgx-spark#sm121#qwen3.5-122b#vllmEnglish

前言

這篇講的是一個看起來像失敗、但其實不是的結果。

套用第一篇的四個 SM121 bug 修法之後,Qwen3.5-122B 在 DGX Spark 上正常運作。輸出正確。模型可以用。但速度穩定在 14 tok/s——大約是 gpt-oss-120B 在同一台機器上的四分之一。

怎麼調都不動。這就是這篇的故事。

用個比喻:想像一條十二線道的公路,六條是鋪好的柏油路,六條還是泥土路。車子在跑——沒有壞掉——但一半的車道在工程速限裡爬行。硬體沒有問題。架構裡一半的層(GDN 層)缺少最佳化的軟體支援。你沒辦法靠調整駕駛方式來修一條還沒鋪好的路。


我想做什麼

目標很單純:用 Qwen3.5-122B-A12B-NVFP4 當 DGX Spark 的主力模型。122B 參數,NVFP4 量化,128 GB 統一記憶體——算法沒問題:122B × 4-bit ≈ 61 GB,剩下空間給 KV cache。gpt-oss-120B 在同一台機器上能跑 59 tok/s,所以對 122B NVFP4 的預期也在這個量級。也許稍慢一點——模型更大,架構不同——但應該在同一個數量級。

14 tok/s 不在預期裡。


我做了什麼

套用第一篇的修法(SM121 PTX 路徑、Marlin thread race、SupportsQuant、排除 CUTLASS_FP4)之後,模型正常載入,輸出正確。前幾個 token 出得很快,然後吞吐量穩定在 14 tok/s。

把能調的全試了:

  • 拿掉 --enforce-eager — 本來就沒有,不是這個問題
  • KV cache dtype — fp8,跟 gpt-oss 一樣,沒有差別
  • --max-num-batched-tokens — 上下調整,幾乎沒有影響
  • VLLM_MXFP4_BACKEND=marlin — 已設定,啟動 log 確認有讀到
  • --moe-backend marlin — 已設定
  • GPU 記憶體使用率 — 0.90,標準值

14 tok/s 沒有動。這就是「調參問題」變成「架構問題」的時刻。


問題真正在哪

Qwen3.5-122B-A12B 是混合架構,不是標準 Transformer。它把兩種層混在一起:

  • 標準 attention 層 — 一般的 Transformer MHA/MLA,Marlin 有針對這種計算形狀特別最佳化的 kernel(可以想像成:有專用工具)
  • GDN(Gated Delta Network)層 — SSM 風格的遞迴層,必須保持 BF16

Marlin 對標準 linear 層和 MoE expert GEMM 有快速的特化 kernel。對 GDN,沒有。每個 GDN GEMM 都走 generic fallback 路徑——能跑,但慢。

這也解釋了第一篇的 SupportsQuant 修法為什麼不能省:沒有它,vLLM 會把 GDN 層量化成 NVFP4,GDN 的遞迴 hidden state 損壞,輸出變成垃圾。修法讓 GDN 保持 BF16——正確的行為——但代價是 GDN 跑在沒有特化 kernel 的路徑上。

在 GB10 的 273 GB/s 頻寬下,算法很直接:搬動 61 GB 的 weights 一次需要約 0.22 秒。GB10 上 122B NVFP4 的理論 decode 上限約 30 tok/s。要達到這個上限,每一層都需要高效的 kernel。當一半的架構(GDN)走 generic fallback,吞吐量往一半的上限平均——14 tok/s 就是這個平均的落點。


得到了什麼

結果是 14 tok/s,不是理論上限的 ~30 tok/s。但這個過程沒有白費。

確認了:

  • 第一篇的 SM121 fix stack 對 Qwen3.5-122B 是有效的。輸出正確。
  • SupportsQuant 是必須的——沒有它,GDN 層被量化,輸出垃圾。這個 bug 不直觀,從零開始診斷要花好幾個小時。
  • GB10 上 122B NVFP4 的理論 decode 上限是 ~30 tok/s。等 Marlin 加入 GDN kernel 後,這是要驗證的目標值。

確立了:

  • 14 tok/s 是目前的下限,不是 bug。沒有任何設定錯誤。
  • 瓶頸是軟體缺口(Marlin 缺少 GDN kernel),不是硬體限制。
  • GB10 有足夠的算力跑 Qwen3.5-122B。問題完全在軟體堆疊。

診斷模式: 如果 Qwen3.5-122B 在 SM121 上跑很慢,你已經設了 VLLM_MXFP4_BACKEND=marlin--moe-backend marlin,啟動 log 確認顯示 Using backend: marlin,輸出也正確——你碰到的就是 kernel 缺口。停止調整。等 kernel 來了數字才會動。


結論

套用第一篇的修法後,Qwen3.5-122B 在 DGX Spark 上正確運作。14 tok/s 不是故障——是目前 Marlin 所能支援的軟體上限。

現在如果需要在 GB10 上互動使用:gpt-oss-120B 59 tok/s 是可用的選項。Qwen3.5-122B 14 tok/s 適合離線批量任務,對延遲要求不高的場景。

如果你是因為 Qwen 跑很慢才找到這篇:你沒有漏掉任何 flag。你已經到達上限了。等 Marlin GDN kernel 來了再回來看。