🏠 总目录📚 本教程 09 · 怎么评估 ← →
📑 本页目录(点开跳转)

09 · 怎么评估:FID 与 CLIP Score

⏱ 38 分钟 | ⭐ 两个几乎每篇论文都在报的数字,以及它们各自看不见什么


🎯 一句话

FID 量「这一批图整体像不像真图」,CLIP Score 量「这一张图对不对得上提示词」—— 而你真正在乎的构图、手指、小字、审美,两个都不测。

前面几章讲的全是怎么把图生成出来。这一章讲最后一件事:生成出来之后,你凭什么说这一版比上一版好。


📏 一、FID 到底在算什么

FID(Fréchet Inception Distance)分三步:

  1. 把真图和生成图都送进同一个 Inception 网络,取倒数第二层的输出 —— 每张图变成一个 2048 维向量。
  2. 真图那一堆向量当成一个高斯分布(均值 $\mu_r$、协方差 $\Sigma_r$),生成图那一堆当成另一个($\mu_g,\Sigma_g$)。
  3. 算这两个高斯之间的 Fréchet 距离:

$$\mathrm{FID}=\lVert\mu_r-\mu_g\rVert^2+\mathrm{Tr}\!\left(\Sigma_r+\Sigma_g-2\left(\Sigma_r\Sigma_g\right)^{1/2}\right)$$

⭐ 人话翻译:第一项是「两堆点的中心差多远」,第二项是「两堆点的形状(往哪些方向散、散多开)差多少」。两项都为 0 才是 0。越小越好。

⚠️ 注意这里的措辞:FID 从头到尾只用了均值和协方差。它把两堆图各压成了「一个中心 + 一个椭球」,除此之外的一切信息都被丢掉了。这一句是下面四个坑的共同来源。

FID 只比较两团点的中心和形状,不看任何一张图真图特征生成图特征中心差多远 + 形状差多少⭐ 全程只用了均值和协方差 —— 四个坑全从这一句来实测:两组来自同一分布、真值该是 0,n=100 却算出 21.4,n=10000 才降到 0.214⚠️ 而高斯 vs 每维只取 ±1(两阶矩一样、形状天差地别)FID 只有 0.1127,基线 0.1088
看这张图**没画什么**:它没有一张具体的图像。⭐ FID 只拿两团点的**中心和形状**做比较 —— 所以「每张都很怪但整体分布对」照样能拿高分。

🕳️ 二、坑①:它对样本量极敏感(这一条可以直接跑出来)

下面这段用两组来自同一个分布的随机特征算 Fréchet 距离。既然是同一个分布,理论上答案该是 0:

# 09 章:Fréchet 距离对样本量有多敏感
import numpy as np

def frechet(a, b):
    """两堆特征各当成一个高斯,算它们之间的 Fréchet 距离(FID 的算法本体)"""
    mu1, mu2 = a.mean(0), b.mean(0)
    s1, s2 = np.cov(a, rowvar=False), np.cov(b, rowvar=False)
    d = mu1 - mu2
    w, v = np.linalg.eigh(s1)                       # ⭐ 用对称形式算 (S1·S2)^{1/2} 的迹,避开复数
    s1h = (v * np.sqrt(np.clip(w, 0, None))) @ v.T
    ev = np.linalg.eigvalsh(s1h @ s2 @ s1h)
    return float(d @ d + np.trace(s1) + np.trace(s2)
                 - 2 * np.sqrt(np.clip(ev, 0, None)).sum())

rng = np.random.default_rng(0)
D = 64
print("A. 两组样本来自【同一个分布】,理论上 FID 应该是 0")
for n in [100, 500, 1000, 2000, 5000, 10000, 50000]:
    print("   n =%6d   FID = %7.3f"
          % (n, frechet(rng.standard_normal((n, D)), rng.standard_normal((n, D)))))

n = 20000
print("\nB. n=20000 时:")
print("   同一分布(基线)              FID = %.4f"
      % frechet(rng.standard_normal((n, D)), rng.standard_normal((n, D))))
print("   高斯 vs 每维只取 +1/-1        FID = %.4f"
      % frechet(rng.standard_normal((n, D)), rng.choice([-1.0, 1.0], size=(n, D))))

实测输出:

A. 两组样本来自【同一个分布】,理论上 FID 应该是 0
   n =   100   FID =  21.422
   n =   500   FID =   4.346
   n =  1000   FID =   2.129
   n =  2000   FID =   1.098
   n =  5000   FID =   0.446
   n = 10000   FID =   0.214
   n = 50000   FID =   0.044

B. n=20000 时:
   同一分布(基线)              FID = 0.1088
   高斯 vs 每维只取 +1/-1        FID = 0.1127

A 段怎么读:真值是 0,而 n=100 时算出 21.4,n=10000 时才降到 0.214 —— 相差约一百倍,全部是样本量造成的虚高,和图好不好没有半点关系。规律大致是「样本翻倍、虚高减半」。

