跳转到内容

扩散模型教程第2章:前向加噪与反向去噪

本章是系列第 2 章:把 DDPM 的前向加噪反向去噪两套机制讲到”你能画出训练循环、说清每个参数为什么这么设”的粒度。 前置第 1 章 生成直觉与问题设定不讲:采样加速(DDIM / 一致性模型)留到第 6 章,条件生成与生物落地留到第 6、8 章。 与第 3 章的分工:本章讲机制细节(课表怎么排、预测目标怎么选);第 3 章 DDPM 三式精讲把这些收敛成”闭式加噪 / ε 损失 / 反向采样”三式,讲它们如何咬合。

学完本章,你应能在不看笔记的情况下完成下列自检:

  1. 说清前向过程为什么没有可学习参数,并写出”从 x0x_0 一步跳到 xtx_t“的闭式。
  2. 解释 βt\beta_t 为什么要”慢慢变大”,并说出 linear 与 cosine 课表的形状差别与适用场景。
  3. 说明反向单步为什么也建模成高斯,以及这对步数 TT 提出了什么要求。
  4. 讲清 ε / x0 / v 三种预测目标数学等价但实践不等价的原因,并对一个具体场景选出首选目标。
  5. 指出至少两个”参数调坏了”的现象,并定位到是课表还是预测目标的问题。

字数与深度定位:机制深讲章(约 8500–12000 汉字)。做严格证明推导,公式只保留讲清”当前在学什么”的最小集。


第 1 章第 5 节给过扩散全链条 9 步鸟瞰。为聚焦,本章把它简化成 5 大块:

全链条 5 大块,本章聚焦②③

本章主战场是 ② 前向加噪 + ③ 训练网络——前向怎么设计、网络学什么、三种预测目标怎么选。④ 反向采样本章只讲”标准 DDPM 采样”的机制骨架,快而准的采样器(DDIM、DPM-Solver)留到第 6 章。⑤ 评估与应用在第 7、8 章。

一句话记住:本章 = 把”训一个能生成的 DDPM”这一块讲透。

在深入之前,先给你三个可以随时回来对照的锚点:

  1. 前向过程是”确定式的加噪”——不需要神经网络,一条数学闭式就能把干净数据 x0x_0 一步跳到任意时刻的带噪样本 xtx_t。这是训练能高效跑起来的根本原因。
  2. 反向过程是”学出来的去噪”——神经网络的唯一工作是:对每一个 tt,把”这张带噪样本里加进去了多少噪声”预测出来(或等价地预测 x0x_0、预测 vv)。
  3. DDPM 里所有超参(TTβt\beta_t 课表、预测目标)都在解同一个矛盾:每一步要足够小(模型才学得动),整条链又要足够短(训练和采样才跑得起)。

3. 前向过程:把数据”泡”进噪声

Section titled “3. 前向过程:把数据”泡”进噪声”

想象你拿一滴染色的细胞悬液,把它一点点稀释进培养液里。每一步稀释都很小,但稀释一千次,你就再也认不出原来那滴是什么了——最后看起来就是”背景”。

这就是前向过程在做的事:从数据 x0x_0 出发,一步步加高斯噪声,直到 xTx_T 几乎是标准正态。

前向加噪链

单步前向(这一步没有可学参数,是规定死的):

q(xtxt1)=N(xt;  1βtxt1,  βtI)q(x_t \mid x_{t-1}) = \mathcal{N}\bigl(x_t;\; \sqrt{1-\beta_t}\, x_{t-1},\; \beta_t I \bigr)

翻译:给上一步 xt1x_{t-1} 乘个稍小的系数 1βt\sqrt{1-\beta_t},再叠上一点方差为 βt\beta_t 的高斯噪声。βt\beta_t 就是这一步”加多少噪声”。

3.3 前向最重要的一件事:闭式跳步

Section titled “3.3 前向最重要的一件事:闭式跳步”

因为高斯加高斯还是高斯,把上面这条式子从 x0x_0 一路推到 xtx_t,可以合并成一个闭式:

q(xtx0)=N(xt;  αˉtx0,  (1αˉt)I)q(x_t \mid x_0) = \mathcal{N}\bigl(x_t;\; \sqrt{\bar{\alpha}_t}\, x_0,\; (1-\bar{\alpha}_t) I \bigr)

重参数化写成一个采样公式(这行是本章最重要的公式,请记住):

xt=αˉtx0+1αˉtε,εN(0,I)x_t = \sqrt{\bar{\alpha}_t}\, x_0 + \sqrt{1-\bar{\alpha}_t}\, \varepsilon, \quad \varepsilon \sim \mathcal{N}(0,I)

其中 αt=1βt\alpha_t = 1 - \beta_tαˉt=s=1tαs\bar{\alpha}_t = \prod_{s=1}^{t} \alpha_s,是从 1 到 tt 的”累计保留系数”。

为什么这行这么关键? 因为它告诉你:训练时不用真的一步步加 1000 次噪声,只要采一个随机的 tt,代入公式,一次乘加就能拿到 xtx_t。这就是 DDPM 训练能又快又稳的根本原因。第 3 章会把这一式称作”第一式”,作为整个三式坐标系的起点。

