DGX Spark · part 42
[Benchmark] DGX Spark 跑 Qwen3.8-27B 到 65 tok/s:無投機只有 12.3,差別全在草稿預算
❯ cat --toc
- 前言
- 先算一次:273 ÷ 18.77 = 14.54,你的上限不用跑 benchmark 就知道
- 實測 12.32,吃掉理論上限的 85%
- 我試了兩條路想撈剩下那 15%,兩條都空手
- 唯一的槓桿:讓一趟讀取吐出多個 token
- 65 tok/s 從哪裡來?不是換方法,是把草稿預算從 8 調到 12
- 一個數字紀律:這裡的中位數不能只跑五發
- 同一個旗標,在寫程式上大幅變快,在短對話上變慢 12%
- 開了投機解碼,產出的內容會變 —— 但這不能怪投機解碼
- 照著做:這台機器上跑 Qwen3.8-27B 的配置
- 進階:量測過程、六個判斷錯的地方,以及完整數據
- 我以為 dense 模型會吃到頻寬紅利,結果沒有
- 85% 這個數字,我第一次算成 93%
- 怎麼證明它沒有偷偷反量化?用頻寬,不要用 log
- 兩根便宜槓桿,兩根都死
- 最貴的一次:我把草稿預算開太小,而且是被問了才發現
- 第二貴的一次:我用五發就想把數字寫進標題
- 一個我提出來、然後被自己的數據推翻的模型
- 一個會讓你追錯方向的坑
- 完整數據
- 補一則對 #19 的更正
- 收穫
TL;DR
GB10 的頻寬 273 GB/s,Qwen3.8-27B NVFP4 的語言主幹 18.77 GB,每吐一個 token 就要整份讀一次,上限 14.54 tok/s。實測無投機 12.32,吃掉約 85%。我試了兩條被推薦的優化路徑想撈剩下的,一條量不出效果,一條 SM121 不支援。真正有用的只有投機解碼:DFlash2 配草稿預算 12,寫程式的工作十發中位 65.02(範圍 56.6 到 69.3),是基準的 5.28 倍。而從 53.89 到 65 之間差的不是方法,是我一開始把草稿預算開太小。
前言
你可以找十個壯漢來搬家,但門就那麼寬,一次只過得去一個人。多找人不會讓搬家變快,能動的只有兩件事:把家具拆小,或者讓每個人一趟多扛幾件。
這是 DGX Spark 系列第 42 篇。#19 量到 NVFP4 比 FP8 慢,把死因判給硬體;#25 修正了一半,指出 NVFP4 贏的地方在頻寬不在算力。這篇補上最後一塊:頻寬還剩多少,以及剩下的該怎麼拿。
答案是頻寬幾乎沒剩了,而該拿的東西在另一個地方 —— 而且我一開始拿錯了,還是被人問了才發現。
先算一次:273 ÷ 18.77 = 14.54,你的上限不用跑 benchmark 就知道
大型語言模型吐字的時候,每產生一個 token,都要把整份權重從記憶體讀進晶片算一次。不是讀一部分,是整份。所以單流生成速度有一個很硬的物理上限:
頻寬 ÷ 每個 token 要讀的位元組數 = 每秒能吐幾個 token
GB10 的統一記憶體頻寬是 273 GB/s(LPDDR5X,NVIDIA 官方規格)。分母要小心:我用的 RadixArk/Qwen3.8-27B-NVFP4 整包 20.42 GB,但裡面有東西是純文字對話不會讀的。拆開 safetensors 的 header 逐張量加總:
| 部位 | 大小 | 每個 token 都讀? |
|---|---|---|
| 語言主幹 | 18.77 GB | 是 |
| vision tower | 0.86 GB | 只有給圖片的時候 |
| MTP 頭 | 0.79 GB | 只有開投機解碼的時候 |
看第一列就好:純文字對話的分母是 18.77 GB,不是 20.42。
273 ÷ 18.77 = 14.54 tok/s。這台機器跑這顆模型,不開投機解碼就是這個天花板。

