Commit 83626817ea535fd039311c3f6a03fac4c00e92b9

Authored by yibo
1 parent 03001df7

minimax-h3 api.py: 加 cfg_scale/negative_prompt 入口,quality-tuning-plan 补实测记录

pipeline 本身支持 cfg_scale/negative_prompt,之前一直裸跑默认值没传。同时补上
2026-08-21 分辨率/Turbo 对比的实测结论:原生1344×768肉眼优于832×480,但ref2va场景下
Turbo开/4步反而比关Turbo跑20步更好(跟纯T2V的旧结论相反,说明这条要按分区分别测)。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
docs/todo/quality-tuning-plan.md
@@ -10,9 +10,16 @@ H3 原生分辨率是 1344×768(短边 768px)。我们线上默认 **832×48 @@ -10,9 +10,16 @@ H3 原生分辨率是 1344×768(短边 768px)。我们线上默认 **832×48
10 真实上é™è¢« `api.py` çš„ `ROWS_LIMIT=20000`ï¼ˆå¸§æ•°Ã—å®½Ã—é«˜çš„æ˜¾å­˜å®‰å…¨çº¿ï¼‰å¡æ­»â€”—这是 Turing æ˜¾å¡ 10 真实上é™è¢« `api.py` çš„ `ROWS_LIMIT=20000`ï¼ˆå¸§æ•°Ã—å®½Ã—é«˜çš„æ˜¾å­˜å®‰å…¨çº¿ï¼‰å¡æ­»â€”—这是 Turing 显å¡
11 fp32-only(无高效 bf16/fp16 attentionï¼‰å¯¼è‡´çš„æ˜¾å­˜ä»£ä»·ï¼Œä¸æ˜¯éšæ‰‹è®¾çš„å‚æ•°ã€‚ 11 fp32-only(无高效 bf16/fp16 attentionï¼‰å¯¼è‡´çš„æ˜¾å­˜ä»£ä»·ï¼Œä¸æ˜¯éšæ‰‹è®¾çš„å‚æ•°ã€‚
12 12
13 -**è¦åšçš„实测**:在æœåŠ¡å™¨ä¸Šç›´æŽ¥è·‘ä¸€æ¬¡æŽ¥è¿‘åŽŸç”Ÿçš„åˆ†è¾¨çŽ‡ï¼ˆæ¯”å¦‚ 1344×768,短时长/低帧数控制  
14 -rows ä¸è¶…é™ï¼‰ï¼Œè·ŸçŽ°åœ¨çš„ 832×480 é»˜è®¤æ¡£åŒ prompt/seed å¯¹æ¯”ï¼Œçœ‹ç”»è´¨å·®è·æœ‰å¤šå¤§ã€æ˜¾å­˜/耗时代价  
15 -多大。`ROWS_LIMIT` æ”¯æŒ `H3_ROWS_LIMIT` 环境å˜é‡ä¸´æ—¶è¦†ç›–,ä¸ç”¨æ”¹ä»£ç å°±èƒ½æµ‹ã€‚ 13 +**2026-08-21 已实测**:ref2va åˆ†åŒºï¼ŒåŒ prompt/seed=42,`0f22388f7847`(1344×768×64帧,
  14 +峰值显存 15.49GB)vs `06bb43196c46`(832×480×124帧,峰值显存 11.47GBï¼Œå…¶ä½™å‚æ•°ç›¸åŒï¼‰â€”—
  15 +**原生分辨率肉眼明显更好**ã€‚ä½†ä¸æ˜¯æ²¡é—®é¢˜ï¼šä¸‰æ¡å¯¹æ¯”测试(å«ä¸‹é¢ç¬¬ 2 项那æ¡ï¼‰è‚‰çœ¼çœ‹**都还有
  16 +ç‘•ç–µ**â€”â€”ç”»é¢æ¨¡ç³Š/细节糊ã€è¿é•œæˆ–动作的抖动/æ‹–å½±ã€äººç‰©äº”官å˜å½¢ï¼ŒåŽŸç”Ÿåˆ†è¾¨çŽ‡åªæ˜¯ç›¸å¯¹æœ€å¥½ã€‚
  17 +判断是å£å¤´ç›®æµ‹ï¼Œæ²¡æœ‰åšå®¢è§‚指标也没有é€å¸§æˆªå›¾å®šä½å…·ä½“哪几秒出问题。详è§
  18 +`CHANGELOG.md` 2026-08-21(下åˆï¼‰ä¸€èŠ‚ã€‚
  19 +
  20 +**还没åšçš„**:默认分辨率之外的中间档(比如 1024×576)没试过;原生分辨率因为
  21 +`ROWS_LIMIT` åªèƒ½åŽ‹åˆ° 64 帧(2.7秒),跟 832×480 能跑到 124 帧(5.2ç§’ï¼‰ä¸æ˜¯ç­‰æ—¶é•¿å¯¹æ¯”,
  22 +时长本身对观感的影å“还没拆开看。
16 23
17 ## 2. Turbo 4 æ­¥ vs 关闭 Turbo è·‘ 20+ 步——现æˆçš„开关,从没系统测过 24 ## 2. Turbo 4 æ­¥ vs 关闭 Turbo è·‘ 20+ 步——现æˆçš„开关,从没系统测过
18 25
@@ -20,9 +27,12 @@ rows ä¸è¶…é™ï¼‰ï¼Œè·ŸçŽ°åœ¨çš„ 832×480 é»˜è®¤æ¡£åŒ prompt/seed 对比,看ç @@ -20,9 +27,12 @@ rows ä¸è¶…é™ï¼‰ï¼Œè·ŸçŽ°åœ¨çš„ 832×480 é»˜è®¤æ¡£åŒ prompt/seed 对比,看ç
20 (`fl2va`/`ref2va` å„一个)。ä¸ç”¨æ¢æ–‡ä»¶å°±èƒ½éªŒè¯çš„路径:console 早就支æŒå…³æŽ‰ Turboã€è·‘ 20/50 27 (`fl2va`/`ref2va` å„一个)。ä¸ç”¨æ¢æ–‡ä»¶å°±èƒ½éªŒè¯çš„路径:console 早就支æŒå…³æŽ‰ Turboã€è·‘ 20/50
21 步全精度(`turbo=false`),但**默认值是"Turbo 开/4步"**(为了速度),从没系统对比过画质。 28 步全精度(`turbo=false`),但**默认值是"Turbo 开/4步"**(为了速度),从没系统对比过画质。
22 29
23 -**è¦åšçš„实测**ï¼šåŒ prompt/seed,Turbo å¼€(4æ­¥) vs å…³(20æ­¥) å„跑一æ¡ï¼Œå¯¹æ¯”帧间差异/音频å“度/  
24 -肉眼观感。之å‰åœ¨çº¯æ–‡ç”Ÿè§†é¢‘上测过一次类似的(结论是步数越多帧间差异越å°ã€éŸ³è´¨è¶Šå¥½ï¼Œè§  
25 -`CHANGELOG.md` 「15 秒时长实测ã€ä¸€èŠ‚ï¼‰ï¼Œä½†æ²¡æœ‰åœ¨çŽ°åœ¨çš„é»˜è®¤åˆ†è¾¨çŽ‡/R2V åœºæ™¯ä¸‹é‡æ–°éªŒè¯è¿‡ã€‚ 30 +**2026-08-21 已实测(结论跟之å‰çš„纯 T2V 结论相å)**:ref2va åˆ†åŒºï¼ŒåŒ 832×480×124帧/
  31 +prompt/seed=42,`06bb43196c46`(Turboå¼€/4步,峰值显存 11.47GB)vs `807e042dce0d`
  32 +(Turboå…³/20步,峰值显存 9.56GB)——**Turboå¼€/4步肉眼å而更好**。之å‰åœ¨çº¯æ–‡ç”Ÿè§†é¢‘上测过
  33 +一次类似的(结论是步数越多帧间差异越å°ã€éŸ³è´¨è¶Šå¥½ï¼Œè§ `CHANGELOG.md` 「15 秒时长实测ã€
  34 +一节)这次在 ref2va 场景下**没有å¤çް**,说明这æ¡ä¸æ˜¯é€šç”¨ç»“论,是分区相关的(T2V vs
  35 +ref2va,或者还有别的没控制ä½çš„å˜é‡ï¼‰ï¼Œ**æ¯ä¸ªåˆ†åŒºè¦åˆ†åˆ«æµ‹ï¼Œä¸èƒ½åªæµ‹ä¸€æ¬¡å°±å®šæ¡£**。
26 36
27 ## 3. CFG scale / negative prompt——入å£å·²ç»åŠ ä¸Šäº†ï¼Œè¿˜æ²¡åšè¿‡ A/B 37 ## 3. CFG scale / negative prompt——入å£å·²ç»åŠ ä¸Šäº†ï¼Œè¿˜æ²¡åšè¿‡ A/B
28 38
@@ -49,8 +59,15 @@ pipeline æœ¬èº«æ”¯æŒ `cfg_scale`(默认 1.0,等于没有 CFG 引导)和 ` @@ -49,8 +59,15 @@ pipeline æœ¬èº«æ”¯æŒ `cfg_scale`(默认 1.0,等于没有 CFG 引导)和 `
49 å¯¹åº”çš„æ¨¡åž‹æ–‡ä»¶ï¼Œä¸æ˜¯æ”¹ä¸ªå‚数就行**,工作é‡å’Œç½‘络下载时间都è¦å•独评估(æœåŠ¡å™¨å‡ºå£å¸¦å®½çº¦ 59 å¯¹åº”çš„æ¨¡åž‹æ–‡ä»¶ï¼Œä¸æ˜¯æ”¹ä¸ªå‚数就行**,工作é‡å’Œç½‘络下载时间都è¦å•独评估(æœåŠ¡å™¨å‡ºå£å¸¦å®½çº¦
50 5.9MB/s,è§é¡¶å±‚ `CLAUDE.md`「硬件的三æ¡ç¡¬é™åˆ¶ã€ï¼‰ã€‚ 60 5.9MB/s,è§é¡¶å±‚ `CLAUDE.md`「硬件的三æ¡ç¡¬é™åˆ¶ã€ï¼‰ã€‚
51 61
  62 +**2026-08-21 æ›´æ–°**ï¼šè¿™ä¸€é¡¹çš„å‰æè¢«ç¬¬ 2 项的实测推翻了——ref2va 场景下 Turboå¼€/4步肉眼
  63 +å而比关闭 Turbo è·‘ 20 æ­¥æ›´å¥½ï¼Œä¸”æ›´å¿«ã€æ˜¾å­˜æ›´çœã€‚**没有ç†ç”±å†ä¸ºäº†"画质æ¢é€Ÿåº¦"去下载 8 æ­¥
  64 +LoRA**,除éžä»¥åŽæµ‹åˆ«çš„分区/场景å‘现关 Turbo 明显更好,æ‰é‡æ–°è¯„估。暂时æç½®ã€‚
  65 +
52 ## å»ºè®®çš„å®žæµ‹é¡ºåº 66 ## 建议的实测顺åº
53 67
54 -1 å’Œ 2 ä¸éœ€è¦ä¸‹è½½ä»»ä½•新文件ã€ä¸éœ€è¦æ”¹ä»£ç ï¼Œæœ€å¿«èƒ½å‡ºç»“果,优先åšã€‚3 的入å£å·²ç»åŠ ä¸Šäº†  
55 -(è§ä¸Šé¢ï¼‰ï¼Œç›´æŽ¥åœ¨ console é‡Œå¡«å‚æ•°æµ‹å°±è¡Œã€‚4 需è¦å°æ”¹ `api.py` 把 `audio_flow_shift` 串上  
56 -(目å‰è¿˜æ²¡æœ‰å…¥å£ï¼‰ã€‚5 最åŽå†çœ‹è¦ä¸è¦æŠ•入。 68 +**2026-08-21 æ›´æ–°**:1ã€2 两项已在 ref2va 分区跑过一轮实测(结论è§ä¸Šé¢å¯¹åº”å°èŠ‚ï¼‰ï¼Œä½†ä¸‰æ¡
  69 +æµ‹è¯•è‚‰çœ¼çœ‹éƒ½è¿˜æœ‰ç‘•ç–µï¼ˆæ¨¡ç³Šã€æŠ–åŠ¨/æ‹–å½±ã€äº”官å˜å½¢ï¼‰ï¼Œè¯´æ˜Žå…‰è°ƒåˆ†è¾¨çއ/Turbo ä¸å¤Ÿï¼Œ**接下æ¥
  70 +åº”è¯¥åš 3**(cfg_scale/negative_prompt,入å£å·²ç»åŠ ä¸Šï¼Œç›´æŽ¥åœ¨ console 填傿•°æµ‹ï¼Œçœ‹èƒ½ä¸èƒ½
  71 +压ä½è¿™äº›ç‘•疵)。4 需è¦å°æ”¹ `api.py` 把 `audio_flow_shift` 串上(目å‰è¿˜æ²¡æœ‰å…¥å£ï¼‰ã€‚5 å·²ç»
  72 +æç½®ï¼ˆè§ä¸Šé¢ï¼‰ã€‚å¦å¤– 1ã€2 的实测目å‰åªåœ¨ ref2va 一个分区åšè¿‡ï¼Œfl2va/纯 T2V 是å¦åŒæ ·ç»“论
  73 +还没验è¯ï¼Œä¹Ÿæ²¡æœ‰æ‹†å¼€çœ‹æ˜¯"分辨率"还是"帧数/æ—¶é•¿"在起作用。
minimax-h3/api.py
@@ -67,6 +67,11 @@ class GenReq(BaseModel): @@ -67,6 +67,11 @@ class GenReq(BaseModel):
67 # 短边 480 时约 390 行,而目标视频本身才 14430 行。 67 # 短边 480 时约 390 行,而目标视频本身才 14430 行。
68 reference_image_urls: list[str] = [] 68 reference_image_urls: list[str] = []
69 ref_image_short_edge: int = Field(480, ge=64, le=2048) 69 ref_image_short_edge: int = Field(480, ge=64, le=2048)
  70 + # CFG 引导强度 / 负面提示词。pipeline 自己默认 cfg_scale=1.0(约等于不引导)、
  71 + # negative_prompt="",我们的代码之前从没传过,一直裸跑默认值。Optional,留空=不覆盖,
  72 + # 跟以前行为一样;蒸馏 LoRA(turbo)模型引导太强有时反而出伪影,调高前留意这点。
  73 + cfg_scale: Optional[float] = Field(None, ge=0)
  74 + negative_prompt: Optional[str] = Field(None, max_length=2000)
70 75
71 @model_validator(mode="after") 76 @model_validator(mode="after")
72 def _check_rows(self): 77 def _check_rows(self):
@@ -226,9 +231,12 @@ def worker(): @@ -226,9 +231,12 @@ def worker():
226 if not j.req.turbo: 231 if not j.req.turbo:
227 pipe.clear_lora() 232 pipe.clear_lora()
228 keyframes, keyframe_indices = _keyframes(j.req) 233 keyframes, keyframe_indices = _keyframes(j.req)
229 - video, audio = pipe(prompt=j.req.prompt, height=j.req.height, width=j.req.width, 234 + cfg_scale = j.req.cfg_scale if j.req.cfg_scale is not None else 1.0
  235 + negative_prompt = j.req.negative_prompt if j.req.negative_prompt is not None else ""
  236 + video, audio = pipe(prompt=j.req.prompt, negative_prompt=negative_prompt,
  237 + height=j.req.height, width=j.req.width,
230 num_frames=j.req.frames, num_inference_steps=j.req.steps, 238 num_frames=j.req.frames, num_inference_steps=j.req.steps,
231 - seed=j.req.seed, flow_shift=fs, 239 + seed=j.req.seed, flow_shift=fs, cfg_scale=cfg_scale,
232 keyframes=keyframes, keyframe_indices=keyframe_indices, 240 keyframes=keyframes, keyframe_indices=keyframe_indices,
233 references=_references(j.req), 241 references=_references(j.req),
234 ref_image_short_edge=j.req.ref_image_short_edge) 242 ref_image_short_edge=j.req.ref_image_short_edge)