💀 所以:用 1000 张算出来的 FID 和用 50000 张算出来的 FID,不是同一把尺子上的两个数,是两把不同的尺子。 业界惯例是 50000 张,低于 10000 张的 FID 基本不该拿来做横向比较。 ⚠️ 更要命的是这个偏差永远是正的:少抽样本只会让 FID 变大,不会让它变小。于是「我这版样本少一点」不是「误差大一点」,是系统性地把自己算差。

B 段是坑③:右边那组每一维只取 +1 或 −1 —— 一个长在 64 维超立方体顶点上的分布,和高斯形状完全不同,但它俩的均值和协方差一模一样。结果 FID 是 0.1127,而同一个分布的基线是 0.1088。⭐ 两个天差地别的分布,得分和「完全相同」没有区别 —— 因为 FID 只看均值和协方差,它在设计上就看不见别的。

💀 落到图上就是:只要整批图的特征分布对得上,每一张单独看都很怪(六根手指、糊掉的招牌字)也能拿到漂亮的 FID。FID 从来不评价任何一张图。


🕳️ 三、另外两个坑

坑②:它依赖那个特征提取网络。 FID 里的「Inception」不是修饰词,是尺子本身。换一个骨干(CLIP 特征、DINOv2 特征),甚至换一个 Inception 的权重版本,分数就变,排名也可能跟着变。⭐ 换句话说,FID 测的其实是「在 Inception 眼里像不像」,而 Inception 是拿 ImageNet 分类训出来的 —— 它对纹理敏感,对版式和文字基本无感。

坑④:跨论文不可比。 上面两条叠加,再加上大家的预处理不一致:resize 到 299 用的插值方式(双线性 / 双三次 / Lanczos)、要不要中心裁剪、JPEG 压缩质量、真图那一侧用的是训练集还是验证集。这些每一样都能动几个点。

⭐ 判据:论文表格里的 FID,只有在同一行实验设置下才有意义。看到别人报的 FID,先找三件事:样本量多少、真图那一侧是什么、预处理怎么做的。找不到 → 那个数字只能当广告看。


🧲 四、CLIP Score:另一个方向的一半

FID 完全不看提示词。CLIP Score 补的就是这一半:把图过 CLIP 的图像编码器、提示词过文本编码器,两个向量算余弦相似度(通常再乘 100、并把负值截成 0)。越大越好。

⚠️ 它的坑只有一条,但很致命:它只测「对不对」,不测「好不好看」。 一张构图糟糕、光线奇怪、手指畸形的图,只要内容确实是「一只戴帽子的猫」,就能拿到和精美版本一样的分。

⚠️ 还有一条实操上会咬人的:CLIP Score 和 CFG 强度基本是单调关系 —— 把 CFG 往上拉,图越来越贴提示词,CLIP Score 一路涨,而画面开始过饱和、细节崩坏,FID 同时变差。所以论文里常见的不是一个点,是一条 FID–CLIP 权衡曲线:⭐ 你不是在挑「最好的模型」,是在挑这条曲线上停在哪。(这个滑块本身在本板块 06 章讲过。)


⚖️ 五、人评怎么做才不浪费

图像生成里,人评不是「补充」,是唯一直接测你在乎的东西的办法。但它很贵,所以三条规矩必须守住:

⚠️ 还有一条容易被忽略:人评同样受样本量限制。30 组对比只够判断「明显更好 / 明显更差」,分辨不了「好 3 个百分点」。


🔭 六、最要紧的一条:尺子本身也会坏

站内《数据这一关》第 13 章把这件事说成一句话:评测集是你唯一的尺子,而尺子本身也是一份数据 —— 它会被抽错、被污染、被磨损。 这条判据在这里一字不改地成立,而且加倍成立,因为 FID 和 CLIP Score 都不是你的目标,只是代理。

⭐ 磨损是最容易忽略的一种坏法。那一章跑过一个实验:从一堆真实水平几乎一样的候选里,每次挑评测分最高的那个 —— 试过 200 个候选之后,被选中那个的分数至少虚高 4.5 个百分点,而这个虚高不会出现在任何置信区间里(置信区间只管抽样误差,不管选择偏差)。你每天拿 FID 挑 checkpoint、挑调度器、挑 CFG,干的正是这件事。

⭐ 对策便宜到没有借口不做:把评测提示词集切成 dev 和 test。dev 随便调随便看;test 有配额,每季度只准跑三次并记录在案。

⭐ 而最后一条判据来自《模型上线之后》第 15 章:代理指标必须定期回验它和真实目标的相关性还在不在。做法是攒 5–10 组「FID 变化 vs 人评变化」画散点 —— 相关性一旦消失,这把尺子就已经不指向你要的东西了,而你还会继续做出一串「成功」的实验。


🔗 这一章连到哪里