抽象公式看多了容易滑过去,我们拿一个具体数字走一遍。设某一维”像素”x0=0.8x_0 = 0.8,在某个中等时刻 αˉt=0.49\bar{\alpha}_t = 0.49(于是 αˉt=0.7\sqrt{\bar{\alpha}_t} = 0.71αˉt=0.510.714\sqrt{1-\bar{\alpha}_t} = \sqrt{0.51} \approx 0.714),并抽到噪声 ε=0.5\varepsilon = 0.5

xt0.7×0.8+0.714×0.5=0.56+0.357=0.917x_t \approx 0.7 \times 0.8 + 0.714 \times 0.5 = 0.56 + 0.357 = 0.917

同一个 x0x_0、同一个 ε\varepsilon,若换到更晚的时刻使 αˉt=0.01\bar{\alpha}_t = 0.01(则 αˉt=0.1\sqrt{\bar{\alpha}_t} = 0.11αˉt0.995\sqrt{1-\bar{\alpha}_t} \approx 0.995):

xt0.1×0.8+0.995×0.5=0.08+0.4975=0.5775x_t \approx 0.1 \times 0.8 + 0.995 \times 0.5 = 0.08 + 0.4975 = 0.5775

对比这两个结果,你应该看到两件事:一是信号被压扁x0x_0 前面的系数从 0.7 掉到 0.1,原始信息越来越弱;二是噪声逐渐主导,高 ttxtx_t 的取值几乎完全由 ε\varepsilon 决定,看起来更像噪声而不是数据。训练时网络在低 tt 主要”擦细噪”,在高 tt 则要在几乎纯噪声里猜结构——这个难度沿 tt 的变化,正是下一节噪声课表要设计的东西。

3.4 生物类比:一次性稀释 vs 逐级稀释

Section titled “3.4 生物类比:一次性稀释 vs 逐级稀释”

做 PCR / qPCR 标准曲线时,你会做梯度稀释。理论上”稀释 1000 次到某浓度”和”直接稀释一次到相同浓度”结果一样——因为稀释是线性可组合的。前向过程正是这个道理:单步加噪虽然定义在 t1tt-1 \to t,但整条链在数学上可以直接”跳”到任意 tt

值得多想一层的是这条链的教学含义:前向过程虽然”不训练”,却不是可有可无的配角。它实际上为网络铺出了一条从易到难的噪声课程——低 tt 处样本几乎干净,网络要学的是”擦掉最后一点细噪”这种精细活;高 tt 处样本几乎是纯噪声,网络要学的是”从一团乱麻里猜出大致该有什么结构”这种粗放活。前向课表决定了这条课程每一档的难度分布,而网络必须在所有档上都学会去噪。这就是为什么第 3 节反复强调”训练时 tt 要随机均匀采样”——你不能只在容易的档上练,否则采样走到困难的高 tt 段时网络就抓瞎了。这层理解会一直延续到第 6 章:那里讲的”采样步数怎么分配”,本质就是在问”这条课程的哪些档最值得多花算力”。

事实你要带走的记忆
前向过程有可学参数吗?没有βt\beta_t 是超参、αˉt\bar{\alpha}_t 是它的累积
训练时怎么用它?tt、采 ε\varepsilon、代入闭式,得到 xtx_t
它决定了什么?决定”tt 时刻的噪声等级”——这就是下一节讲的课表

4. 噪声课表 β_t / ᾱ_t:整条链怎么”排”出来

Section titled “4. 噪声课表 β_t / ᾱ_t:整条链怎么”排”出来”

如果每一步 β\beta 都一样大,会出现两种糟糕情形:

  • β\beta 太大:前几步就把信号打没了,模型永远学不到”接近干净数据”的那一段。
  • β\beta 太小:走了 1000 步还没变成纯噪声,xTx_T 不服从 N(0,I)\mathcal{N}(0,I),采样起点就错了。

所以需要一条噪声课表(noise schedule):{β1,β2,,βT}\{\beta_1, \beta_2, \dots, \beta_T\},让噪声等级从”几乎没加”平滑过渡到”几乎全是噪声”。

看懂课表最关键的量不是 βt\beta_t,而是 αˉt\bar{\alpha}_t——它直接告诉你”tt 时刻还剩多少原信号”。

直觉含义端点
βt\beta_ttt新加多少噪声从约 1e-4 慢慢升到约 2e-2
αt=1βt\alpha_t = 1-\beta_ttt保留多少信号接近 1,缓慢下降
αˉt=αs\bar{\alpha}_t = \prod \alpha_s到第 tt累计保留了多少 x0x_0从约 1 单调降到约 0
1αˉt\sqrt{1-\bar{\alpha}_t}xtx_t 中噪声成分的幅度从约 0 升到约 1

一句话:αˉt\bar{\alpha}_t 就是”信噪比曲线”。课表设计的实质就是设计这条曲线的形状。

