第 2 讲 · 流匹配 · Flow Matching

Generative AI with Stochastic Differential Equations · Lecture 02。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 Maps to:MIT 6.S184 Generative AI with Stochastic Differential Equations(IAP 2026),Lecture 2 · 22-Jan-2026 · Flow Matching;Lab 2(Flow Matching and Score Matching)的第 1、2 部分(2.1–2.3)、3.1 和第 4 部分。 阅读材料:原课讲义 Holderrieth & Erives, An Introduction to Flow Matching and Diffusion Models(2026 版,arXiv:2506.02070)第 3 章;Lecture 2 slides(20260122_Lecture_02.pdf);原始论文 Lipman et al. (2023) Flow Matching for Generative Modeling、Liu et al. (2023) Rectified Flow、Albergo & Vanden-Eijnden (2023) Stochastic Interpolants。 依据说明:本讲以原课讲义第 3 章为主线:条件与边缘概率路径、条件与边缘向量场、边缘化技巧(定理 9)、连续性方程(定理 11)、流匹配与条件流匹配损失(定理 12)、Algorithm 3,以及 slides 里的”流匹配矩阵”。原课 Lab 2 的线性路径(任意分布之间搭桥)放在 §6.1。“环形数据上的旋转场""条件轨迹与边缘轨迹的交叉""有限数据集上的精确最优解会背诵""训练损失的地板 C 与梯度噪声""调度的比较”等实验是本讲义补充的;其中调度比较的结果与常见说法不一致,§6.2 如实报告。 配套代码 Code:code/lecture02/(6 个脚本 + 3 个模块;PyTorch + matplotlib;脚本 2–50 秒,最长的 06 号约 50 秒,都完整运行过) 预计阅读时间:5 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

学完这一讲,你应该能够:

  1. 说清楚条件概率路径和边缘概率路径的定义与区别,会从边缘路径采样,并解释为什么”能采样、算不出密度”。
  2. 推导高斯条件路径 N(αtz,βt2I)\mathcal{N}(\alpha_t z, \beta_t^2 I) 的条件向量场,并把回归目标化简成 α˙tz+β˙tϵ\dot\alpha_t z + \dot\beta_t\epsilon(CondOT 时是 z−ϵz - \epsilon)。
  3. 陈述并证明边缘化技巧:边缘向量场 = 条件向量场按后验 p(z∣xt=x)p(z \mid x_t = x) 加权平均,它让粒子沿着边缘概率路径走;理解连续性方程的直觉。
  4. 陈述并证明定理 12:条件流匹配损失与流匹配损失只差一个常数,梯度相同;知道这个常数是什么、它为什么让训练损失降不到 0、为什么条件目标的梯度噪声更大。
  5. 写出并实现流匹配训练算法(Algorithm 3),训练一个流模型,并用正确的方式评估它(看样本,而不是看损失)。
  6. 理解流匹配的推广与局限:任意分布之间的搭桥;调度的选择没有放之四海而皆准的答案;有限数据集上的精确最优解只会背诵训练集。

0.2 先修与本讲范围

需要的背景在哪里
流模型、ODE、欧拉法、Algorithm 1第 1 讲 §2–§3
高斯的重参数化与相加、狄拉克 δ前置讲 P1 §2
贝叶斯公式、后验;边缘分布”采样易、密度难”P1 §3
条件期望与均方误差分解(本讲最核心的工具)P1 §4
散度、连续性方程的粒子视角P1 §5.2、§6.3
训练循环、带噪声目标的回归、广播 bug前置讲 P2 §1.2、§3

本讲只讲流模型(ODE)。得分函数、SDE 采样、去噪扩散模型是第 3 讲的内容;条件生成(按提示生成)是第 4 讲。

0.3 本讲地图 Map

§1  问题:怎样训练流模型?为什么"先设计路径、再反推向量场"
§2  概率路径:条件路径、边缘路径、高斯路径与三种调度            ← 代码 01
§3  向量场:条件向量场;边缘化技巧;连续性方程;有限数据的陷阱    ← 代码 02、03
§4  损失:流匹配 vs 条件流匹配(定理 12);常数 C;Algorithm 3   ← 代码 04
§5  实验:训练流匹配模型                                        ← 代码 05
§6  推广:任意分布搭桥;调度的选择;训练出的网络会背诵吗?      ← 代码 06
§7  全景:流匹配矩阵、文献里的名字
§8  小结   §9  常见误区   §10 练习   §11 延伸阅读   §12 下一讲预告

0.4 记号 Notation(新增的部分)

记号意思
pt(x∣z)p_t(x \mid z)条件概率路径:以一个数据点 zz 为条件,p0(⋅∣z)=pinitp_0(\cdot\mid z) = p_{\text{init}},p1(⋅∣z)=δzp_1(\cdot\mid z) = \delta_z
pt(x)p_t(x)边缘概率路径:∫pt(x∣z) pdata(z) dz\int p_t(x\mid z)\,p_{\text{data}}(z)\,dz
αt,βt\alpha_t, \beta_t噪声调度(noise schedule):pt(⋅∣z)=N(αtz,βt2I)p_t(\cdot\mid z) = \mathcal{N}(\alpha_t z, \beta_t^2 I);α˙t,β˙t\dot\alpha_t, \dot\beta_t 是对 tt 的导数
ut(x∣z)u_t(x \mid z)条件向量场(原课讲义写作 uttarget(x∣z)u_t^{\text{target}}(x\mid z))
ut(x)u_t(x)边缘向量场(原课讲义写作 uttarget(x)u_t^{\text{target}}(x)):训练的真正目标
utθ(x)u_t^\theta(x)神经网络向量场
LFM\mathcal{L}_{\text{FM}},LCFM\mathcal{L}_{\text{CFM}}流匹配损失、条件流匹配损失
t∼Unift \sim \mathrm{Unif}tt 在 [0,1][0, 1] 上均匀分布

0.5 一张总图:流匹配矩阵

Lecture 2 的 slides 用一张 2×3 的”矩阵”概括整讲,建议先记住它,读完再回来看:

概率路径向量场损失函数
条件(针对单个数据点 zz)pt(x∣z)p_t(x\mid z):有公式ut(x∣z)u_t(x\mid z):有公式LCFM\mathcal{L}_{\text{CFM}}:能算
边缘(对整个数据分布平均)pt(x)p_t(x):只能采样ut(x)u_t(x):算不出来LFM\mathcal{L}_{\text{FM}}:算不出来

slides 的注解是:“条件” = “针对单个数据点”,“边缘” = “对数据点的分布平均”。第一行的东西都是解析公式;第二行的东西都算不出来,但第二行才是我们真正想要的。整讲的故事就是:用第一行能算的东西,学到第二行算不出的东西。


1. 问题:怎样训练流模型? · The training problem

第 1 讲造好了流模型:X0∼pinitX_0 \sim p_{\text{init}},沿 utθu_t^\theta 走到 t=1t = 1。没训练的网络只会产生”无意义的东西”;而用第 1 讲的”理想向量场”(我们提前算出来的那个),同样的采样循环就能把噪声变成五峰数据。所以训练要回答的问题是:

怎样调整 θ\theta,使得从 X0∼pinitX_0 \sim p_{\text{init}} 出发、沿 utθu_t^\theta 走到 t=1t = 1 时,X1∼pdataX_1 \sim p_{\text{data}}?

两条”直接”的路都走不通:

  • 最大似然:用 P1 §6.2 的瞬时变量替换,log⁡p1θ(x)\log p_1^\theta(x) 可以写成”沿轨迹倒着积分散度”。但每算一次似然都要模拟一遍 ODE、每一步都要算散度(dd 次反向传播或带噪声的 Hutchinson 估计,P2 §2.4),训练代价高得离谱。这就是”连续归一化流”的困境。
  • 直接回归:如果我们知道”正确的”向量场 ut(x)u_t(x),训练就是一个普通的回归问题 min⁡θE∥utθ(x)−ut(x)∥2\min_\theta\mathbb{E}\lVert u_t^\theta(x) - u_t(x)\rVert^2。但正确的向量场是什么?满足”终点是 pdatap_{\text{data}}“的向量场有无穷多个(§2.4 会看到一个例子),而且我们只有数据样本,没有 pdatap_{\text{data}} 的公式。

流匹配的思路是先设计路径,再反推向量场:

  1. 先规定粒子在每个时刻应该服从什么分布:一条从 pinitp_{\text{init}} 到 pdatap_{\text{data}} 的概率路径 ptp_t(§2)。
  2. 再找一个让粒子恰好沿着这条路径走的向量场 utu_t(§3)。这一步对单个数据点很容易,对整个数据分布则靠”边缘化技巧”。
  3. 最后用回归去学这个向量场,并证明:虽然 utu_t 算不出来,但可以对一个能算的”条件”目标做回归,效果完全一样(§4)。

打个比方:与其直接告诉每辆车”该怎么开”,不如先规定”每个时刻路上的车流密度应该长什么样”,再反推出每个位置、每个时刻车的速度。


