~/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-19更新於 2026-04-072 分鐘閱讀#dgx-spark#sm121#qwen3.5-122b#vllmEnglish
cat --toc

TL;DR

Qwen3.5-122B 在套用第一篇的 SM121 修法後能在 DGX Spark(GB10)正常啟動,輸出正確。速度穩定在 14 tok/s,怎麼調都不動。根本原因:Marlin 沒有針對 GDN(Gated Delta Network)SSM 層的特化 kernel,導致這些層走 generic fallback 路徑。沒有 flag 能修它。10B active MoE 光看頻寬的理論上限是 ~55 tok/s,實測 14——差距在計算,不在頻寬。在 Marlin 把 GDN kernel 補上之前,互動式任務用 gpt-oss-120B(~59 tok/s)。

白話版:1220 億參數的 AI 模型,為什麼只跑 14 tok/s?

先解釋一下數字。1220 億參數代表這個 AI 模型有 1220 億個可調整的「旋鈕」——參數越多,模型通常越聰明、能處理的任務越複雜。Qwen3.5-122B 是目前最大的開源模型之一,能力接近 ChatGPT 等級。

14 tok/s 代表每秒生成 14 個字。能用嗎?能。舒服嗎?不太。打字聊天會有明顯的等待感,像跟一個打字很慢的人對話。同一台機器上另一個類似大小的模型(gpt-oss-120B)可以跑到 59 tok/s,快了四倍。

為什麼差這麼多?不是機器的問題,也不是設定的問題。Qwen3.5-122B 用了一種比較新的架構(GDN,一種混合了傳統 Transformer 和 SSM 的設計),而目前的軟體還沒有針對這種架構做最佳化。就像一條 12 線道的高速公路,6 條已經鋪好柏油路、6 條還是泥土路——車子在跑,但一半的車道在施工限速。

這篇文章記錄了我怎麼從「以為是自己設定錯」到「確認是軟體層的限制」的整個過程。如果你也在跑大模型,這篇可以讓你少踩幾輪 debug。


前言

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

套用第一篇的四個 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 頻寬下,演算法要用 MoE 的正確版本。Qwen3.5-122B-A10B 每個 token 只激活 8/256 個 expert,實際只有 ~10B 參數在跑,4-bit 量化下每步搬 ~5 GB——頻寬上限約 55 tok/s,不是 30。之前寫「每步搬 61 GB」是把總 weight 量當作每步流量,這是把 MoE 當 dense 算。一個完全最佳化的 stack 應該遠超過 14 tok/s。但當 48 層裡有 36 層(linear-attention + GDN 層)走 generic fallback 路徑,吞吐量塌到 14 tok/s——大約是頻寬上限的 1/4,代表瓶頸是計算不是記憶體頻寬。


得到了什麼

結果是 14 tok/s,遠低於一個有效率 kernel stack 應該能達到的速度。但這個過程沒有白費。

確認了:

  • 第一篇的 SM121 fix stack 對 Qwen3.5-122B 確實有用。輸出正確。
  • SupportsQuant 是必要的——沒有它,GDN 層被量化,輸出垃圾。這個 bug 不直觀,從零開始診斷要花好幾個小時。
  • GB10 上 10B-active MoE 的頻寬上限是 ~55 tok/s;加上 attention/norm 開銷後實際目標會低一點。等 Marlin 加入 GDN kernel 後,該對著這個值驗證,不是現在的 14。

確立了:

  • 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 來了再回來看。

常見問題

為什麼 Qwen3.5-122B 在 DGX Spark 上套用所有 SM121 修法後仍只有 14 tok/s?
Qwen3.5-122B-A10B 是混合 MoE 架構,48 層裡有 36 層是 linear-attention + GDN(Gated Delta Network)SSM。Marlin 對標準 linear/MoE 層有特化 kernel,但 GDN 沒有。每個 GDN GEMM 走 generic fallback 路徑。在 GB10(273 GB/s)上,10B active 的 MoE 光看頻寬理論上限是 ~55 tok/s;GDN kernel 缺口把實測吞吐拉到 ~14 tok/s——瓶頸在計算,不在頻寬。
Qwen3.5-122B 在 DGX Spark 的 14 tok/s 是設定錯誤還是 kernel 缺口?
是軟體 kernel 缺口,不是設定錯誤。如果你已設定 VLLM_MXFP4_BACKEND=marlin、--moe-backend marlin,且啟動 log 確認顯示 'Using backend: marlin',這就是上限了。先別再調,等 Marlin 把 GDN kernel 補上。
GB10 上 Qwen3.5-122B NVFP4 的理論 decode 上限是多少?
光看頻寬約 ~55 tok/s。MoE 的正確算法是用 active params:Qwen3.5-122B-A10B 每個 token 只激活 ~10B 參數(256 個 expert 選 8 個),4-bit 量化下每步只搬 ~5 GB。273 GB/s ÷ 5 GB ≈ 55 tok/s。加上 attention/norm 的額外開銷,實際上限會低一點,但絕對遠高於現在觀察到的 14 tok/s。本文之前版本寫「122B × 4-bit = 61 GB → 30 tok/s」是把 MoE 當 dense 算,不對。
在 DGX Spark 上,現在應該用 gpt-oss-120B 還是 Qwen3.5-122B?
互動式使用選 gpt-oss-120B,~59 tok/s。Qwen3.5-122B 的 14 tok/s 適合對延遲要求不高的離線批次任務。等 Marlin 把 GDN kernel 補上後再重新評估 Qwen3.5-122B。