手算一下 αˉt\bar{\alpha}_t,把符号变成数。 假设一个极简课表,T=5T=5βt\beta_t 分别取 [0.1,0.2,0.3,0.4,0.5][0.1, 0.2, 0.3, 0.4, 0.5](真实课表值小得多,这里放大只为看清趋势)。逐步累乘 αt=1βt\alpha_t = 1-\beta_t

ttβt\beta_tαt\alpha_tαˉt\bar{\alpha}_t(累乘)αˉt\sqrt{\bar{\alpha}_t} 信号1αˉt\sqrt{1-\bar{\alpha}_t} 噪声
10.10.90.9000.9490.316
20.20.80.7200.8490.529
30.30.70.5040.7100.704
40.40.60.3020.5500.835
50.50.50.1510.3890.921

看最后两列你就抓住了全部直觉:信号系数 αˉt\sqrt{\bar{\alpha}_t} 从 0.949 单调降到 0.389,噪声系数 1αˉt\sqrt{1-\bar{\alpha}_t} 反向从 0.316 升到 0.921,两者在 t=3t=3 附近交叉——那就是”信号和噪声各占一半”的转折点。每一步 βt\beta_t 只是局部小改动,但累乘效应让 αˉt\bar{\alpha}_t 快速衰减,这解释了为什么真实课表里单步 βt\beta_t 那么小(约 1e-4 到 2e-2)却仍能在 TT 步后把信号打到接近 0。

Linear(DDPM 原论文):βt\beta_t10410^{-4} 线性升到 0.020.02T=1000T=1000。低分辨率数据没问题,但在高分辨率下有个毛病——大量步数都用在”已经几乎是纯噪声”的阶段做无用功

Cosine(改进 DDPM,Nichol & Dhariwal 2021):改成直接设计 αˉt\bar{\alpha}_t,让它像 cos2\cos^2 曲线一样平滑下降,末端不会太快掉到 0。结果是高分辨率图像和后来许多蛋白 / 分子扩散模型的默认选择

为什么”高分辨率”会让 linear 失效,值得说清机制。图像分辨率越高,相邻像素的冗余越大——一张 256×256 的图,把每个像素独立加一点噪声,整体的”语义信号”其实衰减得很慢,因为你还能从大量相邻像素里恢复出结构。换句话说,高分辨率数据在同样的 αˉt\bar{\alpha}_t 下,实际可辨认程度比低分辨率高。linear 课表是按低分辨率(CIFAR 32×32)调出来的,直接搬到高分辨率,就会出现”名义上加了很多噪声、语义上其实还很清楚”的错配——结果是链条前半段网络在学”几乎不用去噪”的平凡任务,真正的噪声破坏都堆在末尾很短一段。cosine 把 αˉt\bar{\alpha}_t 的下坠推后、拉平,正是为了在高分辨率下把”语义信号的真实衰减”重新摊匀到整条链上。这解释了为什么同一条 linear 课表,在 CIFAR 上好用、在 256 图上就发灰糊。

两种课表的适用场景

4.3 看图说话:两条课表的信噪比曲线

Section titled “4.3 看图说话:两条课表的信噪比曲线”
sqrt(α̅_t) 沿 t 变化(示意)

(数值是示意,帮你抓住形状。上面那条更靠上的是 cosine,下面那条更早下坠的是 linear。)

  • linear 在中段就把信号砸掉大半——网络在 t0.4Tt \approx 0.4T 处已经面对”很难辨认”的输入。
  • cosine 在整条链前 60% 都保留了较多信号,等于把学习难度更均匀地铺开

这个”把难度铺开”的思路,你会在本章后面讲预测目标、以及第 6 章讲采样步数分配时反复见到——它几乎是扩散模型所有调参的底层母题。

现象可能是课表哪儿出问题
生成图像整体糊、细节缺失β\beta 上升太快,中段信号丢太早
生成图像有明显低频噪点、颜色发灰末端 αˉT\bar{\alpha}_T 没足够小,xTx_T 分布 ≠ N(0,I)\mathcal{N}(0,I)
loss 在小 tt 很低、大 tt 一直下不去tt 处信号几乎全无,网络在噪声上硬拟合
训练前期 loss 忽上忽下tt 均匀采样但 loss 尺度差异大,可考虑 loss reweighting

想象一个 DGGE(变性梯度凝胶电泳)——梯度设置决定了不同 TmT_m 的 DNA 在哪段位置解链。你要的是”整段电泳区间都提供有意义的分辨”,而不是前半段没变、后半段全散。课表就是设计这个变性梯度。

  • 课表设计 = 设计 αˉt\bar{\alpha}_t 曲线的形状。
  • 记住两条经验:低分辨率 linear 够用;高分辨率 / 复杂结构(蛋白、分子)默认 cosine
  • 别只盯着 βt\beta_t 看,画出 αˉt\sqrt{\bar{\alpha}_t} 你才知道网络实际面对的是什么。这个前向可视化甚至不需要 GPU,第 9 章会做成可运行脚本。
  • 课表是训练前就定死的超参,一旦确定就贯穿训练与采样两端:训练时它决定网络在哪些脏度上考试,采样时它又决定每一步该退多远。所以换课表往往意味着重训——这也是为什么社区 checkpoint 都会显式标注自己用的是 linear 还是 cosine,混用会 silently 训歪。