2. 概率路径 · Probability paths

2.1 条件概率路径:从噪声到一个数据点

先只看一个数据点 zz。一条条件(插值)概率路径是一族分布 pt(⋅∣z)p_t(\cdot\mid z),0≤t≤10 \le t \le 1,满足

p0(⋅∣z)=pinit,p1(⋅∣z)=δz.p_0(\cdot\mid z) = p_{\text{init}},\qquad p_1(\cdot\mid z) = \delta_z.

它把初始的噪声分布逐渐”收缩”成单个数据点。原课讲义说,你可以把概率路径想成分布空间里的一条轨迹。

最重要的例子是高斯条件路径(原课讲义 Example 8,“by far the most important”):取两个连续可微、单调的函数 αt,βt\alpha_t, \beta_t(噪声调度),满足 α0=β1=0\alpha_0 = \beta_1 = 0、α1=β0=1\alpha_1 = \beta_0 = 1,令

pt(⋅∣z)=N(αtz, βt2Id).p_t(\cdot\mid z) = \mathcal{N}(\alpha_t z,\ \beta_t^2 I_d).

t=0t = 0 时是 N(0,I)\mathcal{N}(0, I),t=1t = 1 时方差为 0、是 δz\delta_z(P1 §2.4)。从它采样只需一行(P1 §2.1 的重参数化):

x=αtz+βtϵ,ϵ∼N(0,I).x = \alpha_t z + \beta_t\epsilon,\qquad \epsilon \sim \mathcal{N}(0, I).

01 号脚本第 1 部分对 z=(3,2)z = (3, 2)、CondOT 调度(αt=t\alpha_t = t、βt=1−t\beta_t = 1 - t)验证:样本均值沿直线从原点移向 zz,标准差从 1.0018 缩到 0.0000(t=1t = 1)。对单个数据点而言,这条路径没有任何难处。

2.2 边缘概率路径:对所有数据点平均

把数据点也变成随机的:先抽 z∼pdataz \sim p_{\text{data}},再抽 x∼pt(⋅∣z)x \sim p_t(\cdot\mid z)。这样得到的 xx 的分布叫边缘概率路径:

z∼pdata, x∼pt(⋅∣z) ⟹ x∼pt,pt(x)=∫pt(x∣z) pdata(z) dz.z \sim p_{\text{data}},\ x \sim p_t(\cdot\mid z)\ \Longrightarrow\ x \sim p_t,\qquad p_t(x) = \int p_t(x\mid z)\,p_{\text{data}}(z)\,dz.

由条件路径的两个端点条件,立刻得到 p0=pinitp_0 = p_{\text{init}}、p1=pdatap_1 = p_{\text{data}}:边缘路径在噪声和数据之间插值。对高斯路径,采样就是 x=αtz+βtϵx = \alpha_t z + \beta_t\epsilon,zz 从数据集里随便挑。

原课讲义特别强调:我们能采样 ptp_t(式 (12)),但算不出它的密度(式 (13) 的积分)。这正是 P1 §3.4 的”采样容易、密度难”。01 号脚本第 2 部分在五峰数据上验证了两件事(这里能写出闭式的 ptp_t,只因为 pdatap_{\text{data}} 是高斯混合):

时刻祖先采样 vs 闭式 ptp_t到 N(0,I)\mathcal{N}(0, I) 的距离到 pdatap_{\text{data}} 的距离
t=0t = 0+0.0000−0.00031.7330
t=0.5t = 0.5−0.00120.34120.9132
t=1t = 1+0.00321.7387−0.0015

(能量距离,噪声地板约 ±0.003。)两步采样得到的分布和闭式解一致;两端分别与噪声、数据无法区分。

2.3 三种调度

调度 (αt,βt)(\alpha_t, \beta_t) 决定”中途路过哪些分布”。本讲比较三种:

调度αt\alpha_tβt\beta_t说明
CondOTtt1−t1 - t噪声与数据的直线插值;SD3、Meta Movie Gen 用它;原课讲义 Algorithm 3 的默认
SqrtBetatt1−t\sqrt{1 - t}原课 Lab 2 用的路径
Cosinesin⁡πt2\sin\frac{\pi t}{2}cos⁡πt2\cos\frac{\pi t}{2}αt2+βt2=1\alpha_t^2 + \beta_t^2 = 1(“方差保持”),与 DDPM 一族的路径同类

一个有用的量是信噪比 SNRt=αt2/βt2\mathrm{SNR}_t = \alpha_t^2/\beta_t^2:数据信号的”能量”和噪声”能量”之比。01 号脚本第 3 部分:

tt0.10.30.50.70.9
CondOT 的 SNR0.0120.1815.481
SqrtBeta 的 SNR0.0110.130.51.68.1
Cosine 的 SNR0.0250.2613.940

三者两端相同(0 和 ∞),中途差别很大:SqrtBeta 的噪声消失得最晚;t=0.5t = 0.5 时 Cosine 路径上的分布离数据最近(能量距离 0.32,另两者约 0.83–0.90)。

三种调度的边缘概率路径

调度不改变终点(t=1t = 1 永远是 pdatap_{\text{data}}),只改变路径中途的样子。它会影响训练和少步采样,但影响的方向并不简单(§6.2)。

2.4 概率路径只规定”快照”

slides 有一句提醒:“概率路径只规定边缘分布(每一张快照),不规定单个粒子怎样随时间运动(没有动力学)。”

01 号脚本第 4 部分给了一个具体的例子。数据是一个环(72 个小高斯排成半径 3 的圆,几乎是旋转对称的),于是每个时刻的 ptp_t 也几乎是旋转对称的。设 utu_t 是让粒子沿 ptp_t 走的边缘向量场(§3),再给它加一个旋转场 w(x)=ω(−x2,x1)w(x) = \omega(-x_2, x_1)。旋转场沿着 ptp_t 的等高线转圈:div⁡(ptw)=∇pt⋅w+ptdiv⁡w=0+0\operatorname{div}(p_t w) = \nabla p_t\cdot w + p_t\operatorname{div}w = 0 + 0(P1 §5.4),所以加上它不改变任何时刻的分布:

时刻只用 utu_t:与 ptp_t 的能量距离ut+u_t + 旋转:与 ptp_t 的能量距离
t=0.5t = 0.5+0.0002−0.0004
t=1t = 1−0.0008−0.0008

两组粒子在每个时刻的分布都等于 ptp_t,终点都是环形数据。但同一个噪声起点的终点相差 1.995 弧度(约 114°,标准差 0.003),正好是 ω=2\omega = 2 在单位时间里转过的角度:

同一条概率路径,两个向量场

所以”选定一条概率路径”并不能唯一确定向量场。流匹配选的是一个特别的向量场:由条件向量场按后验平均得到的边缘向量场。它的轨迹是左图那样”不绕弯”的。

📌 代码 01:python3 01_probability_paths.py。


3. 向量场 · Vector fields

3.1 条件向量场:把噪声送到一个数据点

对每个数据点 zz,设 ut(⋅∣z)u_t(\cdot\mid z) 是一个条件向量场:它的 ODE 让粒子沿着条件路径走:

X0∼pinit,ddtXt=ut(Xt∣z) ⟹ Xt∼pt(⋅∣z)(0≤t≤1).X_0 \sim p_{\text{init}},\quad \frac{d}{dt}X_t = u_t(X_t\mid z)\ \Longrightarrow\ X_t \sim p_t(\cdot\mid z)\quad(0 \le t \le 1).

对高斯路径,它可以手算出来(原课讲义 Example 10)。**第一步:先写出流。**令

ψt(x0∣z)=αtz+βtx0.\psi_t(x_0\mid z) = \alpha_t z + \beta_t x_0.

若 X0∼N(0,I)X_0 \sim \mathcal{N}(0, I),则 Xt=ψt(X0∣z)=αtz+βtX0∼N(αtz,βt2I)X_t = \psi_t(X_0\mid z) = \alpha_t z + \beta_t X_0 \sim \mathcal{N}(\alpha_t z, \beta_t^2 I):这个流的轨迹恰好服从条件路径。**第二步:从流反推向量场。**流的定义是 ddtψt=ut(ψt)\frac{d}{dt}\psi_t = u_t(\psi_t),即

α˙tz+β˙tx0=ut(αtz+βtx0∣z)对所有 x0.\dot\alpha_t z + \dot\beta_t x_0 = u_t(\alpha_t z + \beta_t x_0\mid z)\quad\text{对所有 } x_0.

把 x=αtz+βtx0x = \alpha_t z + \beta_t x_0 换回来(x0=(x−αtz)/βtx_0 = (x - \alpha_t z)/\beta_t),整理得

 ut(x∣z)=(α˙t−β˙tβtαt)z+β˙tβtx \boxed{\ u_t(x\mid z) = \Big(\dot\alpha_t - \frac{\dot\beta_t}{\beta_t}\alpha_t\Big)z + \frac{\dot\beta_t}{\beta_t}x\ }

