~/blog/dgx-spark-minimax-h3-span-upscaler

DGX Spark · part 41

[Benchmark] 在 DGX Spark 上跑 MiniMax-H3!可惜現在沒辦法用 NVIDIA VSR 放大

cat --toc

TL;DR

在 DGX Spark(GB10、121 GB 統一記憶體、aarch64)上跑 MiniMax-H3 的完整配置與最佳化順序。時間的大頭有兩塊:取樣 56%、放大 32%。而 NVIDIA 自家的 Video Super Resolution 在這台裝不了——nvidia-vfx 只發 x86_64 的 wheel,NVIDIA 員工在論壇明講「目前沒有計畫」要支援 Spark。換成 4.3 MB 的開源 SPAN,放大從 316 秒掉到 49 秒;生產組態(14 步 + SageAttention + SPAN)實測 741.0 秒,是 20 步起點 1,477 秒的一半。

🔊 開聲音。1920×1080、362 幀、15.08 秒,畫面和聲音出自同一次計算。這支就是 DGX Spark 用本文那組配置算出來的。

白話版:有些加速功能,你這台就是裝不了

軟體世界有一個大家默默假設的前提:只要肯裝,功能就會有。 版本不對就升級,相依套件缺就補,再不行就自己從原始碼編一份。

但有一類東西不吃這一套。廠商發的是已經編好的二進位檔,而且只針對特定的 CPU 架構發。你的機器如果不是那個架構,就沒有東西可以裝——不是難裝,是不存在。自己編也不行,因為裡面根本沒有可以編的原始碼。

DGX Spark 用的是 ARM 架構晶片,而市面上絕大多數 AI 加速套件只針對 Intel/AMD 那一系的 x86 發行。大部分時候你不會遇到,因為主流套件兩邊都發。但只要遇到一次,那就是一堵完全沒有門的牆。

這篇前半是把 H3 在這台跑起來的完整教學,後半是我撞上那堵牆之後繞出來的路——而繞出來的那條,結果比原本要走的還快。


前言

這篇假設你手上有一台 DGX Spark,而且想用它生影片,不是跑聊天模型。

MiniMax-H3 是 33B 的影音同步生成模型:你給它一段文字,它一次吐出畫面聲音——對白、環境音、配樂全是同一次計算的產物,所以嘴型天生對得上。我在一張 RTX 5090 上跑過同一顆模型,那篇的重點是三個開關把時間砍一半。

這台不一樣。它的記憶體多得多(121 GB 統一記憶體),但 CPU 是 ARM,而那件事會在你最想不到的地方擋住你。

下面先給完整配置,再給實測數字和最佳化的順序,最後才是那堵牆與我一路上判錯的幾次。

第一步:把環境準備好

# ① 先停掉常駐的推論模型 —— 這一步不能跳
# (下面是我這台的服務名,換成你自己的)
systemctl --user stop ds4-mia-v053-0731-8000.service

# ② 起 ComfyUI,--cache-none 是必要的不是可選的
~/comfy-venv/bin/python ~/ComfyUI/main.py --listen 127.0.0.1 --port 8188 \
  --cache-none --use-sage-attention

(--use-sage-attention 開的是 SageAttention——一套把注意力運算換成更快實作的套件,裝好之後就只是這個開關。)

為什麼要先停別的模型? GB10 規格上是 128 GB 統一記憶體,free -g 實際看到 121 GB 可用,CPU 和 GPU 共用同一池。常駐的推論模型吃掉約 85 GB,而 H3 生成時峰值約 72 GB——兩個加起來超過總量,所以不能並存。停掉之後記憶體會從 116/121 掉到 4/121,H3 才有地方站。

為什麼 --cache-none 是必要的? ComfyUI 的執行快取是照節點輸入算的。同一組提示詞加同一個 seed 送第二次,整份圖會全部命中快取,秒數回 0.00——而它不會報錯。你做 benchmark 的時候只會看到一個好得不像話的數字,然後拿它去下結論。

第二步:五個檔案,每個有自己的目錄

