~/blog/minimax-h3-rtx5090-character-lock

MiniMax-H3 on RTX 5090 · part 3

[Benchmark] 1080p 不是不支援,是要跑三個半小時:H3 生《神鵰》重逢,用參考圖把楊過鎖回來

cat --toc

TL;DR

拿 H3 生一段有角色的影片,踩到三件事。一,非原生解析度不是不支援,是會掉下懸崖:864×480 要 105 秒、1280×720 要 239 秒(幾乎線性)、1920×1080 要 12,599 秒,而 shim 多半沿用 300 秒的預設逾時,所以先回了 502。二,遠景人臉必糊,放大救不了,只能把鏡頭推近。三,「鬢邊白髮」在模型眼裡是年齡不是身分,文字鎖不住角色——最後用 z-image 生參考圖走 h3-r2v,121.4 秒把人鎖回來。

封面:霧鎖深谷,兩個穿長袍的身影站在遠處,面容完全看不清;前景的石頭上攤著一卷工筆人物畫,畫中人的臉是整張圖唯一清晰的一張臉——MiniMax-H3 on RTX 5090 系列 #3。

前言

有些人你講三句話對方就知道是誰,有些人你講一整段,對方腦裡浮出來的還是別人。

這次想用 H3 生一段《神鵰》絕情谷重逢:楊過站在谷底,小龍女白衣飄過來。第一篇把它跑起來、第二篇把時間砍下去,都在回答「能不能跑」跟「多快」;這篇第一次真的拿它生一段有人、有戲的影片。

結果生出來的東西,氛圍全對,人不對——楊過是楊過他爺爺,而且臉是糊的。修了三輪才把人鎖回來。最貴的一課是:光靠提示詞,模型就算知道楊過是誰,也鎖不住他的長相。

這篇的結論

三個可以直接套用的結論:

  • 要生多大:原生解析度的效能懸崖在哪,以及為什麼該用 ffmpeg 後製而不是叫模型生大的
  • 鏡頭怎麼擺:人物戲的構圖下限是什麼,以及為什麼放大救不了糊臉
  • 角色怎麼鎖:什麼時候文字提示詞就夠、什麼時候非得給參考圖

起手:一段全景重逢,氛圍對了但人不對

H3 本身跑在 ComfyUI 裡,它雖然有 API,但不是那種一行 curl 就能直接打的介面。所以中間墊了一層 shim(轉接層):它收 OpenAI 風格的 JSON 請求,翻譯成 ComfyUI 的 workflow 送進去,再把結果撈回來。這樣寫腳本、串進其他流程都方便得多。

送進去的 request 長這樣:

{
  "model": "h3-t2v",
  "prompt": "古裝武俠電影感,幽暗的絕情谷底,斷崖與枯樹,薄霧籠罩。白髮亂鬚的楊過與白衣小龍女隔著花樹相望,風動衣袂,鏡頭緩推",
  "size": "864x480"
}

h3-t2v 就是 text-to-video——只給文字,生出影片。158 幀、6.58 秒的片,生成 105 秒。輸出回來是 1728×960——後端在出片前接了一層 2 倍放大,也就是 Part 2 講的 VSR(video super resolution,影片超解析度:用另一個模型把畫面補大,比重新生成便宜得多)。

起手版:氛圍全對,但楊過老得不像樣,而且遠景的臉是糊的

兩個問題同時出現:遠景那兩個人的臉是一團霧,而且楊過看起來六十歲。

1080p 不是不支援,是要跑三個半小時

這條管線我當初就是這樣設計的:先用一個時間與品質都可以接受的解析度生原稿,再交給 VSR 放大。Part 2 整篇在講的就是這件事。所以「生小的再放大」不是這次撞牆後想出來的變通,是前提。

但前提歸前提,不這樣做到底會怎樣?我一直沒有真的量過。這次順手試了:填 1920x1080 送出去——等了幾分鐘,502。印象中接著改填 1280x720,也是 502。(這個「也是」後來證明是我記錯的,下面會講。)

兩發不同尺寸、同一個錯誤,結論還能是什麼?shim 只認原生的 864×480,別的尺寸它不接受——這句話寫進了筆記,也差點寫進這篇文章。

它是錯的。

回頭撈後端 ComfyUI 的 /history,那幾發後端都有收到,也都跑完、寫出了檔案。沒有一發被拒絕。真正的數字是這樣:

送進去的尺寸畫素相對原生後端實際耗時時間相對原生
864×480(原生)1.0×105 秒1.0×
1280×7202.2×239 / 229 秒2.2×
1920×10805.0×12,599 秒120×

解析度懸崖:864×480 要 105 秒、720p 要 239 秒(近線性)、1080p 要 12,599 秒(120 倍)

這張表看最後一列。720p 是 2.2 倍畫素、2.2 倍時間,幾乎完全線性;1080p 是 5 倍畫素,時間卻是 120 倍——三個半小時。

