Repository navigation
proposal: 建立生图与视频模型的选型判据与实验规程 #465
Description
背景
Windup 的 2D 生成链路是:文生图出母版 → i2v 出一段视频 → 抽帧 → 抠图 → 脚线对齐 → 打包。这条链路上游是模型,下游全部是补救。母版与动作帧的质量上限由模型对该动作的理解决定,后处理只能修边角。
当前的模型选择是历史沿用而非测量结果:生图默认 gpt-image-2、兜底 gemini-3.1-flash-image-preview(08-25 起,PR #638;本提案发起时是 gemini-2.5-flash-image),视频固定 kling-v2-5-turbo,时长在 ai_engine/strategy/concrete.py 硬编码为 5 秒。既有的质量判断分散在若干次单点实验里,彼此分母不同、不可复现,也无法预测下一个动作会怎么失败。
同时,主仓已经积累了一批可用的量化能力:成色落库(#322)、可数四问判官(#324)、站位偏离检测(#396)、尺度漂移补偿(#308)、抠图两模型并集(#403)。这些读数目前只服务于单个 PR 的验收,没有被组织成一套可复用的选型判据。
问题
- 判据不成体系。可算的读数只有若干条,其余靠人工目测,结论不可复现、换人换天会变。
- 缺少主排名指标。没有一个能把质量与成本合并的口径,导致「便宜」与「好用」无法比较。
- 候选集受限于已接入的端点。
/v1/videos只服务可灵,其余厂商在 FAL 队列面且 provider 已移除,直接横评会把「没接入」误判为「不值得选」。 - 时长口径未经验证。一次性动作(attack)在 5 秒内会出现后段冗余,可能触发出画与漂移判据,把动作设计问题记到模型头上。
方案
建立一套模型选型判据与实验规程,产出两张表:生图的「模型 × 画风」适配矩阵,和视频的模型排名。
判据分层
- 硬闸口(纯算法,决定单帧废否):出画、死帧、多主体、站位漂移、尺度漂移、首帧偏移、时长与帧率履约。
- clip 级闸口(决定该段能否交付):动作语义正确、循环接缝、步态相位、最小动量。
- 连续读数(纯算法):分区动量、模糊度、帧间闪烁、身份一致度、角色像素高度、画风保真。
- 语义题(判官):动作语义、凭空多物、画风相似、刚体守恒。
- 运营指标:调用失败率、审核拒绝率、出片延迟、同输入方差。
主排名指标:单位成本可交付的动作序列数。主分析按 intention-to-treat 计,失败、审核拒绝与超时计入成本且记零产出;仅在成功样本上配对比较会产生幸存者偏差。
判官规程:只问可数的封闭问题;先以人工黄金集标定并公布判官与人的一致率,未标定的判官读数不入账;人与判官均只做配对比较,不做绝对打分。人工投入集中在标定一次与事后抽检,不参与每轮评测。
分期
- 仪器标定:用既有归档素材在盲验证集上冻结阈值,逐条给出 precision/recall 与人工复核的错例;估计方差并给出最小可检测效应。不产生调用成本。
- 时长探针:同模型同输入比较两档时长的可交付率与单价。
- 生图画风矩阵。
- 视频横评:候选限定为
/v1/videos可达的可灵系,母版取自第 3 步产物,两期串联而非割裂。 - FAL 队列面哨兵样本,用于判断是否值得重建该 provider。
不包含
- 不改动生产链路的默认模型与默认时长。本 Issue 只产出判据与结论,切换默认值另立 Issue。
- 不重建 FAL 队列面 provider,只跑哨兵样本。
- 不评价动作节奏。视频输出匀速,节奏由抽帧与引擎每帧时长决定,不属于模型能力。
- 不覆盖三渲二路线。该路线多朝向为本地渲染,不参与按次计费的模型横评。
验收
- 判据清单落地为可执行的度量代码,每条硬闸口在盲验证集上有 precision/recall。
- 判官与人工标注的一致率被测量并公布。
- 产出生图「模型 × 画风」矩阵,每格给出通过率与置信区间。
- 产出视频模型排名,按主排名指标给出,并显式标注结论适用范围。
- 时长口径有实测依据,而非沿用默认值。
- 全部实验可由归档脚本从原始输入重跑出同一组读数。
进度(2026-08-23 更新)
| 分期 | 状态 | 产物 |
|---|---|---|
| 1 仪器标定 | 进行中,此前卡住 | 见下「分期 1」 |
| 2 时长探针 | 已跑,结论可用 | 见下「分期 2」 |
| 3 生图画风矩阵 | 完成 | phase1b(n=20)+ 画风分档 |
| 4 视频横评 | 已跑一轮 | 见下「分期 4」 |
| 5 FAL 队列哨兵 | 已跑 | 见下「分期 5」 |
分期 2:时长探针
原设计是「同模型同输入比较两档时长的可交付率与单价」。实跑改用尺度漂移当主判据 —— 可交付率在这几档上全是 100%,分不开;而漂移是用户能直接看到的「忽大忽小」。
同一张首帧、同一条提示词,测主体高占画面高相对首帧的最大增幅:
| 模型 | 时长 | 尺度漂移 |
|---|---|---|
| veo 3.1 | 4s | +7% |
| veo 3.1 | 8s | +21% |
| kling-3.0-turbo | 3s | +2% |
| kling-v2-5-turbo | 5s | +6% |
结论:漂移随时长单调上升。 所以时长是质量参数不只是成本参数 —— 简单循环动作(走路、待机、飞行)取短,复杂一次性动作(攻击、跳跃)才加长。当前 i2v(..., seconds=5) 写死。
时长下限按型号不同:v2-5-turbo / v2-6 最短 5s;o1 / v3 std / 3.0-turbo 支持 3s。3s@24fps = 73 帧,抽 32 帧仍够,但这条要有断言而不是靠巧合。
分期 4:视频横评
原设计限定「/v1/videos 可达的可灵系」。实跑扩到了队列面,因为人工判定最好的型号只在那一面。
同一张首帧(#511 修复后产出:中灰底、主体占幅 42.5%)、同一条产品提示词(用 VideoFrameStrategy._build_prompt 组装,非手抄):
| 模型 | 时长 | 尺度漂移 | 人工判定 |
|---|---|---|---|
| seedance-2.0 | 5s | +0% | 第二好 |
| kling-3.0-turbo | 3s | +2% | 最好 |
| kling-v3 std | 3s | +3% | 把「飞」做成了走路 |
| kling-v2-5-turbo(现役) | 5s | +6% | 一般 |
| veo 3.1 | 4s | +7% | 强,但约 3 倍价 |
| veo 3.1 | 8s | +21% | 时长越长越放飞 |
| kling-v2-6 | 5s | +27% | 出杂物 |
| vidu q1 | 5s | +0% | 1080p、重构了画面,口径不同不可直比 |
适用范围(按验收 4 必须显式标注):n=1、单角色(一只鸟)、单动作(custom「飞」)、单一首帧。这不是模型排名,是一次同条件对照;要成排名需重复次数与多角色多动作,尚未做。
前置条件:首帧主体占幅是决定性的。#511 之前只有 16.2%,模型会自己推镜并重构角色(鸟变成了另一种生物)。所以横评必须在首帧修复之后做,之前的结论不可用。
分期 4:按动作 × 角色铺开之后的第一条硬结论
原先那一轮是 n=1、单角色、单动作,正文里已标注「不是模型排名」。08-24 按 4 角色 × 3 动作 ×
3 模型 × 2 重复重跑(同一套首帧预处理、提示词由 VideoFrameStrategy._build_prompt 生成并存档),
得到一条单动作那轮结构上碰不到的结论:
kling-3.0-turbo 在待机动作上会推镜。
| 模型 | idle 主体放大中位 | 放大 >30% 的条数 | walk | attack |
|---|---|---|---|---|
| kling-3.0-turbo | 23.4% | 4/8 | 1.2% | 0.0% |
| kling-v2-5-turbo(现役) | 3.0% | 0/8 | 1.7% | 0.0% |
| seedance-2.0 | 1.9% | 0/8 | 3.0% | 0.0% |
读数是主体高占画面高相对首帧的最大放大倍率。最差一条(walker idle)轨迹为
0.626 → 1.000,角色涨满整幅画面;wolf idle 两次分别 +58.9% 与 +47.4%,knight idle +38.8%。
只在 idle 上出现,走路与攻击两个动作三个模型都干净。
机制上讲得通:待机要求原地站立,主体几乎没有可动的部分,模型转而移动镜头。
据此,把生产默认视频模型换成 kling-3.0-turbo 这件事应当暂缓 —— 待机是最常用的动作之一,
按这个比例约一半的待机产出会被重构图。要换主力需先解决这条,或对待机单独走别的型号。
一条判据形态上的更正
同一 payload 重复 6 次测得尺度漂移的变异系数是 50.8%,据此曾判「尺度漂移排不出模型名次」。
那个结论只对「按中位数比较几个百分点」成立。40~60% 的重构图是另一个量级,改用计数判据
(放大 >30% 的条数)就分得很开:4/8 对 0/8 对 0/8。判据形态要跟着效应量走,把
「某个量在某个效应量下排不出」读成「这个量没用」会把真信号一起丢掉。
时长档位:1080p 不改善模糊
同首帧、同提示词、同动作,只差 std(1280×720) 与 pro(1920×1080) 两档,配对 8 组:
羽化边合池 0.777±0.425 → 0.719±0.400,按阈值判「糊」的比例两档都是 25%,差值仅为标准差的 14%。
产物分辨率与码率已核(pro 确为 1920×1080、码率高 40~56%),故测试有效。
交付要降到项目 sprite 画布,源端多出的分辨率在降采样一步被丢弃,升档位不是模糊这条的解法。
分期 5:FAL 队列面哨兵
零成本探活 14 个图生视频端点(空 body POST,400=端点在且鉴权过、404=无此路由;无鉴权对照 401 证明不是网关乱回),全部 400:
fal-ai/veo3.1/image-to-video、fal-ai/veo3.1/fast/image-to-videofal-ai/kling-video/o1/image-to-videofal-ai/vidu/q1|q2|q3/image-to-videobytedance/seedance-2.0/{,fast/,mini/}image-to-video、bytedance/seedance-2.5/image-to-videobyteplus/下同样四条
结论:值得重建该 provider —— 不只是补能力,而是人工判定最好的型号 kling-3.0-turbo 只存在于这一面,/v1/videos 的 model 枚举里没有它。设计与实现见 #332。
三条实测的接口事实:路径必须带 queue/ 前缀(少了全部 404);vidu 的 i2v 只支持 viduq1 / q2-pro / q2-turbo / q3-pro / q3-turbo,裸 q2/q3 报 model not found;duration 字段类型不统一(seedance 与 kling-v3 是字符串,vidu 是整数)。
分期 1:已产出第一份 precision/recall(验收 1 可打勾)
用生产语料当盲验证集:43 条 ≥8 帧序列全部人工分型标注(可多选:抠穿 / 边缘 / 糊·画风变 / 变形·身份变 / 抖动·漂移 / 没问题),1 条跳过。类型计数:边缘 23、抠穿 17、糊 17、抖动 13、变形 6、完全没问题 3。
| 判据 | 目标 | precision | recall | F1 |
|---|---|---|---|---|
净抠穿 punch_max > 0.02 |
抠穿 | 0.88 [0.66,0.97] | 0.88 [0.66,0.97] | 0.88 |
净抠穿 > 0(旧规矩) |
抠穿 | 0.47 [0.32,0.63] | 1.00 [0.82,1.00] | 0.64 |
|暗边比-1| > 0.15(不可入账) |
边缘 | 0.62 [0.43,0.78] | 0.70 [0.49,0.84] | 0.66 |
暗边比 < 0.85(只抓暗侧) |
边缘 | 0.40 | 0.17 | 0.24 |
配色漂移 > 0.30 |
糊 | 0.20 | 0.12 | 0.15 |
四条结论,其中两条推翻了既有做法:
-
净抠穿的阈值应是 0.02 而不是 0。 「判据是
>0不是幅度阈值」这条规矩来自出画指标,套到净抠穿上是过度泛化 —— 按>0判,precision 只有 0.47(19 个误报,多数其实是边缘或抖动问题);按>0.02判,F1 由 0.64 提到 0.88。 -
边缘这一类目前没有可入账的判据,F1 会骗人。 边缘的正例占 23/42,对每条序列都说「有边缘问题」这个平凡预测器的 F1 就是 0.708(precision 0.548、recall 1.0)。
|暗边比-1| > 0.15的 F1 只有 0.653,低于平凡基线;它的 AUC 也只有 0.581±0.09,排序能力接近随机。一条判据必须先赢过平凡预测器才谈得上可用。按这条重看本表:净抠穿
>0.02的 0.882 与羽化边的 0.703 都高于各自的平凡基线 0.576(正例 17/42),成立;暗边那两条都不成立。边缘问题以白边为主这个观察仍然有效(只抓「比内部暗」那一侧 recall 仅 0.17、漏 19/23,两侧都抓才到 0.70),白边=背景残留没抠净,与抠穿是两个相反方向的病 —— 但把它做成判据需要另一个量,当前这个不够。
-
糊 / 画风变的判据是羽化边宽。
半透明像素数 ÷ 主体周长 ÷ (√主体像素数/64) ≥ 1.27:留一法 F1 0.703、precision 0.650(CI 0.433–0.819)、recall 0.765(CI 0.527–0.904)、AUC 0.727±0.082。它在一组已知答案的控制样本上两侧全部判对。配色漂移(precision 0.20 / recall 0.12)等同随机,不入账。详见下节。 -
净抠穿能拒掉孔洞率的闭合形状假阳性。 6 条
punch_max == 0的序列无一被判抠穿,其中包含孔洞率 20.0% 的 Remove the FennoAI configuration file #33 与 10.3% 的 前端 MS2 初始骨架:目录结构、模块接口与依赖边界 #58 —— 两者人工判定都是边缘问题而非抠穿。这坐实了「孔洞率与净抠穿必须成对读」。
分期 1:糊 / 画风变的判据与机制
判据:羽化边宽 feather_rel = 半透明像素数 ÷ 主体周长 ÷ (√主体像素数 / 64),逐帧取中位,
阈值 1.27,≥ 判「糊」。误报 7 条、漏报 4 条,逐条见归档。
机制:边缘从硬阶跃变成渐变,根因即 #475 定位的那条 —— 像素画项目的 game_style 为空,
出口跳过像素化,序列帧走 LANCZOS 重采样。
已知答案的控制样本,两侧全部判对。 归档里有同一条序列(#64)三帧的「交付」与「按母版色板
补做像素化后」两份。像素化后的画布是 60×50~74×45,先按 NEAREST 放大到主体像素数与交付帧
相当再量(否则量到的是尺寸不是画风):
| 帧 | 交付 | 像素化后 |
|---|---|---|
| 0 | 3.634 | 0.933 |
| 8 | 3.215 | 0.990 |
| 16 | 3.404 | 0.970 |
它不是在测暗边:对 halo 标签的 AUC 只有 0.487,等同随机。
分期 1:一条标定集分数更高、却被控制样本否决的判据
色阶负载 主体内亮度落差 ÷ √主体像素数,在同一标定集上 AUC 0.889、留一法 F1 0.769,
两项都高于上面那条。但它过不了同一组控制样本:像素化修复之后读数反而由 1.83 升到 2.10、
仍判「糊」。原因是它跟的是对比度,而像素化把色板吸附到两端之后对比度是上升的(154.9→179.0)。
标定集上分数更高、却测不到机制的量,不入账。 一条有独立已知答案的控制样本,否决权高于
在 42 条样本上挑出来的 AUC。
两个可迁移的仪器教训:
- 整幅统计量测不到局部退化。 主体对比度单用能到留一法 F1 0.750,但它是整幅统计量,
物理上够不着「手持道具糊掉」这类局部缺陷——是相关不是机制。 - 筛样本的条件不能与被测量相关。 分块量过渡带宽度时设了「块内落差 ≥15 才计入」,而糊本身
会压平落差 → 糊掉的块被门槛排除 → 只剩仍锐利的边被量到 → 读数方向整体翻转(AUC 0.31~0.46)。
同批还栽过一次「块须 75% 前景覆盖」,把又细又贴轮廓的手持道具排除。门槛与被测量相关时应改为
权重,而非排除。
尚未查清:feather_rel 对 cut 标签的 AUC 是 0.741,与对 blur 的 0.727 同量级,而两个标签在本集
共现 11/17,分不开;去掉带 halo 的序列后只剩 n=19、糊 6 条,AUC 0.628±0.145,区间很宽;控制样本
只有一条序列三帧。
归档:模型选型实验/糊判据_20260823/(calibration_final.json 定稿判据、控制样本读数与被否决
判据的理由;README.md 列出全部 30 个候选量各自的 AUC 与留一法 F1)。
样本量限制要说清:43 条中「完全没问题」只有 3 条,正负极不平衡;precision 的置信区间下界普遍在 0.4~0.66。这一份能支撑「哪条判据可用、阈值取多少」,不足以支撑跨模型或跨版本的比较。
归档:模型选型实验/抠图分型标注_20260823/(labels.json 人工标签、calibration.json 逐条读数与错例、items.json 样本与三组量、index.html 标注页可重跑)。
分期 1:原卡点(已绕开)
卡了三天,卡点是 phase0/标注/标注表.md 那 90 条人工标注一条都没填 → 没有 precision/recall → 不敢给任何指标定阈值 → 验收 1 过不了。
改用生产语料当盲验证集:现有 197 条已完成任务、1714 帧真实产物(工具见下),比当初造的合成标定集更贴近交付物。已按孔洞率分层抽出 20 条序列(低 7 / 中 6 / 高 7,覆盖 0.11%~67.95%)送人工标注 —— 只问一个离散事实「这条序列的抠图有没有明显问题」,不问程度分档(程度分档三次尝试全失败,见分期 3 报告)。
两个仪器坑已写进工具 README,复用时先读:
- 86% 的存量母版整幅不透明(08-19 及以前),孔洞率 / 净抠穿 / 出画在它上面恒读 0 或恒触边。不剔掉会把基线压向「很好」
- 孔洞率与净抠穿必须成对读。孔洞率对闭合形状假阳性(挥舞拖尾把背景圈住,一帧读到 73.2% 实际没坏);净抠穿对暗部褪色是盲的(真退化只读 0.1%),而暗部褪色正是 i2v 序列中后段角色本体破碎,表现为抠图抠穿 #497 的机制
另一个仪器教训(花了真金白银才发现):两组样本尺寸不同时,几乎任何量都会「完全分开」,分开的是尺寸不是被测属性。做像素画判据时非像素组全是 1024px、像素组全是 256px,读出三个「完全分开」的假信号;把非像素组缩到 256 后全部重叠。
归档
- 产物基线工具:
工具/产物查看器/(fetch.py拉产物量读数、metrics.py尺子、baseline.py出基线、deploys.py部署时间线;README 记着上述仪器坑) - 横评产物:
_参考资料/角色成品归档/鸟_模型横评_20260821/(8 条原视频 + 共同首帧 + 逐条读数) - 标注集:
模型选型实验/抠图标注_20260823/
按验收 6「全部实验可由归档脚本从原始输入重跑出同一组读数」:基线与横评的读数都能由上述脚本重跑,标注集的人工标签随集合归档。
Activity
johnnyzhang-eng commentedon Aug 20, 2026
仪器标定已开工,首轮结论是判据本身还不能用:现有归档素材的提示词版本、抠图版本与画布各不相同,其中被当作反例的那条主体抠图有近两成被打穿,据此得出的读数测的是抠图故障而不是模型。归档能提供正例,提供不了处理同质的配对反例,因此改为按已知失败配方现造一组配对样本,把提示词版本与管线 commit 一并钉住后再冻结阈值。进度与读数会持续更新在本条下面。
johnnyzhang-eng commentedon Aug 20, 2026
标定集已按冻结的提示词与 commit 造好,两臂唯一差异是母版朝向,抠图后主体内孔洞 0.40%,
_bg_key返回 None 的帧 0/16,没有踩 #278 里那条非纯色底导致两层后处理静默失效的坑。但这批样本没能验成步态指标,原因不在指标:逐帧看全片,选错母版那一臂确实在前三分之一转身,而
pick_cycle从转身之后取单周期、把转身整段裁掉,交付的 16 帧与对照臂几乎无异。也就是说母版选错这件事在视频层可见、在交付帧层不可见,pick_cycle把它救了回来,代价是一段付费视频的前三分之一被消耗且下游看不到母版选错了。这属于产品判断,不在本 Issue 范围内定,需要的话另开一条。johnnyzhang-eng commentedon Aug 21, 2026
生图这一轮跑完了三个模型各八张,有两条结论值得先同步。
一是三个模型都出不了正侧视母版。人工标 24 张只有 1 张是纯侧面,其余是身体朝右但转向观众的四分之三;方向倒是没问题,判官判 22/24 朝右且与人工一致。这不是模型之间的差异而是共同的天花板,而 walk 母版必须朝侧向是我们已经写死的契约,正面或四分之三母版会让模型靠转身去调和图文矛盾。也就是说母版这一步目前拿不到合格的侧视姿态,得靠参考图或别的手段补,不是换个模型能解决的。
二是判官在"侧视程度"这类程度分档上不可用,三次尝试的一致率分别是 25%、50%、43%,第三次已经把人工用的几何判据原样写进提示词。同一个判官在"朝哪边"这种离散事实上是 22/24。所以判官规程要加一条:只问离散事实,不问程度分档。侧视程度这条读数改由人工抽检,理由是它在排名里也用不上——三个模型的正侧视率都接近零,它区分不了模型。
另外分辨率那条轴确实生效,要 32px 时像素块更大、64px 更小,三个模型方向全对;但都不履约绝对值,实际逻辑高比要求的大两到三倍,且三个模型都不做限色,色数全部顶到 256。
johnnyzhang-eng commentedon Aug 23, 2026
补了 08-21/22 的进度:分期 2、4、5 都已跑完并写进正文,分期 1 改用生产语料当盲验证集(197 条任务/1714 帧),已抽出 20 条分层样本送人工标注。分期 4 的结论显式标了适用范围——n=1 单角色单动作,是同条件对照不是模型排名。
johnnyzhang-eng commentedon Aug 23, 2026
分期 1 有第一份 precision/recall 了:43 条生产序列人工分型标注,净抠穿的阈值应取 0.02 而非 0(F1 0.64→0.88),「判据是 >0」那条来自出画指标、套到净抠穿上是过度泛化。边缘问题以白边为主不是暗边,只抓暗侧漏 19/23。糊/画风变目前没有可用的量,precision 0.20、recall 0.12。
johnnyzhang-eng commentedon Aug 26, 2026
08-24 那轮时长与模型共线:3.0-turbo 全 3s,v2-5-turbo 与 seedance 全 5s,idle 三组各 n=8 也是这个分布。方向上混杂解释不了这个结果——分期 2 的结论是漂移随时长上升,而 3s 那组反而最大,所以推镜归给模型站得住;但表里建议补一列时长,否则读者判断不了这一点。