~/blog/h3-ltx-two-stage-dgx-spark

DGX Spark · part 47

[影片生成] 用 Sol-H3 兩段式,DGX Spark 比純 H3 生片快 1.89 倍

cat --toc

TL;DR

MiniMax-H3 只畫 672×384 草稿、LTX-2.5 三步精修到 1344×768,在 DGX Spark 上 110.6 秒,原生直出要 208.5 秒——快 1.89 倍。模型留在記憶體裡再跑一次是 66.8 秒。同一套流程在 RTX 5090 上只快 1.28 倍,因為兩段模型合計 53.6 GiB,而這張卡只有 31.84 GiB,每跑一次都得換模型。但絕對值上 Spark 仍比 5090 慢 2–4 倍(110.6 對 40.3 秒)。

手繪風社群封面:一台擬人化的 DGX Spark 小方盒同時抱著兩塊模型方塊、表情輕鬆,旁邊較小的顯示卡只抱得住一塊、另一塊掉在地上;右側四張資訊卡寫著 208.5 → 110.6 秒、兩段合計 53.6 GiB、第二發 66.8 秒、純 H3 第二發省 0%。標題是「同一台機器,換個做法快 1.89 倍」。

前言

搬家的時候如果只借得到一台小貨車,真正花時間的不是開車,是每趟回來重新裝箱。換一台大車,同樣的東西同樣的路,時間卻少一半——不是車開得比較快,是你不用再拆裝。

上一篇我把 NVIDIA Sol-H3 的兩段式做法搬到 RTX 5090 上:MiniMax-H3 只畫 672×384 的草稿,放大到 1344×768 那段交給 LTX-2.5 跑三步精修。結論誠實但有點掃興——單發比下來只快 1.28 倍,跟原生直出幾乎打平。

那篇留了一個沒回答的問題。兩段式要同時用到兩套模型,而 5090 塞不下,所以每跑一發都得把上一段換出去。省下來的算力,是不是都被換模型吃掉了?

要回答這題需要一台放得下的機器。我有一台 DGX Spark,統一記憶體 121 GiB。

110.6 秒對 208.5 秒

四種跑法,同一句提示詞、同一個 seed、同樣 5 秒 1344×768 帶音訊。

下面會一直出現「冷機」跟「熱機」,先定義清楚——這兩個詞跟溫度無關,講的是模型在不在記憶體裡:冷機=剛清空,這一發要從硬碟把模型讀進來;熱機=上一發剛跑完、模型還躺在記憶體裡,這一發直接用。

表裡每個秒數都是整條 workflow 從送出到完成的時間——草稿取樣、交接、放大、精修取樣、VAE 解碼、出檔,全部含在內,不是只算模型跑了多久。所以熱機省下來的 43.7 秒不是算力省下來的,而是不用反覆把模型搬進搬出記憶體:第二發的草稿和精修都是重新算的,省掉的是那一次搬運。這件事我在進階那節逐一查過被重用的節點,因為它是整篇最值得懷疑的一格。

DGX SparkRTX 5090
原生 1344×768 直出(冷機)208.5 秒51.5 秒
兩段式(冷機)110.6 秒40.3 秒
兩段式(熱機,模型還在記憶體)66.8 秒30.6 秒

這些倍數都是同一台機器內部比,兩段式對原生,不是跟另一台比:

  • Spark:冷機對冷機,110.6 對 208.5,兩段式快 1.89 倍
  • 5090:冷機對冷機 40.3 對 51.5 快 1.28 倍;熱機對熱機 30.6 對 41.5 快 1.36 倍

Spark 的熱機那格只有兩段式的 66.8 秒。原生的對應數字我後來補到了,但那是把 GPU 鎖在 2200 MHz 之後才量得到的——不鎖的話機器會在第二發中途斷電,這件事下一篇專門寫。鎖頻改變了絕對秒數,所以它不能跟表裡其他格相除,我把它單獨放在後面一節。