这就是原课讲义式 (20)。02 号脚本第 1 部分从 N(0,I)\mathcal{N}(0, I) 出发、对三种调度分别模拟这个 ODE(欧拉 1000 步),粒子在每个时刻都服从 N(αtz,βt2I)\mathcal{N}(\alpha_t z, \beta_t^2 I),t=1t = 1 时全部收缩到 zz。唯一的例外是 SqrtBeta 在 t=1t = 1 时还剩约 0.02 的标准差:它的 β˙t=−1/(21−t)\dot\beta_t = -1/(2\sqrt{1 - t}) 在终点发散,最后几步速度太大,1000 步的欧拉法也跟不上(离散化误差,不是公式错了)。

原课讲义说,条件向量场乍看毫无用处:它只会把所有噪声送到同一个已知的数据点 zz。但它是构造真正的生成向量场的积木。

回归目标的另一种写法。 把 x=αtz+βtϵx = \alpha_t z + \beta_t\epsilon 代入上式,ϵ\epsilon 的系数和 zz 的系数分别化简为

ut(αtz+βtϵ∣z)=α˙tz+β˙tϵ.u_t(\alpha_t z + \beta_t\epsilon\mid z) = \dot\alpha_t z + \dot\beta_t\epsilon.

其实这就是”固定一对 (z,ϵ)(z, \epsilon) 时,粒子 xt=αtz+βtϵx_t = \alpha_t z + \beta_t\epsilon 的速度”:对 tt 求导即得。02 号脚本第 3 部分在 1000 组随机 (z,ϵ,t)(z, \epsilon, t) 上核对了两种写法(最大差 10−1310^{-13} 量级)。训练时用第二种写法,不用除以 βt\beta_t,数值上更稳定。对 CondOT,目标就是 z−ϵz - \epsilon,与 tt 无关。

条件轨迹的形状。 CondOT 的条件流 ψt=tz+(1−t)x0\psi_t = tz + (1 - t)x_0 是从 x0x_0 到 zz 的线段、匀速运动(02 号脚本第 2 部分:欧拉法 5 步就精确到舍入误差)。这就是”条件最优传输”(conditional optimal transport, CondOT)这个名字的来历。其他调度呢?

三种调度的条件轨迹

调度路径长度 / 直线距离t=0.5t = 0.5 时离直线多远速度范围
CondOT1.00000恒为 4.27
SqrtBeta1.05060.443.75 → 111.66
Cosine1.11230.873.92 → 5.66

(x0=(1.5,−2)x_0 = (1.5, -2),z=(3,2)z = (3, 2)。)Cosine 和 SqrtBeta 在中途有 αt+βt>1\alpha_t + \beta_t > 1,点 αtz+βtx0\alpha_t z + \beta_t x_0 比线段离原点更远,轨迹向外鼓出;SqrtBeta 的速度在终点附近暴增到 CondOT 的 26 倍。注意,这些都是条件轨迹;生成时走的是边缘向量场,它的轨迹另当别论(§6.2)。

3.2 边缘化技巧:把条件向量场平均起来

现在是整讲最关键的一步。

定理 9(边缘化技巧):设 ut(x∣z)u_t(x\mid z) 是条件向量场。定义边缘向量场 ut(x)=∫ut(x∣z) pt(x∣z) pdata(z)pt(x) dz.u_t(x) = \int u_t(x\mid z)\,\frac{p_t(x\mid z)\,p_{\text{data}}(z)}{p_t(x)}\,dz. 则它的 ODE 沿着边缘概率路径走:X0∼pinit, ddtXt=ut(Xt)⇒Xt∼ptX_0 \sim p_{\text{init}},\ \frac{d}{dt}X_t = u_t(X_t) \Rightarrow X_t \sim p_t。特别地,X1∼pdataX_1 \sim p_{\text{data}}:边缘向量场把噪声变成数据。

公式里的权重 pt(x∣z)pdata(z)pt(x)\frac{p_t(x\mid z)p_{\text{data}}(z)}{p_t(x)} 就是贝叶斯公式(P1 §3.1)给出的后验:

p(z∣xt=x)=pt(x∣z) pdata(z)pt(x)"看到带噪声的 x 以后,它来自数据点 z 的可能性".p(z \mid x_t = x) = \frac{p_t(x\mid z)\,p_{\text{data}}(z)}{p_t(x)}\quad\text{"看到带噪声的 } x\text{ 以后,它来自数据点 } z \text{ 的可能性"}.

所以边缘向量场可以写成一个条件期望:

ut(x)=E[ ut(xt∣z) ∣ xt=x ]=E[ α˙tz+β˙tϵ ∣ xt=x ].u_t(x) = \mathbb{E}\big[\,u_t(x_t\mid z)\ \big|\ x_t = x\,\big] = \mathbb{E}\big[\,\dot\alpha_t z + \dot\beta_t\epsilon\ \big|\ x_t = x\,\big].

原课讲义的直觉是:对每个可能的数据点 zz,取”把我带到 zz 的速度” ut(x∣z)u_t(x\mid z),再按”我相信 xx 来自 zz 的程度”加权平均。

第 1 讲的”理想向量场” E[z−ϵ∣xt=x]\mathbb{E}[z - \epsilon \mid x_t = x] 正是 CondOT 路径的边缘向量场。gmm_oracle.py 把它推广到任意调度:当 pdatap_{\text{data}} 是高斯混合时,后验可以按成分精确算出(每个成分内用 P1 练习 3 的高斯条件化公式)。

只用数据样本也能估计它。 把式中的 pdatap_{\text{data}} 换成 mm 个样本、后验换成归一化的权重 wj∝N(x;αtzj,βt2I)w_j \propto \mathcal{N}(x; \alpha_t z_j, \beta_t^2 I),就得到一个蒙特卡洛估计(自归一化重要性采样)。03 号脚本第 1 部分在 4 个点上与闭式解比较(10 次平均的误差):

数据样本数 mm101001,00010,000100,000
t=0.3t = 0.31.700.210.0840.0260.010
t=0.7t = 0.75.181.780.750.320.24

估计确实收敛到边缘向量场,验证了”后验加权平均”的直觉。但 tt 越大,后验越集中在少数几个数据点上(权重”退化”),需要的样本多得多;而且这种估计要对每个查询点遍历大量数据。流匹配用回归绕开了它:网络在训练中自动完成这个”后验平均”(§4)。

条件轨迹 vs 边缘轨迹。 条件路径的定义本身就提供了一种”走法”:每个粒子配一个随机的数据点,沿条件轨迹(CondOT 时是直线)走过去。它在每个时刻的分布当然就是 ptp_t。边缘向量场则用一个确定的 ODE 实现了同一条分布路径。03 号脚本第 3 部分在一维两峰数据上比较两者(2000 个粒子):

时刻条件直线:与 ptp_t 的距离边缘 ODE:与 ptp_t 的距离
t=0.5t = 0.5+0.0020−0.0005
t=1t = 1+0.0039−0.0010

分布都对;但按起点排序后,终点顺序颠倒的相邻对数:条件直线 1024 对(共 1999 对),边缘 ODE 0 对。

条件轨迹 vs 边缘轨迹

条件直线大量交叉:起点在下面的粒子可能被配到上面的峰。边缘向量场在每个点上把所有”路过这里的条件速度”取平均,相当于把交叉的直线”理顺”成互不相交的曲线(第 1 讲 §2.5:ODE 的轨迹不能交叉)。

3.3 连续性方程

为什么平均以后的向量场恰好沿着 ptp_t 走?证明需要一个基本工具。

定理 11(连续性方程):从 X0∼p0X_0 \sim p_0 出发的流模型 ddtXt=ut(Xt)\frac{d}{dt}X_t = u_t(X_t) 满足 Xt∼ptX_t \sim p_t(对所有 tt),当且仅当 ∂tpt(x)=−div⁡(ptut)(x)对所有 x 和 t.\partial_t p_t(x) = -\operatorname{div}\big(p_t u_t\big)(x)\quad\text{对所有 } x \text{ 和 } t.

直觉(P1 §5.2):ptutp_t u_t 是”概率的流量”(密度 × 速度);散度是单位体积的净流出,负散度就是净流入。左边是某处概率密度随时间的变化率,右边是流入该处的净概率质量。概率总量守恒(积分永远是 1),两边必须相等。P1 §6.3 从”跟着粒子走”的角度推出过同一个方程:ddtlog⁡pt(Xt)=−div⁡ut(Xt)\frac{d}{dt}\log p_t(X_t) = -\operatorname{div}u_t(X_t)。

03 号脚本第 2 部分在 30×30 的网格上用有限差分检验(五峰数据,闭式的 ptp_t 和 utu_t):

调度时刻边缘向量场的相对残差把速度放大 10% 后的残差
CondOT0.3 / 0.6 / 0.91.8e−7 / 3.8e−7 / 5.0e−70.10 / 0.10 / 0.10
Cosine0.3 / 0.6 / 0.99.5e−8 / 9.9e−8 / 1.7e−70.10 / 0.10 / 0.10