懸崖就落在 720p 跟 1080p 之間。過了那條線,它不是慢一點,是掉下去。

而 502 是 shim 回的,不是後端。shim 輪詢後端結果的逾時預設是 300 秒(video_history_timeout,可用環境變數覆蓋),超過就 catch 例外回 502——但後端不會停,它會一路把那三個半小時跑完,然後把檔案安靜地放在那裡

所以更正兩件事:

  1. H3 不挑尺寸,它只是會變得非常慢。 想要什麼解析度都送得進去。
  2. 我把 720p 也記成 502,那多半是記錯了。 那兩發實際只跑 239 和 229 秒,都在 300 秒門檻內,照理應該正常回傳。唯一確定會 502 的是 1080p。 ⚠️ 這裡有個死無對證的地方:當天 shim 啟動時有沒有把逾時調小過,我翻遍腳本沒找到痕跡,傾向是預設的 300 秒——但這條沒有正面證據。

做法沒變,只是理由變了。要 1080p,用原生解析度生完再放大:

ffmpeg -i jinyong.mp4 -vf "scale=1920:1080:flags=lanczos" jinyong_1080p.mp4

原本的設計是對的,只是現在它有數字撐著:先生原稿再放大,不是因為模型不接受大尺寸,是因為叫它直接生一段 1080p 影片要三個半小時,而放大只要幾秒。抓法大致就是用目標尺寸的一半去生,再放大回來。(後端的 VSR 已經先做過一次 2 倍放大,下面那條 ffmpeg 只是把 1728×960 的成品補到剛好的 1920×1080。)

但這條路有前提,而下一節就是它失效的地方。VSR 確實會補出細節——Part 2 講過,那些放大後才出現的紋理是它生的,不是原稿裡本來就有的。它補得出看起來合理的質感,補不回原稿沒有解析出來的正確資訊

真正的分界線不在題材,而在目標資訊在原稿裡有沒有留下足夠的像素。谷底的霧、衣袂的擺動、崖壁的紋理,原稿都有輪廓,放大只是把它們變銳利;但遠景裡那張臉只佔幾十個像素,五官的位置根本沒被解出來,VSR 補出來的會是一張「看起來像臉的東西」,不是那個人的臉。

遠景的臉救不回來,只能把鏡頭推近

第二個問題單純得多,但也更硬。

864×480 的資訊量,分給一張站在谷底的臉,像素就是不夠。我原本以為輸出端那層 2 倍放大能補回來——不能。放大只是把糊的東西放大,原始資訊沒有憑空出現。

解法是換構圖,不是換參數。我把整段改成全近景:楊過特寫、小龍女特寫、相視雙人特寫。生成 98.5 秒,臉不糊了。

貼臉版:全部近景,臉清楚了,但楊過還是楊過他爺爺

所以在這個解析度拍人物戲,鏡頭最遠就只能擺到這裡:要看得清臉,就得推近。要遠景大場面配清楚的人臉,得等原生解析度更高的版本,或者接受它糊。

「鬢邊白髮」把楊過寫老了:描述詞會蓋過身分

臉清楚了,但人還是不對。楊過看起來仍然六十歲。

我當時的想法是:「鬢邊白髮、一身粗布」是楊過的一部分——原著裡他就是這造型,寫進提示詞應該是在指認這個角色。

模型讀到的完全是另一回事。在它眼裡,「白髮」「粗布」「滄桑」只是年齡和外型的描述,不會因此知道這個人就是楊過。所以它老老實實生了一個白髮、穿粗布、看起來很滄桑的人——一個老人,不是楊過。

反過來看才想通:模型不是不知道楊過是誰,是光靠文字提示詞,它抓不到任何能固定長相的特徵。 你講的每個形容詞它都會照做,而形容詞加起來不等於一個人。

用 z-image 生參考圖,把臉當錨點餵進去

既然文字鎖不住,就給它看臉。

先用 z-image 生兩張靜態參考圖,一張楊過一張小龍女。z-image 生靜態臉很穩——它不用管動態、不用管鏡頭,只要把一張臉畫清楚,這正好補上 H3 不擅長生靜態人臉的地方:

{
  "model": "z-image-hq",
  "prompt": "《神鵰》楊過,40歲,鬢邊幾縷白髮,劍眉,眼神滄桑,粗布衣衫,正面半身",
  "size": "1024x1024"
}

楊過參考圖

小龍女參考圖

然後從 h3-t2v 改走 h3-r2v——reference-to-video,差別就是它多吃一組參考圖,生成時會拿那些圖當視覺依據。兩張臉用 images 陣列帶進去:

{
  "model": "h3-r2v",
  "prompt": "古裝武俠愛情重逢,絕情谷底薄霧幽暗,楊過與小龍女隔著花樹相望,風動衣袂,鏡頭緩推,近景",
  "size": "864x480",
  "images": [
    { "url": "file:///tmp/yangguo_ref.png", "role": "reference" },
    { "url": "file:///tmp/xiaolongnv_ref.png", "role": "reference" }
  ]
}

