第 02 章:扩散模型 10 分钟速通 —— 从 DDPM 到 Flow Matching

论文Continuous Latent Diffusion Language Model

项目地址ByteDance-Seed/Cola-DLM

核心困惑:Cola DLM 用的 Flow Matching 和经典 DDPM 有什么关系?为什么选择 Flow Matching 而不是 DDPM?


一、先建立直觉

想象你有一滴墨水滴入水中。前向过程是墨水逐渐扩散、最终变成均匀的浑水(噪声)。反向过程是:如果你能精确地知道每一瞬间水的流动方向(速度场),你就能倒放这个过程——从浑水恢复出那滴墨水。

  • DDPM:把时间切成很多小段,每段学一个"去噪"操作
  • Flow Matching:直接学习连续的速度场,一步到位

二、DDPM 回顾:离散步长的去噪

2.1 前向过程

DDPM 定义一个 T T T 步的 Markov 链,逐步向数据添加高斯噪声:

q ( x t ∣ x t − 1 ) = N ( x t ; 1 − β t   x t − 1 , β t I ) q(x_t \mid x_{t-1}) = \mathcal{N}(x_t; \sqrt{1 - \beta_t} \, x_{t-1}, \beta_t I) q(xtxt1)=N(xt;1βt xt1,βtI)

其中 β t \beta_t βt 是噪声调度(noise schedule),通常从小到大递增。

利用重参数化技巧,可以直接从 x 0 x_0 x0 跳到任意 x t x_t xt

q ( x t ∣ x 0 ) = N ( x t ; α ˉ t   x 0 , ( 1 − α ˉ t ) I ) q(x_t \mid x_0) = \mathcal{N}(x_t; \sqrt{\bar{\alpha}_t} \, x_0, (1 - \bar{\alpha}_t) I) q(xtx0)=N(xt;αˉt x0,(1αˉt)I)

其中 α ˉ t = ∏ s = 1 t ( 1 − β s ) \bar{\alpha}_t = \prod_{s=1}^{t} (1 - \beta_s) αˉt=s=1t(1βs)

数值例子:假设 β t = 0.01 \beta_t = 0.01 βt=0.01(常数), T = 1000 T = 1000 T=1000

  • t = 0 t = 0 t=0 x 0 x_0 x0 是原始数据
  • t = 500 t = 500 t=500 α ˉ 500 ≈ 0.0067 \bar{\alpha}_{500} \approx 0.0067 αˉ5000.0067,数据几乎全是噪声
  • t = 1000 t = 1000 t=1000 α ˉ 1000 ≈ 0 \bar{\alpha}_{1000} \approx 0 αˉ10000,纯高斯噪声

2.2 反向过程

反向过程学习从噪声恢复数据:

p θ ( x t − 1 ∣ x t ) = N ( x t − 1 ; μ θ ( x t , t ) , σ t 2 I ) p_\theta(x_{t-1} \mid x_t) = \mathcal{N}(x_{t-1}; \mu_\theta(x_t, t), \sigma_t^2 I) pθ(xt1xt)=N(xt1;μθ(xt,t),σt2I)

训练目标是预测噪声 ϵ \epsilon ϵ

L simple = E t , x 0 , ϵ [ ∥ ϵ − ϵ θ ( x t , t ) ∥ 2 ] \mathcal{L}_{\text{simple}} = \mathbb{E}_{t, x_0, \epsilon}\left[\|\epsilon - \epsilon_\theta(x_t, t)\|^2\right] Lsimple=Et,x0,ϵ[ϵϵθ(xt,t)2]

2.3 DDPM 的问题

  1. 需要很多步:通常 T = 1000 T = 1000 T=1000 步,推理时需要跑 1000 次模型前向(即使有 DDIM 加速也需要 50-100 步)
  2. 离散步长的误差累积:每一步的去噪都有误差, T T T 步累积后误差可能很大
  3. 方差调度需要手工设计 β t \beta_t βt 的选择对生成质量影响很大

三、Score-based 视角:连接 DDPM 和 Flow Matching 的桥梁

3.1 Score Function

Score function 是数据分布的对数梯度:

s ( x ) = ∇ x log ⁡ p ( x ) s(x) = \nabla_x \log p(x) s(x)=xlogp(x)

它指向数据密度增长最快的方向。如果你知道 score function,你就知道从任意点出发应该往哪个方向走才能到达高密度区域。

3.2 Score Matching

直接计算 ∇ x log ⁡ p ( x ) \nabla_x \log p(x) xlogp(x) 需要知道 p ( x ) p(x) p(x)(这就是我们想求的),所以用一个神经网络 s θ ( x , t ) s_\theta(x, t) sθ(x,t) 来近似。训练目标:

L score = E t , x 0 , x t [ ∥ s θ ( x t , t ) − ∇ x t log ⁡ q ( x t ∣ x 0 ) ∥ 2 ] \mathcal{L}_{\text{score}} = \mathbb{E}_{t, x_0, x_t}\left[\|s_\theta(x_t, t) - \nabla_{x_t} \log q(x_t \mid x_0)\|^2\right] Lscore=Et,x0,xt[sθ(xt,t)xtlogq(xtx0)2]