擴散模型   minimax_h3_fl2va_pruned_nvfp4.safetensors      → models/diffusion_models/
文字編碼器 qwen3vl_32b_heretic_minimax_h3_nvfp4.safetensors → models/text_encoders/
影片 VAE   minimax_h3_video_vae_fp16.safetensors          → models/vae/
音訊 VAE   minimax_h3_audio_vae_fp32.safetensors          → models/vae/
放大器     2xNomosUni_span_multijpg.safetensors           → models/upscale_models/

影片和音訊各有自己的 VAE,因為它們是兩條獨立的輸出。

NVFP4 在 GB10 上是原生的。 NVFP4 是一種 4 位元的數字格式——同一份權重用它存,檔案小很多,代價是精度低一點。關鍵在於這張晶片認得這個格式:GB10 是 Blackwell 世代(晶片代號 sm_121),nvfp4 會出現在啟動訊息的 Native ops 那一行,代表它跑在真的硬體指令上而不是用軟體模擬——所以量化版本除了省磁碟也真的省時間。⚠️ 這一點不能外推到非 Blackwell 的卡,那裡 NVFP4 只省磁碟。

第三步:取樣參數

取樣器     res_multistep + simple
步數       14
fps        24 · length 362(= 15.08 秒)
解析度     960×540 生成 → 放大到 1920×1080
Spectrum   開啟(作者預設值)

Spectrum 是 H3 的社群節點包(ComfyUI-Spectrum-MiniMax-H3),取樣那一段由它接手。

步數為什麼是 14 不是範本的 20? 20 是保守值。實測 14 步在這台省 14.5%(1,477 → 1,263.5 秒),而我看不出畫質差別。

⚠️ 但這裡有個我自己沒補上的缺口:我判「看不出差別」看的是畫面。這條產線是拿來講話的,而對白的品質我沒有在 14 步和 20 步之間並排比過。我上線的是 14 步。

為什麼是 960×540 生成再放大,不直接生 1080p? 因為便宜太多,而且方向跟直覺相反。我在一支約 5 秒的短片上做過對照(20 步 + Spectrum、同 seed):原生 1344×768 要 637 秒,而 960×540 生成再用 ESRGAN 放大兩倍只要 349.9 秒——快 1.82 倍,輸出畫面還更大。取樣的畫布小很多,省下來的遠比放大器多花的多。

⚠️ 那組對照是短片、20 步,跟本文這條 15 秒 / 14 步的產線不是同一份工作,只能拿來看方向,不能換算成秒數。

最佳化的順序:先量,再改

這是我建議的順序,而且第一件事不是改任何東西,是先知道時間花在哪

同一支 997 秒的影片,拆成三段:

階段秒數佔比
取樣(14 步)55856%
Real-ESRGAN 放大31632%
載入 + VAE 解碼 + 編碼12312%

997 秒拆成三段:取樣 558 秒佔 56%、Real-ESRGAN 放大 316 秒佔 32%、載入解碼存檔 123 秒只佔 12%。最該先動的是中間那塊,而它是整條線上我唯一沒量過的

光是放大這一段就吃掉三分之一。 而我在調步數、換 SageAttention 的那兩天裡,從來沒量過它。

⚠️ 順帶推翻一個常見直覺:「VAE 解碼很花時間」是錯覺。 載入、兩顆 VAE、影片編碼加起來才 123 秒,比放大器少一半以上。

知道這個之後,最佳化的順序就很清楚:先動放大器,再動取樣。

放大器:這台走不了 NVIDIA 的路,所以走開源的

NVIDIA 的 Video Super Resolution 在這台裝不上——這是硬限制,下一節給完整證據。所以我改試 spandrel 支援的輕量架構,選了 SPAN

放大同樣的 362 幀:

放大器秒數模型大小
Real-ESRGAN x2plus316.064 MB
SPAN49.24.3 MB
(雙線性拉大,當基準)15.4

最後那 15.4 秒是三個都要付的讀檔、縮放與存檔,拿它當基準。前兩列已經扣掉基準了,所以是放大器花掉的時間。

放大同樣的 362 幀,Real-ESRGAN 要 316 秒而 SPAN 只要 49.2 秒;基準那一列是不做放大、只讀檔存檔的 15.4 秒,三個變體都要付