5. 反向过程:网络到底在学什么

Section titled “5. 反向过程:网络到底在学什么”

前向过程是”往数据里泡噪声”,反向过程就是倒过来——从纯噪声出发,一步步”擦掉一点点噪声”,最终擦出一张干净数据。

关键区别:前向不需要学,反向必须学。因为”给一张纯噪声图,往回退一步应该长什么样”不是数学能直接闭式给出的——它取决于训练数据的分布

反向去噪链

神经网络的工作:对每一个时刻 tt、每一张带噪样本 xtx_t,预测”从 xtx_t 往回退一步应该是什么样”。

为什么不能”一步到位”直接从噪声跳回数据

Section titled “为什么不能”一步到位”直接从噪声跳回数据”

一个很自然的疑问:既然前向能用闭式一步从 x0x_0 跳到 xtx_t,反向为什么不能训一个网络,一步从 xTx_T 直接吐出 x0x_0?答案藏在”多解”里。给定一张纯噪声 xTx_T,能还原成的干净数据不是唯一的——同一堆噪声可以是任何一张合理图像的起点。如果强迫网络一步预测 x0x_0,它面对的是一个极度多峰的目标,只能输出所有可能答案的”平均”,结果就是一张糊成一团的均值图(这正是第 1 章讲的 VAE 偏糊的同款病根)。

多步去噪把这个”病态的一步大跳”拆成许多”良性的小步”。每一小步只需要问:“在当前这个脏度上,往回挪一点点,最可能的样子是什么?“脏度相邻的两个时刻分布非常接近,条件分布近似单峰高斯,网络就能给出锐利的预测。多步的本质,是用”迭代精炼”把一个无法回答的多峰问题,拆成一连串能回答的近单峰问题。 这也解释了为什么步数不能太少——步子迈大了,相邻分布差异变大,单峰假设破裂,生成质量就掉。

反向单步也被建模成高斯分布:

pθ(xt1xt)=N(xt1;  μθ(xt,t),  Σθ(xt,t))p_\theta(x_{t-1} \mid x_t) = \mathcal{N}\bigl(x_{t-1};\; \mu_\theta(x_t, t),\; \Sigma_\theta(x_t, t)\bigr)
  • 均值 μθ\mu_\theta:网络输出,代表”这一步的最佳猜测”。
  • 方差 Σθ\Sigma_\theta:DDPM 原论文里直接固定为 βtI\beta_t Iβ~tI\tilde{\beta}_t I,不学;改进 DDPM 会把它也学出来(主要改善似然,对 FID 不一定有帮助)。

为什么单步也是高斯? 因为前向每一步都是高斯且步长很小,反向单步在数学上可以证明”近似仍是高斯”。这就是为什么 DDPM 需要 TT 很大(T=1000T=1000)——只有步长足够小,“反向也是高斯”这个假设才成立。这也回答了第 1 章埋的那个问题:“为什么扩散要那么多步。”

关键点:DDPM 里的网络其实不直接输出 μθ\mu_\theta,而是输出一个更好训练的量——下一节讲。

一个值得先说清的桥梁:假设网络预测出了噪声 εθ(xt,t)\varepsilon_\theta(x_t, t),反向单步的均值就能写成

μθ(xt,t)=1αt(xtβt1αˉtεθ(xt,t))\mu_\theta(x_t, t) = \frac{1}{\sqrt{\alpha_t}}\Bigl(x_t - \frac{\beta_t}{\sqrt{1-\bar{\alpha}_t}}\,\varepsilon_\theta(x_t, t)\Bigr)

不必背这条式子,但要看懂它在说什么:网络预测的噪声,通过一个只含已知课表系数的公式,被直接换算成”这一步该往哪儿退”。这就是为什么”预测噪声”和”知道怎么去噪”是等价的——采样时把预测的 εθ\varepsilon_\theta 代进去,加上一点由 Σθ\Sigma_\theta 决定的随机扰动,就得到 xt1x_{t-1},如此循环到 x0x_0。第 3 章会把这条采样递推作为”第三式”精讲。

5.3 三种等价的预测目标:ε / x0 / v

Section titled “5.3 三种等价的预测目标:ε / x0 / v”

DDPM 训练时,网络到底该输出什么?数学上有三种等价选法:

预测目标网络输出直觉代表工作
ε-predictionεθ(xt,t)\varepsilon_\theta(x_t, t)xtx_t 里加进去的噪声是什么样”DDPM 原论文(Ho 2020)默认
x0-predictionx^0(xt,t)\hat{x}_0(x_t, t)xtx_t 背后那张干净图长什么样”一些蛋白 / 分子扩散模型
v-predictionvθ(xt,t)v_\theta(x_t, t)上面两者的加权组合,一个”角度速度”量Salimans & Ho 2022(蒸馏)、SD 2.x