先講清楚一件事:Spark 每一格都比 5090 慢 2 到 4 倍。 兩段式在 Spark 上 110.6 秒,5090 上 40.3 秒。快的是方法在這台機器上的加成,不是機器本身。

怎麼設定

不用自己寫程式,裝 T8star 的節點包就能在 ComfyUI 裡跑這套流程。

H3 這一側要的東西我全部放在同一個 repo 了——兩顆 transformer、文字編碼器、兩顆 VAE、turbo LoRA、conditioning 快取、自製節點、還有 workflow 本身,而且目錄是照 ComfyUI 的 models/ 樹排好的,所以一行 hf download 下去就位,不用自己對資料夾: huggingface.co/coolthor/MiniMax-H3-pruned-NVFP4

只有 LTX-2.5 要另外抓,因為它的授權跟 H3 不同,不能鏡像在同一個 repo 裡。

下面的指令都在 Spark 的終端機裡跑,前提是你已經有一套會動的 ComfyUI。如果還沒有,先把 ComfyUI 裝起來再回來。

一、先拿到權重(模型檔案)的存取權

兩個 repo 都是 gated —— 要先在網頁上按同意條款,帳號才拿得到下載權。沒先處理這一步,下面的 hf download 會直接回 401。

先用瀏覽器開 coolthor/MiniMax-H3-pruned-NVFP4Lightricks/LTX-2.5,各按一次同意條款,然後:

hf auth login

⚠️ H3 那個 repo 的 gating 是刻意的——MiniMax-H3 的社群授權排除歐盟、英國、南韓與美國,那個限制跟著權重走。

二、權重

# H3 那一側:transformer、文字編碼器、兩顆 VAE、turbo LoRA 都在同一個 repo
hf download coolthor/MiniMax-H3-pruned-NVFP4 --local-dir ComfyUI/models \
  --include "diffusion_models/minimax_h3_fl2va*" "text_encoders/*" "vae/*" \
            "loras/minimax_h3_fl2v*" "conditioning_cache/*" "custom_nodes/*"

# LTX 那一側(授權不同,另外抓)
hf download Lightricks/LTX-2.5 --local-dir ComfyUI/models \
  --include "diffusion_models/ltx-2.5-22b-distilled-transformer-nvfp4.safetensors" \
            "vae/ltx-2.5-*" "latent_upscale_models/*"

上面那串會把 custom_nodes/ 放到 ComfyUI/models/ 底下,位置不對,搬一次:

mv ComfyUI/models/custom_nodes/ComfyUI-CondCache ComfyUI/custom_nodes/

三、節點包(兩個,少一個圖就載不起來)

git clone https://github.com/T8mars/comfyui-minimax-h3-audio-T8 \
  ComfyUI/custom_nodes/comfyui-minimax-h3-audio-T8

git clone https://github.com/xmarre/ComfyUI-Spectrum-MiniMax-H3 \
  ComfyUI/custom_nodes/ComfyUI-Spectrum-MiniMax-H3

T8 那包提供交接用的兩個節點:MiniMaxH3SolEngineDraftToLTXT8Advanced(把草稿交給 LTX 之前裁幀、裁比例)與 MiniMaxH3SolEngineLTXIdentityRefinerSetupT8Advanced(設定精修怎麼跑)。

第二包提供 SpectrumApplyMiniMaxH3,workflow 的節點 7 會用到。少裝這包的症狀是整張圖載不進來,不會告訴你少了哪個節點。

LTXVLatentUpsampler 是 ComfyUI 核心內建的,不用另外裝。

四、Workflow

不用自己接。這就是我實際跑出本文所有數字的那張,32 個節點,已經重新編號、沒有任何內部路徑:

⬇︎ minimax-h3-ltx-hybrid-refine-nogemma.json

拖進 ComfyUI 就會展開。同一張也在 HF repoworkflows/ 底下,跟權重一起抓比較省事;上面這個直連是給還沒申請權重、想先看圖長什麼樣的人。