边缘向量场在有限差分的精度内处处满足连续性方程;速度放大 10%,残差立刻变成 10% 量级。

3.4 边缘化技巧的证明

有了连续性方程,证明定理 9 只需验证 ut(x)u_t(x) 满足它。原课讲义的推导只有五步:

∂tpt(x)=(i)∂t ⁣∫pt(x∣z) pdata(z) dz=∫∂tpt(x∣z) pdata(z) dz=(ii)∫−div⁡(pt(⋅∣z) ut(⋅∣z))(x) pdata(z) dz=(iii)−div⁡(∫pt(x∣z) ut(x∣z) pdata(z) dz)=(iv)−div⁡(pt(x)∫ut(x∣z) pt(x∣z) pdata(z)pt(x) dz)=(v)−div⁡(pt ut)(x).\begin{aligned} \partial_t p_t(x) &\overset{(i)}{=} \partial_t\!\int p_t(x\mid z)\,p_{\text{data}}(z)\,dz = \int \partial_t p_t(x\mid z)\,p_{\text{data}}(z)\,dz\\ &\overset{(ii)}{=} \int -\operatorname{div}\big(p_t(\cdot\mid z)\,u_t(\cdot\mid z)\big)(x)\,p_{\text{data}}(z)\,dz\\ &\overset{(iii)}{=} -\operatorname{div}\Big(\int p_t(x\mid z)\,u_t(x\mid z)\,p_{\text{data}}(z)\,dz\Big)\\ &\overset{(iv)}{=} -\operatorname{div}\Big(p_t(x)\int u_t(x\mid z)\,\frac{p_t(x\mid z)\,p_{\text{data}}(z)}{p_t(x)}\,dz\Big)\\ &\overset{(v)}{=} -\operatorname{div}\big(p_t\,u_t\big)(x). \end{aligned}

(i) 用边缘路径的定义,交换求导和积分;(ii) 每条条件路径各自满足连续性方程(因为 ut(⋅∣z)u_t(\cdot\mid z) 是它的条件向量场);(iii) 散度是对 xx 的线性运算,可以和对 zz 的积分交换;(iv) 乘以再除以 pt(x)p_t(x);(v) 括号里正是边缘向量场的定义。

这个证明的精髓在 (ii)→(iii):连续性方程对向量场是”线性”的(流量 p up\,u 可以叠加)。每条条件路径都守恒,它们的叠加也守恒;而叠加后的总流量除以总密度,就是后验加权平均的速度。

3.5 一个陷阱:有限数据集上的精确解只会背诵

如果把 pdatap_{\text{data}} 换成一个有限的训练集 {z1,…,zN}\{z_1, \dots, z_N\}(真实训练的情形),边缘向量场仍然可以精确算出:后验是对 NN 个点的 softmax(gmm_oracle.EmpiricalOracle)。它生成什么?03 号脚本第 4 部分(2000 个噪声起点,欧拉 500 步):

训练点数 NN向量场与某个训练点距离 < 0.01到最近训练点的中位距离
20训练集上的精确最优场100%0.0000
20真实分布的边缘场(对照)0.1%0.361
200训练集上的精确最优场100%0.0000
2000训练集上的精确最优场100%0.0000
2000真实分布的边缘场(对照)6.9%0.033

精确最优场背诵训练集

训练集上的精确边缘向量场把每个噪声都送到某一个训练点上:它的边缘路径在 t=1t = 1 时是”训练点上的 δ 函数之和”,只能复现训练集。§4 会看到,这正是条件流匹配损失在有限数据上的全局最优解。真实的生成模型能产生新样本,恰恰是因为神经网络没有精确学到这个解(§6.3)。

📌 代码 02、03:python3 02_conditional_vector_fields.py、python3 03_marginalization_trick.py。


4. 损失 · Learning the marginal vector field

4.1 流匹配损失:理想但算不出来

我们想让网络等于边缘向量场。最自然的做法是均方误差,即流匹配损失:

LFM(θ)=Et∼Unif, x∼pt∥utθ(x)−ut(x)∥2=Et, z∼pdata, x∼pt(⋅∣z)∥utθ(x)−ut(x)∥2.\mathcal{L}_{\text{FM}}(\theta) = \mathbb{E}_{t\sim\mathrm{Unif},\ x\sim p_t}\big\lVert u_t^\theta(x) - u_t(x)\big\rVert^2 = \mathbb{E}_{t,\ z\sim p_{\text{data}},\ x\sim p_t(\cdot\mid z)}\big\lVert u_t^\theta(x) - u_t(x)\big\rVert^2.

第二个等号用了边缘路径的采样方法。原课讲义的描述是:随机抽一个时间 tt,从数据集里抽一个 zz,加点噪声得到 xx,算网络输出和边缘向量场的均方误差。问题在于 ut(x)u_t(x) 是一个对所有数据的积分,算不出来。

4.2 条件流匹配损失,以及定理 12

把边缘向量场换成条件向量场,就得到条件流匹配损失:

LCFM(θ)=Et, z, x∼pt(⋅∣z)∥utθ(x)−ut(x∣z)∥2.\mathcal{L}_{\text{CFM}}(\theta) = \mathbb{E}_{t,\ z,\ x\sim p_t(\cdot\mid z)}\big\lVert u_t^\theta(x) - u_t(x\mid z)\big\rVert^2.

条件向量场有公式,所以这个损失很容易算。可是,对着条件向量场回归有什么意义?我们要的是边缘向量场啊。答案是:

定理 12:LFM(θ)=LCFM(θ)+C\mathcal{L}_{\text{FM}}(\theta) = \mathcal{L}_{\text{CFM}}(\theta) + C,其中 CC 与 θ\theta 无关。因此 ∇θLFM=∇θLCFM\nabla_\theta\mathcal{L}_{\text{FM}} = \nabla_\theta\mathcal{L}_{\text{CFM}};用随机梯度下降最小化 LCFM\mathcal{L}_{\text{CFM}},就等价于最小化 LFM\mathcal{L}_{\text{FM}}。特别地,若网络足够灵活,LCFM\mathcal{L}_{\text{CFM}} 的最小值点满足 utθ⋆=utu_t^{\theta^\star} = u_t。

用 P1 的语言,证明只有两行。 记回归目标 T=ut(xt∣z)T = u_t(x_t\mid z)(一个随机变量,依赖于 zz 和 ϵ\epsilon),输入是 (xt,t)(x_t, t)。§3.2 刚说过,边缘向量场是 TT 的条件期望:ut(x)=E[T∣xt=x]u_t(x) = \mathbb{E}[T \mid x_t = x]。于是由 P1 §4.3 的均方误差分解:

E∥utθ(xt)−T∥2⏟LCFM=E∥T−E[T∣xt,t]∥2⏟C = E[Var⁡(T∣xt,t)]+E∥E[T∣xt,t]−utθ(xt)∥2⏟LFM.\underbrace{\mathbb{E}\lVert u_t^\theta(x_t) - T\rVert^2}_{\mathcal{L}_{\text{CFM}}} = \underbrace{\mathbb{E}\lVert T - \mathbb{E}[T\mid x_t, t]\rVert^2}_{C\ =\ \mathbb{E}[\operatorname{Var}(T\mid x_t, t)]} + \underbrace{\mathbb{E}\lVert \mathbb{E}[T\mid x_t, t] - u_t^\theta(x_t)\rVert^2}_{\mathcal{L}_{\text{FM}}}.

**对嘈杂的目标做回归,等于对它的条件期望做回归再加一个常数。**条件目标 TT 是”嘈杂但有公式”的,它的条件期望(边缘向量场)是”干净但算不出来”的,而均方误差恰好让两者的梯度相同。原课讲义给的是一个直接展开的证明(把平方展开、交叉项里代入式 (18)、再用积分的线性),本质是同一件事。

这也解释了”条件期望”在这门课里为什么如此重要:只要损失是均方误差,网络学到的就是目标的条件期望,不管目标本身多么嘈杂。第 3 讲的去噪得分匹配会再用一次同样的论证。

4.3 数值验证:常数 C 是多少

04 号脚本第 1 部分在五峰数据、CondOT 路径上,用 20 万个分层样本(tt 取 100 个等分点)对五个”模型”同时算两个损失:

模型LCFM\mathcal{L}_{\text{CFM}}LFM\mathcal{L}_{\text{FM}}差
零场 u=0u = 018.347611.49596.8517
未训练的网络18.410311.55826.8521
训练 200 步8.82432.00326.8212
训练 3000 步6.89770.07966.8181
理想向量场本身6.81840.00006.8184

直接计算的 C=EtEx[Var⁡(T∣xt)]=6.8205C = \mathbb{E}_t\mathbb{E}_x[\operatorname{Var}(T\mid x_t)] = 6.8205(GaussianPathGMMOracle.target_variance 用全方差公式算出每个点的条件方差)。LFM\mathcal{L}_{\text{FM}} 从 11.5 到 0 相差上百倍,差值却几乎不变(0.5% 以内的出入是抽样误差)。