快 6.4 倍,模型小 15 倍。

整條產線的實測:

組態SageAttention放大器秒數
20 步ESRGAN1,477
14 步ESRGAN1,263.5
14 步ESRGAN1,010
14 步SPAN981.2
14 步SPAN741.0

五發實測的階梯:1,477 → 1,263.5 → 1,010 → 981.2 → 741.0 秒。第二發和第四發差的只有放大器,省下的 282.3 秒比開 SageAttention 的 253.5 秒還多;兩個開關一起開就是最下面那根,剛好是起點的一半

看第二列和第四列——那兩發的唯一差別是放大器:1,263.5 → 981.2,省 282.3 秒(22.3%)

最後一列是生產組態,兩個開關一起開。這個數字原本一直是推算的(把兩邊省下的相乘,約 743 秒),而推算不該印在一張都是實測值的表裡。所以我補跑了一發:741.0 秒execution_cached=0。推算跟實測差 2 秒。

後來為了換掉台詞又跑了同一組態一次:731.0 秒。所以這一格的 run-to-run 差異大約 1.4%——個位數的秒差別當成訊號。

那一發的產物就是下面這支——順便讓它自己講這篇文章的重點:

🔊 開聲音。生產組態(14 步 + SageAttention + SPAN)的實際產物,這一發 731.0 秒。台詞是簡體的,因為繁體會讓 H3 的句子中段崩壞。

⚠️ 為什麼隔了這麼久才量到?原因在第二幕第⑤節。

⚠️ 畫質我只在手機上看過,分不出差別。 大螢幕的並排複驗還沒做。ESRGAN 的檔案我留著沒刪,想換回去隨時可以。

同一支影片,三台機器:314 / 741 / 1,383 秒

同一顆模型、同一支 15.08 秒 / 362 幀 / 1920×1080 有聲片,三台各自的上線組態:

機器上市組態秒數對 5090
RTX 5090202514 步 · SageAttention · RTX VSR314.01.0×
DGX Spark(GB10)202514 步 · SageAttention · SPAN741.02.4×
改裝 2080 Ti 22G201820 步 · SageAttention · RTX VSR1,3834.4×

八年的硬體差距在這件事上是 4.4 倍——而三台都跑得完。

⚠️ 這不是單變因對照,是三台各自的上線組態。 最大的不對齊是步數:2080 Ti 那發是 20 步,另外兩台是 14 步。在 GB10 上量到 20→14 省 14.5%,所以 2080 Ti 改 14 步應該會更快,但那一發我沒跑過。

VSR 在 aarch64 上裝不了,而 NVIDIA 說目前沒有計畫要改

如果你也在 DGX Spark 或 Jetson 上想裝 nvidia-vfx,不用查了。我把一整天的查證壓縮成下面這四層。

第一層,wheel 不存在。(wheel 就是 Python 那個已經編譯好、下載下來直接裝的檔案。)pip download nvidia-vfx 在 aarch64 上直接失敗。NVIDIA 自家索引上只有兩種:x86_64 的 Linux(manylinux_2_27_x86_64.manylinux_2_28_x86_64)和 Windows amd64。沒有任何一個 ARM 的。

第二層,原始碼有,但編出來也載不到東西。 這一層我原本寫錯,查證後改成正確的版本。

NVIDIA 確實公開了 Maxine-VFX-SDK 的原始碼,所以「沒得編」是錯的。但打開 nvvfx/src/NVVideoEffectsProxy.cpp 就會看到它在做什麼:

#define nvLoadLibrary(library) dlopen("lib" library ".so", RTLD_LAZY)
static const HINSTANCE NvVfxLib = nvLoadLibrary("NVVideoEffects");
... nvGetProcAddress(getNvVfxLib(), "NvVFX_CreateEffect");

每一個 API 都是 dlopen + dlsym 公開的是一層轉接,效果本體在 libNVVideoEffects.so 裡,而那個 .so 是閉源的、只隨 wheel 發、只發 x86_64。你可以把這層轉接編成 aarch64,編完它會去 dlopen 一個這個平台上不存在的東西。