在 DGX Spark 上一定要用 -nogemma 那張,不要用含 Gemma 的版本。 那版在這台機器上直接報錯,詳細原因在後面進階那節。

五、兩個要自己確認的設定

精修起跑 sigma 壓到 0.78。 sigma 是精修那一段「要從多亂的狀態開始重畫」的刻度——數字越大,LTX 把草稿打得越散、重畫得越徹底。workflow 裡已經設好 0.78, 0.643, 0.546, 0。官方常數是 0.909375(下面都寫 0.909),打太散就會連臉一起重畫成另一個人——上一篇有六格對照。

啟動後檢查節點有沒有載進去。 LoadConditioningT 是自製節點不在任何 registry,載不到的話 workflow 會在讀 conditioning 那一格失敗,而錯誤訊息長得像「節點不存在」不是「檔案不見」,很容易往錯的方向查:

curl -s http://<your-spark-ip>:8188/object_info \
  | python3 -c "import sys,json;d=json.load(sys.stdin);print([n for n in ('LoadConditioningT','MiniMaxH3SolEngineDraftToLTXT8Advanced','SpectrumApplyMiniMaxH3') if n in d])"

三個名字都印出來才算好了。

為什麼比原生快:差別在 53.6 GiB 塞不塞得下

兩段式要同時用到的東西,一項一項加起來(GiB 是記憶體容量單位,比硬碟廠商標的 GB 略大一點,這裡的數字都是模型實際佔的量):

Stage 1(MiniMax-H3)
  minimax_h3_fl2va_pruned_nvfp4          11.67 GiB
  qwen3vl_32b_heretic_minimax_h3_nvfp4   14.61 GiB
  minimax_h3_video_vae_fp16               4.85 GiB
  minimax_h3_audio_vae_fp32               0.56 GiB
  minimax_h3_fl2v_turbo_4step             1.82 GiB

Stage 2(LTX-2.5)
  ltx-2.5-22b-distilled-transformer      17.44 GiB
  ltx-2.5-video-vae-conv-bf16             1.35 GiB
  ltx-2.5-audio-vae-bf16                  0.34 GiB
  ltx-2.5-latent-spatial-upscaler-x2      0.93 GiB
                                        ─────────
                                        約 53.6 GiB

加上工作空間,實測峰值 104 / 121 GiB

記憶體容量對照:兩段式需要 53.6 GiB 同時常駐(MiniMax-H3 那段 33.5、LTX-2.5 那段 20.1),RTX 5090 可用 31.84 GiB 連第一段都放不下,DGX Spark 可用 121 GiB 兩段一起放得下,實測峰值 104
圖 1:同一個方法在兩台機器上差這麼多,關鍵就在這 53.6 GiB 塞不塞得下。5090 的 31.84 GiB 連 Stage 1 自己的 33.5 GiB 都跨不過去,所以每一發都得換模型;Spark 的 121 GiB 讓兩段一起躺著,第二發不用再載。

我這張 5090 回報 31.84 GiB 可用,連 Stage 1 自己的 33.5 GiB 都塞不進去。(31.84 與下面的 121 都是我這兩台實測回報的可用量,不是規格書上的 32 GB / 128 GB。)所以 5090 上每跑一發的實際順序是:載入 H3、畫草稿、把 H3 整個換出去、載入 LTX、精修、換出去。下一發從頭再來。

Spark 這邊兩段一起躺在記憶體裡,第二發開始不用再載。冷機到熱機省下 43.7 秒(110.554 減 66.820),絕大部分是那個載入時間。

原生的常駐紅利是 0%,但要先鎖頻才量得到

兩段式的第二發省下 43.7 秒,原生的第二發一秒都省不到。 這是整篇的核心:常駐幫得上的是兩段式,不是這台機器。

要量到原生那一格得先把 GPU 鎖在 2200 MHz(它自己會衝到 2450),不鎖的話第二發跑到一半就斷電:

冷機熱機變化
原生(鎖頻 2200)246.6 秒251.3 秒+1.9%
兩段式(未鎖頻)110.6 秒66.8 秒−39.6%