三者之间怎么互换? 因为前向闭式 xt=αˉtx0+1αˉtεx_t = \sqrt{\bar{\alpha}_t}\, x_0 + \sqrt{1-\bar{\alpha}_t}\, \varepsilon,只要知道 xtx_t 和其中一个(ε\varepsilonx0x_0vv),另外两个就能立刻算出来。所以数学上三选一完全等价——网络学的都是同一件事,只是”输出坐标”不同。

三种目标虽然数学等价,loss 的信噪比却不同——网络实际”学起来的难易度”随 tt 的分布也不同。用大白话讲:

  • 预测 ε:当 tt 很大时,xtx_t 几乎是纯噪声,“预测噪声”其实就是”复述输入”,loss 天然很小,网络在这段没什么可学。优点:小 tt(图像最后几步的细节)loss 主导,生成细节好。
  • 预测 x0:反过来。当 tt 很小时,xtx0x_t \approx x_0,“预测 x0x_0“就是”复述输入”,loss 天然很小。优点:大 tt(决定整体结构的粗生成阶段)loss 主导。
  • 预测 vv=αˉtε1αˉtx0v = \sqrt{\bar{\alpha}_t}\,\varepsilon - \sqrt{1-\bar{\alpha}_t}\, x_0,可理解为”角度上的速度”,它的 loss 权重在整条 tt 上都比较均匀,没有明显偏科。所以做蒸馏(后来成为一致性模型的基础)和少步采样时特别受欢迎。
三种预测目标的 loss 侧重

用一个生物场景把这层”偏科”讲透。设计蛋白骨架时,一条主链的整体折叠拓扑(是三螺旋束还是 β 桶)在扩散的tt 阶段就基本定型了——那时结构还是一团模糊的坐标云,网络要在最脏的地方猜出”大形状往哪个方向收敛”。而侧链取向、局部键角这些细节是小 tt 阶段的事。对蛋白设计来说,拓扑对了细节可以后续用 ProteinMPNN、能量最小化去修,拓扑错了整个骨架就废了。所以你希望网络把学习容量优先投在大 tt——这正是 x0-prediction 的 loss 侧重。反过来,自然图像里”整体构图”通常没那么脆弱,反倒是最后几步的纹理细节决定观感,于是 ε-prediction 的小 tt 侧重更合适。同一个数学骨架,因为任务关心的”脏度区间”不同,最优预测目标就不同——这就是为什么不能无脑照抄图像领域的默认设置。

场景首选备选为什么
图像扩散(256×256 及以下)εvε 是原生默认,社区支持最好
高分辨率图像 / 潜空间扩散vεv-prediction 是 SD 2.x 默认,训练稳定
蛋白骨架、大分子结构x0vtt(骨架结构)比小 tt(细节)更关键
计划用蒸馏 / 少步采样vv 是 progressive distillation 与一致性模型的常规选择
训练不稳、loss 震荡严重ε → vv 的 loss 尺度在整条 tt 上更均匀

5.6 一个常被忽略但很关键的细节:loss 加权

Section titled “5.6 一个常被忽略但很关键的细节:loss 加权”

无论选哪种预测目标,训练时都是这条简化 loss(以 ε-prediction 为例):

Lsimple=Et,x0,ε[εεθ(xt,t)2]\mathcal{L}_{\text{simple}} = \mathbb{E}_{t, x_0, \varepsilon}\Bigl[\bigl\| \varepsilon - \varepsilon_\theta(x_t, t) \bigr\|^2\Bigr]

DDPM 原论文有个”工程上很漂亮的 trick”:丢掉了严格 ELBO 推导里的权重系数,把 loss 简化成上面这个”权重全 1”的 MSE。看起来是简化,实际效果更好——因为它相对更重视中大 tt 处的学习,正好补上 ε-prediction 那边”大 tt loss 天然小”的短板。

一句话记住:DDPM 那条大家背下来的 Lsimple\mathcal{L}_{\text{simple}},本质是”预测目标 + loss 加权”两件事被打包成了默认配置。你换预测目标 = 换默认加权,两件事要一起考虑。第 3 章会把这条 loss 作为”第二式”单独精讲。

5.7 生物类比:三种”标注同一张图”的方式

Section titled “5.7 生物类比:三种”标注同一张图”的方式”

想象你在标注一张荧光显微镜图像,目标是”细胞核在哪”。三种标注法:

  • 标 mask(对应 x0):直接勾出细胞核区域,在结构层面直接给答案。
  • 标 background(对应 ε):勾出非细胞核区域,即”噪声”,在细节处贡献大。
  • 标梯度 / 边界(对应 v):勾出核 / 非核交界的梯度信息,是前两者的中间形态。

三种标注信息量等价——从任何一种都能重建其他两种。但训练一个分割模型时,选哪种当标签,模型的学习曲线和最终强弱项会不一样。这就是 ε / x0 / v 之争的本质。

5.8 完整采样流程:从纯噪声走回数据

Section titled “5.8 完整采样流程:从纯噪声走回数据”