两个重要推论:

  • 条件流匹配损失的最小值不是 0,而是 CC。理想向量场自己的 LCFM=6.82\mathcal{L}_{\text{CFM}} = 6.82。训练曲线停在 CC 附近不再下降是正常的,那是目标里不可约的噪声(P2 §3.3)。
  • 损失值几乎不反映模型的好坏。“训练 3000 步”与”理想向量场”的 LCFM\mathcal{L}_{\text{CFM}} 只差 0.08(1%),而前者生成的样本仍有可见的瑕疵(§5)。

4.4 代价:梯度噪声更大

既然期望相同,用 LCFM\mathcal{L}_{\text{CFM}} 有什么代价?04 号脚本第 2 部分取”训练 200 步”的网络,先在 20 万个样本上算两个完整梯度:余弦相似度 0.993(相对差 12%,说明即使 20 万个样本,条件目标的梯度噪声也不小)。再看小批量梯度与”真梯度”的余弦相似度(50 次平均):

批大小用条件目标(LCFM\mathcal{L}_{\text{CFM}})用边缘场(LFM\mathcal{L}_{\text{FM}},实际中拿不到)
640.1920.281
2560.3130.539
10240.5760.769
40960.7180.911

同样的批大小下,条件目标的梯度噪声明显更大:目标里多了一份随机性(“这个 xx 究竟来自哪个 zz”)。这里用条件目标、批大小 4096 的梯度质量,大致只相当于用边缘场、批大小 1024 的水平。这就是”用能算的目标代替算不出的目标”的代价,也是流匹配常用大批量的原因之一(原课 Lab 2 用 1000)。

4.5 噪声来自哪里:常数 C 随时间的分布

CC 是对 tt 平均的结果。按时刻分开看(04 号脚本第 3 部分),C(t)=Ex∼pt[Var⁡(T∣xt=x)]C(t) = \mathbb{E}_{x\sim p_t}[\operatorname{Var}(T\mid x_t = x)]:

tt00.10.30.50.70.90.99
CondOT15.0316.8910.942.491.902.292.04
Cosine37.0831.6312.183.072.394.374.93

以 CondOT 为例:t=0t = 0 时 xtx_t 就是噪声 ϵ\epsilon,完全看不出数据点在哪,目标 z−ϵz - \epsilon 的条件方差等于数据的总方差 tr⁡Cov⁡(z)=15.03\operatorname{tr}\operatorname{Cov}(z) = 15.03。t→1t \to 1 时 xt≈zx_t \approx z,数据点已经确定,但噪声 ϵ\epsilon 看不出来,条件方差趋于 tr⁡Cov⁡(ϵ)=2\operatorname{tr}\operatorname{Cov}(\epsilon) = 2。中间某处最小。所以条件流匹配损失的大部分”地板”来自 tt 接近 0 的那一段,那里的回归目标几乎是纯噪声。很多论文因此对 tt 做非均匀采样或给损失加权(例如 SD3 用”logit-normal”分布把 tt 的采样集中在中间段,第 5 讲会再谈),本质上是在决定把训练的”注意力”分给哪一段时间。

4.6 高斯路径的流匹配,以及 Algorithm 3

把高斯路径的公式代进去,条件流匹配损失变成(原课讲义式 (30)–(31)):

LCFM(θ)=Et∼Unif, z∼pdata, ϵ∼N(0,I)∥utθ(αtz+βtϵ)−(α˙tz+β˙tϵ)∥2.\mathcal{L}_{\text{CFM}}(\theta) = \mathbb{E}_{t\sim\mathrm{Unif},\ z\sim p_{\text{data}},\ \epsilon\sim\mathcal{N}(0,I)}\big\lVert u_t^\theta(\alpha_t z + \beta_t\epsilon) - (\dot\alpha_t z + \dot\beta_t\epsilon)\big\rVert^2.

对 CondOT:

LCFM(θ)=E∥utθ(tz+(1−t)ϵ)−(z−ϵ)∥2.\mathcal{L}_{\text{CFM}}(\theta) = \mathbb{E}\big\lVert u_t^\theta\big(tz + (1 - t)\epsilon\big) - (z - \epsilon)\big\rVert^2.

原课讲义说:“抽一个数据点、抽一点噪声,然后算一个均方误差。“slides 把这两个量叫”噪声与数据的直线插值”和”数据与噪声之差”。

Algorithm 3  流匹配训练(CondOT 高斯路径)
输入:数据集,神经网络 u^θ
for 每个小批量:
    从数据集抽 z;抽 t ~ Unif[0, 1];抽 ε ~ N(0, I)
    x ← t·z + (1 − t)·ε                    (一般情形:x ~ p_t(·|z))
    L(θ) ← ‖u^θ_t(x) − (z − ε)‖²            (一般情形:‖u^θ_t(x) − u_t(x|z)‖²)
    θ ← 梯度更新(L(θ))

对应的 Python(fm_lib.py,节选):

for step in range(1, steps + 1):
    z = sample_data(batch, g)                            # 数据点
    t = torch.rand(batch, 1, generator=g) * (1 - 1e-4)  # 时间,形状 (n, 1);避开 t = 1
    noise = torch.randn(z.shape, generator=g)            # ε
    x = path.sample_conditional(z, t, noise)             # x_t = α_t z + β_t ε
    target = path.target(z, noise, t)                    # α̇_t z + β̇_t ε(CondOT:z − ε)
    pred = model(x, t)
    assert pred.shape == target.shape                    # P2 §1.2 的广播 bug
    loss = ((pred - target) ** 2).sum(dim=1).mean()
    opt.zero_grad(); loss.backward(); opt.step()

原课讲义列出了这个算法三个”惊人”的特点:

  1. 不需要模拟(simulation-free):训练时从不模拟 ODE,也不需要散度和行列式(对比 §1 的最大似然)。
  2. 就是回归:和监督学习没什么两样,只是目标带噪声。
  3. 极其简单:很难想象比这更简单的训练目标。

原课讲义提到,Stable Diffusion 3、Meta Movie Gen 等模型都是用这个简单的过程训练的。训练好以后,用第 1 讲的 Algorithm 1 采样即可。整套流程在文献里叫流匹配(flow matching)。

📌 代码 04:python3 04_fm_vs_cfm_loss.py。


5. 实验:训练一个流匹配模型 · Training

5.1 训练过程:看样本,不要看损失

05 号脚本第 1 部分按原课 Lab 2 的设置训练:4 个 64 宽的隐藏层(SiLU),5000 步,批大小 1000,Adam、学习率 10−310^{-3},五峰数据,CondOT 路径。每 500 步记录训练损失、真实误差 LFM\mathcal{L}_{\text{FM}}(只因数据分布已知才能算)和生成样本的质量(欧拉 100 步):

步数训练损失减去下限 CLFM\mathcal{L}_{\text{FM}}样本能量距离权重误差 TV落在峰之间
5008.807+1.9870.4740.01010.0482.5%
10007.084+0.2640.1660.00900.0301.1%
20006.928+0.1080.0920.00220.0420.8%
30006.917+0.0970.0770.00330.0210.5%
40006.871+0.0510.0690.00260.0220.3%
50006.890+0.0700.0370.00020.0330.6%

训练只用了约 5 秒。训练损失很快贴近下限 C≈6.82C \approx 6.82,之后在 +0.05 到 +0.1 之间随批量噪声上下波动;真实误差 LFM\mathcal{L}_{\text{FM}} 却一直在下降(0.47 → 0.037)。样本指标的变化更”粗”:能量距离在 1500 步后就进入噪声地板,权重误差在 0.01–0.04 之间波动,“落在峰之间”的比例从 2.5% 缓慢降到约 0.5%。

实践中怎样判断训练进度? 真实问题里 LFM\mathcal{L}_{\text{FM}} 算不出来,损失又几乎不动,所以只能定期生成样本,用合适的指标(图像上常用 FID 等)去评估。这是训练扩散 / 流模型时的普遍做法。

5.2 训练好的网络 vs 理想向量场

05 号脚本第 2 部分让网络和理想场从同一批噪声出发,比较不同步数(能量距离 / 权重误差 / 落在峰之间):

欧拉步数网络理想向量场
12.541 / 0.709 / 100%2.775 / 0.750 / 100%
40.078 / 0.063 / 7.1%0.081 / 0.081 / 2.7%
160.0031 / 0.029 / 0.9%0.0016 / 0.025 / 0.1%
100−0.0006 / 0.033 / 0.2%−0.0023 / 0.021 / 0.0%