对于高斯噪声, ∇ x t log ⁡ q ( x t ∣ x 0 ) = − ϵ 1 − α ˉ t \nabla_{x_t} \log q(x_t \mid x_0) = -\frac{\epsilon}{\sqrt{1 - \bar{\alpha}_t}} xtlogq(xtx0)=1αˉt ϵ,所以 score matching 和 noise prediction 是等价的。

3.3 关键洞察

Score function 定义了一个向量场(vector field)。如果你知道这个向量场,就可以用 ODE(常微分方程)从噪声走到数据:

d x d t = f ( x , t ) + g ( t ) ⋅ s θ ( x , t ) \frac{dx}{dt} = f(x, t) + g(t) \cdot s_\theta(x, t) dtdx=f(x,t)+g(t)sθ(x,t)

这就是连接 DDPM 和 Flow Matching 的桥梁——从离散步长的去噪到连续速度场的积分


四、Flow Matching:直接学习连续流

4.1 核心思想

Flow Matching 跳过了 score function 的中间步骤,直接学习一个速度场 v ψ ( z t , t ) v_\psi(z_t, t) vψ(zt,t),使得:

d z t d t = v ψ ( z t , t ) \frac{dz_t}{dt} = v_\psi(z_t, t) dtdzt=vψ(zt,t)

从噪声 z 1 ∼ N ( 0 , I ) z_1 \sim \mathcal{N}(0, I) z1N(0,I) 出发,沿着速度场积分,就能到达数据 z 0 z_0 z0

z 0 = z 1 + ∫ 1 0 v ψ ( z t , t )   d t = Φ 0 ← 1 ψ ( z 1 ) z_0 = z_1 + \int_1^0 v_\psi(z_t, t) \, dt = \Phi^\psi_{0 \leftarrow 1}(z_1) z0=z1+10vψ(zt,t)dt=Φ01ψ(z1)

4.2 条件 Flow Matching

直接学习全局速度场很难,Flow Matching 的技巧是:对每个数据点 z 0 z_0 z0,定义一个从噪声到该点的条件路径,然后学习条件速度场。

最简单的路径是线性插值:

z t = ( 1 − t ) ⋅ z 0 + t ⋅ z 1 , t ∈ [ 0 , 1 ] z_t = (1 - t) \cdot z_0 + t \cdot z_1, \quad t \in [0, 1] zt=(1t)z0+tz1,t[0,1]

对应的条件速度场:

u t ( z t ∣ z 0 ) = z 1 − z 0 u_t(z_t \mid z_0) = z_1 - z_0 ut(ztz0)=z1z0

训练目标:

L FM = E t , z 0 , z 1 [ ∥ v ψ ( z t , t ) − u t ( z t ∣ z 0 ) ∥ 2 ] \mathcal{L}_{\text{FM}} = \mathbb{E}_{t, z_0, z_1}\left[\|v_\psi(z_t, t) - u_t(z_t \mid z_0)\|^2\right] LFM=Et,z0,z1[vψ(zt,t)ut(ztz0)2]

4.3 Flow Matching vs DDPM

维度 DDPM Flow Matching
数学框架 SDE(随机微分方程) ODE(常微分方程)
"噪声"过程 离散步长 + 随机采样 连续流 + 确定性传输
训练目标 预测噪声 ϵ \epsilon ϵ 预测速度场 v v v
推理方式 多步去噪(随机) ODE 求解(确定性)
步数需求 通常 50-1000 步 通常 10-50 步
数学优雅度 需要精心设计 β t \beta_t βt 路径选择更自由

五、Cola DLM 中的 Flow Matching

5.1 连续流先验

Cola DLM 用 Flow Matching 参数化隐空间先验 p ψ ( z 0 ) p_\psi(z_0) pψ(z0)。基础分布是标准高斯 p 1 = N ( 0 , I ) p_1 = \mathcal{N}(0, I) p1=N(0,I),学习一个向量场 v ψ ( z t , t ) v_\psi(z_t, t) vψ(zt,t)

z 1 ∼ N ( 0 , I ) , d z t d t = v ψ ( z t , t ) , z 0 = Φ 0 ← 1 ψ ( z 1 ) z_1 \sim \mathcal{N}(0, I), \quad \frac{dz_t}{dt} = v_\psi(z_t, t), \quad z_0 = \Phi^\psi_{0 \leftarrow 1}(z_1) z1N(0,I),dtdzt=vψ(zt,t),z0=Φ01ψ(z1)

在代码中(inference.py:356-357),Euler 求解器的更新规则是:

def _diffusion_dt(t_curr, t_next):
    return (float(t_curr) - float(t_next)) / max(T, 1.0)

每一步的更新(inference.py:649):

txt_next = txt - drift * dt  # z_{t-Δ} = z_t - (Δ/T) * v_ψ

5.2 时间步 schedule

Cola DLM 使用线性时间步(inference.py:478):

timesteps = torch.linspace(int(T), 0, timestep_num + 1, dtype=torch.float32)