前面讲的都是”反向单步”。把单步串成完整采样,才是生成一张样本的全过程。标准 DDPM 采样(ancestral sampling)是这样一条循环:

  1. 从标准正态里抽一张纯噪声 xTN(0,I)x_T \sim \mathcal{N}(0, I),作为起点。
  2. t=T,T1,,1t = T, T-1, \dots, 1 逐步递减:
    • (xt,t)(x_t, t) 喂给网络,得到预测噪声 εθ(xt,t)\varepsilon_\theta(x_t, t)
    • 用 5.2 的换算公式算出这一步的均值 μθ\mu_\theta
    • 采一份新的高斯噪声 zz(当 t=1t=1 时不加,直接取均值),得到 xt1=μθ+σtzx_{t-1} = \mu_\theta + \sigma_t z
  3. 走完 TT 步,得到的 x0x_0 就是生成样本。
DDPM 完整采样循环

有三个细节值得注意,它们都会在后面章节被反复提起:

  • 每一步都要重新抽一份随机噪声 zz(最后一步除外)。正是这份逐步注入的随机性,让同一个起点 xTx_T 每次也可能走出不同结果——这是标准 DDPM 采样”随机”的来源。第 6 章讲的 DDIM 会把这份随机性去掉,变成确定式采样。
  • 这条循环要跑满 TT 次网络前向T=1000T=1000 就是 1000 次),这正是扩散”采样慢”的直接原因。第 6 章的采样加速就是在减少这个次数。
  • 采样和训练用的是同一个网络、同一套课表系数,没有任何额外训练。如果采样时用的课表或换算公式与训练时不一致,生成就会崩——这是初学者最常见的 bug。
  • 反向单步被建模成高斯 N(μθ,Σθ)\mathcal{N}(\mu_\theta, \Sigma_\theta)μθ\mu_\theta 由网络学、Σθ\Sigma_\theta 常直接固定。
  • 网络的”输出坐标”有三种(ε / x0 / v),数学等价,但 loss 在 tt 上的加权不同,实践效果不等价。
  • ε 是原生默认(图像),v 是稳定通用的现代选择(高分辨率 / 蒸馏 / 少步),x0 在结构类生成(蛋白骨架)里更常见。

把课表和反向高斯假设合起来看,就能理解 TT 这个数字背后的取舍。TT 太小会同时踩两个坑:

  1. 反向高斯假设失效TT 小意味着单步跨度大,“反向单步近似高斯”不再成立,模型学到的均值就系统性偏了。
  2. 课表被迫陡峭:要在少数几步里从干净走到纯噪声,βt\beta_t 必须很大,中段信号会被砸得太快。

TT 太大,训练和采样成本又线性上升。T=1000T=1000 是原论文在质量与成本之间找到的经验平衡点。

给一个数值直觉。linear 课表下单步保留系数 1βt\sqrt{1-\beta_t} 大约在 0.999(tt 小)到 0.99(tt 大)之间。用 0.999 这个量级估算,走 1000 步后累计保留的信号约是 0.99910000.370.999^{1000}\approx 0.37 这个量级的进一步衰减——实际因为后段 βt\beta_t 更大,αˉT\bar{\alpha}_T 会掉到 10510^{-5} 量级,xTx_T 才足够接近纯噪声。如果你把 TT 砍到 50,为了让末端同样接近纯噪声,每步的 βt\beta_t 就得放大约 20 倍,单步跨度骤增,“反向近似高斯”立刻失效。这就是为什么”想采样快就直接减小训练 TT“是错的——它动的是训练网格的密度,代价是整个高斯假设塌掉。

这里要区分一个常见误解:训练用的 TT 和采样实际走的步数(NFE)不是一回事。训练需要网络见过足够密的 tt 网格,所以 TT 大;但采样时可以用 DDIM、DPM-Solver 等在更少步上积分(几十步甚至几步就出图)。“训练网格密”和”采样步数少”并不矛盾——这正是第 6 章采样加速的核心,本章先埋下这个区分。


7. 训练循环:把前面所有零件装起来

Section titled “7. 训练循环:把前面所有零件装起来”

到这里,你已经有了训练一个 DDPM 需要的全部零件。把它们组装成一个训练步:

  1. 从数据集采一批干净样本 x0x_0
  2. 为每个样本采一个随机时间步 tUniform(1,T)t \sim \text{Uniform}(1, T)
  3. 采一份标准高斯噪声 εN(0,I)\varepsilon \sim \mathcal{N}(0, I)
  4. 用闭式一步造出带噪样本 xt=αˉtx0+1αˉtεx_t = \sqrt{\bar{\alpha}_t}\, x_0 + \sqrt{1-\bar{\alpha}_t}\, \varepsilon
  5. (xt,t)(x_t, t) 喂给网络,得到预测(εθ\varepsilon_\thetax^0\hat{x}_0vθv_\theta)。
  6. 算与真实目标的 MSE,反向传播更新网络。
DDPM 一个训练步

注意这个循环里没有”逐步加噪”这一步——第 4 步一次乘加就得到任意脏度的样本。这就是第 3 节强调的闭式跳步带来的直接工程收益。一个实践细节:训练时通常维护网络参数的 EMA(指数滑动平均)副本用于采样,它比原始权重更平滑、生成质量更稳,这是几乎所有扩散实现的默认做法。