實測 12.32,吃掉理論上限的 85%
用 SGLang 跑,context 262144、KV cache 用 bf16、mem-fraction-static 設 0.90。十次重複,每次的提示詞都加不重複前綴避開快取:
| 值 | |
|---|---|
| 十發中位 | 12.3162 |
| 最低 / 最高 | 12.3022 / 12.3844 |
| 極差 | 0.67% |
換到長文和短對話,分別是 12.42 與 12.33 —— 三種工作型態差不到 1%。
這種穩定度本身就是證據。如果瓶頸在算力,不同工作型態的計算量不一樣,速度就會跟著跳;現在它紋風不動,代表決定速度的是「搬 18.77 GB 要多久」,跟你叫它做什麼無關。
12.32 ÷ 14.54 = 約 85%。
我試了兩條路想撈剩下那 15%,兩條都空手
那道縫隙要跟排程、取樣、框架本身的 overhead 一起分。但這是推論,所以我去試了兩個有外部依據的候選,都只跑不開投機的基準:
| 做法 | 依據 | 結果 |
|---|---|---|
| 把容器 pin 到十顆 Cortex-X925 大核心 | MiaAI-Lab 實測 +2~7% | 量不出來,效應 +0.029%,而自身跨輪漂移 0.751% |
換 flashinfer_cutedsl 後端 | SGLang 的選項清單裡有 | 不支援,啟動就被擋 |
第二個的錯誤訊息很乾脆:
mm_fp4 does not support backend 'cute-dsl' with capability 121
第一個更值得說。效應量 +0.029% 遠小於漂移不說,方向還在兩輪之間翻面(第一輪 +0.056%,第二輪 −0.135%)—— 那是雜訊的長相,不是效果的長相。
所以「換 kernel 撈不回來」不再只是我從算式推的,是去試過兩條路都空手。
唯一的槓桿:讓一趟讀取吐出多個 token
投機解碼(speculative decoding)的作法是:先用一個很小很快的模型猜出接下來好幾個 token,再讓大模型一次驗證這一整批。猜對的直接採用,猜錯的丟掉重來。
關鍵在於「驗證一批」跟「產生一個」對大模型來說,讀取權重的成本是一樣的 —— 都是把 18.77 GB 搬一次。所以只要猜得夠準,一趟就能換到好幾個 token。
這正是 DGX Spark 的主場。它用統一記憶體,驗證那一批幾乎不用額外成本;換到一台算力吃緊的機器上,驗證本身就會變成新瓶頸,紅利就吃不到了。