把 x86_64 的 wheel 拆開,就看得到本體長什麼樣:

nvidia_vfx-0.1.0.1-cp312-abi3-manylinux_2_27_x86_64.whl
  597 MB · 39 個檔案 · 可編譯原始碼 0 個

  libnvinfer.so.10              TensorRT
  libnvidia-ngx-vsr.so.1.8.2    45 MB ← VSR 本體
  libnpp*.so.12                 NVIDIA Performance Primitives
  *.py                          5 個檔,只是薄薄一層 binding

裡面全是 NVIDIA 的閉源二進位。另外那個 NVIDIA-Maxine/nvidia-vfx-python-samples repo 是範例應用,跟上面的 SDK 原始碼是兩回事,兩個都不含效果實作。

第三層,從設計上就沒打算給。 我在機器上找那顆 libnvidia-ngx-vsr.so,全機沒有。有的是 /usr/lib/aarch64-linux-gnu/libnvidia-ngx.so.580.159.03——那是 loader,不是 VSR 本體。

Quarkslab 的逆向分析講得很直白:Linux 上的 libnvidia-ngx-dl{feature}.so"not publicly provided"。⚠️ 他們分析的是比較舊的 NGX 驅動檔案,不是現在這顆 wheel;但跟我在機器上看到的一致——驅動帶載入器,功能本身要另外拿,而另外拿的那條路只通 x86_64。

第四層,官方明講沒有計畫。 NVIDIA 員工 aniculescu 在 DGX Spark 論壇串「No nvidia-vfx wheel for DGX Spark」(2026-04-01)的回覆:

There is currently no plan to add NVIDIA VFX support on Spark

那個論壇串的起因跟我完全一樣:在 Spark 上裝 Comfy-Org/Nvidia_RTX_Nodes_ComfyUI 卡在缺 wheel,對應 GitHub issue #9。

⚠️ 有四個名字很像的東西很容易混淆,查之前先分清楚:

產品平台
Maxine / Video Effects SDK + nvidia-vfxLinux + Windows,僅 x86_64 ← 本題
RTX Video Super Resolution(消費級驅動功能)消費 GPU 驅動,無批次 API
RTX Video SDKWindows only
Maxine NIM(現在叫 AI for Media)另一條發佈線,雲、資料中心、工作站都能跑

這台專屬的三個坑

① 記憶體只能用 free -g 量。 GB10 的 nvidia-smi memory 欄位回 [N/A],那是壞的不是零——統一記憶體架構下 GPU 沒有自己的一塊 VRAM 可以報。我一開始盯著 nvidia-smi 看不到數字,以為是權限問題查了半天。

② 換 ComfyUI 實例要等記憶體真的降下來。 殺掉一個佔著 72 GB 的實例之後,不要 sleep 10 就起新的——那 72 GB 放不完,新實例載上去會逼系統挑一個程式殺掉來救記憶體(OOM killer)。要一直查 free -g,剩餘量夠了再起。

③ 不要加 LD_LIBRARY_PATH=/usr/local/cuda-13.2/compat pip 版的 torch 不需要它,單變數實測過。


進階:一路上判錯的幾次

不讀這節不影響使用。上面的配置是結論,這節是怎麼走到那裡的——每一節都照同一個形狀寫:遇到什麼問題 → 我以為要怎麼解 → 實際做了什麼 → 結果 → 回頭看那個預想錯在哪

① 放大器到底吃掉多少時間

遇到什麼問題 整條產線 997 秒,我知道放大是其中一段,但不知道它佔多少。

我以為要怎麼解 跑兩次完整流程、換掉放大器、相減。那是 34 分鐘,而且每換一個候選就要再付一次。

實際做了什麼 換個角度:放大器吃的是解碼之後的圖,跟畫面是怎麼生出來的完全無關。 所以不需要生成,拿一支現成的影片當輸入就好:

LoadVideo → GetVideoComponents → ImageScale(960,540) → [受測放大器] → CreateVideo → SaveVideo

結果 成功。三個變體 15 分鐘全部量完:

A 雙線性拉大(基準,不算放大)  15.442 s
B RealESRGAN                  331.466 s
C SPAN                         64.626 s