把上面六步落成伪代码,你会发现它短得惊人——这正是 DDPM 工程友好的体现:

for x0 in dataloader: # 1. 采一批干净数据
t = randint(1, T, size=batch) # 2. 每个样本一个随机时间步
eps = randn_like(x0) # 3. 采标准高斯噪声
xt = sqrt(abar[t]) * x0 \
+ sqrt(1 - abar[t]) * eps # 4. 闭式一步造带噪样本
eps_pred = net(xt, t) # 5. 网络预测噪声
loss = mse(eps, eps_pred) # 6. 与真实噪声算 MSE
loss.backward(); opt.step(); opt.zero_grad()
ema.update(net) # 维护 EMA 副本供采样

逐行对照三件值得强调的事:

  • abar[t] 是预计算好的常量表,不是网络的一部分。整条噪声课表在训练开始前就算好存成一个长度 TT 的数组,训练时按 tt 索引即可。前向过程”没有可学参数”这句话在代码里就体现为:abar 是个 buffer,不进 optimizer。
  • t 是每个样本独立随机采的,同一个 batch 里不同样本处在完全不同的脏度。这让网络在一个 batch 内就见过从”几乎干净”到”几乎纯噪声”的全谱,训练信号非常丰富。
  • net(xt, t) 里的 t 必须喂进网络。网络要知道”现在这张图有多脏”才能给出正确的去噪量,所以 tt 通常经过正弦位置编码后加进每一层。漏掉 tt 是新手最常见的 bug 之一——网络会退化成”对所有脏度给同一个平均去噪”,生成一片糊。

要特别分清:上面这个循环是训练,跑完得到一个训好的 net。真正生成样本是另一套循环——从 xTN(0,I)x_T \sim \mathcal{N}(0,I) 出发,反复调用 net 逐步去噪到 x0x_0。训练循环里网络在”随机脏度上做回归”,采样循环里网络在”沿一条轨迹反复被查询”。第 1 章埋过、第 3 章会精讲的”训练与采样必须分家”,在代码层面就是这两个独立的 for 循环。本章聚焦训练循环,标准 DDPM 采样和它的加速留给第 6 章。

DDPM 训练循环虽短,但有几个”不报错却训歪”的隐蔽 bug,值得提前记住:

症状常见根因怎么查
生成一片灰糊、看不出结构tt 没喂进网络,或时间嵌入接错层打印网络对不同 tt 的输出,看是否随 tt 变化
loss 降到很低但采样全是噪声采样用的课表系数与训练不一致核对采样代码里的 abar 和训练是同一张表
loss 一直不降或 NaN数据没归一化到 [1,1][-1,1],或学习率过大先确认数据尺度,再降 lr 试跑
生成质量比训练指标暗示的差采样用了原始权重而非 EMA 副本采样时切换到 ema 权重
换了 x0/v 预测后训练崩目标换了,但 loss 或采样公式没同步换三处(目标、loss、采样换算)必须一致

这些坑的共同点是:它们不会抛异常,只会让结果悄悄变坏。所以扩散模型的调试纪律是——先用一个玩具数据集(比如二维点云)把整条训练-采样链跑通、确认能生成出正确分布,再上真实数据。第 9 章的可运行脚本正是为此设计。

7.4 数据预处理:常被跳过却很关键

Section titled “7.4 数据预处理:常被跳过却很关键”

上面伪代码的 dataloader 里藏着一个前提:数据已经归一化到网络和噪声匹配的尺度。DDPM 的标准做法是把数据线性映射到 [1,1][-1, 1],因为前向加的是标准高斯噪声,xTx_T 的尺度大约在 [1,1][-1,1] 量级,数据尺度和它对齐,网络才好学。对生物数据这一步尤其要小心:分子坐标、蛋白帧、基因表达的原始尺度千差万别,直接扔进去往往训练不稳。第 8 章会讲每类生物数据各自的归一化惯例。


8. score-based / SDE 视角:另一个模型还是另一种视角?

Section titled “8. score-based / SDE 视角:另一个模型还是另一种视角?”

你在论文和社群里会频繁看到”score matching""SDE""Langevin 采样”这些词,容易误以为它们是和 DDPM 并列的另一套模型。它们其实是同一件事的另一种视角

  • DDPM 让网络预测噪声 ε\varepsilon;而”分数”(score)指的是对数概率密度的梯度 xlogp(x)\nabla_x \log p(x),也就是”在数据空间里,往哪个方向走概率密度上升最快”。在高斯前向下,预测 ε\varepsilon 和估计 score 只差一个已知系数——本质上是同一个量。你训了一个 ε-预测网络,就等于训了一个 score 估计器。
  • 把 DDPM 的离散”加噪 TT 步”取连续时间极限(让步数趋于无穷、每步趋于无穷小),前向过程就变成一个随机微分方程(SDE),反向也对应一个反向 SDE,或一个去掉随机项的等价概率流 ODE