步数够多时,网络样本的能量距离也在噪声地板以内;同一个噪声起点,网络与理想场的终点距离中位数只有 0.066(峰的标准差是 0.4)。但细看仍略差:权重误差 0.033 vs 0.021,峰之间 0.2% vs 0.0%。步数很少时,两者一样塌缩、模糊(第 1 讲 §3.6),少步误差主要由 ODE 本身的弯曲决定。(n=1n = 1 时网络没有完全塌缩到 E[z]\mathbb{E}[z],因为它在 t=0t = 0 处学到的场和 E[z]−x\mathbb{E}[z] - x 有偏差。)

5.3 网络在哪个时间段学得最差

05 号脚本第 3 部分按时刻分开算 Ex∼pt∥utθ−ut∥2\mathbb{E}_{x\sim p_t}\lVert u_t^\theta - u_t\rVert^2:

tt00.20.40.60.80.99
均方误差0.0650.0240.0290.0470.0340.093
相对误差1.97%0.84%0.23%0.28%0.21%0.57%

相对误差在两端最大。t=0t = 0 处的理想场只是线性的 E[z]−x\mathbb{E}[z] - x,按理最好学,但那里回归目标最吵(§4.5:C(0)≈15C(0) \approx 15,全程最大),网络对一个很吵的目标做回归,估计误差自然最大。t→1t \to 1 时理想场在峰附近变化剧烈(每个峰都在”收紧”),绝对误差也变大。中段反而最准。“哪一段时间最难”取决于用什么衡量,这也是”怎样分配 tt 的采样”会成为一个设计问题的原因。

5.4 没有闭式解的数据

05 号脚本第 4 部分不改任何超参数,在原课 Lab 2 的另外三个数据集上训练(能量距离;噪声地板是两批真样本之间的距离):

数据生成样本噪声地板对照:纯噪声
双月牙−0.0012−0.00110.758
棋盘格0.0035+0.00161.066
同心圆0.0005−0.00130.995

流匹配生成的样本

同一套代码就能学会这些形状:流匹配只需要数据样本。双月牙、同心圆的能量距离在噪声地板以内;棋盘格略高。但能量距离对”尖锐的边”不敏感:棋盘格的生成样本有 15.1% 落在白格或方块外(真实数据是 0%),图上方块被抹成了圆团。这个小网络、5000 步学不出锐利的边界(练习 6 看更长的训练)。一个教训:评估生成模型时,单一的分布指标往往不够,要结合问题本身的结构去看。

📌 代码 05:python3 05_train_flow_matching.py(约 20 秒;--quick 是几秒钟的冒烟测试)。


6. 推广与局限 · Extensions and caveats

6.1 任意分布之间的搭桥

推导流匹配时,我们从没用到”pinitp_{\text{init}} 是高斯”。原课 Lab 2 第 4 部分的线性路径:

xt=(1−t) x0+t z,x0∼pinit (任意), z∼pdata,x_t = (1 - t)\,x_0 + t\,z,\qquad x_0 \sim p_{\text{init}}\ (\text{任意}),\ z \sim p_{\text{data}},

条件向量场 ut(x∣z)=(z−x)/(1−t)u_t(x\mid z) = (z - x)/(1 - t),回归目标就是 z−x0z - x_0。只要能从两个分布各自采样,就能在它们之间训练一个流。06 号脚本第 1 部分让同心圆直接”流”成双月牙:

起点分布与双月牙的能量距离
同心圆(线性路径)0.0025
N(0,I)\mathcal{N}(0, I)(CondOT 高斯路径,对照)0.0029
噪声地板−0.0016

从同心圆流到双月牙

原课 Lecture 3 的 slides 举了几个应用:无声视频 → 有声视频、低分辨率图像 → 高分辨率图像、未扰动的细胞 → 扰动后的细胞。高斯起点的特殊之处只在于:它的条件路径有得分函数的公式(第 3 讲需要),而且对称、容易采样。

6.2 调度的选择:没有一个放之四海而皆准的答案

一个常见的说法是:“CondOT 的轨迹最直,所以少步采样最好;这是 SD3 选择 rectified flow 的原因。“我们在玩具数据上检验了这个说法,结果并不支持它。

先用理想边缘向量场比较(排除训练误差,06 号脚本第 2 部分):

调度路径长度/直线距离(中位数)最大速度(中位数)n=2n = 2n=4n = 4n=8n = 8n=64n = 64
CondOT1.04954.40.5510.0870.0210.0035
SqrtBeta1.04324.10.4180.0740.0170.0034
Cosine1.04355.00.3290.0660.0180.0039

(后四列是欧拉 nn 步样本的能量距离。)在这份数据上,CondOT 的边缘轨迹反而略弯一些,少步(n=2,4n = 2, 4)的质量也略差。SqrtBeta 的条件轨迹在终点速度暴增(§3.1),边缘轨迹却很平稳。三者的差别其实都不大(路径长度只差约 0.6%,n≥16n \ge 16 后几乎相同)。再看训练出来的网络(第 3 部分;能量距离 / TV / 峰之间):

调度n=4n = 4n=8n = 8n=100n = 100
CondOT0.111 / 0.088 / 8.2%0.033 / 0.043 / 2.1%0.0086 / 0.021 / 0.5%
SqrtBeta0.080 / 0.056 / 13.8%0.021 / 0.036 / 4.7%0.0039 / 0.022 / 0.8%
Cosine0.099 / 0.097 / 7.2%0.039 / 0.056 / 2.5%0.014 / 0.034 / 0.7%

没有一致的赢家:n=4n = 4 时 SqrtBeta 的能量距离最小、落在峰之间的样本却最多;不同指标给出不同的排序。练习 7 还表明,把数据缩放到不同的尺度,排序会再变。

怎样理解?

  • “条件轨迹是直线”不等于”边缘轨迹是直线”。 CondOT 保证的是每一条条件轨迹是直线;边缘轨迹是它们的后验平均,弯不弯取决于数据分布本身(粒子要先”决定”去哪个峰)。
  • 调度的优劣要在真实数据上用大规模实验判断。 SD3 的论文(Esser et al., 2024)在图像上系统比较了多种路径与时间采样方式,报告 rectified flow(即 CondOT)配合非均匀的时间采样整体表现最好。那是在高维图像、大模型上的经验结论,不是一个对所有数据都成立的定理。二维玩具上的结果不能直接推广到图像,反过来也一样。

6.3 训练出来的网络会背诵吗?

§3.5 说,有限训练集上的精确最优解只会复现训练点。那么用这 20 个训练点训练一个网络(06 号脚本第 4 部分),它生成什么?

生成方式离某个训练点 < 0.05到最近训练点的中位距离
训练集上的精确最优场100%0.000
网络,训练 5000 步7.4%0.155
网络,训练 20000 步47.8%0.053
真实分布的边缘场(对照)2.3%0.336

训练出来的网络介于背诵和泛化之间

网络介于两者之间:它的样本明显向训练点聚拢。5000 步时,样本铺在相邻训练点之间的连线上,像是在训练点之间”插值”;训练到 20000 步时,近一半样本离某个训练点不到 0.05,网络在一点点逼近那个”背诵”的最优解。

这个现象在大规模扩散模型上也被观察到:训练数据越少、训练越久,越容易复现训练图像(Somepalli et al., 2023;Carlini et al., 2023)。反过来说,扩散 / 流模型能生成新样本,靠的是网络学不准那个精确最优解:容量有限、训练有限、神经网络倾向于光滑的函数。为什么”学不准”恰好产生了”好的新样本”,是一个活跃的研究问题。

📌 代码 06:python3 06_bridging_and_schedules.py(约 50 秒;--quick 是几秒钟的冒烟测试)。


7. 全景 · The big picture

7.1 原课的总结(Summary 14)

流匹配训练的是边缘向量场 utu_t。构造它的步骤:

  1. 选一条条件概率路径 pt(x∣z)p_t(x\mid z),满足 p0(⋅∣z)=pinitp_0(\cdot\mid z) = p_{\text{init}}、p1(⋅∣z)=δzp_1(\cdot\mid z) = \delta_z;
  2. 找一个条件向量场 ut(x∣z)u_t(x\mid z),它的流把 pinitp_{\text{init}} 变成 pt(⋅∣z)p_t(\cdot\mid z)(等价地:满足连续性方程);
  3. 边缘向量场 ut(x)=∫ut(x∣z)pt(x∣z)pdata(z)pt(x)dzu_t(x) = \int u_t(x\mid z)\frac{p_t(x\mid z)p_{\text{data}}(z)}{p_t(x)}dz 沿边缘路径走,把噪声变成数据;
  4. 最小化条件流匹配损失 LCFM\mathcal{L}_{\text{CFM}} 来学习它。

对高斯路径:

pt(x∣z)=N(αtz,βt2I),ut(x∣z)=(α˙t−β˙tβtαt)z+β˙tβtx,LCFM=E∥utθ(αtz+βtϵ)−(α˙tz+β˙tϵ)∥2.p_t(x\mid z) = \mathcal{N}(\alpha_t z, \beta_t^2 I),\quad u_t(x\mid z) = \Big(\dot\alpha_t - \tfrac{\dot\beta_t}{\beta_t}\alpha_t\Big)z + \tfrac{\dot\beta_t}{\beta_t}x,\quad \mathcal{L}_{\text{CFM}} = \mathbb{E}\big\lVert u_t^\theta(\alpha_t z + \beta_t\epsilon) - (\dot\alpha_t z + \dot\beta_t\epsilon)\big\rVert^2.