A 那 15.442 秒是三個都要付的讀檔、縮放與存檔,拿它當基準。扣掉基準才是放大器花掉的時間:ESRGAN 316.0 秒、SPAN 49.2 秒

回頭看那個預想 我以為「要量一個階段就得跑整條產線」——那是錯的。只要那個階段不在意上游是怎麼來的,就可以把它拆出來單獨量。這一招對任何「吃圖吐圖」的節點都成立,而 ComfyUI 的產線裡這種節點很多。

② 那個 −103 秒的 VAE

遇到什麼問題 想知道時間的分佈,但只有總時間。

我以為要怎麼解 拿總時間減掉我知道的兩塊。冷載入(第一次把 38 GiB 權重從磁碟讀進記憶體)我憑印象估 211 秒,取樣有 log 可以直接算,剩下的就是「VAE + 放大 + 編碼」,推出來大約 228 秒。

實際做了什麼 用上一節那招直接量 ESRGAN。

結果 失敗——而且是很難看的那種失敗。單獨量到的 ESRGAN 就有 316 秒,比我估的整個「VAE + 放大 + 編碼」還多。套進我的公式,VAE 會算出 −103 秒

負的解碼時間。

我把這件事派給 Codex 跑,它拒絕把那個數字填進去,並且指出「228 秒的估值與本次直接量測不相容」——那是對的做法。不是把負數寫進表格然後加一句「可能有測量誤差」,而是宣告兩份數據互斥、要求先解決矛盾。

回頭看那個預想 錯的不是分解的方法,是那個 211 秒的冷載入估值——它從頭到尾沒有被量過,卻撐起了整張表。分解表只要是靠估算填出來的,實際量到任何一格就得整張重算;而且要先確認新舊兩份數據有沒有衝突,有衝突就丟掉舊的。

③ 我判 VSR 死刑時,拿錯了尺

遇到什麼問題 要判斷 GB10 到底能不能用 NVIDIA 的 VSR。

我以為要怎麼解 查官方的支援清單就知道了。

實際做了什麼 查了舊版 Maxine SDK 的 install_feature.sh,裡面列的全是資料中心卡(T4、A2、A10、A16、A40、L4、L40、A100、H100),於是我判定 GB10 的 compute capability(NVIDIA 給每代晶片的能力編號)不在範圍內。

結果 結論對了(確實不能用),理由是錯的

新的 nvidia-vfx wheel 其實支援 Turing 到 Blackwell——我後來在一張 2018 年的 2080 Ti 上把它裝起來跑了。擋住 GB10 的從來不是 compute capability,是 CPU 架構。同一批查證裡我還說錯一件事:我寫「GX10 的驅動 580.159.03 差一點點不到 580.82」,而 580.159 > 580.82——驅動那關其實過了

回頭看那個預想 我以為「查支援清單」是一個動作,實際上它是兩個問題:哪一份清單、對應哪一條發行線。拿錯的尺會給你對的結論和錯的理解,而錯的理解會在下一台機器上背叛你——我就是拿那個錯理解去判 2080 Ti,結果判反了。

④ 補量 SPAN 總時間時,我漏了一個旗標

遇到什麼問題 換 SPAN 之後的總時間我一直是用推算的(997 − 267 ≈ 730),想要真數字。

我以為要怎麼解 跑一發完整流程就知道了。

實際做了什麼 寫了腳本:停推論模型、起 ComfyUI、送工作流、讀 /history 的時間戳。

結果 拿到 981.243 秒。差一點就填進文章——然後我去看啟動訊息,印的是 Using pytorch attention我的腳本漏了 --use-sage-attention

所以那 981 秒是 PyTorch 內建注意力(SDPA)的數字。如果拿它跟 1,010 秒(開 Sage 的那筆)比,會得出「SPAN 只省 3%」的錯誤結論。正確的對照是 1,263.5 秒(同樣沒 Sage 的 ESRGAN 基準):−282.3 秒,22.3%,跟單獨量放大器推算出來的 267 秒吻合。