原生的第二發不但沒變快,還慢了 4.7 秒。

為什麼原生吃不到:它沒有任何節點可以重用。 兩段式第二發有 18 個節點被快取,原生是 0 個。那 121 GiB 對原生毫無意義,因為它沒有第二套模型要留。

順便踩到的坑:這台機器長時間滿載會整台斷電

實驗跑到一半,機器整台沒電了。

不是當機,是斷電——要人走到現場按電源。而且同一天發生兩次,兩次都在跑原生 1344×768 的連續第二發:第一發整整 202 秒滿載跑完還活著,第二發沒有間隔直接接上去,90 秒後斷電。

兩段式在同一台機器上跑了四發全部活著,而且記憶體峰值 104 GiB 比出事時的 74 GiB 還高。

差別是連續滿載的時間長度。原生是一口氣 200 秒不間斷;兩段式最長的一段只有 110 秒,中間還有 VAE 解碼、交接、重新編碼這些相對輕的階段。

這不是這個流程造成的,而且有解:把 GPU 鎖在 2200 MHz,同樣的連續兩發就都跑得完,代價是每一發慢約 20%。NVIDIA 開發者論壇上有一筆症狀相似的回報,驅動版本和推論模型都跟我這台一樣。怎麼查出來的、鎖頻為什麼有效,下一篇專門寫。

不過話講回來,鎖頻之後原生也跑得完了。兩段式撐得住這件事是真的,但鎖頻是更簡單的解法——對這篇來說,值得用兩段式的理由還是那 1.89 倍。


進階:量測方法與三個要交代的差異

不讀這節不影響使用。上面那條路照著接就會動。

每個數字都是 ComfyUI /history 的起訖時間差

execution_successexecution_start 除以 1000。每一發都記 execution_cached.nodes 的長度——空的是冷機,有數字的是熱機,而那個數字本身就是證據。

冷機發之前先清:

curl -X POST http://<your-spark-ip>:8188/free \
  -H 'Content-Type: application/json' \
  -d '{"unload_models":true,"free_memory":true}'

熱機發不清,而且要換 seed。我第一次跑的時候兩發同一個 seed,第二發回來 0.006 秒、cached=31——整張圖都被快取了,那不是熱機是快取命中。換 seed 之後才是 18。

那 18 個被重用的節點,我逐一查過

這是整篇最需要驗證的一格:66.8 秒到底是「模型不用重新載入」還是「草稿沒有重畫」。如果是後者,那個數字就沒有意義。

被快取的 18 個:4 個 VAELoader、2 個 UNETLoader、1 個 CLIPLoader、1 個 LoraLoaderModelOnly、1 個 LatentUpscaleModelLoader——九個載入器。剩下是 BasicGuider ×2、KSamplerSelect、BasicScheduler、SpectrumApplyMiniMaxH3、IdentityRefinerSetup、LTXVConditioning、LoadConditioningT,全是設定,加上一個提示詞節點。

沒被快取、真的重跑的 14 個裡面包含兩顆 SamplerCustomAdvanced——H3 的草稿取樣和 LTX 的精修取樣都重算了,加上 VAEEncode、VAEDecode ×2、VAEDecodeAudio、DraftToLTX 交接、LatentUpsampler,以及換了 seed 的 RandomNoise。

草稿是重畫的,所以省下的 43.7 秒不可能是算力省下來的。我把它歸給模型載入,但那是推論不是直接量到的——execution_cached 報的是節點輸出被重用,不等於直接量到磁碟 I/O 或 GPU 常駐。要確認得另外量配置與讀取時間。

三個跟上一篇不一樣的地方

LTX 用 nvfp4,上一篇是 int8-convrot。 同一天我在 5090 上把兩者各跑三發熱機,中位數 30.574 對 30.819 秒,差 0.245 秒,而同一組自己最快最慢就差 6 秒——速度上分不出高下,選 nvfp4 純粹因為它小 2.6 GiB。

