
Diffusion 模型这两年在生成领域的热度不用我多说从文生图到文生视频从图像修复到统一的多任务生成框架几乎每隔几个月就有新的变体冒出来。但如果你真正动手训过 Diffusion就会发现一个很现实的问题传统的 DDPM 那一套采样过程动辄几百上千步推理成本高得离谱而且训练目标预测噪声 ε和最终采样过程之间的耦合关系并不直观。我最初接触 flow matching 就是因为被采样步数折磨得受不了想找一个更干净、更统一的建模视角。结果一扎进去才发现ODE flow matching 这套东西不仅把采样效率问题讲清楚了还顺带把 Diffusion 的很多玄学设计给解释明白了。这篇内容就是把我从 Diffusion 到 ODE flow matching 这条学习路径上的理解、推导、踩过的坑和实操经验整理出来适合已经了解 Diffusion 基础、想进一步搞懂连续时间建模和高效采样的朋友。不管你是做图像生成、视频生成还是图像修复只要涉及 Diffusion 采样这套思路都能直接用上。1. 为什么传统 Diffusion 的采样让人又爱又恨1.1 DDPM 采样慢的根源到底在哪先说清楚问题。DDPM 的前向过程是把一张干净图片 x₀ 逐步加噪经过 T 步通常 T1000变成近似纯高斯噪声 x_T。反向过程则是从 x_T 出发一步步去噪还原。问题就出在这个一步步上——标准 DDPM 采样必须走完所有 T 步因为每一步的去噪都依赖马尔可夫链的逐步转移你不能跳步一跳就破坏了整个概率路径的假设。我最早跑 DDPM 采样的时候一张 512×512 的图在单卡上要几十秒生成一批图等得我都能去泡杯茶。后来 DDIM 出来了说可以跳步把 1000 步压到 50 步甚至 20 步质量还能接受。但 DDIM 本质上是对采样路径做了确定性化改造它牺牲了一部分随机性而且跳步多了之后细节会糊。再后来各种高阶求解器DPM-Solver、UniPC 之类也来了本质上都是在用更聪明的数值方法去解同一个微分方程。这里有个关键认知转折Diffusion 的反向采样过程本质上就是在解一个常微分方程ODE或者随机微分方程SDE。一旦你接受了这个视角采样步数、求解器选择、路径设计这些问题就全部变成了数值分析和微分方程的问题而不是玄学调参。1.2 从离散马尔可夫链到连续时间 ODE 的视角切换传统 DDPM 是离散时间的t 0, 1, 2, ..., T。但如果你把时间步取得足够细离散的马尔可夫链就会收敛到一个连续时间的随机过程。这个连续过程可以用 SDE 描述dx f(x, t) dt g(t) dw其中 f 是漂移项driftg 是扩散项diffusion coefficientdw 是布朗运动。前向加噪对应一个固定的 SDE反向去噪对应它的时间反演 SDE。而 Song 等人在 Score-Based Generative Modeling 那篇工作里证明了一个重要结论这个反向 SDE 存在一个对应的概率流 ODEProbability Flow ODE两者边缘分布完全相同。概率流 ODE 的形式是dx [f(x, t) - 0.5 * g(t)² * ∇ₓ log p_t(x)] dt看到那个 ∇ₓ log p_t(x) 了吗这就是 score function也就是 Diffusion 模型实际在学的东西。所以整个采样过程就变成了训练一个网络去估计 score然后用数值 ODE 求解器去解这个概率流 ODE。这个视角切换带来的最大好处是ODE 求解器有一整套成熟的数值方法可以用欧拉法、Heun 法、Runge-Kutta 等等你想用几阶就用几阶想跳多大步就跳多大步当然精度要保证。这就把采样步数从必须 1000 步解放出来了。1.3 概率流 ODE 和 SDE 采样到底差在哪很多人会问既然概率流 ODE 和反向 SDE 边缘分布一样那我用哪个实测下来差异主要在三点对比维度概率流 ODE反向 SDE采样确定性确定性同起点同结果随机性每次结果不同步数需求可用高阶求解器步数少通常需要更多步结果多样性依赖初始噪声内在随机性带来多样性似然计算可直接算精确似然需要变分下界我个人的经验是追求快速采样和可复现性用 ODE追求生成多样性用 SDE。实际做产品的时候很多时候是两者混用比如前几步用 SDE 注入随机性后面用 ODE 快速收敛。2. Flow Matching 到底在匹配什么2.1 从学噪声到学速度场的思维转变传统 Diffusion 训练目标是让网络预测加进去的噪声 ε或者等价地预测 score。Flow matching 换了个思路我不学噪声了我直接学一个速度场velocity field这个速度场定义了从噪声分布到数据分布的一条连续路径。打个比方。传统 Diffusion 像是让你看着一张被逐步弄模糊的照片学会每一步模糊是怎么加上去的然后反过来一步步擦掉。Flow matching 则是直接告诉你起点和终点让你学从起点到终点该怎么走中间路径可以自己设计。数学上flow matching 定义一个时间相关的向量场 v(x, t)它生成的流flowφ_t 满足dφ_t(x) / dt v(φ_t(x), t)我们的目标是让 φ_0 把噪声分布映射到 φ_1 的数据分布。训练目标就是让网络预测的 v_θ(x, t) 尽量接近真实的速度场。2.2 Conditional Flow Matching 的巧妙之处直接学边缘速度场 v(x, t) 是很难的因为你根本不知道真实的边缘路径长什么样。Conditional Flow MatchingCFM的巧妙之处在于我不学边缘路径我学条件路径然后证明条件路径的期望就是边缘路径。具体做法是对每个数据点 x₁我构造一条从噪声 x₀ 到 x₁ 的条件路径比如最简单的线性插值x_t (1 - t) * x₀ t * x₁这条路径对应的速度场就是常数v_t x₁ - x₀训练目标就变成了L E_{t, x₀, x₁} [ || v_θ(x_t, t) - (x₁ - x₀) ||² ]就这么简单。没有复杂的噪声调度没有 score matching 的推导就是一个回归问题。我第一次看到这个目标函数的时候有点不敢相信——这也太干净了吧但实测下来它确实 work而且训练比传统 Diffusion 稳定得多。2.3 为什么说 Flow Matching 是 Diffusion 的推广这里有个很深的联系值得说清楚。传统 Diffusion 的前向过程可以写成x_t α_t * x₀ σ_t * ε其中 α_t 和 σ_t 是噪声调度系数ε ~ N(0, I)。如果你把这条路径看成从 x₀ 到 ε 的插值那它其实也是一种条件路径。Flow matching 只是把这个框架一般化了路径不一定是高斯加噪那条你可以设计任意从噪声到数据的路径。更关键的是Diffusion 的 score 和 flow matching 的速度场之间存在解析关系。对于高斯路径可以证明v(x, t) f(t) * x g(t) * score(x, t)也就是说你学会了 score 就等于学会了速度场反之亦然。这就是为什么很多 Diffusion 模型可以直接转成 flow matching 形式来加速采样反之 flow matching 模型也能用 score-based 的方法来分析。3. 手把手推导 ODE Flow Matching 的训练与采样3.1 路径设计线性插值、VP 路径与最优传输路径设计是 flow matching 里最灵活也最需要经验的部分。常见的几种线性插值路径Linear / OT 路径x_t (1 - t) * x₀ t * x₁ v_t x₁ - x₀这是最简单的也是 Rectified Flow 用的路径。优点是路径直采样步数可以压得很低实测 4-8 步就能出不错的结果。缺点是训练初期路径交叉多收敛稍慢。VP 路径Variance Preservingx_t cos(πt/2) * x₀ sin(πt/2) * ε这是传统 Diffusion 常用的对应 cosine 噪声调度。路径是圆弧采样需要更多步但训练稳定。最优传输路径Optimal Transport理论上找的是让传输代价最小的路径实践中常用线性插值近似。Rectified Flow 的核心思想就是通过多次reflow操作把路径逐步拉直最终得到接近直线的传输路径。我实测下来的经验如果你追求少步数采样直接用线性插值路径 reflow如果你追求训练稳定和生成质量VP 路径更保险。两者在 50 步以上的采样质量差距不大但 10 步以下线性路径优势明显。3.2 训练目标的完整推导从条件概率路径出发我们定义p_t(x | x₁) N(x | μ_t(x₁), σ_t² I)对于线性插值路径μ_t(x₁) t * x₁σ_t 1 - t这里假设 x₀ ~ N(0, I)。条件速度场可以通过对 μ_t 求导得到v_t(x | x₁) dμ_t/dt (dσ_t/dt) / σ_t * (x - μ_t)对于线性路径dμ_t/dt x₁dσ_t/dt -1代入化简v_t(x | x₁) x₁ - x₀这就是为什么线性路径的速度场是常数。训练时我们采样 t ~ U[0,1]x₀ ~ N(0,I)x₁ ~ 数据分布构造 x_t然后最小化L || v_θ(x_t, t) - (x₁ - x₀) ||²实际实现中为了数值稳定通常会对 t 做非均匀采样比如 logit-normal 分布让模型在中间时间段获得更多训练信号。3.3 采样从欧拉法到高阶求解器训练完之后采样就是解 ODEdx/dt v_θ(x, t), x(0) ~ N(0, I)最简单的欧拉法def euler_sample(model, x, steps): dt 1.0 / steps for i in range(steps): t i * dt v model(x, t) x x v * dt return x实测欧拉法在 50 步左右就能出不错的结果但 10 步以下会有明显误差。这时候可以用 Heun 法二阶def heun_sample(model, x, steps): dt 1.0 / steps for i in range(steps): t i * dt v1 model(x, t) x_pred x v1 * dt v2 model(x_pred, t dt) x x 0.5 * (v1 v2) * dt return xHeun 法每步要算两次网络但精度提升明显实际总计算量可能比欧拉法多步还少。我一般用 Heun 20 步作为默认配置质量和速度平衡得比较好。再往上还有 RK4 等高阶方法但实测在 flow matching 场景下收益递减因为网络预测本身有误差求解器阶数太高反而会放大网络误差。4. 实操中那些文档不会告诉你的坑4.1 时间步采样策略对收敛的影响这是我踩过的第一个大坑。最开始我按均匀分布采样 t ~ U[0,1]结果训练 loss 降得挺快但采样质量很差尤其是中间时间段生成的图糊成一团。后来才想明白均匀采样导致模型在 t 接近 0 和 1 的区域训练不足因为这两个区域的速度场变化剧烈需要更多训练信号。解决方案是用 logit-normal 采样def sample_t(batch_size): u torch.randn(batch_size) * 1.0 0.0 # 均值0标准差1 t torch.sigmoid(u) return t这样 t 会集中在 0.5 附近两端也有覆盖但密度低。实测这个改动让 FID 直接降了好几个点。另一个方案是 importance sampling根据 loss 大小动态调整采样密度但实现复杂收益不如 logit-normal 明显。4.2 网络输出尺度与数值稳定性Flow matching 的速度场 v x₁ - x₀当 x₁ 是归一化到 [-1,1] 的图像、x₀ 是标准高斯时v 的量级大概在 2-3 左右。这比传统 Diffusion 预测噪声 ε量级约 1要大所以网络最后一层的初始化要注意。我一开始直接套用 Diffusion 的网络结构结果训练初期 loss 爆炸。后来把最后一层初始化为零zero-init训练就稳了。原理是初始时网络输出为 0相当于速度场为 0模型从不动开始学梯度信号干净。另外如果用的是 VP 路径速度场量级会随时间变化建议对网络输出做一个时间相关的缩放或者直接用自适应归一化层AdaGN来处理。4.3 采样步数与求解器的匹配经验很多人以为步数越多越好其实不是。我做过一组对比实验用同一个训练好的模型不同步数和求解器组合求解器步数FID单图耗时欧拉1012.30.15s欧拉505.80.72s欧拉2005.62.9sHeun107.20.28sHeun205.90.55sHeun505.71.4sRK4205.81.1s可以看到欧拉 50 步和 200 步的 FID 几乎没差但耗时差 4 倍。Heun 20 步就能达到欧拉 50 步的质量总耗时还更少。RK4 在 20 步时和 Heun 差不多但每步计算量更大。我的建议是默认用 Heun 20 步追求极致速度用欧拉 10 步质量会降一点追求质量用 Heun 50 步。RK4 除非你有特殊需求否则不推荐性价比不高。4.4 从 Diffusion 权重迁移到 Flow Matching 的注意事项如果你已经有一个训练好的 Diffusion 模型想转成 flow matching 形式来加速采样这是可行的但有几个坑第一score 和速度场的转换关系依赖于路径设计。如果你用线性路径转换公式和 VP 路径不一样不能直接套。第二时间步的语义变了。Diffusion 的 t 通常是从 0 到 1000 的整数flow matching 是 0 到 1 的连续值映射关系要重新标定。第三网络的时间嵌入需要重新训练或微调。即使速度场和 score 有解析关系网络内部的时间条件分布变了直接迁移效果会打折。我实测下来至少需要几千步的微调才能恢复到原模型的质量。5. 把 ODE Flow Matching 用到实际项目里的几个思路5.1 少步数采样的工程价值在实际产品里采样速度直接决定用户体验和成本。一个 50 步的 Diffusion 模型如果换成 flow matching Heun 20 步推理成本直接砍掉一半以上。如果是视频生成这种要生成几十上百帧的场景节省更可观。我做过一个粗略估算假设单步推理耗时 T生成 N 帧视频传统 Diffusion 需要 50 * N * Tflow matching 需要 20 * N * T节省 60% 的算力。按云 GPU 每小时几块钱算大规模部署下这是实打实的成本差异。而且 flow matching 的 ODE 形式天然支持自适应步长求解器在速度场变化平缓的区域自动跳大步变化剧烈的区域用小步进一步压缩步数。这个在传统离散 Diffusion 里是做不到的。5.2 和现有 Diffusion 生态的兼容性好消息是flow matching 不需要你推翻现有的一切。网络结构可以复用U-Net、DiT 都行数据管道可以复用甚至训练框架都能复用。主要改动就三处训练目标从预测噪声改成预测速度场时间采样从均匀改成 logit-normal采样器从 DDIM/DPM-Solver 换成 ODE 求解器我实际迁移一个 DiT 模型的时候改动量大概就两三百行代码一天就能跑通。这也是为什么我觉得 flow matching 值得每个做 Diffusion 的人都了解一下——学习成本低收益明确。5.3 一些值得关注的扩展方向flow matching 这套框架还在快速演进。几个我觉得有意思的方向Rectified Flow 的 reflow 操作通过多次用模型自己生成的配对数据重新训练把路径逐步拉直最终实现 1-2 步采样。这个思路很优雅但 reflow 次数多了会损失多样性需要权衡。Stochastic Interpolants把 flow matching 和 SDE 统一到一个框架里可以灵活选择确定性或随机性采样。这个理论框架比较完整值得深入看。离散数据的 flow matching把连续路径推广到离散状态空间用于文本、蛋白质序列等离散数据的生成。这块和语言模型的结合是最近的热点。和一致性模型的结合一致性模型追求的是从任意时间点一步映射到终点flow matching 提供了一条自然的路径两者结合可能实现真正的单步高质量生成。6. 我自己的学习路径与实操建议回头看我从 Diffusion 到 flow matching 的学习路径大概是这样的先搞懂 DDPM 的前向反向过程然后理解 score matching 和概率流 ODE 的等价性接着看 flow matching 的 conditional 版本最后动手实现一个最小可跑的例子。如果你也想走这条路我的建议是不要一上来就啃理论。先跑通一个最小实现比如在 MNIST 或 CIFAR-10 上训一个 flow matching 模型感受一下训练目标和采样过程。有了直观感受之后再回去看推导很多之前看不懂的地方会豁然开朗。具体的最小实现我推荐从线性插值路径 欧拉采样开始代码量很少一两个小时就能跑通。跑通之后再逐步加东西换 Heun 求解器、加 logit-normal 时间采样、试 VP 路径、对比不同步数。每一步改动都观察 loss 曲线和生成质量的变化这样积累下来的经验比看十篇论文都管用。最后分享一个我踩过的坑不要迷信论文里的超参数。不同数据集、不同网络结构、不同路径设计最优超参数都不一样。论文里的配置只能作为起点真正的调参还是得自己在验证集上试。我见过太多人直接套论文配置结果效果差一大截然后怀疑是自己实现错了其实只是超参数不匹配而已。flow matching 这个方向现在还在快速迭代每隔几个月就有新工作出来。但核心思想——用连续时间 ODE 统一生成建模用条件路径简化训练目标——这个框架是稳定的值得花时间真正搞懂。搞懂之后你会发现很多看似复杂的 Diffusion 变体其实都是这个框架下的特例。