生成 121.4 秒。楊過終於是楊過。

最終版:帶參考圖走 h3-r2v,身分鎖住了

分工變得很清楚:靜態的臉交給 z-image,動態的戲交給 H3。兩邊各做自己擅長的事。

總結這三個坑

踩到的坑我原本以為實際上
尺寸shim 不支援非原生解析度支援,但 1080p 要跑 120 倍時間,shim 300 秒就逾時
糊臉輸出端放大可以補補不了,原始像素不夠,只能推近鏡頭
角色寫清楚外型就等於指認角色模型把外型讀成屬性,身分要靠參考圖

三個都是同一種錯:我把看到的症狀當成了原因。 502 看起來像「不支援」,其實是逾時;臉糊看起來像「解析度不夠」,那是對的但解法在構圖不在放大;人不對看起來像「描述不夠精確」,實際上再精確的描述也鎖不住身分。


進階:完整實驗參數與後端紀錄

不讀這節也不影響操作;照前面的做法跑,就能避開這幾個坑。這節是給想重現、或想接著往下調的人。

六發生成的完整取樣參數

所有六發用同一組取樣設定,從後端 /historyKSamplerSelect / BasicScheduler / RandomNoise 節點讀出來:

參數
samplerres_multistep
schedulersimple
steps14
denoise1.0
noise_seed42
blend_weight0.5
degree4
ridge_lambda0.1
window_size2.0
flex_window0.75
warmup_steps5
tail_actual_steps1
max_history8

cfg 查不到——它在 BasicGuider 裡是連結型輸入,後端不存數值。

幀數全部 158 幀 = 6.58 秒,換算 24 fps。

六發的對照表

用途尺寸耗時權重參考圖
起手全景864×480105 秒fl2va_pruned_nvfp4
1080p 嘗試1920×108012,599 秒fl2va_pruned_nvfp4
720p 嘗試 ×21280×720239 / 229 秒fl2va_pruned_nvfp4
貼臉近景864×48098.5 秒fl2va_pruned_nvfp4
最終 r2v864×480121.4 秒ref2va_pruned_nvfp42 張

⚠️ r2v 慢的那 16 秒,我不敢說是參考圖的代價

最終版比起手版慢了 16 秒(105 → 121.4),很容易解釋成「參考圖進 workflow 有成本」。但看最後一欄,還有另一種可能:r2v 用的是不同的權重檔(ref2va vs fl2va),而這兩條路線的文字編碼器也不同,交錯呼叫會逼系統卸載重載十幾 GB。

也就是說那 16 秒裡有多少是參考圖、有多少是換模型,我沒有拆開量過。要證明是前者,得在同一個模型已經載入的狀態下連跑兩發才算數。這篇不下這個結論。

幾個查不到的東西(誠實記錄)

  • cfg:後端不存,如上
  • 輸出檔名:/history 只存 prompt 定義,不存產出檔名
  • 輸出解析度:/history 只記錄輸入的 864×480,那層 2 倍放大是後端 pipeline 做的,沒有留下輸出尺寸紀錄
  • shim 當天的逾時設定:翻遍啟動腳本沒找到覆蓋 COMFYUI_VIDEO_HISTORY_TIMEOUT 的痕跡,推定是預設 300 秒,但這是推定不是證據

一個待查的矛盾

我先前的筆記記著 h3-r2v 走 20 步,但這次後端撈出來六發全部是 14 步。可能是筆記過時,也可能是 shim 改過設定。還沒查清楚,先記在這裡。

相關工具

常見問題

MiniMax-H3 可以生 1080p 嗎?
可以,但代價高到不實用。同一段 158 幀的內容,原生 864×480 跑 105 秒,1280×720 跑 239 秒(畫素多 2.2 倍、時間多 2.2 倍,幾乎線性),但 1920×1080 跑了 12,599 秒,也就是三個半小時。畫素只多 5 倍,時間多了 120 倍。實務上要 1080p 請用原生解析度生完再拿 ffmpeg 放大。
生出來的人臉很糊怎麼辦?
把鏡頭推近。864×480 的原生解析度分給遠景裡的一張臉,像素根本不夠,而這不是事後放大能救的——放大只會把糊的東西放大。人物戲一律用近景構圖。
為什麼在提示詞裡描述角色外型,生出來卻不像那個角色?
因為模型把外型描述讀成屬性,不是身分。我寫「鬢邊白髮、一身粗布」想指認楊過,模型讀到的是「一個白髮、穿粗布的老人」。要鎖身分,文字不夠,得給參考圖走 h3-r2v。

接著讀

不想錯過新文章?

訂閱我確保不漏接!

隨時一鍵退訂。