兩段式跑的是不載 Gemma 的版本。 LTX 精修那段的提示詞是固定的一句,所以可以算一次存起來,之後直接讀檔,不用把 14.32 GiB 的文字編碼器載進來。這台機器上更是非做不可——含 Gemma 的那版在這裡直接報錯:

ValueError: not enough values to unpack (expected 4, got 1)
  sd1_clip.py:266

sd1_clip.py:266forward 裡,它把 process_tokens(同檔 172 行)的回傳解成四個值,而這台機器上拿到一個。看起來是我這套 ComfyUI 跟那條路徑的版本對不上,但我沒有驗到那一層——**我沒有查到這是所有 Spark 都會遇到的,只能說我這台會。**換成讀快取的版本剛好繞過那一格,而且語意等價:快取就是用同一句提示詞算出來的,我比對過逐字相同。

主表的原生熱機那一格是空的,因為未鎖頻時量不到。 兩次嘗試都把機器弄斷電——第一次跑到一半沒電,第二次在同一個 ComfyUI process 裡連跑兩發原生,第二發 90 秒後沒電。後來鎖頻 2200 才量到 246.627 / 251.302 秒,但那是另一個組態,所以我放在單獨一節,沒有併進主表。

冷機那一格有兩發:208.515 秒與 201.852 秒,差 6.7 秒(3.2%),這台每次跑本來就會差這麼多。上面表格用的是第一發。

這台機器的執行環境

機型                   ASUS Ascent GX10(GB10),121 GiB 統一記憶體
系統                   DGX OS,kernel 6.17.0-1032-nvidia,驅動 580.173.02
ComfyUI 節點總數        1157
LTX transformer        ltx-2.5-22b-distilled-transformer-nvfp4      17.44 GiB
H3 transformer         minimax_h3_fl2va_pruned_nvfp4                11.67 GiB
文字編碼器              qwen3vl_32b_heretic_minimax_h3_nvfp4         14.61 GiB
精修起跑 sigma          0.78, 0.643, 0.546, 0
草稿步數 / 精修步數      4 / 3
輸出                   1344×768,124 幀,24 fps,含音訊

sigma 那組值跟上一篇一樣,理由也一樣——官方的 0.909375 在這條路上會把臉重畫成另一個人。六格對照在上一篇


這個系列的其他文章H3 只畫草稿,LTX-2.5 收尾:RTX 5090 上的兩段式影片產線

常見問題

兩段式影片生成在 DGX Spark 上比原生快多少?
冷機對冷機是 110.6 秒對 208.5 秒,快 1.89 倍。模型留在記憶體裡再跑一次是 66.8 秒,省下 39.6%。原生的同一項省 0%——把 GPU 鎖在 2200 MHz 之後量到 246.6 秒對 251.3 秒,第二發還比第一發慢了一點。同一套流程在 RTX 5090 上冷機快 1.28 倍、熱機快 1.36 倍。
為什麼同一個方法在 DGX Spark 上的效果比 RTX 5090 好?
兩段式要同時用到 MiniMax-H3 與 LTX-2.5 兩套模型,合計約 53.6 GiB。RTX 5090 只有 31.84 GiB,每跑一次都得把上一段換出去,省下的算力被載入吃掉。DGX Spark 的 121 GiB 統一記憶體放得下兩段,省下的才真的落袋。
DGX Spark 跑影片生成比 RTX 5090 快嗎?
不快。每一種跑法 DGX Spark 都慢 2 到 4 倍,兩段式 110.6 秒對 5090 的 40.3 秒。快的是方法在這台機器上的加成,不是機器本身。
在 DGX Spark 上跑這個流程需要注意什麼?
LTX 精修那段不要載 Gemma 文字編碼器,改讀預先算好的 conditioning 快取——含 Gemma 的版本在 DGX OS 的 ComfyUI 上會直接報錯。另外這台機器在長時間滿載下會整台斷電——把 GPU 鎖在 2200 MHz 就不會了,代價是每一發慢約 20%,下一篇專門寫。

接著讀

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。