理解 score 视角,还能顺带看懂Langevin 采样这个词:既然 score 指向”概率密度上升最快的方向”,那从一个随机点出发,反复”沿 score 方向走一小步、再加一点随机扰动”,就能逐渐走到高概率区(数据所在的地方)。这正是反向去噪在做的事——每一步既朝着”更像数据”的方向修正,又保留一点随机性以覆盖多样性。

这个统一视角的价值不在于换一个模型,而在于它把采样问题变成了数值积分问题。一旦你把反向过程看成”解一个微分方程”,就能套用各种成熟的 ODE / SDE 数值解法器来加速采样:低阶的 Euler、高阶的 Heun、专为扩散设计的 DPM-Solver,本质都是在解同一个反向方程,只是用了精度和步数权衡不同的数值格式。第 6 章讲的这些采样器,全都建立在这个视角上。

入门阶段你只需记住一句话:DDPM 是 score-based / SDE 框架的一个离散特例,它们不是竞争关系,而是同一件事的两种坐标写法。等你需要理解高阶采样器、或读到 Flow Matching 这类”换路径”的方法时,再回来深挖这条线(第 5 章、第 6 章)。


  • 能说清前向过程没有可学参数,并写出从 x0x_0xtx_t 的闭式
  • 理解闭式跳步为什么让训练能高效跑起来
  • 能画出 αˉt\sqrt{\bar{\alpha}_t} 曲线,说出 linear 与 cosine 的形状差别与适用场景
  • 能解释反向单步为什么是高斯,以及这为什么要求 TT
  • 能讲清 ε / x0 / v 数学等价但 loss 加权不等价,并对一个场景选出首选
  • 知道训练用的 TT 和采样 NFE 不是一回事
  • 能默画 DDPM 的一个训练步(采 x0x_0 → 采 tt → 采 ε\varepsilon → 闭式造 xtx_t → 预测 → MSE)
  • 明白 score-based / SDE 是 DDPM 的另一种视角,不是另一个模型

Q1. 有人说”训练 DDPM 要先把每张图逐步加噪 1000 次存下来再喂给网络”。这句话哪里错了?

参考要点

错在”逐步加噪 1000 次”。前向有闭式,训练时对每个样本随机采一个 tt,一次乘加就得到 xtx_t,根本不需要真的滚完整条链,也不需要预存。逐步加噪只是定义这条链,不是训练的实现方式。

Q2. 你训练一个 256×256 的病理图扩散模型,用了 linear 课表,发现生成图整体发灰、细节糊。可能是什么问题?

参考要点

高分辨率下 linear 课表在中段就把信号砸掉太多,网络在大 tt 处面对近乎纯噪声硬拟合,细节学不出来。优先换 cosine 课表(把学习难度更均匀铺开)。同时检查末端 αˉT\bar{\alpha}_T 是否足够小——发灰有时也来自 xTx_T 分布偏离 N(0,I)\mathcal{N}(0,I)

Q3. 既然 ε / x0 / v 数学上完全等价,为什么蛋白骨架生成常用 x0 而不是图像默认的 ε?

参考要点

因为 loss 加权不同。蛋白任务里”整体折叠拓扑”(大 tt 决定)比”局部细节”(小 tt 决定)更关键,而 x0-prediction 的 loss 恰好在大 tt 处主导,把网络的学习容量导向结构生成。ε 则相反,loss 集中在小 tt(细节),更适合图像。

Q4. 同事说”我要把 T 从 1000 改成 20,这样采样快 50 倍”。这个想法的问题在哪?

参考要点

混淆了训练 TT 和采样 NFE。把训练 TT 直接砍到 20 会让单步跨度过大、反向高斯假设失效、课表被迫陡峭,训练直接垮掉。想要采样快,正确做法是保持训练 T=1000T=1000,在采样时用 DDIM / DPM-Solver 等在少数步上积分(第 6 章)。训练网格密和采样步数少并不矛盾。


  • 第 1 章 生成直觉:本章把第 1 章 §7 的最小公式展开成完整的前向 / 反向机制。
  • 第 3 章 DDPM 三式精讲:把本章的前向闭式、Lsimple\mathcal{L}_{\text{simple}}、反向采样收敛成三个方程,讲它们如何咬合成一个坐标系。本章是底座,第 3 章是精讲。
  • 第 6 章 训练与采样旋钮:把本章埋的”采样 NFE ≠ 训练 T""高阶采样器”展开成 DDIM、DPM-Solver 的实战调参。
  • 第 8 章 生物读者轨道:本章讲的 x0-prediction、cosine 课表在蛋白骨架扩散里的具体应用。

文献 / 资源为什么看阅读深度建议
Ho et al., DDPM, 2020前向闭式、Lsimple\mathcal{L}_{\text{simple}}、固定方差的原始出处精读方法节
Nichol & Dhariwal, Improved DDPM, 2021cosine 课表、可学方差的来源读课表与方差两节
Salimans & Ho, Progressive Distillation, 2022v-prediction 的出处与动机读 v-prediction 定义
Song et al., Score-based SDE, 2021理解 DDPM 与 SDE / score 的统一视角先看综述图,再按需深挖

说明:本章聚焦机制与参数取舍;具体采样器与生物落地在后续章节按主题展开。