回頭看那個預想 我以為對照組只要「同一個工作、同一個 seed」就成立。實際上要對齊的是整條啟動指令——少一個旗標,兩發就跨了兩種不同的注意力實作,而那個差異(20%)比我要量的東西還大。要手動下指令的機器反而容易犯這個錯,因為每次都是自己敲,而自己敲就會漏。

⑤ 補跑的時候,我把整台機器弄爆了

遇到什麼問題 要把上一節那發重跑一次,這次帶上 --use-sage-attention

我以為要怎麼解 殺掉舊的 ComfyUI、等一下、起新的。

實際做了什麼 腳本寫的是 pkill 之後 sleep 10

結果 失敗,而且是這輪最貴的一次。舊實例佔著約 72 GB 統一記憶體,10 秒放不完;新實例載上去,整台機器的記憶體被榨乾,系統開始挑程式殺。被殺的是 tailscaled——所以我的 SSH 直接斷線,四分半鐘連不上。連鎖還把 user@1000.service 打掉,/run/user/1000 整個消失,於是 systemctl --user 一律回「Failed to connect to bus」,推論模型也起不回來。

修法是 sudo systemctl reset-failed user@1000.servicestart,runtime dir 回來之後才能把推論模型帶起來。

回頭看那個預想 我以為「釋放 72 GB」是一件耗時固定的事,所以 sleep 10 就夠。實際上那是一件耗時不定的事,唯一正確的寫法是一直查 free -g,直到剩餘量足夠為止。而且系統挑的受害者不會是佔記憶體最多的那個——它挑了 tailscaled,也就是我唯一的進入通道。

還沒收的尾

  • Cache-DiT 量到 −9.3%(996.956 → 903.990 秒)但沒上線。 空跑一次證明它不動 torch/triton、跟 Spectrum 可以共存,現在先隔離在另一個目錄裡,要上線只是裝回去。
  • 對白在 14 步下的品質沒驗。 我只比過畫面,沒有在 14 步和 20 步之間並排聽過對白。

常見問題

DGX Spark 跑得動 MiniMax-H3 嗎?
跑得動。GB10 有 121 GB 統一記憶體,H3 生成時峰值約 72 GB,一支 15 秒 1080p 有聲片在生產組態(14 步 + SageAttention + SPAN)實測 741 秒。要注意的是,它不能跟常駐的推論模型同時跑——我這台平常還掛著一個吃掉 85 GB 的,兩個加起來就超過總量。
DGX Spark 可以用 NVIDIA 的 Video Super Resolution 嗎?
不行。nvidia-vfx 只發 x86_64 的 wheel(以及 Windows amd64),GB10 是 aarch64。NVIDIA 員工在 DGX Spark 論壇串裡逐字回覆「There is currently no plan to add NVIDIA VFX support on Spark」。要注意這句話說的是「目前沒有計畫」,不是「永遠不會」——但在他們改變計畫之前,這台就是裝不上。
那 DGX Spark 上的影片放大要用什麼?
開源的 SPAN。放大 362 幀從 Real-ESRGAN 的 316 秒掉到 49 秒,而模型只有 4.3 MB(ESRGAN 是 64 MB)。整條產線實測從 1,263.5 秒掉到 981.2 秒,省 22.3%。手機上看不出畫質差別,大螢幕的複驗還沒做。
怎麼量一顆 ComfyUI 節點花了多少時間?
放大器吃的是解碼後的圖,跟畫面怎麼生出來的無關。所以不要跑完整流程,改接一條只有放大的小流程:LoadVideo → GetVideoComponents → ImageScale → 受測放大器 → CreateVideo → SaveVideo,拿一支現成影片當輸入。三個變體 15 分鐘量完,不用每次付 17 分鐘的取樣。
SageAttention 2.2.0 裝得上 sm_121 + aarch64 嗎?
裝得上。社群普遍的說法是 sm_121 要自己用 compute_121a 編 v3,但 2.2.0 的 wheel 在 torch 2.13.0+cu130 的 aarch64 環境直接裝起來就能跑,省下 20.1% 的時間(1263.5 → 1010 秒)。這個 20.1% 還是保守的;在其他條件完全相同的兩發之間比,差距是 31.6%。

接著讀

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。