默认 T = 1000 T = 1000 T=1000 t i m e s t e p _ n u m = 16 timestep\_num = 16 timestep_num=16,所以时间步是 [ 1000 , 937.5 , 875 , … , 62.5 , 0 ] [1000, 937.5, 875, \ldots, 62.5, 0] [1000,937.5,875,,62.5,0]

5.3 条件 Flow Matching 损失

训练时(代码未开源,论文式 2.1.7),损失是:

L FM = ∑ b = 1 B E t , z 0 , z 1 [ ∥ v ψ ( z t ( b ) , t ; z 0 ( < b ) ) − u t ( b ) ( z 0 , z 1 ) ∥ 2 ] \mathcal{L}_{\text{FM}} = \sum_{b=1}^{B} \mathbb{E}_{t, z_0, z_1}\left[\|v_\psi(z_t^{(b)}, t; z_0^{(<b)}) - u_t^{(b)}(z_0, z_1)\|^2\right] LFM=b=1BEt,z0,z1[vψ(zt(b),t;z0(<b))ut(b)(z0,z1)2]

注意这里的条件: v ψ v_\psi vψ 的输入不仅有当前 block 的 z t ( b ) z_t^{(b)} zt(b),还有前面所有 block 的 z 0 ( < b ) z_0^{(<b)} z0(<b)(stop gradient)。这就是分块因果的体现。

5.4 为什么选择 Flow Matching 而不是 DDPM?

  1. 更少的步数:Flow Matching 的 ODE 求解通常只需要 10-50 步,DDPM 需要 50-1000 步
  2. 确定性生成:ODE 是确定性的,相同的初始噪声总是产生相同的输出(便于调试和复现)
  3. 更自然的连续空间适配:Flow Matching 天然在连续空间定义,不需要像 DDPM 那样设计离散步长
  4. 数学框架更统一:条件 Flow Matching 的训练目标非常简洁

六、一个完整的数值例子

假设我们要用 Flow Matching 学习一个 2D 分布(两个高斯混合):

Step 1:采样数据点 z 0 = ( 3 , 2 ) z_0 = (3, 2) z0=(3,2)

Step 2:采样噪声 z 1 = ( − 0.5 , 1.2 ) z_1 = (-0.5, 1.2) z1=(0.5,1.2)(来自 N ( 0 , I ) \mathcal{N}(0, I) N(0,I)

Step 3:线性插值路径 t = 0.5 t = 0.5 t=0.5 时:

z 0.5 = ( 1 − 0.5 ) ⋅ ( 3 , 2 ) + 0.5 ⋅ ( − 0.5 , 1.2 ) = ( 1.25 , 1.6 ) z_{0.5} = (1 - 0.5) \cdot (3, 2) + 0.5 \cdot (-0.5, 1.2) = (1.25, 1.6) z0.5=(10.5)(3,2)+0.5(0.5,1.2)=(1.25,1.6)

Step 4:条件速度场 u t = z 1 − z 0 = ( − 3.5 , − 0.8 ) u_t = z_1 - z_0 = (-3.5, -0.8) ut=z1z0=(3.5,0.8)

Step 5:训练,让神经网络 v ψ ( z 0.5 , 0.5 ) v_\psi(z_{0.5}, 0.5) vψ(z0.5,0.5) 预测 u t = ( − 3.5 , − 0.8 ) u_t = (-3.5, -0.8) ut=(3.5,0.8)

Step 6:推理,从 z 1 ∼ N ( 0 , I ) z_1 \sim \mathcal{N}(0, I) z1N(0,I) 出发,沿着学到的速度场积分 16 步,得到 z 0 z_0 z0


七、面试追问清单

基础(⭐)

  1. DDPM 的前向过程和反向过程分别做什么?
  2. Flow Matching 的训练目标是什么?
  3. 为什么 Flow Matching 比 DDPM 需要更少的推理步数?

进阶(⭐⭐)

  1. Score function 和速度场的关系是什么?
  2. 条件 Flow Matching 的"条件"是什么意思?
  3. Cola DLM 中 T = 1000 T = 1000 T=1000 t i m e s t e p _ n u m = 16 timestep\_num = 16 timestep_num=16 的关系是什么?

专家(⭐⭐⭐)

  1. Flow Matching 和 DDPM 在什么条件下数学上等价?
  2. 为什么 Cola DLM 选择线性插值路径而不是最优传输路径?
  3. 分块因果的条件 Flow Matching 损失和标准 Flow Matching 损失有什么区别?

八、下期预告

下一章我们将深入离散扩散的技术细节——为什么 LLaDA 和 MDLM 选择了在离散空间做扩散,它们遇到了什么问题,以及这些问题如何推动了 Cola DLM 的设计决策。


系列导航

第 01 章:语言生成的三次范式之争

第 02 章:扩散模型 10 分钟速通 ← 你在这里

第 03 章:离散扩散的困境

第 04 章:Cola DLM 架构全景

第 05 章:Text VAE 深度解剖

第 06 章:分块因果 DiT 先验

第 07 章:推理流水线逐行拆解

第 08 章:工程实现评析

第 09 章:评测复现与结果深度分析

第 10 章:从文本到多模态


作者Yunzenn

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