7.2 文献里的名字

同一个想法在 2022–2023 年被几组人独立提出,名字不同:

名字论文在本讲的语言里
Flow Matching / Conditional Flow MatchingLipman et al., ICLR 2023本讲的框架;“CondOT”路径
Rectified FlowLiu, Gong & Liu, ICLR 2023CondOT 路径(直线插值)+ 训练 z−ϵz - \epsilon;另有”reflow”把轨迹拉直(扩展讲第 7 讲)
Stochastic InterpolantsAlbergo & Vanden-Eijnden, ICLR 2023用”插值函数” I(t,x0,z)I(t, x_0, z) 构造路径,包含 ODE 和 SDE 两种走法;与本讲大体等价
Denoising Diffusion(DDPM 等)Ho et al., 2020;Song et al., 2021某些高斯路径(方差保持 / 方差爆炸)+ 预测噪声或得分;第 3 讲会对照

原课讲义附录 E 的说法是:对高斯路径,这些框架本质上是等价的;流匹配的优点在于简单和通用(任意 pinitp_{\text{init}},任意路径)。


8. 小结 · Summary

  1. 问题:没有现成的”正确向量场”,最大似然又太贵。流匹配先设计概率路径,再反推向量场,最后用回归学它。
  2. 概率路径:条件路径 pt(⋅∣z)p_t(\cdot\mid z) 从噪声收缩到一个数据点;边缘路径 pt=∫pt(⋅∣z)pdata(z)dzp_t = \int p_t(\cdot\mid z)p_{\text{data}}(z)dz 从噪声插值到数据,能采样、算不出密度。高斯路径 N(αtz,βt2I)\mathcal{N}(\alpha_t z, \beta_t^2 I) 由调度决定;概率路径只规定快照,不唯一确定向量场。
  3. 条件向量场 ut(x∣z)=(α˙t−β˙tβtαt)z+β˙tβtxu_t(x\mid z) = (\dot\alpha_t - \frac{\dot\beta_t}{\beta_t}\alpha_t)z + \frac{\dot\beta_t}{\beta_t}x;在 x=αtz+βtϵx = \alpha_t z + \beta_t\epsilon 处等于 α˙tz+β˙tϵ\dot\alpha_t z + \dot\beta_t\epsilon(CondOT:z−ϵz - \epsilon)。
  4. 边缘化技巧:边缘向量场 = 条件向量场按后验加权平均 = E[α˙tz+β˙tϵ∣xt=x]\mathbb{E}[\dot\alpha_t z + \dot\beta_t\epsilon \mid x_t = x],它沿边缘路径走。证明靠连续性方程和它对流量的线性。边缘轨迹不交叉,是交叉的条件轨迹的”理顺”版本。
  5. 定理 12:LFM=LCFM+C\mathcal{L}_{\text{FM}} = \mathcal{L}_{\text{CFM}} + C,C=E[Var⁡(条件目标∣xt)]C = \mathbb{E}[\operatorname{Var}(\text{条件目标}\mid x_t)]。梯度相同,但条件目标的梯度噪声更大;损失的最小值是 CC 而不是 0,大部分来自 tt 接近 0 的那一段。
  6. Algorithm 3:抽 zz、tt、ϵ\epsilon → x=αtz+βtϵx = \alpha_t z + \beta_t\epsilon → 回归 α˙tz+β˙tϵ\dot\alpha_t z + \dot\beta_t\epsilon。不模拟 ODE、就是回归、极其简单。评估要看样本,不看损失。
  7. 推广与局限:线性路径能在任意两个分布之间搭桥;调度的优劣没有普适答案;有限数据上的精确最优解只会背诵训练集,训练出来的网络介于背诵与泛化之间,训练越久越靠近背诵。

9. 常见误区 · Common pitfalls

  1. “条件流匹配学到的是条件向量场。” 网络的输入里没有 zz,它看到的只是 xtx_t 和 tt。用均方误差回归,它学到的是条件目标在给定 (xt,t)(x_t, t) 时的条件期望——边缘向量场(§4.2)。
  2. “训练损失降不到 0,说明模型或代码有问题。” 损失的最小值是 C>0C > 0(本讲的例子里约 6.82),而且损失值几乎不反映模型质量(§4.3、§5.1)。
  3. “CondOT 的生成轨迹是直线。” 条件轨迹是直线;生成时走的边缘轨迹一般是曲线(§6.2)。
  4. “流匹配训练时要模拟 ODE。” 训练时完全不模拟;只有采样时才模拟(§4.6)。
  5. “边缘概率路径确定了向量场。” 同一条路径可以由无穷多个向量场实现,例如加上一个沿等高线的旋转场(§2.4)。
  6. ”pinitp_{\text{init}} 必须是高斯。” 对线性路径,任何能采样的分布都可以(§6.1)。高斯的好处是条件得分有公式(第 3 讲)。
  7. “把损失训练到最低就是最好的模型。” 在有限数据上,LCFM\mathcal{L}_{\text{CFM}} 的全局最优解只会背诵训练集(§3.5、§6.3)。
  8. “时间 tt 写成 (n,) 也一样。” 和 (n, d) 的张量相乘时可能触发广播 bug(P2 §1.2)。本讲的代码统一用 (n, 1) 并加了 assert。

10. 练习 · Exercises

练习 1(条件向量场)。对 Cosine 调度 αt=sin⁡πt2\alpha_t = \sin\frac{\pi t}{2}、βt=cos⁡πt2\beta_t = \cos\frac{\pi t}{2},写出 ut(x∣z)u_t(x\mid z) 和回归目标 α˙tz+β˙tϵ\dot\alpha_t z + \dot\beta_t\epsilon。验证在 t=0t = 0 处 u0(x∣z)=π2zu_0(x\mid z) = \frac{\pi}{2}z。

参考答案

α˙t=π2cos⁡πt2\dot\alpha_t = \frac{\pi}{2}\cos\frac{\pi t}{2},β˙t=−π2sin⁡πt2\dot\beta_t = -\frac{\pi}{2}\sin\frac{\pi t}{2},β˙tβt=−π2tan⁡πt2\frac{\dot\beta_t}{\beta_t} = -\frac{\pi}{2}\tan\frac{\pi t}{2}。所以 ut(x∣z)=π2(cos⁡πt2+tan⁡πt2sin⁡πt2)z−π2tan⁡πt2 x=π2(zcos⁡(πt/2)−tan⁡πt2 x)u_t(x\mid z) = \frac{\pi}{2}\big(\cos\frac{\pi t}{2} + \tan\frac{\pi t}{2}\sin\frac{\pi t}{2}\big)z - \frac{\pi}{2}\tan\frac{\pi t}{2}\,x = \frac{\pi}{2}\big(\frac{z}{\cos(\pi t/2)} - \tan\frac{\pi t}{2}\,x\big)。回归目标 π2(cos⁡πt2 z−sin⁡πt2 ϵ)\frac{\pi}{2}(\cos\frac{\pi t}{2}\,z - \sin\frac{\pi t}{2}\,\epsilon)。t=0t = 0 时 u0=π2zu_0 = \frac{\pi}{2}z:一开始粒子朝 zz 的方向出发,与位置无关。

练习 2(边缘向量场的两个端点)。对 CondOT 路径,证明 u0(x)=E[z]−xu_0(x) = \mathbb{E}[z] - x,u1(x)=xu_1(x) = x(假设数据分布有密度)。用第 1 讲 §3.6 的结论解释 u0u_0 的含义。

参考答案

ut(x)=E[z−ϵ∣xt=x]u_t(x) = \mathbb{E}[z - \epsilon \mid x_t = x]。t=0t = 0 时 x0=ϵx_0 = \epsilon,zz 与 ϵ\epsilon 独立,所以 E[z−ϵ∣ϵ=x]=E[z]−x\mathbb{E}[z - \epsilon\mid\epsilon = x] = \mathbb{E}[z] - x:一开始所有粒子都朝数据的均值走(欧拉法一步就塌缩到 E[z]\mathbb{E}[z])。t=1t = 1 时 x1=zx_1 = z,ϵ\epsilon 与 zz 独立,E[z−ϵ∣z=x]=x−0=x\mathbb{E}[z - \epsilon\mid z = x] = x - 0 = x:终点处的速度就是位置本身(“沿着从原点出发的射线继续向外”,因为 xt=tz+(1−t)ϵx_t = tz + (1-t)\epsilon 在 t→1t \to 1 时的速度 z−ϵz - \epsilon 平均来看就是 zz)。