去哪 为什么
数据这一关 13 · 评测集也是数据 ⭐ 本节那条「尺子本身也会坏」的完整版,也是全站评测方法论的总入口。80 分钟,里面有本章用到的那个磨损实验(试 200 个候选虚高 4.5pp)、分层抽样把长尾层的置信区间从 ±12.59pp 收到 ±6.89pp 的对照表、四种查污染的办法,以及一次「FID 涨了却没用」的同类事故复盘(NDCG 从 0.712 跳到 0.781,灰度后满意度纹丝不动)
大模型全景导论 11 · 评测体系 榜单那一侧的通用陷阱。本章坑④(跨论文不可比)在那里叫「报告条件不对等」,它给的检查法直接能搬过来:看到任何对比图,先找「用的什么提示词 / 跑了几次怎么取 / 温度是多少」。它还算过一笔本章第五节要用的账:100 题的评测集只能分辨 8 个百分点以上的差距,想分辨 3 个点需要约 700 题
大模型全景导论 11b · 私有评测集怎么建 怎么建自己那把尺子的入门版:从真实失败里捞 20–50 个案例、分维度打标签、按「能写代码判 / 判不了但有标准 / 主观」三档定评分方式。⚠️ 它点名的三个错误本章全会撞上:只放难题(分数全挤在一起)、只放当前模型答错的(换模型就失效)、不分维度只看总分
模型上线之后 15 · 长期效应与代理指标 「代理指标不等于真实目标」这条判据的出处。它给了可执行的门槛(相关系数 ρ > 0.7 且方向一致率 > 85% 才能拿来做决策),也给了不回验的代价:一个跑了 14 个月才被发现的代理失效。⭐ 它那条「半年一次重新验证整条指标链」,就是本章末尾那个散点图该多久画一次

✅ 检查点

  1. FID 计算时,每张图被压成了多少维的向量?这个向量来自哪个网络?
  2. FID 公式里的两项各自在量什么?
  3. 两组样本来自同一个分布时,FID 的理论值是多少?实测 n=100 和 n=10000 分别算出多少?
  4. 为什么说「每一张图都很怪」和「FID 很好看」可以同时成立?B 段那个实验怎么证明这一点?
  5. CLIP Score 高,能说明图好看吗?把 CFG 拉高会让这两个指标各自往哪走?
  6. 人评为什么要用成对比较而不是 1–5 打分?
  7. 什么叫评测集「磨损」?一个便宜的对策是什么?
👀 答案
  1. 2048 维,来自 Inception 网络倒数第二层。⭐ 所以 FID 测的是「在 Inception 眼里像不像」,而 Inception 是 ImageNet 分类模型,对纹理敏感、对版式和文字基本无感。
  2. 第一项 $\lVert\mu_r-\mu_g\rVert^2$ 量两堆特征的中心差多远;第二项那个迹量两堆的形状(往哪些方向散、散多开)差多少。⭐ 除了均值和协方差,别的信息一概没用上。
  3. 理论值 0。实测 n=100 是 21.4,n=10000 是 0.214 —— 差约一百倍,全部是样本量造成的虚高。而且偏差永远是正的,样本少只会把自己算差。
  4. 因为 FID 只比较两个分布的均值和协方差,从不评价任何单张图。B 段:右边那组每维只取 +1/−1(长在超立方体顶点上),和高斯形状完全不同但两阶矩一模一样 —— 算出 0.1127,而同一分布的基线是 0.1088,两者没有区别。
  5. 不能。 CLIP Score 只测「图和提示词对不对得上」,一张丑但内容对的图照样高分。把 CFG 拉高:CLIP Score 一路涨,FID 变差 —— 论文里那条 FID–CLIP 权衡曲线就是这么来的,你是在选停在曲线的哪一点。
  6. 因为 1–5 的绝对刻度在人和人之间不可比,而且同一个人的刻度会随看过的图漂移。成对比较只要求排序,再用 Elo / Bradley–Terry 汇总。另外两条同样是硬要求:盲评 + 左右顺序随机,题目集固定且来自真实请求。
  7. 磨损 = 样本没变,但你看它的次数变多了。《数据这一关》13 的实验:从 200 个真实水平相当的候选里挑分最高的那个,分数至少虚高 4.5 个百分点,而这个虚高不出现在任何置信区间里。对策:把评测集切成 dev / test,dev 随便看,test 每季度只准跑三次并记录在案。

🛑 可以停在这里

读到这里,你已经能看懂论文表格里那两列数字在说什么、以及它们各自漏掉了什么,也能给自己那套图搭一个不至于骗自己的评测流程:固定的提示词集 + 盲评成对比较 + FID/CLIP 只当粗筛 + dev/test 分开。

什么时候回来:看到别人报的 FID 想判断能不能信时,回看第二、三节那三个要先问的问题(样本量、真图那一侧、预处理);发现「指标一直在涨、图看着没变好」时,回看第六节 —— 那基本就是尺子磨损或者代理失效。

⚡ 走神救援

先记住这几件事

下一节 👉 附录A-速查.md

打卡记录保存在你的浏览器里,首页能看到总进度