DGX Spark 單機運行 FP8 剪枝版的 Ref2VA 與 FL2VA,並透過 SGLang 部署。
spark-2 上兩個服務同時常駐,前面一個轉發器分派;下面是兩者用同一段提示詞的成品與實測數字
上面兩支是 8 步的實驗性短片,用來比較兩個服務;下面這支是同一套部署跑出來的 50 步完整版,含音效
由四個子模型組成的開源影片生成模型。
按「▶ 跑一支任務」看一支 8 步、5 秒的任務依序經過哪個模型;切換 Ref2VA/FL2VA 看兩者差在哪。秒數都是實測,動畫本身有加速
現行 FP8 剪枝服務跑完的每一支任務都收在這裡(1344×768、24 fps、seed 1);同一設定跑過多次的,列出次數與範圍
FP8 剪枝是唯一「畫面正確、兩份放得下、SGLang 在 GB10 上跑得動」的版本。
各版本都用同一支 8 步、5 秒、1344×768、seed 1 的漢堡任務比較;點標題展開
結論:FP8 剪枝是唯一同時滿足三個條件的選項 —— 畫面正確、檔案夠小能放兩份、SGLang 在 GB10 上跑得動。代價是每步比 BF16 慢 28%,換到的是兩個模型同時常駐、不必花 3 分鐘重啟切換。
| 版本 | DiT 檔 | 冷啟動 | 文字編碼 | 參考圖 | 去噪 ×7 | 每步 | 解碼 | 全程 | 峰值(API) | 峰值(取樣) | 狀態 |
|---|
--quantization fp8):每步 91 s、峰值 13 GB、冷啟 10:19,畫質相當但慢 23%,GB10 的 FP8 核心是瓶頸text_encoder=resident換角、10 秒、5 秒三支的記憶體高原都在 106 到 110 GB:序列變長拉長的是時間,不是記憶體。兩支 15 秒預告的取樣峰值(賭場 115.9、恐怖片 115.4 GB)基線就有 90 GB,因為當時 FL2VA 與 Ref2VA 兩個服務同時常駐,不能與單服務的數字直接比;它們自己的 GPU 峰值只有 42.2 與 41.6 GB,是 DiT 換成 FP8 剪枝檔的結果。
quant_method 屬性),上游還沒修;ComfyUI 直接吃 LoRA。三個主要差距:美術使用的模型小 3 倍、GPU 頻寬快 6 倍、LoRA 讓步數少 6 到 12 倍。
'RowParallelLinearWithLoRA' object has no attribute 'quant_method'。LoRA 檔沒問題,624 個 key 載入、套到 208 層都成功--lora-path,SGLang 就無條件把所有線性層換成包裝物件;H3 每個區塊前向時直接讀 linear.quant_method,包裝層沒有這個屬性(pipeline.py · minimax_h3.py)為什麼差 3 分鐘:SGLang 沒有換模型指令,只能重啟;重啟後還要跑一支假任務把 62 GB 全讀一遍。ComfyUI 不重啟、不暖機、檔案又只有三分之一。解法:關暖機省一半,或兩個 FP8/INT8 服務同時常駐就不用換。
為什麼他能用我不能:LoRA 檔一樣,載入的程式不一樣。ComfyUI 直接套;SGLang 的 H3 模型在每個區塊探測能否用 MXFP8 時直接讀 linear.quant_method,LoRA 包裝層沒有這個屬性就崩。改成 getattr 兩行即可,上游未修。
'RowParallelLinearWithLoRA' has no attribute 'quant_method'quant_method,修法是掛完後用 getattr 重新驗證minimax_h3.py 今天確認仍直接讀 linear.quant_method來源:sglang #37456 DGX Spark 配方 · #38170 · #40171 · #39514 · #40127 · lightx2v #24 · 同事 movieeasymake · H3-Optimizations
兩個服務同時常駐是安全的:平常 89 GB,有任務在跑時 98 GB,離機器的 121 GB 還有 23 GB。單一容器用量約 25.5 GiB,離 108 GB 上限很遠。
與 BF16 版本畫面看不出差異。同一支任務 BF16 是每步 74.8 s、全程 9:40,所以 FP8 慢 28%。
完全沒有參考圖,角色、漢堡塔、鐵絲網、藍天都是從文字生成。不必編碼參考圖、輸入序列也短,所以每步快 39%。含 32 kHz 音軌。
| 項目 | Ref2VA(左) | FL2VA 純文字(右) |
|---|---|---|
| 提示詞 | 同一段,只有兩處指向參考圖的字改寫(見下方) | |
| 參考素材 | 一張角色參考圖 | 無 |
| 每步去噪 | 95.6 s | 58.2 s,快 39% |
| 全程 | 12:08 | 7:25 |
| VAE 解碼 | 35.6 s | 35.7 s,相同 |
| 峰值(API) | 29.1 GB | 25.7 GB |
in the exact style of <Picture 1>,純文字沒有圖可指,改為 in a flat cartoon styleThe pink starfish character from <Picture 1>,改為 A pink starfish character為什麼需要轉發器:SGLang 一個服務只能載一個模型,兩個服務各有各的佇列、互不知情。轉發器負責分派,並確保同一時間只有一支任務進 GPU。
| task 欄位 | 用途 | 需要的素材 | 實際走 |
|---|---|---|---|
ref2va | 參考角色、場景、聲音;換角 | 至少一個 conditions | 30110 |
t2va | 純文字生成影片與聲音 | 不需要 | 30120 |
fl2va | 首尾幀補間 | 首幀、尾幀擇一或兩者 | 30120 |
# 送任務(立刻回號碼牌;排隊在伺服器端,斷線不會取消)
curl.exe -X POST http://{spark-2-ip}:30100/v1/videos \
-H "Content-Type: application/json" -d "@request_t2va_8.json"
# 查狀態與下載(用同一個埠,會自動轉回正確的後端)
curl.exe -s http://{spark-2-ip}:30100/v1/videos/<id>
curl.exe -s -L http://{spark-2-ip}:30100/v1/videos/<id>/content -o out.mp4
# 看轉發器與兩個後端的健康、目前鎖在誰手上
curl.exe -s http://{spark-2-ip}:30100/health
兩件要注意的事:一、不填 task 時轉發器會依內容自己推斷並補上,但明確填寫比較保險。二、30110 與 30120 仍可直接存取,但繞過轉發器就沒有排隊保護,建議一律走 30100。
# 兩個服務(在 spark-2 主機以 {host-user} 執行)
bash {nfs-dir}/minimax_h3/host/h3-up.sh ref2va_fp8 up|down|restart|status
bash {nfs-dir}/minimax_h3/host/h3-up.sh fl2va_fp8 up|down|restart|status
bash {nfs-dir}/minimax_h3/host/h3-up.sh ref2va_bf16 restart # 換回 BF16 單模型
# 轉發器
bash {nfs-dir}/minimax_h3/host/h3-router.sh up|down|restart|status|logs| 問題 | 原因 | 解法 |
|---|---|---|
| FL2VA 要不要下載 135 GB | 官方分割是完整目錄 | 比對後發現兩分割的 transformer 設定完全相同,文字編碼器與 VAE 可共用;只下載 19.5 GB 權重+兩個設定檔,用符號連結組出 FL2VA 目錄 |
| SGLang 一個服務載不了兩個模型 | 模型是啟動參數 | 開兩個容器、兩組埠;腳本加 MODEL_VARIANT 與 H3_PORT 參數 |
| 兩邊佇列互不知情 | 各自獨立的 scheduler | 前面放轉發器做全域鎖,送出前先查兩邊是否在忙 |
API 回 task is required | H3 必填 task 欄位 | 轉發器在缺少時依內容自動補上 |
| 客戶端逾時後仍產生任務 | 轉發器仍在排隊等待 | 等待迴圈加 is_disconnected() 檢查,斷線就放棄;並加一小時上限 |
| 監看腳本找不到 log | 兩服務的 log 檔名加了分割後綴 | tasks.sh/run_test.sh 改成自動選最新的 log,可用 H3_LOG 覆寫 |
相關檔案:router/h3_router.py、host/h3-up.sh、host/h3-router.sh、model/FL2VA/、quant/diffusion_models/minimax_h3_*_pruned_fp8_scaled.safetensors
# 回應 { "id": "9326c620-...", "status": "queued", "backend": "ref2va", "queue_position": 1, "queue_ahead": 0 } # backend:送去哪個模型。queue_ahead:前面還有幾支 # 詳情(提示詞、參數、素材)用 GET /v1/videos/<id>/detail 查,任何人都看得到
curl.exe -s http://{spark-2-ip}:30100/v1/videos/<id>
# 完成後會多出這幾個欄位
{ "status": "completed", "inference_time_s": 728.2, "peak_memory_mb": 29752,
"file_path": "{workspace}/minimax_h3/outputs/<id>.mp4" }
# status 可能是:queued(排隊或生成中)、completed、failed(error 寫原因)、
# stopping(有人刪了它,服務重啟中)、deleted(已被刪除)、lost(伺服器已經沒有這筆)
# 跑到第幾步、還要多久:GET /v1/progress
curl.exe -s -L http://{spark-2-ip}:30100/v1/videos/<id>/content -o out.mp4
<Picture 1>、<Video 1>、<Audio 1> 指向素材<Picture 1>、<Picture 2>…;建議 1~2 張,3 張起可能特徵混淆;每步約慢 27%(2 張)、67%(3 張)/v1/videos/v1/videos/<id>/v1/videos/<id>/detail/v1/videos/<id>/content/v1/videos/v1/progress/v1/models/v1/prompt/optimizedone 的 text 就是改寫好的英文提詞/health/v1/videos/<id>?stop=1;已完成的影片移到回收區刪除生成中的任務會重啟服務。SGLang 沒有中止功能,DELETE /v1/videos/<id>?stop=1 會重啟那個模型的服務來停下 GPU(FL2VA 約 6 分、Ref2VA 約 7.5 分,期間它的其他任務要等)。快跑完的任務建議等它完成;每次刪除都會記下來源 IP。
| 欄位 | 可用值 | 說明 |
|---|---|---|
num_inference_steps | 2 到 100 | 官方預設 50(正式品質),8 步是速度測試;超過 50 沒實測。程式只要求至少 2 步,沒有上限,100 是這份文件建議的上限。時間幾乎與步數成正比 |
target.duration_seconds | 4 到 15 | 5 秒變 10 秒,每步時間約 ×2.3 |
target.short_edge | 768 | 其他值會印警告;畫質未驗證 |
target.aspect_ratio | 21:9、16:9、4:3、1:1、3:4、9:16 | 16:9 是 1344×768 |
seed | 整數 | 同 seed 加同參數可重現 |
flow_shift | 12.0 | 影片;官方預設,不建議改 |
audio_flow_shift | 3.0 | 聲音;官方預設 |
conditions[].uri | 本機路徑 | 要搭配 multipart 附檔(-F "files=@…"),轉發器會用檔名比對後改寫成伺服器位址 |
name | 任意文字,80 字內 | 選填,任務名稱,顯示在生成台「最近的任務」與查詢結果。不填會自動命名為 日期_時間_任務 id(台灣時間),例如 20260924_091850_9326c620-… |
backend | ref2va、fl2va | 選填,強制指定後端,蓋過 task 的自動判斷 |
curl.exe -s http://{spark-2-ip}:30100/v1/progress # 正在跑哪一支、第幾步、每步秒數、剩多久;queue 是排隊中的
# 要看更多(記憶體、GPU、log)再進容器:
ssh -p 2201 root@{spark-1-ip}
bash {workspace}/minimax_h3/tasks.sh # 精度組合、任務清單、進行中的步數與預計完成
bash {workspace}/minimax_h3/status.sh # 記憶體、GPU、API 健康、最近 log
bash {nfs-dir}/minimax_h3/host/h3-up.sh ref2va_fp8 up|down|restart|status
bash {nfs-dir}/minimax_h3/host/h3-up.sh fl2va_fp8 up|down|restart|status
bash {nfs-dir}/minimax_h3/host/h3-router.sh up|down|restart|status|logs
bash {nfs-dir}/minimax_h3/host/h3-control.sh up|down|status|logs # 讓「刪除生成中的任務」能重啟服務
| 現象 | 原因 | 怎麼辦 |
|---|---|---|
回 task is required | 沒填 task,而且內容判斷不出來 | 明確加上 "task" 欄位 |
| 一直是 queued | 前面還有任務,queue_ahead 是前面的支數 | 正常現象,等就好;不要了就 DELETE /v1/videos/<id>(任何人都能刪) |
| 刪除已完成的任務 | 所有人都看不到這支任務與它的詳情 | 影片移到伺服器的 outputs/.trash/,需要找回請洽管理者;每次刪除都會記下來源 IP |
| DELETE 回 409 | 這支已經在 GPU 上生成;SGLang 沒有中止功能 | 加 ?stop=1 會重啟該模型的服務來停止它(冷啟動 FL2VA 約 6 分、Ref2VA 約 7.5 分,期間該模型的其他任務要等);快跑完的就等它完成 |
| 狀態 failed,error 寫「後端拒收」 | 輪到它時後端才檢查參數,不合規就擋下 | 看 error 裡的原因改參數再送 |
| 回「是本機路徑,但這次沒有附上同名檔案」 | uri 寫了本機路徑卻沒用 multipart 附檔 | 加上 -F "files=@<檔案>",檔名要與 uri 的檔名一致 |
| 素材上傳了但任務沒送成功 | 後端拒收或請求格式有誤 | 轉發器會立刻刪掉那批素材,不必手動清 |
| 兩個素材變成同一張 | 附檔同名,或中文檔名被換成底線後撞名,後面的蓋掉前面的 | 每個檔案用不同的英文檔名,uri 也跟著改 |
| 回 503「服務重啟中」 | 有人刪了生成中的任務,該模型正在冷啟動 | 等幾分鐘;已完成的影片照樣能查、能下載,排隊中的任務會在服務回來後自動送出 |
30110 與 30120 仍可直接存取,但繞過轉發器就沒有排隊保護,兩邊同時生成會讓記憶體貼近上限且互搶 GPU。建議一律走 30100。
資料由 quant/results_pruned.jsonl、各組 log 與 mem_samples.csv 產生(build_report_data.py)。新增一組:跑 run_test.sh、在 runs_meta.json 補名稱與顏色、重新產生 data.js。「實測總結」Q3 的任務清單另由 quant_tools/build_measured.py 讀 spark-2 兩個 FP8 服務的 log 與 API,產生 measured.js(2026-09-29 補入)。第二分頁的 10 秒案例從 WebUI 送出,沒有 run_test 紀錄,資料取自 serve_spark2.log 與 mem_samples.csv(2026-09-21 補入)。