练习 3(定理 12 的直接证明)。仿照 §4.2,用 P1 §4.3 的分解证明:LCFM−LFM=Et,xt[E[∥T∥2∣xt]−∥ut(xt)∥2]\mathcal{L}_{\text{CFM}} - \mathcal{L}_{\text{FM}} = \mathbb{E}_{t, x_t}\big[\mathbb{E}[\lVert T\rVert^2\mid x_t] - \lVert u_t(x_t)\rVert^2\big],其中 T=α˙tz+β˙tϵT = \dot\alpha_t z + \dot\beta_t\epsilon。它为什么一定非负?什么时候等于 0?

参考答案

由分解,差 =E∥T−E[T∣xt]∥2=E[Var⁡(T∣xt)]= \mathbb{E}\lVert T - \mathbb{E}[T\mid x_t]\rVert^2 = \mathbb{E}[\operatorname{Var}(T\mid x_t)],而条件方差 =E[∥T∥2∣xt]−∥E[T∣xt]∥2= \mathbb{E}[\lVert T\rVert^2\mid x_t] - \lVert\mathbb{E}[T\mid x_t]\rVert^2,后者就是 ∥ut(xt)∥2\lVert u_t(x_t)\rVert^2。方差非负;等于 0 当且仅当几乎处处 TT 由 xtx_t 唯一确定,例如数据分布是单个点 δz0\delta_{z_0} 时(那时 xtx_t 唯一确定 ϵ\epsilon)。

练习 4(线性路径)。对线性路径 xt=(1−t)x0+tzx_t = (1 - t)x_0 + tz,验证 ut(x∣z)=(z−x)/(1−t)u_t(x\mid z) = (z - x)/(1 - t) 是条件向量场,并说明 pinit=N(0,I)p_{\text{init}} = \mathcal{N}(0, I) 时它就是 CondOT 高斯路径。

参考答案

条件流 ψt(x0∣z)=(1−t)x0+tz\psi_t(x_0\mid z) = (1 - t)x_0 + tz,对 tt 求导得 z−x0z - x_0;把 x0=(x−tz)/(1−t)x_0 = (x - tz)/(1 - t) 代入:z−x−tz1−t=z−x1−tz - \frac{x - tz}{1 - t} = \frac{z - x}{1 - t}。若 x0∼N(0,I)x_0 \sim \mathcal{N}(0, I),则 xt∼N(tz,(1−t)2I)x_t \sim \mathcal{N}(tz, (1 - t)^2 I),正是 αt=t\alpha_t = t、βt=1−t\beta_t = 1 - t 的高斯路径;代入式 (20):(1+t1−t)z−x1−t=z−x1−t(1 + \frac{t}{1 - t})z - \frac{x}{1 - t} = \frac{z - x}{1 - t},一致。

练习 5(梯度噪声与批大小)。§4.4 的表里,条件目标需要大约多大的批,才能达到边缘目标批大小 256 时的梯度质量?粗略地用”余弦相似度 ≈ 1/1+σ2/(B∥g∥2)1/\sqrt{1 + \sigma^2/(B\lVert g\rVert^2)}”(σ2\sigma^2 是单样本梯度的方差之和)解释这个现象。

参考答案(提示)

边缘目标 B=256B = 256 时余弦 0.54;条件目标在 B=1024B = 1024 时 0.58,所以大约需要 4 倍的批。按公式,余弦由”噪声 / 信号”比 σ2/(B∥g∥2)\sigma^2/(B\lVert g\rVert^2) 决定;条件目标的单样本方差 σCFM2\sigma^2_{\text{CFM}} 更大(多了”来自哪个 zz“的随机性),要达到同样的余弦,BB 要按 σCFM2/σFM2\sigma^2_{\text{CFM}}/\sigma^2_{\text{FM}} 的比例放大。

练习 6(编程:更长的训练)。在 05_train_flow_matching.py 第 4 部分里,把棋盘格的训练步数改成 20000,再试一次把 make_model 的 hidden 改成 128。“落在白格或方块外”的比例怎样变化?

参考答案(作者机器上的结果)

5000 步、64 宽:15.1%;20000 步、64 宽:约 8.2%(能量距离 0.0022);20000 步、128 宽:约 6.8%(能量距离 0.0024)。训练更久、网络更宽都能让边界更锐利,但能量距离几乎看不出这种改进——再次说明要结合问题本身的结构来评估。(128 宽、20000 步约需 35 秒。)

练习 7(编程:数据的尺度与调度)。把 06_bridging_and_schedules.py 第 2 部分的数据换成 GaussianMixture.ring(5, radius=R, std=R/10, weights=[...]),分别取 R=1,2,8R = 1, 2, 8,比较三种调度的路径长度比和 n=4n = 4 时的能量距离(除以 RR 以便比较)。排序会随 RR 变化吗?

参考答案(作者机器上的结果,300 条轨迹、500 步)
RR路径长度比 CondOT / SqrtBeta / Cosinen=4n = 4 能量距离 / RR
11.430 / 1.149 / 1.1260.020 / 0.038 / 0.007
21.318 / 1.171 / 1.1910.014 / 0.020 / 0.008
41.049 / 1.039 / 1.0450.026 / 0.022 / 0.018
81.015 / 1.014 / 1.0130.081 / 0.063 / 0.079

排序随尺度变化:R=1,2R = 1, 2 时 Cosine 的少步质量明显最好,R=8R = 8 时 SqrtBeta 最好;CondOT 在这几种尺度上都不是最好的。一个可能的解释是:数据离原点近时(RR 小),起点(半径约 1.25 的噪声)和终点(半径 RR)离得不远,“先拐弯决定去哪个峰”在路径长度里占的比例更大。无论原因如何,结论是调度的优劣和数据的尺度纠缠在一起——这也是实践中要把数据标准化(或调整噪声的尺度)的原因之一。

练习 8(思考:为什么不学条件向量场的”条件版本”?)。如果给网络多一个输入 zz,让它学 utθ(x,z)≈ut(x∣z)u_t^\theta(x, z) \approx u_t(x\mid z),能用来生成吗?

参考答案

不能(或者说没有意义):生成时你要先有一个 zz 才能用这个网络,而 zz 正是我们想生成的东西;而且 ut(x∣z)u_t(x\mid z) 有公式,根本不需要学。流匹配的妙处在于网络看不到 zz,只能输出”在所有可能的 zz 上的平均”,而这个平均恰好是能把噪声变成数据的边缘向量场。(第 4 讲的条件生成是另一回事:那里的条件是标签 / 提示 yy,不是数据点 zz。)


11. 延伸阅读 · Further reading

  • 原课讲义第 3 章和 Lab 2(https://github.com/eje24/iap-diffusion-labs ,2026 分支)。Lab 2 用 SqrtBeta 路径实现条件路径、条件向量场和训练,并在第 4 部分做线性路径的搭桥。
  • Lipman et al., Flow Matching for Generative Modeling(ICLR 2023):提出(条件)流匹配,比较了 OT 路径和扩散路径。
  • Liu, Gong & Liu, Flow Straight and Fast: Learning to Generate and Transfer Data with Rectified Flow(ICLR 2023):直线插值 + reflow。
  • Albergo & Vanden-Eijnden, Building Normalizing Flows with Stochastic Interpolants(ICLR 2023);以及 Albergo, Boffi & Vanden-Eijnden, Stochastic Interpolants: A Unifying Framework for Flows and Diffusions(2023)。
  • Lipman et al., Flow Matching Guide and Code(2024,arXiv:2412.06264):系统的教程,配开源库 flow_matching。
  • Esser et al., Scaling Rectified Flow Transformers for High-Resolution Image Synthesis(SD3 论文,ICML 2024):在图像上大规模比较路径与时间采样方式。
  • 记忆与泛化:Somepalli et al., Diffusion Art or Digital Forgery?(CVPR 2023);Carlini et al., Extracting Training Data from Diffusion Models(USENIX Security 2023);以及一系列用”经验最优解会背诵”出发分析扩散模型泛化的近期论文。
  • 交互式可视化:https://mariogemoll.com/flow-matching (slides 里条件 / 边缘路径的动画来自这里)。

12. 下一讲预告 · Next lecture

本讲只用了 ODE。第 1 讲 §5.4 的预告实验表明:给流模型加噪声需要一个修正项 σt22∇log⁡pt\frac{\sigma_t^2}{2}\nabla\log p_t,其中 ∇log⁡pt\nabla\log p_t 是边缘路径的得分函数。第 3 讲要回答:

  1. 得分函数也能像向量场一样,用”条件得分”的回归学出来吗?——去噪得分匹配,这就是”去噪扩散模型”名字的由来。
  2. 对高斯路径,学会向量场和学会得分函数是不是一回事?——一个简单的换算公式说”是”。
  3. 为什么加了修正项的 SDE 对任意 σt\sigma_t 都沿着 ptp_t 走?——Fokker–Planck 方程:连续性方程 + 热方程(P1 §5.3)。
  4. 文献里的 DDPM、DDIM、“前向过程”、“时间反演”,怎样对应到本讲的概率路径?
← 返回课程目录