深度解析字节前沿研究-Cola DLM第 02 章:扩散模型 10 分钟速通 —— 从 DDPM 到 Flow Matching
第 02 章:扩散模型 10 分钟速通 —— 从 DDPM 到 Flow Matching
论文:Continuous Latent Diffusion Language Model
核心困惑: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(xt∣xt−1)=N(xt;1−βtxt−1,β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(xt∣x0)=N(xt;αˉtx0,(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 αˉ500≈0.0067,数据几乎全是噪声
- t = 1000 t = 1000 t=1000: α ˉ 1000 ≈ 0 \bar{\alpha}_{1000} \approx 0 αˉ1000≈0,纯高斯噪声
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θ(xt−1∣xt)=N(xt−1;μθ(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 的问题
- 需要很多步:通常 T = 1000 T = 1000 T=1000 步,推理时需要跑 1000 次模型前向(即使有 DDIM 加速也需要 50-100 步)
- 离散步长的误差累积:每一步的去噪都有误差, T T T 步累积后误差可能很大
- 方差调度需要手工设计: β 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(xt∣x0)∥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(xt∣x0)=−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) z1∼N(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=Φ0←1ψ(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=(1−t)⋅z0+t⋅z1,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(zt∣z0)=z1−z0
训练目标:
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(zt∣z0)∥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) z1∼N(0,I),dtdzt=vψ(zt,t),z0=Φ0←1ψ(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=1∑BEt,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?
- 更少的步数:Flow Matching 的 ODE 求解通常只需要 10-50 步,DDPM 需要 50-1000 步
- 确定性生成:ODE 是确定性的,相同的初始噪声总是产生相同的输出(便于调试和复现)
- 更自然的连续空间适配:Flow Matching 天然在连续空间定义,不需要像 DDPM 那样设计离散步长
- 数学框架更统一:条件 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=(1−0.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=z1−z0=(−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) z1∼N(0,I) 出发,沿着学到的速度场积分 16 步,得到 z 0 z_0 z0
七、面试追问清单
基础(⭐):
- DDPM 的前向过程和反向过程分别做什么?
- Flow Matching 的训练目标是什么?
- 为什么 Flow Matching 比 DDPM 需要更少的推理步数?
进阶(⭐⭐):
- Score function 和速度场的关系是什么?
- 条件 Flow Matching 的"条件"是什么意思?
- 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 的关系是什么?
专家(⭐⭐⭐):
- Flow Matching 和 DDPM 在什么条件下数学上等价?
- 为什么 Cola DLM 选择线性插值路径而不是最优传输路径?
- 分块因果的条件 Flow Matching 损失和标准 Flow Matching 损失有什么区别?
八、下期预告
下一章我们将深入离散扩散的技术细节——为什么 LLaDA 和 MDLM 选择了在离散空间做扩散,它们遇到了什么问题,以及这些问题如何推动了 Cola DLM 的设计决策。
系列导航
第 02 章:扩散模型 10 分钟速通 ← 你在这里
作者:Yunzenn
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)