Internal Lab Note · Video Generation
MiniMax H3 影片產線實測
一天之內,把 MiniMax H3(ref2va)從「只會照抄音軌的單鏡頭對嘴工具」 摸到「能產出帶字幕的 1080P 多分鏡短片」。這份筆記記的是四組控制變因實測—— 參考圖臉部佔比、段與段的接續方式、 讓模型用你的聲線說新台詞、單次生成內的多鏡頭—— 以及一條 30 秒成品約 30 分鐘的完整產線。
先講結論
TL;DR臉的細節不是解析度給的,是構圖給的。
同樣 1.2K 畫布,遠景構圖的臉只有 170×200 px,證件照構圖有 420×540 px—— 有效像素差 6.7 倍。要靠拉解析度補回來,畫布得從 1280 拉到 3300。 換更強的模型解決不了這題,換構圖才可以。
其餘五條,先看表再決定要不要往下讀:
| 你要的 | 選這個 | 代價 |
|---|---|---|
| 台詞一字不差 (人名/日期/數字) |
TTS 精確音軌 + Use <Audio 1> exactly as it is |
每段都要先跑 TTS,長度被音檔綁死 |
| 長影片、免逐段 TTS | 參考音降級成聲線範本,台詞寫在提示詞裡 | 需要「簡體 + 字數貼合」兩個條件才穩(見結果三) |
| 兩段之間接得住 | 末幀當 anchor(chain) | 畫質單次就掉 29%,段數越多越糊 |
| 兩段之間不劣化 | 各段獨立生成,把接縫當正常剪接點 | 機位會換,不是一鏡到底 |
| 15 秒內真正的一鏡到底 | 單次生成裡用多 shot,不要用「接」的 | 單次上限 362 幀 ≈ 15.08 秒 |
| 1080P 成品 | 540P 生成 → RTX Super Res ×2 | 幾乎沒有代價,見產線一節 |
minimax_h3_ref2va_pruned_int8_convrot(19.5G)
與 minimax_h3_fl2va_pruned_int8_convrot(19.5G),
文字編碼器 qwen3vl_32b_minimax_h3_nvfp4_awq。
所有數字都是同機同日測得,跨硬體不保證可複製。
先搞清楚它能做什麼
Subjects前篇已經把模型配置與工作流講完了,但有一件事當時漏掉——而且漏得很有代表性。
我們原本是讀既有的 workflow JSON 來理解節點能力, 但 JSON 只記錄「我們接了什麼線」,沒接線的 optional 欄位根本不會出現。 於是有兩個欄位在節點裡放了很久沒被發現。改問 ComfyUI 自己之後才看到完整介面:
curl http://127.0.0.1:8188/object_info/MiniMaxH3ReferenceToVideo
| 欄位 | 型別 | 上限 | 說明 |
|---|---|---|---|
| ref_images | IMAGE | 9 | 參考圖,短邊 >2048 會降取樣、不放大 |
| ref_videos | IMAGE 幀序列 | 3 | 參考影片,24fps、2–15 秒 |
| ref_video_audios | AUDIO | 3 | 同編號參考影片的音軌 |
| ref_audios | AUDIO | 3 | 獨立參考音 |
接參考影片用 VHS_LoadVideoPath,一個節點同時輸出 IMAGE(0) 與 AUDIO(2),
剛好對上 ref_video_0 與 ref_video_audio_0,不必自己拆幀。
架構限制:能對嘴的不能硬鎖首幀,能硬鎖首幀的不能對嘴。
MiniMaxH3ImageToVideo(fl2va)有真正的 first_frame/last_frame,
但沒有 audio_vae 與 ref_audios。而 ref2va 這邊,
所謂「首幀必須與 <Picture 2> 完全一致」只是提示詞裡的一句話,不是節點層級的強制。
測試方法
Method- 單一變因。每組對照共用同一段前導影片、同一組音檔、同一個 seed、同一段台詞與場景描述,只換要測的那一項。
- 音檔重用而非重生。TTS 有隨機性,兩組各自重生會讓「畫面差異」混入「聲音差異」,直接重用同一份音檔消除它。
- 第三方 ASR 當裁判。台詞準確度一律用 QwenASR 聽寫後比對,不靠自己判斷。
- 指標算出壞消息時,先檢查指標本身。這條是被實例逼出來的,見下方 Pitfall。
結果一:臉的細節來自構圖,不是解析度
Result 1起因是把日記封面拿去當影片參考圖,臉部鋸齒嚴重。量下來是兩刀:
| 來源 | 畫布 | 臉部區域 | 佔畫面寬 | 有效像素 |
|---|---|---|---|---|
| 日記封面(遠景構圖) | 1280×714 | 170×200 | 13.3% | 34,000 |
| 證件照式頭像 | 1254×1254 | 420×540 | 33% | 226,800 |
第二刀是管線問題:封面只存了 webp(1280 寬、quality 80)給網頁用,沒有留無損母帶。 webp 的有損壓縮專門丟人眼不敏感的高頻細節,而高頻細節正是模型判斷「這張臉長什麼樣」的依據。 臉已經只有 170px 沒細節,再被壓一次。
給人看的產物,和給下一個模型吃的素材,必須分開存。
這類劣化不會報錯、不會 exit 1,只會讓輸出「看起來怪怪的」,所以能藏很久。 設計任何生成管線時先問一句:這個輸出是給人看的,還是給下一個模型吃的?
結果二:段與段怎麼接(A/B/C)
Result 2480P、同第一段、同音檔、同 seed,唯一變因是「第二段拿到什麼」:
| 做法 | 接縫貼齊度 | 段2末幀銳利度 | 相對第1段保留率 | 耗時 |
|---|---|---|---|---|
| A · 末幀當 anchor | 0.9876 | 45.7 | 70.7% | 1.00× |
| B · ref_videos 餵整段 | 0.5899 | 62.9 | 97.3% | 2.53× |
| C · 兩者並用 | 0.5870 | 60.9 | 94.2% | 2.57× |
三個結論:
- 世代累積失真是真的,一次就掉 29%。A 把「已經糊掉的末幀」當首幀依據,於是繼承了上一段的損失。五段接龍會剩 0.707⁴ ≈ 25%。
- C 失敗——兩者不能疊加。接上
ref_videos之後,anchor 圖的首幀約束完全失效。 - 因為 A 的「硬約束」根本不硬。它只是提示詞裡一句「第一格必須與 <Picture 2> 完全一致」——是拜託模型照做,有更強的訊號(整段影片)進來就被壓過去。
結果三:讓模型用你的聲線說新台詞
Result 3
模型叫 ref2va——va 是 video-audio,它從設計上就會生成聲音。
但預設用法在提示詞裡寫著 Use <Audio 1> exactly as it is — do not re-synthesize,
等於主動把語音生成能力關掉,只當複製機用。
把 <Audio 1> 從「照抄的音軌」改宣告成「聲線範本」:
<Audio 1> is a VOICE SAMPLE of <Subject 1> — it exists only to define
her vocal timbre, pitch and accent. Do NOT copy its words.
<Subject 1> speaks NEW dialogue in this shot, generated in that same voice.
參考音說的是 A、要它說的是 B,兩句內容差很遠,才驗得出是「模仿」還是「複製」。三輪收斂:
| 版本 | 與目標台詞 | 與參考音內容 | 音色 | 錯誤形狀 |
|---|---|---|---|---|
| 繁體 + 20 字 | 0.756 | 0.087 | 0.9606 | 句子中間崩壞:「巷口」→「醉咖啡間。全程克以後,」 |
| 簡體 + 20 字 | 0.884 | 0.091 | 0.9577 | 主句全對,尾巴多出「,踏實堵嘴」 |
| 簡體 + 29 字 | 1.000 | 0.087 | 0.9448 | 無 |
兩個獨立成因,各壞一段。
繁體壞句中——MiniMax 是中國模型,訓練資料以簡體為主。整段提示詞(含場景描述與 retention 欄位)轉簡體即消除。
留白壞句尾——20 字配 5.88 秒=語速 3.4 字/秒,而正常是 4.9,有近兩秒沒話講,模型自己補音。台詞字數 ≈ 秒數 × 4.9 即消除。
兩個附帶好處:長影片不必逐段 TTS、不必對齊時間軸;而且長度不再被音檔綁死—— 以前是「先 TTS → 量秒數 → 反推幀數」,現在是「寫台詞 → 字數 ÷ 4.9 → 換算幀數」, 分鏡長度可照敘事需要切。
仍然該用 TTS 的情況:台詞含人名、日期、數字、專有名詞(念錯代價高); 需要逐字對齊字幕;語氣需要反覆確認。0.968 的準確度拿來講「今天太陽好大」很夠, 拿來講客戶名字會出事。
結果四:單次生成內的多鏡頭
Result 4提示詞的 [Shot 1] 這個編號本身就是線索——它暗示可以有 Shot 2、Shot 3。語法是帶時間戳:
[Shot 1] <場景動作>
[Shot 2] At 00:03.000, <動作>
[Shot 3] At 00:05.500, <動作>
搭配兩個跨鏡頭的鎖:<Subject 2> is the environment: … 鎖場景相對位置,
Motion continuity: mandatory — … 鎖方向感。
| 鏡頭 | 提示詞指定 | 實際切在 | 誤差 |
|---|---|---|---|
| Shot 2 | 3.00s | 3.08s | 0.08s |
| Shot 3 | 5.50s | 5.67s | 0.17s |
| Shot 4 | 10.00s | 10.54s | 0.54s |
| Shot 5 | 12.50s | 13.46s | 0.96s |
精度隨進度衰減:前 6 秒誤差 <0.2 秒,後段飄到近 1 秒。 但選 shot 數的判準不是精度越高越好,是看題材——動作/氛圍主導的內容(跑酷、武俠、探險) 鏡頭密度本身就是戲劇感,塞 8–9 個 shot、飄 1 秒沒人感覺得到;台詞主導的內容才需要少一點、 並把要精準對齊的話放前 6 秒。
多 shot 的實際表現是「連續運鏡」,不是「硬切」。
用場景偵測(閾值 0.35 與 0.15)在段內測不到任何切點——一度以為多 shot 失敗, 抽幀才發現構圖確實在變,只是模型是連續運鏡過去的。 所以不要用場景偵測驗證多 shot;也因此,15 秒之內的「無縫一鏡到底」是做得到的, 前提是別用「接」的。
完整產線與成本
Pipeline一支 30 秒、1080P、帶燒錄字幕的成品,實測約 30 分鐘:
| 階段 | 做什麼 | 耗時 |
|---|---|---|
| 1 · 生成 | 960×544、3 段 × 3 shot、聲線範本模式 | 約 20 分 |
| 2 · 超解析度 | RTXVideoSuperResolution ×2 → 1920×1088(695 幀) | 55 秒 |
| 3 · 字幕 | ForcedAligner 字級對齊 + ffmpeg libass 燒錄 | 約 3 分 |
先生低解析度再拉升,比一次生到位划算得多。
H3 的生成成本是超線性的:畫布從 864×480 到 960×544 只增加 26% 面積, 時間卻多了將近 200%。而 RTX Super Res 把 695 幀從 540P 拉到 1080P 只要 55 秒。 用便宜的方式生成、用便宜的方式放大。
解析度必須是 32 的倍數。540 ÷ 32 = 16.875 過不了, 要取 544(960×544,×2 = 1920×1088)。短邊 ≤768、長邊 ≤1344。
resize_type 是動態 combo,API 要用點號展開。
傳 dict 會通過 graph 驗證但執行時報
missing 1 required positional argument。正確寫法:
"resize_type": "scale by multiplier" +
"resize_type.scale": 2.0——與 ref_images.ref_image_0 同一套慣例。
字幕的隱含前提也變了:原本的字幕流程假設「聲音是我們自己 TTS 的,所以有精確音檔」。 聲線範本模式沒有 TTS,但 ForcedAligner 真正需要的是音檔 + 文字—— 音檔從成品抽、文字就是劇本台詞,反而對齊的是實際發出的聲音。 唯一要注意的是斷句行數要跟 aligner 的分段數一致,否則會退化成比例映射。
低解析度會砍掉可用的分鏡類型
Composition這節不是模型能力,是拍出來好不好看——而這些是量測抓不到的, 所有指標合格的成品仍可能敗在這裡。
| 景別 | 可用性 | 說明 |
|---|---|---|
| 近景/特寫 | 安全 | 臉夠大,表情與嘴型撐得住 |
| 中景(腰上) | 安全 | vlog 主力景別 |
| 全身 | 看比例 | 9:16 比 16:9 好掌握 |
| 遠景正面 | 避免 | 臉小+糊,人物讀不出來 |
| 遠景背面/側面 | 可用 | 不靠臉傳達,改靠剪影與動作 |
| 遠景 → 快速拉近 | 可用 | 遠景只是過場,落點在近景 |
密閉空間不能做長距離推鏡,教室會被拉成無限長。
模型沒有空間模型,只有「畫面該怎麼延續」的直覺。人往前走、鏡頭往前推, 它就不斷生成合理的下一段畫面——它不知道這個房間有牆。 走廊、街道、小巷、河岸沒問題(那些空間本來就該無限延伸); 教室、客廳、店內、電梯則要用定點機位或小幅度運鏡。
這條的麻煩在於它不會報錯也不會被指標抓到——每一幀單獨看都合理, 只有連起來才發現那間教室有五十公尺長。
跨段道具不連貫的修法(依成本排序):寫進 <Subject 2> 並標
fully_preserved;或第一段生成後截圖丟進 ref_images 當共用參考
(9 格通常只用了 2 格);或台詞避免提到具體顏色款式。
方法論收穫
Takeaways- 認知邊界等於用過的功能邊界。
ref_videos從一開始就在節點裡, 讀了無數次 workflow JSON 卻從沒看見——因為沒接線的 optional 欄位不會出現在 JSON 裡。 要查能力就問/object_info,不要讀既有工作流。 - 分數告訴你好了多少,錯誤的樣子才告訴你為什麼。0.756 → 0.884 只看數字會結論 「簡體比較好」然後把剩下的誤差當固有損耗吞掉。是「中間崩壞消失、尾巴冒出新雜音」 這個位移,才揭露殘留誤差是另一個獨立成因。
- 被推翻的假設比被證實的假設揭露更多結構。C 組如果成功,我們會得到一個好用的組合, 然後繼續以為「A 是硬約束」。正因為它失敗,才必須解釋「為什麼壓得過」—— 而唯一說得通的解釋是:它從來就不是硬約束。提示詞裡的祈使句不是 API 契約。
- 指標算出壞消息時,先檢查指標本身。0.257 那次差點丟掉一支好片。
- 問錯問題比答錯更難察覺。我們花半天測 A/B/C 想解決「怎麼把兩段接得無縫」, 實驗設計嚴謹、數據乾淨、結論有效——但正確答案是 15 秒之內根本不需要接。
- 把時間攤平成空間,就能用平面比對去抓時間連續性。逐段檢查看不出三段不在同一個房間, 把各段關鍵幀並排成一張圖就一眼看見。多段產出交件前一律做這件事。