视频生成评估指标FVD、IS、KID:原理、小样本与复现实践
发布时间:2026/10/29 4:38:01 锦皓数字建站

1. 视频生成评估的第一道坎把“好不好看”拆成可计算的量我最早在 MiniSora 这类小规模视频生成框架上做实验的时候踩过一个很典型的坑训练 loss 一路平滑下降抽出来的样本肉眼看着也比三天前顺眼但拿 FVD 一算比上一版还高了三十多。当时第一反应是代码写错了反复重算了三遍特征提取器换了一版又一版最后发现问题既不在模型也不在代码而在我从头到尾就没搞清楚这三个指标各自在回答什么问题把它们当成了一个“总分”在用。这件事之后我形成了一个习惯评估视频生成模型先别急着跑指标先想清楚你要问的问题是什么。是想知道“我生成的这批视频整体分布像不像真实视频”还是想知道“单个样本本身画质够不够清晰、内容够不够丰富”又或者“我的评估集只有两三百条视频样本量根本喂不饱协方差估计该用什么替代”FVD、IS、KID 这三个东西恰好对应这三类问题用错场景数字就会骗人。对于刚上手视频生成的人来说最容易产生的误解是“图像评估能用的搬过来就行”。实际上视频多出来的那一维时间轴会彻底改变评价的重心。一张图糊了就是糊了但一段视频糊了可能是每一帧都糊也可能是帧帧都清晰但抖成一团一段视频的语义对不上可能是主体错了也可能是主体对但运动方向反了。图像指标看不见这些它们在时间维度上要么取平均要么直接忽略最后给出的数字和人的观感经常对不上。下面这套内容我打算从计算链路出发把三个指标的实现细节、输入对齐、数值稳定性、以及最容易被忽略的样本量问题一层层拆开讲。MiniSora 这个项目本身的规模不大训练数据也就几万条量级正是那种既需要考虑指标可信度、又请不起大规模人工评测的处境我踩过的坑和用过的补救办法应该能直接抄。1.1 三个指标各自负责回答什么先把分工说清楚。FVD 的全称是 Fréchet Video Distance思路是把生成视频和真实视频分别送进一个固定的三维卷积特征提取器各得到一批特征向量然后假设这两批特征分别服从多维高斯分布用两个高斯分布之间的 Fréchet 距离衡量差异。它测的是分布层面的整体距离既包含画质也包含运动模式、内容分布。它的优点是全面缺点是它对样本量敏感且一旦分数变差你没法立刻知道是哪一项出了问题。IS 是 Inception Score公式是exp(E[KL(p(y|x) || p(y))])其中p(y|x)是分类器对单个样本的类别预测分布p(y)是整个样本集上的边缘分布。它的直觉很朴素如果每个样本的类别预测都很尖锐说明生成内容清晰、可辨识如果整个集合的预测分布在各个类别上铺得很开说明生成内容多样。所以 IS 同时奖励单样本置信度和集合多样性。问题在于视频的分类器该怎么用、在哪个层级聚合没有统一标准。KID 是 Kernel Inception Distance用最大均值差异MMD在特征空间里度量两个分布的距离用的是多项式核。它最大的好处是无偏估计小样本下不会像 FVD 那样系统性偏乐观或偏悲观而且计算过程不需要估计协方差矩阵不需要开平方根数值上稳得多。我一般把这三个当成三个不同刻度的尺子FVD 看整体像不像KID 在小样本下看整体像不像更稳IS 看单样本和多样性的平衡。三者不能互相替代只能互相印证。1.2 只报一个数字的实验记录几乎没法复盘有个细节值得单独说。我早期做实验记录的时候表格里只有一列 FVD后来想把两三个月前的结论翻出来复现发现根本做不到——因为当时的 FVD 是在 16 帧、256 分辨率、某个特定版本的 I3D 权重上算的中间换过一次权重文件两次结果放在一起比较毫无意义。FVD 这个数字脱离计算配置就没有任何意义它不是物理量没有绝对单位。而 IS 单独看也有问题。IS 高不代表视频好因为分类器只对单帧语义敏感对时序一致性几乎无感。我试过一段故意把帧顺序打乱的视频IS 掉得非常有限人的眼睛却能一眼看出那是坏样本。所以 IS 必须和至少一个时序敏感的指标搭配使用。KID 反过来它太稳了稳到有时候区分度不够。两个质量差距明显的模型KID 的差距可能只有小数点后三四位需要配合置信区间才好下结论。所以我的做法是固定主指标用 FVD作为对外汇报的口径KID 用来做早期筛选和交叉验证IS 只作为辅助参考不单独下判断。1.3 MiniSora 这种小规模项目里评估集怎么定评估集这事比指标本身更容易出问题。真实视频参考集reference set如果选得和生成内容的域不一致比如参考集全是户外风景你生成的样本里混了一批室内人脸那 FVD 高只能说明分布不同不能说明质量差。我在 MiniSora 上的做法是参考集从训练集的验证划分里取不做额外的域筛选取 2048 条左右固定随机种子抽一次然后把这个清单的哈希值写进实验日志。数量上我的经验是 1024 是底线2048 比较舒服4096 以上边际收益就很小了。原因是特征提取器输出的维度通常是 1024 维左右不同实现取法不同有的取全局池化后的向量有的取分类层前一层协方差矩阵是 1024×1024样本数不到 1024 时这个矩阵秩亏严重特征值大量接近零Fréchet 距离的数值会变得极不稳定。生成样本这边同样要固定数量且数量必须和参考集一致——不少实现里 FVD 的均值项和协方差项对两边样本量是敏感的一边 2048 一边 512 算出来的数和两边都 2048 算出来的数不是一回事。2. FVD 的实现细节特征提取器才是分数的真正决定项很多人以为 FVD 的难点在 Fréchet 距离那一行公式其实那一行公式网上抄来就能跑。真正决定你分数能不能复现、能不能和别人比的是特征提取那一段。同样的模型换个 I3D 权重、换个帧数、换个归一化方式FVD 能差出几十上百。我把这段叫作“输入管线的一致性”它比模型本身更值得你花时间。2.1 I3D 输入管线的四道对齐用 I3D 提特征你至少要保证下面四件事在生成集和参考集上完全一致缺一件分数就不可比。对齐项具体内容不对齐的后果空间分辨率统一 resize 到 224×224或先短边缩放再中心裁剪裁剪策略不同会改变画面构图特征分布漂移时间采样固定帧数常见 16 或 32等间隔采样随机采样会让同一视频每次算出不同特征时间跨度采样帧覆盖的真实时长一致30fps 取 16 帧跨 0.53 秒8fps 取 16 帧跨 2 秒运动速度被改变数值归一化与特征提取器训练时一致多数是 ImageNet 均值方差也有用 [-1,1] 的输入尺度错位会让激活值整体偏移特征是系统性偏差第二项和第三项是最容易忽略的。MiniSora 早期版本的采样帧率是可配的我做过一次对比同一个模型生成集的帧率从 8fps 调到 24fps其他一切不变FVD 直接掉了将近四十。原因不是模型变好了而是采样后的 16 帧覆盖的时间跨度变了模型在特征提取器眼里看到的是“慢动作”跟参考集的运动速度对不上。所以我现在会在评估脚本里强制把两边重采样到同一个帧率这一步不做后面的数字全是白算。第四项也有坑。生成模型的输出通常在 [-1,1] 或 [0,1] 区间而 I3D 预训练权重期望的输入是 ImageNet 归一化后的值。直接把 [0,1] 的张量喂进去相当于整体加了个偏置所有特征都往一个方向偏算出来的 FVD 会系统性偏高。我见过不少复现笔记里根本没提这一步结果大家报的数互相之间差得很离谱。2.2 均值与协方差样本量不够时分数会骗你Fréchet 距离的公式是FVD ||μ_r - μ_g||² Tr(Σ_r) Tr(Σ_g) - 2·Tr((Σ_r Σ_g)^(1/2))其中μ是特征均值Σ是特征协方差下标r是真实集g是生成集。这个公式本身没什么可操作的但它对Σ的估计质量极其敏感。我做过一次实验从 4096 条真实视频里随机抽不同数量把它们和另一批固定样本比较观察 FVD 的波动。样本数 256 的时候同一个集合换三次随机种子FVD 的波动幅度能到 ±15%512 的时候降到 ±8% 左右1024 以后基本稳定在 ±3% 以内。这意味着如果你的评估集只有两三百条两个模型之间差个十几分的 FVD 根本不构成结论那可能只是采样噪声。这也是我为什么坚持把参考集定在 2048 的原因——既要控制波动又不至于让每次评估跑太久。特征维度是 1024 的话2048 个样本的协方差矩阵是满秩的特征值分布也比较健康。还有个小细节算协方差之前要不要做中心化这个大家都知道要做但中心化用哪一版的均值有讲究。我见过有实现在计算协方差时用了另一批样本的均值导致协方差矩阵不是半正定的后面开平方根直接报错或者返回复数。稳妥的做法是同一次特征提取里同时算均值和协方差别分开跑。2.3 协方差矩阵平方根的数值处理Tr((Σ_r Σ_g)^(1/2))这一项是数值问题的重灾区。直接调scipy.linalg.sqrtm处理两个 1024×1024 矩阵的乘积不但慢而且当矩阵接近奇异时会返回复数、NaN或者给出一个虚部很小但确实非零的结果。有两个处理思路。第一是加正则给两个协方差矩阵的对角线上各加一个很小的eps1e-6 量级让它们变成严格正定。第二是利用一个恒等式绕开非对称矩阵开方。恒等式是这样的Σ_r Σ_g和Σ_r^(1/2) Σ_g Σ_r^(1/2)是相似矩阵前者左乘右乘一个Σ_r^(1/2)和它的逆就能得到后者相似矩阵的特征值完全相同所以它们的平方根矩阵的迹也相同。而Σ_r^(1/2) Σ_g Σ_r^(1/2)是对称半正定的求它的平方根只需要做一次特征分解取特征值的平方根再求和就行又快又稳。import numpy as np def _sqrtm_psd(sigma, eps1e-8): 对称半正定矩阵的平方根用特征分解代替通用 sqrtm。 w, v np.linalg.eigh(sigma) w np.clip(w, eps, None) return (v * np.sqrt(w)) v.T def trace_sqrt_product(sigma_r, sigma_g, eps1e-6): 计算 Tr((Σ_r Σ_g)^(1/2))走对称化路线。 sigma_r sigma_r np.eye(sigma_r.shape[0]) * eps sigma_g sigma_g np.eye(sigma_g.shape[0]) * eps sqrt_r _sqrtm_psd(sigma_r) inner sqrt_r sigma_g sqrt_r # inner 对称半正定特征值开方后求和即为迹 w np.linalg.eigvalsh(inner) w np.clip(w, 0.0, None) return float(np.sqrt(w).sum())这个版本我在 1024 维特征上测过单次计算在秒级以内比scipy.linalg.sqrtm快了差不多一个量级而且不会返回复数。用eigvalsh而不是eig也是刻意的——它只算特征值不算特征向量还能利用对称性速度快一倍以上。Fréchet 距离的完整实现就是三部分相加def frechet_distance(mu_r, sigma_r, mu_g, sigma_g, eps1e-6): diff mu_r - mu_g mean_term float(diff diff) trace_term np.trace(sigma_r) np.trace(sigma_g) cross_term 2.0 * trace_sqrt_product(sigma_r, sigma_g, eps) return mean_term trace_term - cross_term要注意trace_term - cross_term理论上应该非负Fréchet 距离是度量但数值误差可能让它变成 -0.001 这种。我一般会在最后加一句max(value, 0.0)不是为了掩盖问题而是避免下游画曲线的时候出现负值看着别扭。2.4 特征提取的批处理与显存I3D 这类三维卷积对显存的要求比二维网络高得多因为它的激活张量多了一个时间维度。我那张 24G 的卡上输入 16 帧 224×224批大小开到 8 就比较紧张了开到 12 会 OOM。这个批大小不影响最终特征推理模式下没有 BN 统计更新但会影响耗时。我的处理是把特征提取和距离计算拆成两个阶段第一阶段批量提特征存成.npy或者内存映射文件第二阶段读缓存算距离。这样调参的时候不用反复跑特征提取改一下距离计算的实现就能立刻看到结果。MiniSora 的评估脚本现在就是这个结构第一次跑要十几分钟之后每次算指标只要几秒。缓存还有一个好处是可以做特征层面的检查。我习惯在算 FVD 之前先看一眼特征的均值向量范数和协方差矩阵的条件数。如果条件数大得离谱比如超过 1e8说明特征退化严重这时候出来的 FVD 不值得信得先回头查输入管线哪里没对齐。这个检查比等 FVD 算完再看数字能早发现问题。3. IS 用在视频上它测的是帧质量不是运动质量IS 这个指标在图像生成里被用得很熟搬到视频上就有点尴尬。因为它的分类器是二维的一次只能看一帧。那视频怎么办逐帧算完取平均还是对整段视频算一次不同论文里的处理方式不一样报出来的数字也就没法直接比。3.1 IS 的公式到底在奖励什么IS 的公式写出来是exp(E_{x~p_g}[KL(p(y|x) || p(y))])。拆开看KL 散度衡量的是“给定一个样本分类器预测的类别分布”和“整个生成集的平均类别分布”之间的差异。如果每个样本的预测都很尖锐某一类概率接近 1而整个集合又均匀分布在很多类上KL 就大IS 就高。反过来如果模型只会生成同一类东西每个样本的预测都很尖锐但边缘分布p(y)也集中在那一类上KL 就小IS 就低。这本来是个聪明的设计用一次计算同时抓住质量和多样性。但它的前提是分类器靠谱且类别体系跟生成内容的域匹配。问题来了Inception 分类器是在 ImageNet 1000 类上训的你生成的如果是某种特定场景的短视频比如机械臂操作、或者特定风格动画分类器给出的预测可能全是同一类或者全是噪声这时候 IS 反映的就不是质量而是分类器和数据的域差。我在 MiniSora 上就遇到过这个模型明明在进步IS 却在 1.2 附近纹丝不动最后发现是分类器对这批内容几乎没区分度几百个样本预测的 top-1 全集中在三四个类里。3.2 逐帧、逐片段、逐视频三种算法的差异如果非要用 IS 评估视频至少有三个口径可选我逐个说。逐帧算再平均是最简单的做法。把每段视频的每一帧当独立图像送进分类器得到每帧的类别分布然后所有帧的分布一起参与 KL 计算。这个做法的隐含假设是“一帧的质量就能代表视频”完全忽略了时序。好处是样本量大方差小坏处是运动质量好坏完全体现不出来。对每段视频算一次再平均是另一种。把一段视频的所有帧的类别分布先平均得到这段视频的代表分布再按视频为单位算 IS。这个做法更接近“以视频为单位”的评价但平均会把时序问题抹平——帧顺序乱了平均后的分布几乎不变。对每段视频的每个时间片段分别算然后用某种方式聚合这个最接近视频评估的本意但实现复杂、超参数多片段长度、重叠多少不同实现之间差异最大可比性最差。我自己的做法是主报告用口径二因为它是“以样本为单位”的跟人的观感单位一致同时在日志里附一份口径一的结果用来排查“是不是只有个别帧坏了拉低了整体”。两个数放在一起看比单个数字信息量大。提醒一句IS 的绝对值在不同分类器、不同数据集之间完全不可比。只报“我们的 IS 是 8.3”没有意义必须同时说明分类器版本、输入分辨率和聚合方式而且最好只在同一个实验序列内部横向比较。3.3 常见的两种误用第一种是把 IS 当成“画质分”。IS 高只能说明分类器容易认出内容跟清晰度、锐度、有无伪影都不是一回事。我见过一版模型因为画面过锐、对比度拉高IS 反而涨了但人眼看着是过度锐化的塑料感。第二种是把 IS 下降当成模型退化。实际上 IS 下降可能是多样性提升的代价——模型学会了生成更多类别边缘分布变平KL 就会下降。这时候要结合 FVD 或 KID 一起看如果 FVD 也在变差那确实是退化如果 FVD 稳定甚至变好那多半是多样性换来的是好事。我在实验记录里专门加了一栏记录 IS 的方差。同一批样本换个种子重新划分计算IS 的波动通常比 FVD 小但如果波动超过 0.3说明样本量不够或者分类器对这个域不稳这个数就只当参考。4. KID 的三次核计算小样本下它比 FVD 更可信我真正开始重视 KID是因为一次很尴尬的经历。当时只有一个 512 条的小验证集两个模型在 FVD 上差了 20 分我下了结论说新版更好。后来凑够数据重新评估发现那 20 分是噪声两个模型实际水平差不多。从那以后小样本场景我一律先看 KID。4.1 MMD 无偏估计的直觉KID 的核心是最大均值差异MMD把两批样本映射到一个再生核希尔伯特空间比较它们在这个空间里的均值嵌入的距离。用的是多项式核k(x,y) (x·y / d 1)^3其中d是特征维度。MMD 的平方有一个无偏估计形式是三部分MMD²(U, V) 1/(m(m-1)) ΣΣ k(u_i, u_j) # U 内部两两核 1/(n(n-1)) ΣΣ k(v_i, v_j) # V 内部两两核 - 2/(mn) ΣΣ k(u_i, v_j) # 跨集核注意前两项的分母是m(m-1)和n(n-1)刻意排除了自己和自己配对此时核值最大这就是“无偏”的来源。FVD 里估计协方差矩阵是有偏的样本少的时候会系统性地低估协方差导致距离偏小KID 把这个偏差去掉了所以在小样本下更接近真实距离。实现上多项式核可以直接展开成矩阵运算def polynomial_kernel(x, y, degree3, gammaNone, coef01.0): x: (m, d), y: (n, d) - (m, n) 的核矩阵。 if gamma is None: gamma 1.0 / x.shape[1] return (gamma * (x y.T) coef0) ** degree def mmd2_unbiased(x, y, degree3): m, n x.shape[0], y.shape[0] k_xx polynomial_kernel(x, x, degree) k_yy polynomial_kernel(y, y, degree) k_xy polynomial_kernel(x, y, degree) # 去掉对角项实现无偏估计 sum_xx (k_xx.sum() - np.trace(k_xx)) / (m * (m - 1)) sum_yy (k_yy.sum() - np.trace(k_yy)) / (n * (n - 1)) sum_xy k_xy.mean() return float(sum_xx sum_yy - 2 * sum_xy)这段代码有个细节值得说k_xx.sum() - np.trace(k_xx)这个写法等价于把对角线上的自配对排除。如果你的实现里忘了减掉对角线算出来的 MMD 会偏小而且样本越少偏得越多——这正好是 KID 想要避免的那种偏差。4.2 子集采样与方差控制KID 的一个常见用法是随机抽固定大小的子集重复计算多次报告均值和标准差。原论文里推荐的子集大小是 50 或 100重复几十次。这个做法在小样本下特别有用因为它把“样本量不足”这个事实显式地暴露在标准差里。我在 MiniSora 上的配置是子集大小 100重复 50 次报均值 ± 标准差。生成集和参考集各自按这个规则抽每次抽样的随机种子要固定保证两次评估的抽样过程完全一致否则你没法区分指标变化是模型造成的还是抽样造成的。标准差这个东西很有用。两个模型的 KID 均值相差 0.002但标准差是 0.004那就别急着说谁更好。相反如果均值差 0.01标准差只有 0.001那差距是实打实的。我在做超参搜索的时候会直接按“均值减一个标准差”来排序选保守的那个避免挑到运气好的配置。还有一点KID 对特征维度也敏感。特征维度 1024 的时候多项式核的计算量是 O(m·n·d)2048 个样本大概几秒能算完还在可接受范围。如果特征维度更高比如某些实现用 2048 维建议先做一次随机投影降维否则核矩阵相乘会明显变慢。4.3 FVD 与 KID 的对照这两个指标我几乎总是一起跑因为它们的失效模式不太一样交叉验证能过滤掉不少误判。维度FVDKID度量对象两个高斯分布的 Fréchet 距离特征空间里的 MMD是否有偏有偏小样本低估协方差无偏估计数值范围无上界通常几十到几百通常 0 到 0.1 量级越接近 0 越好计算成本高需要协方差和矩阵开方中核矩阵乘法样本量要求建议 ≥1024100 以上即可用子集估计对异常值较敏感协方差被少数远离样本拉偏相对稳健可比性必须严格同配置才可比同配置下可比跨配置仍不可比我的用途主指标对外汇报早期筛选、小样本交叉验证一个实操建议如果你的评估集只有几百条把 FVD 作为主指标是危险的。正确做法是把 KID 作为主结论依据FVD 只作为参考等评估集扩充后再用 FVD 复核。反过来如果评估集上千两个指标结论一致那结论的可信度就比较高如果两个指标打架通常说明分布差异集中在少数模态上这时候要回去看样本而不是盯着数字。5. 把评估跑成流水线缓存、批大小与复现性指标算得对不对是一回事能不能稳定复现是另一回事。我见过太多“上周算出来 78这周算出来 95”的情况最后追下去都是环境或者配置漂了。这一段专门讲工程层面的事。5.1 特征缓存的三层结构我给评估流水线设计了一个三层缓存用起来很省事。第一层是视频级缓存每条视频真实的或生成的在固定输入管线下的特征向量存成{split}/{sample_id}.npy文件名里带上分辨率、帧数、帧率、特征提取器哈希这四个字段。这样只要任何一项变了文件名就变了不会误用旧缓存。第二层是数据集级缓存把一批特征拼成一个(N, D)的矩阵同时存下均值、协方差、样本 id 列表。均值和协方差在生成新样本时可以增量更新不必每次重算全量。第三层是指标级缓存把(参考集哈希, 生成集哈希, 指标名, 配置哈希)作为 key直接存最终的分数。这一层最省时间调参的时候同一个组合算过一次就不用再算。这个结构的好处是可追溯。任何一次汇报的分数都能顺着哈希链找到当次的样本清单、输入管线参数和代码版本。我现在的实验日志里FVD 那一栏旁边一定跟着两个哈希值看着有点啰嗦但出问题的时候能救命。5.2 批大小与显存的实际权衡特征提取阶段批大小主要影响耗时和显存。我实测过一组数据16 帧、224×224、I3D批大小显存占用每千条耗时4约 8 G基线8约 14 G快约 1.6 倍16OOM不可用批大小不影响特征质量推理模式下但会影响特征的计算精度吗理论上不会实际上如果用了混合精度不同批大小可能带来极微小的差异。我的做法是固定用 fp32 跑评估宁可慢一点也别让数值差异引入不可控变量。另外要注意的是三维卷积网络在批大小变化时某些实现会动态选择不同的卷积算法cuDNN 的 autotune这会导致同一批输入在不同次运行中产生极微小的差异。如果追求严格可复现可以在启动时固定torch.backends.cudnn.benchmark False代价是稍微慢一点。5.3 让两次评估结果可比的最小清单我把这一条做成了脚本里的强制检查任何一项不满足就直接报错退出不让你算出不可比的数字。特征提取器的权重文件哈希一致输入分辨率、帧数、采样帧率一致归一化参数一致参考集清单的哈希一致用同一批真实视频同一个划分生成样本数量与参考集数量一致随机种子一致影响抽样和子集选择计算精度一致统一 fp32指标实现版本一致协方差开方的实现方式变了分数会变第八条容易被忽略。我改过一版平方根实现从scipy.sqrtm换成特征分解版其他一切不变FVD 差了 0.3 左右。虽然很小但足以让两次实验的结论产生歧义。所以现在只要改了指标代码我就会在版本号上打个标记旧结果不复用。6. 从指标读数反推问题几种典型曲线形态指标算出来不是终点用指标指导优化才是。我在 MiniSora 上跑了几个月慢慢积累出一套“看数识病”的经验虽然不严谨但挺实用。6.1 指标组合的读法下面这张表是我总结的几种典型组合都是实际遇到过的。FVDKIDIS可能的成因优先排查方向高高正常整体分布偏离模型没学到目标域数据配比、训练时长、条件输入是否有误高低正常少数模态严重偏离把协方差拉偏了抽 20 个样本人眼看找最差的那几个低低明显下降分布贴合但多样性塌缩检查是否过拟合采样温度是否过低低低高分布和多样性都在改善正常继续观察主观质量突然升高突然升高下降训练崩溃或学习率过大看 loss 曲线、梯度范数波动大稳定稳定评估集样本量不足扩评估集或改用 KID 为主第一行和第二行的区别很关键同样是 FVD 高第二行的情况往往只需要修几个坏样本比如某些条件下的生成失败而不是推翻整个模型。这时候盲目加大训练量是浪费。判断方法是把生成样本按 FVD 的贡献度排序——虽然 FVD 是分布级的但你可以用特征距离做近似排序找出那些离参考分布最远的样本。6.2 训练中后期 FVD 反弹的三种成因这个现象我遇到过好几次每次都不同原因。第一种是过拟合导致的多样性塌缩。训练 loss 一直在降但模型开始只生成训练集里最常见的几种运动模式边缘分布收窄。表现是 FVD 先降后升KID 跟随IS 可能不降反升因为单样本更“标准”了。对策是加正则、早停、或者调整采样温度。第二种是时序退化。模型学会了生成清晰的单帧但帧间一致性变差开始出现闪烁。这种在逐帧指标上完全看不出来FVD 会涨因为 I3D 对时序敏感。对策是检查时序模块或者增加时序一致性相关的损失项。我有一次是因为数据增强里的随机裁剪破坏了帧间对应关系改成对整段视频做相同的裁剪后就好了。第三种是评估管线漂移也就是前面说的配置不一致。有一次 FVD 突然涨了 40查了半天发现是生成脚本的输出帧率参数被改了采样出来的“16 帧”实际覆盖的时间跨度变了。这种情况最应该优先排除因为它跟模型完全无关。排查顺序建议先确认评估管线没变再看样本最后才怀疑模型。我踩过的坑里至少三成出在评估管线。6.3 指标之外小样本人工盲测怎么做指标再细也代替不了人眼。MiniSora 这个规模的项目搞大规模人工评测不现实但小规模的盲测完全做得到而且性价比很高。我的做法是每次对比两个模型随机抽 20 组样本对每组里随机决定 A 和 B 哪个是新版发给三到五个同事让他们回答三个问题哪一段更清晰、哪一段运动更自然、哪一段更像真实拍摄。每个问题强制二选一不允许“都差不多”。最后统计偏好比例。这个规模和流程一次大概半小时比跑一轮完整评估还快。但它能抓住指标抓不到的东西比如“手部变形”“物体穿模”这种局部问题这些问题在高维特征里可能被稀释掉。盲测结果和指标结果如果打架我的经验是优先信盲测然后回头去查指标为什么没反映出来。有一次盲测明显偏向新版但 FVD 是新版更高最后发现是新版改善了运动自然度但增加了背景噪声I3D 对背景变化更敏感。这种洞察光看数字是永远得不到的。最后分享一个小习惯我会在每次实验的日志目录里放一张对照图左边是参考集的随机 8 个样本右边是生成集的随机 8 个样本下面写着当次的三个指标。这样几个月后翻回去一眼就能想起当时模型长什么样比看一堆数字直观得多。这个习惯帮我省了很多次“这个数是不是算错了”的自我怀疑。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。