65 tok/s 從哪裡來?不是換方法,是把草稿預算從 8 調到 12
三種投機解碼都試過,DFlash2 最快。但第一輪我拿到的數字是 53.89,而不是 65 —— 差的那一截只在一個旗標上。
| DFlash2 草稿預算 | 寫程式的 decode | 接受長度 |
|---|---|---|
| 8(recipe 預設) | 53.89 | 6.12 |
| 12 | 65.02(十發 56.6–69.3) | 7.48 |
| 16 | 69.21 | 8.13 |
那個 8 是哪來的?是我照抄別人 recipe 的預設值。 而照抄預設等於繼承別人的調參,不等於繼承別人的最佳解。
判斷「還有沒有空間」要看的指標是飽和度,也就是接受長度除以草稿預算:
| 方法 | 接受長度 | 草稿預算 | 飽和度 | 判讀 |
|---|---|---|---|---|
| DFlash2 | 6.12 | 8 | 76.5% | 快用滿了,加預算有機會 |
| MTP | 4.16 | 5 | 83.2% | 用得最滿,被預算卡住 |
| DSpark | 4.68 | 8 | 58.6% | 猜不準,加預算沒用 |
不是看接受率。接受率高可能只是因為你的預算開太小,它當然容易猜滿。
一個數字紀律:這裡的中位數不能只跑五發
草稿預算 12 這一格我跑了兩次。第一次五發,中位 68.57;第二次全新起容器跑十發,中位 65.02,範圍 56.6 到 69.3。
五發那次的中位落在分佈的高側。 投機解碼的接受率跟生成內容直接相關,所以它的離散度天生就寬 —— 這一格是 19.5%,而不開投機只有 0.67%。離散度這麼寬的量測,五發不足以定中位。
我原本要把 68 寫進這篇的標題,是被要求重現才擋下來的。這裡列 65,以及對同一次量測的無投機基準的比值 5.28 倍 —— 比值比絕對值可靠,機器冷熱不影響它。
同一個旗標,在寫程式上大幅變快,在短對話上變慢 12%
草稿預算不是愈大愈好,要看你拿它做什麼:
| 工作型態 | 草稿預算 8 | 草稿預算 16 | 變化 |
|---|---|---|---|
| 寫程式 | 53.89 | 69.21 | 大幅變快 |
| 長文 | 28.14 | 28.07 | −0.25% |
| 短對話 | 26.04 | 22.97 | −11.8% |
原因還是接受率:程式碼的下一個 token 好猜(73.1%),閒聊很難猜(28.1%)。猜不準的時候,更大的草稿只是讓你付更多驗證成本、丟掉更多。
所以推薦表要分流,不能給一組全域預設:
| 工作型態 | 用什麼 | 實測 |
|---|---|---|
| 寫程式 | DFlash2,--speculative-num-draft-tokens 12 | 65.02(十發 56.6–69.3) |
| 長文 | DFlash2,預算 8 | 28.14 |
| 短對話 | DFlash2,預算 8 | 26.04 |
| 只能用權重內建的 MTP | EAGLE,steps 5 / topk 4 / draft 16 | 41.57 |
看到別人貼「DGX Spark 跑到 XX tok/s」的時候,第一個要問的是他在跑什麼工作,不是他用什麼設定。
開了投機解碼,產出的內容會變 —— 但這不能怪投機解碼
這件事我原本以為不用寫,查完發現一定要寫。
同一個提示詞、temperature=0、固定 seed,不開投機跟開 DFlash2 產出的程式碼不一樣。兩份都是合法的實作,差異從一個 docstring 裡的大小寫開始(Cache 對 cache),之後就各走各的。
我一開始猜是浮點的隨機抖動,測了發現不是:同一組設定連跑三次,兩邊都是逐位元完全一樣。所以是兩條各自穩定、但彼此不同的路徑。
真正的答案來自一個完全不含投機解碼的對照 —— 無投機的伺服器,同一個請求,一次單獨送、一次同時送兩個:
batch=1 39e462cb7494b66f...
batch=2 之一 b660d8f884b9d35c...
batch=2 之二 b660d8f884b9d35c...
光是把並行請求從 1 個變成 2 個,輸出就變了,而同一批裡的兩個請求彼此完全一致。批次改變矩陣乘法的加總順序,浮點不滿足結合律,在機率幾乎平手的位置就足以讓選擇翻面。
所以投機解碼的差異是同一個現象。任何會改變 batch 形狀的東西都可能這樣,不是投機解碼特有的缺陷。但你該知道它會發生 —— 尤其如果你有那種「同樣輸入必須得到同樣輸出」的測試。
照著做:這台機器上跑 Qwen3.8-27B 的配置
環境是單台 DGX Spark(GB10 / SM121 / aarch64 / 128 GB 統一記憶體),驅動 580.159.03。用 MiaAI-Lab 的 SGLang recipe,那是我找得到把 DFlash2 在這台機器上跑得起來的公開作法。
--mem-fraction-static 0.90 # 不要用 0.95
--context-length 262144 # YaRN 關閉
--kv-cache-dtype bf16 # 不要用 fp8
--fp4-gemm-backend flashinfer_cutlass # 不要用 auto
--speculative-algorithm DFLASH
--speculative-num-draft-tokens 12 # 寫程式用 12,短對話用 8
第一條是因為 0.95 配上比較高的同時請求數,實測會把整台機器弄到重開。第三條有兩個獨立理由:DFlash 投機解碼與所有 KV cache 量化根本不相容,因為它的 draft 需要 non-causal attention,而各家 backend 都拒絕這個組合,engine 直接起不來(vLLM #41559);另外我自己在 2026-03-30 量到過 fp8 KV 會讓輸出陷入無限重複。第四條是因為這版 SGLang 不會把 auto 改寫成它最後選中的後端,用 auto 之後就查不出它到底跑了哪個 backend。
還有一個跟設定無關但會讓你懷疑人生的坑:DFlash2 的串流回應,一個事件平均帶 3.75 個 token。用事件數算速度會得到大約 9 tok/s,看起來像壞掉了。一律用回應裡的 completion_tokens 除以時間。
進階:量測過程、六個判斷錯的地方,以及完整數據
不讀這節不影響使用。上面的結論已經完整,這節是拿到那些數字的過程、我判斷錯的地方,以及所有原始值。
我以為 dense 模型會吃到頻寬紅利,結果沒有
當時的狀況:之前在 GB10 上量 NVFP4 全部是 MoE 模型,而 MoE 每個 token 只點亮少數 expert,本來就稀疏,權重位寬減半省下的頻寬相對有限。Qwen3.8-27B 是 dense,每個 token 讀全部權重。
預想的解:所以我以為 dense 的 NVFP4 會明顯超過同尺寸的 FP8,甚至可能翻倍。
做了什麼:照上面的設定跑三個工作型態,拿不開投機的數字。
結果:12.4 左右。而 NVIDIA 開發者論壇上同模型 FP8 的回報大約 15 到 20 —— 那是別人的機器與設定,不是對照組。
反思:我的推論漏了一層。位寬減半確實省下頻寬,但省下來的東西只有在「頻寬是唯一瓶頸」時才會全部變成速度 —— 而它本來就已經是唯一瓶頸,所以省下的頻寬已經反映在 12.4 這個數字裡了。而且我拿來對照的 FP8 數字來自別人的機器、別人的引擎、別人的提示詞,那不是對照組,是三個變數一起變的兩個數字。
85% 這個數字,我第一次算成 93%
當時的狀況:第一次算天花板,我直接拿 du -sb 量模型目錄,得到 20.42 GB。
預想的解:模型有多大,每個 token 就要讀多少。
做了什麼:273 ÷ 20.42 = 13.37,實測 12.44,算出 93%。數字漂亮,差點就這樣寫出去。
結果:拆開 safetensors header 逐張量加總之後,發現裡面有 vision tower 0.86 GB 和 MTP 頭 0.79 GB,純文字對話一個位元組都不會讀。真正的分母是 18.77 GB,天花板 14.54。
反思:du 是衍生數字,我卻拿它當基準。1.65 GB 的誤差聽起來不多,但它讓「頭上還剩多少」從 7% 變成一成多,整整一倍。判斷「還值不值得優化」的時候,那是兩個不同的答案。
怎麼證明它沒有偷偷反量化?用頻寬,不要用 log
當時的狀況:NVFP4 有一個經典失敗模式:引擎讀進 4-bit 權重檔,但算之前先在晶片上反量化回 BF16,於是省下的頻寬一分都沒省到。這種情況下檔案是 4-bit,速度卻是 BF16 的速度。
預想的解:去啟動 log 裡 grep,看它選了哪條 kernel 路徑。
做了什麼:grep 了,拿到 fp4_gemm_runner_backend='flashinfer_cutlass',沒有 marlin(最典型的反量化 fallback)。
結果:這個證據不夠硬。log 印出格式的名字,不代表那條路徑真的在跑 —— 我在另一張卡上被同樣的字串騙過一次。所以改用頻寬反推:
| 假設 | 每 token 足跡 | 天花板 | 實測 12.32 佔 |
|---|---|---|---|
| 真的讀 4-bit | 18.77 GB | 14.54 | 85% |
| 先反量化成 FP8 再讀 | 37.5 GB | 7.28 | 169% |
| 先反量化成 BF16 再讀 | 75.1 GB | 3.64 | 338% |
看後兩列:如果它偷偷反量化了,實測速度會超過物理上限,那不可能發生。所以權重確實以打包後的 4-bit 寬度被讀取。
反思:這個判斷方法比讀 log 硬,因為它不依賴引擎有沒有誠實印出自己在做什麼。任何「我的量化到底有沒有生效」的問題,都可以先用這招問一次。
兩根便宜槓桿,兩根都死
當時的狀況:12.3 離 14.54 還有一成多,想知道那裡面有沒有東西可以撈。
預想的解:兩個候選都有外部依據 —— 大核 pinning 別人量過 +2~7%,flashinfer_cutedsl 在 SGLang 的選項清單裡有但 auto 沒選它。
做了什麼:A/B/A/B 區塊交替設計,兩個配置各跑兩輪、每輪 5 次,配置之間冷卻。用區塊交替而不是一個跑完再跑下一個,是因為連續長跑有熱漂移,交替可以讓漂移對兩邊影響相同,而且兩輪之間的差就是漂移本身的量。
結果:大核 pinning 效應 +0.029%,漂移 0.751%,而且方向跨輪翻面。flashinfer_cutedsl 直接被 capability gate 擋掉。
反思:這裡有一個我原本會犯的錯 —— 我差點用「效應量只有 2~7%、小於我的雜訊門檻,所以測不出來」當理由不做這個實驗。那是錯的:我的門檻是拿去跟外部公開數字比的,同一台機器上同一個 session 的變異只有 0.4%。效應量小於雜訊是量測設計問題,正解是把雜訊壓下去,不是放棄。
最貴的一次:我把草稿預算開太小,而且是被問了才發現
當時的狀況:第一輪三種投機解碼跑完,DFlash2 53.89 全桶最快,結論看起來很乾淨。
預想的解:三種方法各自用它們的推薦設定,誰快誰就是快。
做了什麼:MTP 給 5 個草稿 token,DSpark 和 DFlash2 給 8 個 —— 後兩者照抄 recipe 預設,前者是我自己寫死的。我甚至明文禁止掃描這個參數,理由是別人在另一個推論引擎上量到預算開大反而變慢。
結果:被問「會不會是哪邊搞錯了」之後回頭看接受長度,MTP 的飽和度是 83.2% —— 它把配給它的 5 個用掉 4.16 個,是三者最高。它被預算卡住,不是猜不準。 重跑之後 DFlash2 在預算 12 明顯更快。
反思:兩個錯疊在一起。第一,對照本身不公平,我拿 5 個預算的方法去跟 8 個的比。第二,更嚴重的是我拿另一個引擎的參數掃描結論,去禁止自己引擎的實驗 —— 那個結論在它的脈絡裡是對的,但它不是我這台機器的證據。省下的是半小時,代價是一整天。
第二貴的一次:我用五發就想把數字寫進標題
當時的狀況:預算 12 那格五發中位 68.57,我把它寫進了推薦表和文章標題草稿。
預想的解:五發中位夠了,其他配置的離散度都只有 2~8%。
做了什麼:被問「可以跑一下確認一下真的這麼快嗎」之後,全新起容器重跑十發。
結果:中位 65.02,範圍 56.63 到 69.30,離散度 19.5%。五發那次的中位落在分佈高側。
反思:我用一個平均離散度去推斷一個特別不穩的配置。投機解碼的接受率跟生成內容綁在一起,它的抖動天生就比不開投機大一個量級。離散度超過 15% 的量測,五發不足以定中位。 而這個數字本來要進對外文章的標題 —— 寧可現在垮,不要發出去才垮。
一個我提出來、然後被自己的數據推翻的模型
第一輪的三個點都套得上一個很漂亮的關係:
decode ≈ k × baseline × 接受長度 k 落在 0.69–0.74
我把它寫進第二輪的工單當受測假設,要求每個新配置都算 k 值。結果:
| 配置 | k | 帶內? |
|---|---|---|
| DFlash2 draft 12 | 0.700 | 是 |
| DFlash2 draft 16 | 0.685 | 邊緣 |
| MTP steps7/topk1/draft8 | 0.576 | 否 |
| MTP steps5/topk4/draft16 | 0.610 | 否 |
模型被推翻了。 接受長度不足以單獨預測速度 —— 直線鏈草稿跟樹狀草稿的提案成本結構不一樣,不能共用一個係數。
寫在這裡是因為它示範了一件事:估算的正當用途是設計實驗(該量哪一格、預期落在哪),不是取消實驗。 它被證偽,而證偽本身就是這次量測的產出之一。
一個會讓你追錯方向的坑
想直接指定 FP4 後端做對照,加了 --fp4-gemm-runner-backend 這個旗標。容器立刻 exit(2),而啟動腳本的就緒檢查完全不知情,對著一個從沒開過的埠一直 curl 到自己逾時。整整八分鐘我以為是「服務起不來」。真正的錯誤訊息在容器 log 裡:
sglang serve: error: unrecognized arguments: --fp4-gemm-runner-backend flashinfer_cutedsl
那個欄位在 server 參數裡叫 fp4_gemm_runner_backend,但 CLI 不接受直譯的破折號寫法。
「旗標打錯」跟「服務起不來」在就緒檢查那一層長得一模一樣,兩邊都是連不上,而分辨它們的資訊只存在於另一個檔案。以後寫就緒檢查,要先確認被檢查的東西真的還活著,再開始等它變好。
完整數據
所有回應的 cached_tokens 都是 0,前綴快取確認沒生效。速度一律用 completion_tokens 除以實際耗時,不是串流事件數。每一發的輸出長度都固定在 520 個 token(finish_reason 全部是 length),所以差異純粹是耗時。
⚠️ 標示 5 發的那些格子,精度不如標示 10 發的那兩格。 見上面關於離散度的那節 —— 這裡照實標註,不要把它們當同等強度的證據。
第一輪:三種方法,各方法用自己的預設預算(各 5 發)
| 方法 | 寫程式 | 長文 | 短對話 |
|---|---|---|---|
| 無投機 | 12.44 | 12.42 | 12.33 |
| MTP n=5 | 35.71 / 79.2% | 24.42 / 45.8% | 21.11 / 37.5% |
| DSpark 預算 8 | 42.88 / 52.8% | 19.36 / 15.5% | 17.64 / 13.4% |
| DFlash2 預算 8 | 53.89 / 73.1% | 28.14 / 30.1% | 26.04 / 28.1% |
第二輪:公平對照與參數掃描(只跑寫程式,括號設計 REF→M1→M2→M3→D1→D2→REF,漂移 1.307%,各 5 發)
| 格 | 參數 | decode | 接受率 | 接受長度 | 飽和度 |
|---|---|---|---|---|---|
| REF_A | MTP steps4/topk1/draft5 | 35.70 | 79.40% | 4.16 | 83.2% |
| M1 | MTP steps7/topk1/draft8 | 38.80 | 63.10% | 5.42 | 67.7% |
| M2 | MTP steps4/topk4/draft8 | 38.58 | 51.45% | 4.60 | 57.5% |
| M3 | MTP steps5/topk4/draft16 | 41.57 | 29.75% | 5.47 | 34.2% |
| D1 | DFlash2 draft12 | 68.57 | 62.95% | 7.88 | 65.7% |
| D2 | DFlash2 draft16 | 69.21 | 47.40% | 8.13 | 50.8% |
| REF_B | MTP steps4/topk1/draft5 | 36.17 | 79.64% | 4.19 | 83.9% |
第三輪:獨立重現(全新容器,各 10 發)
| 配置 | 十發原值 | 中位 | 範圍 | 極差 |
|---|---|---|---|---|
| 無投機 | 12.32 / 12.38 / 12.33 / 12.34 / 12.31 / 12.30 / 12.34 / 12.31 / 12.31 / 12.31 | 12.3162 | 12.302–12.384 | 0.67% |
| DFlash2 draft12 | 56.63 / 63.76 / 68.46 / 68.17 / 66.68 / 62.98 / 64.56 / 65.48 / 63.47 / 69.30 | 65.0181 | 56.63–69.30 | 19.5% |
比值:65.0181 ÷ 12.3162 = 5.28 倍。
補一則對 #19 的更正
系列 #19 我寫過這麼一句:
這是晶片級限制。沒有任何 driver 更新、firmware 刷新、軟體 patch 能補上一條不存在的電路。
那句話是錯的。 #25 已經修了一半,指出 mma.kind::mxf4nvf4 在 W4A4 那條路真的會跑;這篇的頻寬反推把另一半也修掉 —— 權重確實以 4-bit 寬度被讀取,晶片沒有缺那個能力。#19 當時看到的慢,是軟體層挑錯 kernel 路徑,不是硬體缺電路。
我把 #19 留著沒重寫,只在頂部加了更新提示。判斷錯的過程留著,比事後改成正確的樣子有用。
收穫
最花時間的地方是那八分鐘的假死。旗標打錯跟服務起不來,在就緒檢查那一層完全分不出來,而分辨它們的資訊在另一個檔案裡。
可以搬走的診斷方法有三個。頻寬反推:你的量化到底有沒有生效,不用讀引擎的 log,把實測速度跟各種假設下的物理上限比一次,超過上限的假設直接淘汰。飽和度:投機解碼還有沒有空間,看接受長度除以草稿預算,不要看接受率。以及最後那個 batch=1 對 batch=2 的對照 —— 要判斷某個差異是不是某個功能造成的,最乾淨的作法是找一個完全不含那個功能、卻能重現同樣差異的設定。
而這整件事最讓我在意的不是那幾倍,是它藏起來的方式。我拿別人量過的結論,禁止了自己該做的量測;又拿五發的中位,當成可以寫進標題的數字。兩次都是用一個看起來夠好的理由,省掉一次該做的觀察 —— 而兩次都是被問了一句話才翻出來的。
常見問題
- DGX Spark 跑 Qwen3.8-27B 最快能到幾 tok/s?
- 寫程式的工作上,DFlash2 投機解碼配草稿預算 12,十發實測中位 65.02 tok/s,範圍 56.6 到 69.3,是同一台機器無投機基準的 5.28 倍。長文與短對話低很多,分別是 28.14 與 26.04,因為投機解碼的接受率跟工作型態直接相關。
- 為什麼我換了 kernel、換了後端,DGX Spark 的速度都沒什麼變?
- 因為單流 decode 卡在把權重從記憶體搬進晶片,不是搬進去之後的計算。實測已經吃掉頻寬上限的約 85%,剩下的還要跟排程、取樣、框架 overhead 分。我實際試過兩條被推薦的優化路徑,一條量不出效果,一條在 SM121 上根本不支援。
- 投機解碼的草稿預算(num-draft-tokens)要設多少?
- 看工作型態,不是看機器。同一顆模型同一台機器上,把 DFlash2 的草稿預算從 8 調到 12,寫程式的工作明顯變快;但調到 16 之後,短對話反而慢了 11.8%。判斷還有沒有空間要看飽和度,也就是接受長度除以草稿預算,不是看接受率。
- 開了投機解碼,產生的內容會跟沒開的時候一樣嗎?
- 不一樣,但那不是投機解碼的問題。我做過對照:完全不開投機解碼,只是把並行請求從 1 個變成 2 個,輸出就變了。批次會改變矩陣乘法的加總順序,浮點又不滿足結合律,在機率幾乎平手的位置就足以讓選擇翻面。任何會改變 batch 形狀的東西都可能這樣。
接著讀
- 2026-05-06火箭起飛:Gemma 4 在 DGX Spark 跑出 670 tok/s 總吞吐(單流 108 tok/s)
Google 2026-05-05 發 Multi-Token Prediction drafter,vLLM PR 同日開、官方 preview docker 同日有。DGX Spark 上實測 Gemma 4 26B-A4B-it FP8 + MTP γ=4:單流 108 tok/s(2.66× baseline)、8 路並行 674 tok/s 總吞吐。一個沒寫進文件的雷:drafter 不能配 base model,要配 -it。
- 2026-06-01[Benchmark] NVFP4 W4A4 在 DGX Spark 上超車 FP8:拔掉 enforce-eager,MoE 從 23 衝到 67 tok/s
GB10 上 NVFP4 W4A4 拔掉 --enforce-eager 後從 23 衝到 67 tok/s,贏 FP8 29% 還省 16GB。Part 32 說 cudagraph 沒用——那只對 dense,MoE 完全相反。
- 2026-04-21[Benchmark] NVFP4 在 GB10 上是陷阱:FP8 快 32%(vLLM + SGLang 雙引擎實測)
NVFP4 理論上更快——位元更少、頻寬更省。但在 DGX Spark 的 GB10 (SM121) 上反而慢 32%。根因:缺硬體指令。vLLM 和 SGLang 雙引擎驗證。
- 2026-05-30[Benchmark] NVFP4 在 DGX Spark 比 FP8 快 1.5 倍——但贏在壓縮,不是那顆 FP4 運算單元
GB10 DGX Spark 上,純 dense 模型單流 decode,NVFP4 比 FP8 快約 1.5 倍。但快的是頻寬(權重檔變小),不是 FP4 tensor core——最快那條路根本沒碰它。
不想錯過新文章?
訂閱我確保不漏接!
隨時一鍵退訂。