符号约定(全程统一,和论文一致)
- x0x_0x0:干净真实样本(原图 / latent)
- xtx_txt:第 ttt 步的带噪样本
- t∈{1,2,...,T}t\in\{1,2,...,T\}t∈{1,2,...,T},原版 DDPM:KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲T=1000\)
- βt∈(0,1)\beta_t \in(0,1)βt∈(0,1):噪声调度系数,提前固定(线性调度等)
- αt=1−βt\alpha_t = 1-\beta_tαt=1−βt
- αˉt=∏i=1tαi\bar\alpha_t = \prod_{i=1}^t \alpha_iαˉt=∏i=1tαi 前 t 个 α 的累乘
- ϵ\epsilonϵ:标准高斯噪声,ϵ∼N(0,I)\epsilon \sim \mathcal{N}(0,I)ϵ∼N(0,I)
- ϵθ(xt,t)\epsilon_\theta(x_t,t)ϵθ(xt,t):网络(UNet/DiT)预测的噪声
条件扩散(带提示词):增加条件 ccc,网络变成 ϵθ(xt,t,c)\epsilon_\theta(x_t,t,c)ϵθ(xt,t,c),训练/推理逻辑框架不变。
DDPM 分为两大块:前向扩散过程(训练用,马尔可夫链,逐步加噪) + 反向去噪过程(推理生成,马尔可夫链,逐步去噪)
一、前向扩散(Forward Process):只在训练时使用
目标:从干净图 x0x_0x0,一步步加高斯噪声,最后 xTx_TxT 近似纯高斯噪声。
马尔可夫假设:xtx_txt 的分布只依赖上一步 xt−1x_{t-1}xt−1
q(xt∣xt−1)=N(xt; αt xt−1, βtI) q(x_t \mid x_{t-1}) = \mathcal{N}\big(x_t;\; \sqrt{\alpha_t}\,x_{t-1},\; \beta_t I\big) q(xt∣xt−1)=N(xt;αt xt−1,βtI)
也就是:
xt=αt xt−1+βt ϵt x_t = \sqrt{\alpha_t}\,x_{t-1} + \sqrt{\beta_t}\,\epsilon_t xt=αt xt−1+βt ϵt
👉 重要闭式推导(DDPM核心简化,不用循环迭代加噪):
可以证明:不需要一步步算 x1,x2...x_1,x_2...x1,x2...,直接由 x0x_0x0 一步算出任意 ttt 的 xtx_txt
xt=αˉt x0+1−αˉt ϵ,ϵ∼N(0,I) \boldsymbol{x_t = \sqrt{\bar\alpha_t}\,x_0 + \sqrt{1-\bar\alpha_t}\,\epsilon},\quad \epsilon\sim \mathcal{N}(0,I) xt=αˉt x0+1−αˉt ϵ,ϵ∼N(0,I)
这个就是你之前一直在看的公式!
特性:
- ttt 很小:αˉt≈1\bar\alpha_t\approx1αˉt≈1,xtx_txt 接近原图,噪声很少
- ttt 很大:αˉt≈0\bar\alpha_t\approx0αˉt≈0,xt≈ϵx_t \approx \epsilonxt≈ϵ,几乎是纯噪声
前向过程是确定性调度 + 随机噪声;前向没有网络,不需要训练,只是用来构造训练数据。
二、训练流程 & 损失函数(核心)
我们的网络 ϵθ\epsilon_\thetaϵθ 学习目标:输入带噪图 xtx_txt、时间步 ttt,预测当时混入的噪声 ϵ\epsilonϵ。
训练单步完整流程
- 从数据集取干净样本 x0x_0x0
- 随机采样一个时间步:t∼Uniform({1,2,...,T})t \sim \text{Uniform}(\{1,2,...,T\})t∼Uniform({1,2,...,T})
- 采样高斯真值噪声:ϵ∼N(0,I)\epsilon \sim \mathcal{N}(0,I)ϵ∼N(0,I)
- 用闭式公式算出带噪样本:
xt=αˉt x0+1−αˉt ϵ x_t = \sqrt{\bar\alpha_t}\,x_0 + \sqrt{1-\bar\alpha_t}\,\epsilon xt=αˉt x0+1−αˉt ϵ - 送入网络:无条件 ϵθ(xt,t)\epsilon_\theta(x_t,t)ϵθ(xt,t);条件版(提示词)ϵθ(xt,t,c)\boldsymbol{\epsilon_\theta(x_t,t,c)}ϵθ(xt,t,c)
- ccc:文本编码器输出的条件向量(CLIP / Qwen-VL)
- 计算损失(简化版MSE损失,DDPM主损失)
Lsimple=Et,x0,ϵ∥ϵ−ϵθ(xt,t,c)∥2 \mathcal{L}{\text{simple}} = \mathbb{E}{t,x_0,\epsilon}\Big\\big\\\|\\epsilon - \\epsilon_\\theta(x_t,t,c)\\big\\\|\^2\\Big Lsimple=Et,x0,ϵ ϵ−ϵθ(xt,t,c) 2 - 梯度反向传播,更新网络权重;冻结文本编码器时,ccc 分支不更新。
✅ 关键点回顾:
训练时 ϵ\epsilonϵ 是我们自己生成的真值,不是从 xtx_txt 反推出来的;网络只看见 xt,t,cx_t,t,cxt,t,c,猜这个 ϵ\epsilonϵ。
原版论文还有更复杂的VLB变分下界损失,工程上大家几乎都只用上面这个简化MSE损失。
三、反向去噪过程(Reverse Process,推理生成)
目标:从纯噪声 xTx_TxT 出发,一步步还原 xT→xT−1→...→x0x_{T}\to x_{T-1}\to ... \to x_0xT→xT−1→...→x0
反向也是马尔可夫链:p(xt−1∣xt)p(x_{t-1}\mid x_t)p(xt−1∣xt)
理论上反向转移分布:
p(xt−1∣xt)=N(xt−1; μθ(xt,t), Σθ(xt,t)) p(x_{t-1}\mid x_t) = \mathcal{N}\big(x_{t-1};\; \mu_\theta(x_t,t),\; \Sigma_\theta(x_t,t)\big) p(xt−1∣xt)=N(xt−1;μθ(xt,t),Σθ(xt,t))
DDPM 把方差固定为 σt2I\sigma_t^2 Iσt2I(不学习方差,只学习均值)
σt2=1−αˉt−11−αˉtβt \sigma_t^2 = \frac{1-\bar\alpha_{t-1}}{1-\bar\alpha_t}\beta_t σt2=1−αˉt1−αˉt−1βt
均值 μθ\mu_\thetaμθ 用网络预测噪声表达:
μθ(xt,t)=1αt(xt−βt1−αˉtϵθ(xt,t,c)) \boldsymbol{\mu_\theta(x_t,t) = \frac{1}{\sqrt{\alpha_t}}\left( x_t - \frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\epsilon_\theta(x_t,t,c) \right)} μθ(xt,t)=αt 1(xt−1−αˉt βtϵθ(xt,t,c))
反向单步采样公式(DDPM原版)
xt−1=μθ(xt,t)+σt⋅z \boldsymbol{x_{t-1} = \mu_\theta(x_t,t) + \sigma_t \cdot z} xt−1=μθ(xt,t)+σt⋅z
KaTeX parse error: Can't use function '\(' in math mode at position 48: ...z=0 \text{ 当 } \̲(̲t=1\)
- KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲t>1\):加上随机噪声 zzz,保证采样随机性
- KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲t=1\):最后一步,不再加噪声,直接得到 x0x_0x0
这就是DDPM推理每一步的迭代公式!
循环:从 KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲t=T\) 降到 KaTeX parse error: Can't use function '\(' in math mode at position 1: \̲(̲t=1\),每一步输入 xt,t,cx_t,t,cxt,t,c,预测噪声 ϵθ\epsilon_\thetaϵθ,算出 xt−1x_{t-1}xt−1。
推理时已知变量清单
- 固定调度表:βt,αt,αˉt,σt\beta_t,\alpha_t,\bar\alpha_t,\sigma_tβt,αt,αˉt,σt(训练前就定好,推理不变)
- 用户提示词编码得到固定条件 ccc(全程所有t共用同一个c)
- 初始 xTx_TxT:推理开始时手动采样的纯高斯噪声
- 网络权重 θ\thetaθ(训练完成后固定)
latent扩散补充(SD/Qwen/Flux/Wan都是latent扩散)
DDPM本身可以在像素空间跑;
latent扩散:
- 训练、推理的整套前向/反向全部在VAE压缩后的隐空间执行
- 反向迭代得到 x0x_0x0(latent)之后,额外一步 VAE Decoder
image=VAE_decode(x0) \text{image} = \text{VAE\_decode}(x_0) image=VAE_decode(x0)
x0x_0x0 本身不是图片!
四、CFG 分类器自由引导(条件扩散推理增强,训练不用!)
SD、ComfyUI里的CFG scale,只在推理阶段使用,训练不存在
同时预测两个噪声:
- 带条件:ϵθ(xt,t,c)\epsilon_\theta(x_t,t,c)ϵθ(xt,t,c)
- 空条件(空提示):ϵθ(xt,t,∅)\epsilon_\theta(x_t,t,\emptyset)ϵθ(xt,t,∅)
融合后的噪声:
KaTeX parse error: Can't use function '\(' in math mode at position 2: \̲(̲\epsilon_{\text...
然后把这个 ϵcfg\epsilon_{\text{cfg}}ϵcfg 代入上面的均值公式,替代原来的 ϵθ\epsilon_\thetaϵθ。
cfg_scale=1:等价不做引导;越大越贴合提示词。
五、完整时序串讲(一句话流水线)
训练阶段
取原图 x0x_0x0 → 随机选t → 采样噪声ϵ\epsilonϵ → 闭式算出带噪图xtx_txt → 提示词编码得到ccc → 网络输入(xt,t,c)(x_t,t,c)(xt,t,c)输出预测噪声ϵθ\epsilon_\thetaϵθ → MSE(ϵ,ϵθ\epsilon,\epsilon_\thetaϵ,ϵθ) → 更新网络。
推理阶段
提示词编码得到固定条件ccc → 随机采样初始纯噪声xTx_TxT → 循环t从T到1:
输入(xt,t,c)(x_t,t,c)(xt,t,c)预测噪声 → 代入反向公式算出xt−1x_{t-1}xt−1 → 循环直到得到x0x_0x0(latent)→ VAE解码得到图片。
六、容易混淆的衍生采样器一句话区分(基于DDPM底座)
- DDPM:反向每一步都加噪声,随机采样,慢,(T=1000)
- DDIM:修改反向公式,去掉随机z,确定性采样,可以大步跳,步数变少
- DPM++ / Euler / Karras(ComfyUI K采样器):重新设计调度与反向更新规则,收敛更快,是现在主流
所有这些采样器,训练阶段完全一样,都是用DDPM的前向+MSE噪声损失训练,只是推理时的迭代方程不同。
七、极简公式速查表(方便复制)
- αt=1−βt\alpha_t = 1-\beta_tαt=1−βt
- αˉt=∏i=1tαi\bar\alpha_t = \prod_{i=1}^t \alpha_iαˉt=∏i=1tαi
- 前向闭式:xt=αˉtx0+1−αˉtϵx_t = \sqrt{\bar\alpha_t}x_0 + \sqrt{1-\bar\alpha_t}\epsilonxt=αˉt x0+1−αˉt ϵ
- 训练损失:L=E∥ϵ−ϵθ(xt,t,c)∥2\mathcal{L} = \mathbb{E}\big\\\|\\epsilon - \\epsilon_\\theta(x_t,t,c)\\\|\^2\\bigL=E∥ϵ−ϵθ(xt,t,c)∥2
- 反向均值:μθ=1αt(xt−βt1−αˉtϵθ)\mu_\theta = \frac{1}{\sqrt{\alpha_t}}\left( x_t - \frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\epsilon_\theta \right)μθ=αt 1(xt−1−αˉt βtϵθ)
- 反向采样:KaTeX parse error: Can't use function '\(' in math mode at position 67: ...al{N}(0,I),z=0(\̲(̲t=1\))