扩散模型教程第2章:前向加噪与反向去噪
本章是系列第 2 章:把 DDPM 的前向加噪与反向去噪两套机制讲到”你能画出训练循环、说清每个参数为什么这么设”的粒度。 前置:第 1 章 生成直觉与问题设定。不讲:采样加速(DDIM / 一致性模型)留到第 6 章,条件生成与生物落地留到第 6、8 章。 与第 3 章的分工:本章讲机制细节(课表怎么排、预测目标怎么选);第 3 章 DDPM 三式精讲把这些收敛成”闭式加噪 / ε 损失 / 反向采样”三式,讲它们如何咬合。
1. 本章目标与验收标准
Section titled “1. 本章目标与验收标准”学完本章,你应能在不看笔记的情况下完成下列自检:
- 说清前向过程为什么没有可学习参数,并写出”从 一步跳到 “的闭式。
- 解释 为什么要”慢慢变大”,并说出 linear 与 cosine 课表的形状差别与适用场景。
- 说明反向单步为什么也建模成高斯,以及这对步数 提出了什么要求。
- 讲清 ε / x0 / v 三种预测目标数学等价但实践不等价的原因,并对一个具体场景选出首选目标。
- 指出至少两个”参数调坏了”的现象,并定位到是课表还是预测目标的问题。
字数与深度定位:机制深讲章(约 8500–12000 汉字)。不做严格证明推导,公式只保留讲清”当前在学什么”的最小集。
2. 本章在全链条中的位置
Section titled “2. 本章在全链条中的位置”第 1 章第 5 节给过扩散全链条 9 步鸟瞰。为聚焦,本章把它简化成 5 大块:
flowchart LR A["① 数据准备<br/>规范化到 -1..1"] --> B["② 前向加噪<br/>q(x_t) 从 x_0 而来"] B --> C["③ 训练网络<br/>预测 ε 或 x0 或 v"] C --> D["④ 反向去噪采样<br/>T 步生成"] D --> E["⑤ 评估 / 应用"]
本章主战场是 ② 前向加噪 + ③ 训练网络——前向怎么设计、网络学什么、三种预测目标怎么选。④ 反向采样本章只讲”标准 DDPM 采样”的机制骨架,快而准的采样器(DDIM、DPM-Solver)留到第 6 章。⑤ 评估与应用在第 7、8 章。
一句话记住:本章 = 把”训一个能生成的 DDPM”这一块讲透。
本章的三句话总纲
Section titled “本章的三句话总纲”在深入之前,先给你三个可以随时回来对照的锚点:
- 前向过程是”确定式的加噪”——不需要神经网络,一条数学闭式就能把干净数据 一步跳到任意时刻的带噪样本 。这是训练能高效跑起来的根本原因。
- 反向过程是”学出来的去噪”——神经网络的唯一工作是:对每一个 ,把”这张带噪样本里加进去了多少噪声”预测出来(或等价地预测 、预测 )。
- DDPM 里所有超参(、 课表、预测目标)都在解同一个矛盾:每一步要足够小(模型才学得动),整条链又要足够短(训练和采样才跑得起)。
3. 前向过程:把数据”泡”进噪声
Section titled “3. 前向过程:把数据”泡”进噪声”3.1 一句话直觉
Section titled “3.1 一句话直觉”想象你拿一滴染色的细胞悬液,把它一点点稀释进培养液里。每一步稀释都很小,但稀释一千次,你就再也认不出原来那滴是什么了——最后看起来就是”背景”。
这就是前向过程在做的事:从数据 出发,一步步加高斯噪声,直到 几乎是标准正态。
flowchart LR X0["x_0<br/>干净数据"] -->|"+β_1 噪声"| X1["x_1"] X1 -->|"+β_2 噪声"| X2["x_2"] X2 -->|"..."| Xt["x_t"] Xt -->|"..."| XT["x_T ≈ N(0,I)<br/>纯噪声"]
3.2 单步前向:一句数学
Section titled “3.2 单步前向:一句数学”单步前向(这一步没有可学参数,是规定死的):
翻译:给上一步 乘个稍小的系数 ,再叠上一点方差为 的高斯噪声。 就是这一步”加多少噪声”。
3.3 前向最重要的一件事:闭式跳步
Section titled “3.3 前向最重要的一件事:闭式跳步”因为高斯加高斯还是高斯,把上面这条式子从 一路推到 ,可以合并成一个闭式:
用重参数化写成一个采样公式(这行是本章最重要的公式,请记住):
其中 ,,是从 1 到 的”累计保留系数”。
为什么这行这么关键? 因为它告诉你:训练时不用真的一步步加 1000 次噪声,只要采一个随机的 ,代入公式,一次乘加就能拿到 。这就是 DDPM 训练能又快又稳的根本原因。第 3 章会把这一式称作”第一式”,作为整个三式坐标系的起点。
把符号变成数:一个一维例子
Section titled “把符号变成数:一个一维例子”抽象公式看多了容易滑过去,我们拿一个具体数字走一遍。设某一维”像素”,在某个中等时刻 (于是 ,),并抽到噪声 :
同一个 、同一个 ,若换到更晚的时刻使 (则 ,):
对比这两个结果,你应该看到两件事:一是信号被压扁, 前面的系数从 0.7 掉到 0.1,原始信息越来越弱;二是噪声逐渐主导,高 时 的取值几乎完全由 决定,看起来更像噪声而不是数据。训练时网络在低 主要”擦细噪”,在高 则要在几乎纯噪声里猜结构——这个难度沿 的变化,正是下一节噪声课表要设计的东西。
3.4 生物类比:一次性稀释 vs 逐级稀释
Section titled “3.4 生物类比:一次性稀释 vs 逐级稀释”做 PCR / qPCR 标准曲线时,你会做梯度稀释。理论上”稀释 1000 次到某浓度”和”直接稀释一次到相同浓度”结果一样——因为稀释是线性可组合的。前向过程正是这个道理:单步加噪虽然定义在 ,但整条链在数学上可以直接”跳”到任意 。
值得多想一层的是这条链的教学含义:前向过程虽然”不训练”,却不是可有可无的配角。它实际上为网络铺出了一条从易到难的噪声课程——低 处样本几乎干净,网络要学的是”擦掉最后一点细噪”这种精细活;高 处样本几乎是纯噪声,网络要学的是”从一团乱麻里猜出大致该有什么结构”这种粗放活。前向课表决定了这条课程每一档的难度分布,而网络必须在所有档上都学会去噪。这就是为什么第 3 节反复强调”训练时 要随机均匀采样”——你不能只在容易的档上练,否则采样走到困难的高 段时网络就抓瞎了。这层理解会一直延续到第 6 章:那里讲的”采样步数怎么分配”,本质就是在问”这条课程的哪些档最值得多花算力”。
3.5 小结
Section titled “3.5 小结”| 事实 | 你要带走的记忆 |
|---|---|
| 前向过程有可学参数吗? | 没有。 是超参、 是它的累积 |
| 训练时怎么用它? | 采 、采 、代入闭式,得到 |
| 它决定了什么? | 决定” 时刻的噪声等级”——这就是下一节讲的课表 |
4. 噪声课表 β_t / ᾱ_t:整条链怎么”排”出来
Section titled “4. 噪声课表 β_t / ᾱ_t:整条链怎么”排”出来”4.1 为什么必须要有”课表”
Section titled “4.1 为什么必须要有”课表””如果每一步 都一样大,会出现两种糟糕情形:
- 太大:前几步就把信号打没了,模型永远学不到”接近干净数据”的那一段。
- 太小:走了 1000 步还没变成纯噪声, 不服从 ,采样起点就错了。
所以需要一条噪声课表(noise schedule):,让噪声等级从”几乎没加”平滑过渡到”几乎全是噪声”。
看懂课表最关键的量不是 ,而是 ——它直接告诉你” 时刻还剩多少原信号”。
| 量 | 直觉含义 | 端点 |
|---|---|---|
| 第 步新加多少噪声 | 从约 1e-4 慢慢升到约 2e-2 | |
| 第 步保留多少信号 | 接近 1,缓慢下降 | |
| 到第 步累计保留了多少 | 从约 1 单调降到约 0 | |
| 中噪声成分的幅度 | 从约 0 升到约 1 |
一句话: 就是”信噪比曲线”。课表设计的实质就是设计这条曲线的形状。
手算一下 ,把符号变成数。 假设一个极简课表,, 分别取 (真实课表值小得多,这里放大只为看清趋势)。逐步累乘 :
| (累乘) | 信号 | 噪声 | |||
|---|---|---|---|---|---|
| 1 | 0.1 | 0.9 | 0.900 | 0.949 | 0.316 |
| 2 | 0.2 | 0.8 | 0.720 | 0.849 | 0.529 |
| 3 | 0.3 | 0.7 | 0.504 | 0.710 | 0.704 |
| 4 | 0.4 | 0.6 | 0.302 | 0.550 | 0.835 |
| 5 | 0.5 | 0.5 | 0.151 | 0.389 | 0.921 |
看最后两列你就抓住了全部直觉:信号系数 从 0.949 单调降到 0.389,噪声系数 反向从 0.316 升到 0.921,两者在 附近交叉——那就是”信号和噪声各占一半”的转折点。每一步 只是局部小改动,但累乘效应让 快速衰减,这解释了为什么真实课表里单步 那么小(约 1e-4 到 2e-2)却仍能在 步后把信号打到接近 0。
4.2 两种最常见的课表
Section titled “4.2 两种最常见的课表”Linear(DDPM 原论文): 从 线性升到 ,。低分辨率数据没问题,但在高分辨率下有个毛病——大量步数都用在”已经几乎是纯噪声”的阶段做无用功。
Cosine(改进 DDPM,Nichol & Dhariwal 2021):改成直接设计 ,让它像 曲线一样平滑下降,末端不会太快掉到 0。结果是高分辨率图像和后来许多蛋白 / 分子扩散模型的默认选择。
为什么”高分辨率”会让 linear 失效,值得说清机制。图像分辨率越高,相邻像素的冗余越大——一张 256×256 的图,把每个像素独立加一点噪声,整体的”语义信号”其实衰减得很慢,因为你还能从大量相邻像素里恢复出结构。换句话说,高分辨率数据在同样的 下,实际可辨认程度比低分辨率高。linear 课表是按低分辨率(CIFAR 32×32)调出来的,直接搬到高分辨率,就会出现”名义上加了很多噪声、语义上其实还很清楚”的错配——结果是链条前半段网络在学”几乎不用去噪”的平凡任务,真正的噪声破坏都堆在末尾很短一段。cosine 把 的下坠推后、拉平,正是为了在高分辨率下把”语义信号的真实衰减”重新摊匀到整条链上。这解释了为什么同一条 linear 课表,在 CIFAR 上好用、在 256 图上就发灰糊。
flowchart LR L["Linear schedule<br/>β 从 1e-4 线性到 0.02"] -->|"低分辨率 OK"| APP1["适用 32×32 CIFAR"] C["Cosine schedule<br/>α̅_t 用 cos² 定义"] -->|"高分辨率更好"| APP2["适用 256×256 图像<br/>蛋白结构 大分子"]
4.3 看图说话:两条课表的信噪比曲线
Section titled “4.3 看图说话:两条课表的信噪比曲线”xychart-beta title "保留信号比例 sqrt(α̅_t)" x-axis "t / T" [0, 0.2, 0.4, 0.6, 0.8, 1.0] y-axis "sqrt(α̅_t)" 0 --> 1 line [1.0, 0.90, 0.65, 0.30, 0.08, 0.01] line [1.0, 0.97, 0.87, 0.65, 0.30, 0.02]
(数值是示意,帮你抓住形状。上面那条更靠上的是 cosine,下面那条更早下坠的是 linear。)
- linear 在中段就把信号砸掉大半——网络在 处已经面对”很难辨认”的输入。
- cosine 在整条链前 60% 都保留了较多信号,等于把学习难度更均匀地铺开。
这个”把难度铺开”的思路,你会在本章后面讲预测目标、以及第 6 章讲采样步数分配时反复见到——它几乎是扩散模型所有调参的底层母题。
4.4 参数调坏的后果(速查表)
Section titled “4.4 参数调坏的后果(速查表)”| 现象 | 可能是课表哪儿出问题 |
|---|---|
| 生成图像整体糊、细节缺失 | 上升太快,中段信号丢太早 |
| 生成图像有明显低频噪点、颜色发灰 | 末端 没足够小, 分布 ≠ |
| loss 在小 很低、大 一直下不去 | 大 处信号几乎全无,网络在噪声上硬拟合 |
| 训练前期 loss 忽上忽下 | 均匀采样但 loss 尺度差异大,可考虑 loss reweighting |
4.5 生物类比:变性梯度电泳
Section titled “4.5 生物类比:变性梯度电泳”想象一个 DGGE(变性梯度凝胶电泳)——梯度设置决定了不同 的 DNA 在哪段位置解链。你要的是”整段电泳区间都提供有意义的分辨”,而不是前半段没变、后半段全散。课表就是设计这个变性梯度。
4.6 小结
Section titled “4.6 小结”- 课表设计 = 设计 曲线的形状。
- 记住两条经验:低分辨率 linear 够用;高分辨率 / 复杂结构(蛋白、分子)默认 cosine。
- 别只盯着 看,画出 你才知道网络实际面对的是什么。这个前向可视化甚至不需要 GPU,第 9 章会做成可运行脚本。
- 课表是训练前就定死的超参,一旦确定就贯穿训练与采样两端:训练时它决定网络在哪些脏度上考试,采样时它又决定每一步该退多远。所以换课表往往意味着重训——这也是为什么社区 checkpoint 都会显式标注自己用的是 linear 还是 cosine,混用会 silently 训歪。
5. 反向过程:网络到底在学什么
Section titled “5. 反向过程:网络到底在学什么”5.1 一句话直觉
Section titled “5.1 一句话直觉”前向过程是”往数据里泡噪声”,反向过程就是倒过来——从纯噪声出发,一步步”擦掉一点点噪声”,最终擦出一张干净数据。
关键区别:前向不需要学,反向必须学。因为”给一张纯噪声图,往回退一步应该长什么样”不是数学能直接闭式给出的——它取决于训练数据的分布。
flowchart RL
XT["x_T ~ N(0,I)"] -->|"去噪一点"| Xtm1["x_{T-1}"]
Xtm1 -->|"..."| Xt["x_t"]
Xt -->|"网络 p_θ(x_{t-1}|x_t,t)"| Xtm2["x_{t-1}"]
Xtm2 -->|"..."| X0["x_0"]
神经网络的工作:对每一个时刻 、每一张带噪样本 ,预测”从 往回退一步应该是什么样”。
为什么不能”一步到位”直接从噪声跳回数据
Section titled “为什么不能”一步到位”直接从噪声跳回数据”一个很自然的疑问:既然前向能用闭式一步从 跳到 ,反向为什么不能训一个网络,一步从 直接吐出 ?答案藏在”多解”里。给定一张纯噪声 ,能还原成的干净数据不是唯一的——同一堆噪声可以是任何一张合理图像的起点。如果强迫网络一步预测 ,它面对的是一个极度多峰的目标,只能输出所有可能答案的”平均”,结果就是一张糊成一团的均值图(这正是第 1 章讲的 VAE 偏糊的同款病根)。
多步去噪把这个”病态的一步大跳”拆成许多”良性的小步”。每一小步只需要问:“在当前这个脏度上,往回挪一点点,最可能的样子是什么?“脏度相邻的两个时刻分布非常接近,条件分布近似单峰高斯,网络就能给出锐利的预测。多步的本质,是用”迭代精炼”把一个无法回答的多峰问题,拆成一连串能回答的近单峰问题。 这也解释了为什么步数不能太少——步子迈大了,相邻分布差异变大,单峰假设破裂,生成质量就掉。
5.2 反向单步的数学骨架
Section titled “5.2 反向单步的数学骨架”反向单步也被建模成高斯分布:
- 均值 :网络输出,代表”这一步的最佳猜测”。
- 方差 :DDPM 原论文里直接固定为 或 ,不学;改进 DDPM 会把它也学出来(主要改善似然,对 FID 不一定有帮助)。
为什么单步也是高斯? 因为前向每一步都是高斯且步长很小,反向单步在数学上可以证明”近似仍是高斯”。这就是为什么 DDPM 需要 很大()——只有步长足够小,“反向也是高斯”这个假设才成立。这也回答了第 1 章埋的那个问题:“为什么扩散要那么多步。”
关键点:DDPM 里的网络其实不直接输出 ,而是输出一个更好训练的量——下一节讲。
一个值得先说清的桥梁:假设网络预测出了噪声 ,反向单步的均值就能写成
不必背这条式子,但要看懂它在说什么:网络预测的噪声,通过一个只含已知课表系数的公式,被直接换算成”这一步该往哪儿退”。这就是为什么”预测噪声”和”知道怎么去噪”是等价的——采样时把预测的 代进去,加上一点由 决定的随机扰动,就得到 ,如此循环到 。第 3 章会把这条采样递推作为”第三式”精讲。
5.3 三种等价的预测目标:ε / x0 / v
Section titled “5.3 三种等价的预测目标:ε / x0 / v”DDPM 训练时,网络到底该输出什么?数学上有三种等价选法:
| 预测目标 | 网络输出 | 直觉 | 代表工作 |
|---|---|---|---|
| ε-prediction | ” 里加进去的噪声是什么样” | DDPM 原论文(Ho 2020)默认 | |
| x0-prediction | ” 背后那张干净图长什么样” | 一些蛋白 / 分子扩散模型 | |
| v-prediction | 上面两者的加权组合,一个”角度速度”量 | Salimans & Ho 2022(蒸馏)、SD 2.x |
三者之间怎么互换? 因为前向闭式 ,只要知道 和其中一个(、、),另外两个就能立刻算出来。所以数学上三选一完全等价——网络学的都是同一件事,只是”输出坐标”不同。
5.4 那实践中为什么还要选?
Section titled “5.4 那实践中为什么还要选?”三种目标虽然数学等价,loss 的信噪比却不同——网络实际”学起来的难易度”随 的分布也不同。用大白话讲:
- 预测 ε:当 很大时, 几乎是纯噪声,“预测噪声”其实就是”复述输入”,loss 天然很小,网络在这段没什么可学。优点:小 (图像最后几步的细节)loss 主导,生成细节好。
- 预测 x0:反过来。当 很小时,,“预测 “就是”复述输入”,loss 天然很小。优点:大 (决定整体结构的粗生成阶段)loss 主导。
- 预测 v:,可理解为”角度上的速度”,它的 loss 权重在整条 上都比较均匀,没有明显偏科。所以做蒸馏(后来成为一致性模型的基础)和少步采样时特别受欢迎。
flowchart TB A["三种预测目标"] --> B["ε-预测<br/>小 t loss 主导<br/>适合细节生成的图像"] A --> C["x0-预测<br/>大 t loss 主导<br/>适合结构生成 如蛋白骨架"] A --> D["v-预测<br/>权重均匀铺开<br/>适合蒸馏 少步 高分辨率"]
用一个生物场景把这层”偏科”讲透。设计蛋白骨架时,一条主链的整体折叠拓扑(是三螺旋束还是 β 桶)在扩散的大 阶段就基本定型了——那时结构还是一团模糊的坐标云,网络要在最脏的地方猜出”大形状往哪个方向收敛”。而侧链取向、局部键角这些细节是小 阶段的事。对蛋白设计来说,拓扑对了细节可以后续用 ProteinMPNN、能量最小化去修,拓扑错了整个骨架就废了。所以你希望网络把学习容量优先投在大 ——这正是 x0-prediction 的 loss 侧重。反过来,自然图像里”整体构图”通常没那么脆弱,反倒是最后几步的纹理细节决定观感,于是 ε-prediction 的小 侧重更合适。同一个数学骨架,因为任务关心的”脏度区间”不同,最优预测目标就不同——这就是为什么不能无脑照抄图像领域的默认设置。
5.5 一张表帮你选目标
Section titled “5.5 一张表帮你选目标”| 场景 | 首选 | 备选 | 为什么 |
|---|---|---|---|
| 图像扩散(256×256 及以下) | ε | v | ε 是原生默认,社区支持最好 |
| 高分辨率图像 / 潜空间扩散 | v | ε | v-prediction 是 SD 2.x 默认,训练稳定 |
| 蛋白骨架、大分子结构 | x0 | v | 大 (骨架结构)比小 (细节)更关键 |
| 计划用蒸馏 / 少步采样 | v | — | v 是 progressive distillation 与一致性模型的常规选择 |
| 训练不稳、loss 震荡严重 | ε → v | — | v 的 loss 尺度在整条 上更均匀 |
5.6 一个常被忽略但很关键的细节:loss 加权
Section titled “5.6 一个常被忽略但很关键的细节:loss 加权”无论选哪种预测目标,训练时都是这条简化 loss(以 ε-prediction 为例):
DDPM 原论文有个”工程上很漂亮的 trick”:丢掉了严格 ELBO 推导里的权重系数,把 loss 简化成上面这个”权重全 1”的 MSE。看起来是简化,实际效果更好——因为它相对更重视中大 处的学习,正好补上 ε-prediction 那边”大 loss 天然小”的短板。
一句话记住:DDPM 那条大家背下来的 ,本质是”预测目标 + loss 加权”两件事被打包成了默认配置。你换预测目标 = 换默认加权,两件事要一起考虑。第 3 章会把这条 loss 作为”第二式”单独精讲。
5.7 生物类比:三种”标注同一张图”的方式
Section titled “5.7 生物类比:三种”标注同一张图”的方式”想象你在标注一张荧光显微镜图像,目标是”细胞核在哪”。三种标注法:
- 标 mask(对应 x0):直接勾出细胞核区域,在结构层面直接给答案。
- 标 background(对应 ε):勾出非细胞核区域,即”噪声”,在细节处贡献大。
- 标梯度 / 边界(对应 v):勾出核 / 非核交界的梯度信息,是前两者的中间形态。
三种标注信息量等价——从任何一种都能重建其他两种。但训练一个分割模型时,选哪种当标签,模型的学习曲线和最终强弱项会不一样。这就是 ε / x0 / v 之争的本质。
5.8 完整采样流程:从纯噪声走回数据
Section titled “5.8 完整采样流程:从纯噪声走回数据”前面讲的都是”反向单步”。把单步串成完整采样,才是生成一张样本的全过程。标准 DDPM 采样(ancestral sampling)是这样一条循环:
- 从标准正态里抽一张纯噪声 ,作为起点。
- 对 逐步递减:
- 把 喂给网络,得到预测噪声 。
- 用 5.2 的换算公式算出这一步的均值 。
- 采一份新的高斯噪声 (当 时不加,直接取均值),得到 。
- 走完 步,得到的 就是生成样本。
flowchart LR
N["x_T ~ N(0,I)"] --> P["网络预测 ε_θ(x_t,t)"]
P --> M["算均值 μ_θ"]
M --> S["加随机扰动 σ_t·z<br/>得到 x_{t-1}"]
S -->|"t 还没到 0"| P
S -->|"t=0"| OUT["生成样本 x_0"]
有三个细节值得注意,它们都会在后面章节被反复提起:
- 每一步都要重新抽一份随机噪声 (最后一步除外)。正是这份逐步注入的随机性,让同一个起点 每次也可能走出不同结果——这是标准 DDPM 采样”随机”的来源。第 6 章讲的 DDIM 会把这份随机性去掉,变成确定式采样。
- 这条循环要跑满 次网络前向( 就是 1000 次),这正是扩散”采样慢”的直接原因。第 6 章的采样加速就是在减少这个次数。
- 采样和训练用的是同一个网络、同一套课表系数,没有任何额外训练。如果采样时用的课表或换算公式与训练时不一致,生成就会崩——这是初学者最常见的 bug。
5.9 小结
Section titled “5.9 小结”- 反向单步被建模成高斯 , 由网络学、 常直接固定。
- 网络的”输出坐标”有三种(ε / x0 / v),数学等价,但 loss 在 上的加权不同,实践效果不等价。
- ε 是原生默认(图像),v 是稳定通用的现代选择(高分辨率 / 蒸馏 / 少步),x0 在结构类生成(蛋白骨架)里更常见。
6. 为什么工业界常见 T=1000
Section titled “6. 为什么工业界常见 T=1000”把课表和反向高斯假设合起来看,就能理解 这个数字背后的取舍。 太小会同时踩两个坑:
- 反向高斯假设失效: 小意味着单步跨度大,“反向单步近似高斯”不再成立,模型学到的均值就系统性偏了。
- 课表被迫陡峭:要在少数几步里从干净走到纯噪声, 必须很大,中段信号会被砸得太快。
而 太大,训练和采样成本又线性上升。 是原论文在质量与成本之间找到的经验平衡点。
给一个数值直觉。linear 课表下单步保留系数 大约在 0.999( 小)到 0.99( 大)之间。用 0.999 这个量级估算,走 1000 步后累计保留的信号约是 这个量级的进一步衰减——实际因为后段 更大, 会掉到 量级, 才足够接近纯噪声。如果你把 砍到 50,为了让末端同样接近纯噪声,每步的 就得放大约 20 倍,单步跨度骤增,“反向近似高斯”立刻失效。这就是为什么”想采样快就直接减小训练 “是错的——它动的是训练网格的密度,代价是整个高斯假设塌掉。
这里要区分一个常见误解:训练用的 和采样实际走的步数(NFE)不是一回事。训练需要网络见过足够密的 网格,所以 大;但采样时可以用 DDIM、DPM-Solver 等在更少步上积分(几十步甚至几步就出图)。“训练网格密”和”采样步数少”并不矛盾——这正是第 6 章采样加速的核心,本章先埋下这个区分。
7. 训练循环:把前面所有零件装起来
Section titled “7. 训练循环:把前面所有零件装起来”到这里,你已经有了训练一个 DDPM 需要的全部零件。把它们组装成一个训练步:
- 从数据集采一批干净样本 。
- 为每个样本采一个随机时间步 。
- 采一份标准高斯噪声 。
- 用闭式一步造出带噪样本 。
- 把 喂给网络,得到预测( 或 或 )。
- 算与真实目标的 MSE,反向传播更新网络。
flowchart LR D["采 x_0"] --> T["采 t"] T --> N["采 ε"] N --> XT["闭式造 x_t"] XT --> NET["网络预测"] NET --> L["MSE loss"] L --> U["反向传播更新 θ"]
注意这个循环里没有”逐步加噪”这一步——第 4 步一次乘加就得到任意脏度的样本。这就是第 3 节强调的闭式跳步带来的直接工程收益。一个实践细节:训练时通常维护网络参数的 EMA(指数滑动平均)副本用于采样,它比原始权重更平滑、生成质量更稳,这是几乎所有扩散实现的默认做法。
7.1 逐行读伪代码
Section titled “7.1 逐行读伪代码”把上面六步落成伪代码,你会发现它短得惊人——这正是 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]是预计算好的常量表,不是网络的一部分。整条噪声课表在训练开始前就算好存成一个长度 的数组,训练时按 索引即可。前向过程”没有可学参数”这句话在代码里就体现为:abar是个 buffer,不进 optimizer。t是每个样本独立随机采的,同一个 batch 里不同样本处在完全不同的脏度。这让网络在一个 batch 内就见过从”几乎干净”到”几乎纯噪声”的全谱,训练信号非常丰富。net(xt, t)里的t必须喂进网络。网络要知道”现在这张图有多脏”才能给出正确的去噪量,所以 通常经过正弦位置编码后加进每一层。漏掉 是新手最常见的 bug 之一——网络会退化成”对所有脏度给同一个平均去噪”,生成一片糊。
7.2 训练和采样是两套循环
Section titled “7.2 训练和采样是两套循环”要特别分清:上面这个循环是训练,跑完得到一个训好的 net。真正生成样本是另一套循环——从 出发,反复调用 net 逐步去噪到 。训练循环里网络在”随机脏度上做回归”,采样循环里网络在”沿一条轨迹反复被查询”。第 1 章埋过、第 3 章会精讲的”训练与采样必须分家”,在代码层面就是这两个独立的 for 循环。本章聚焦训练循环,标准 DDPM 采样和它的加速留给第 6 章。
7.3 训练时最容易踩的几个坑
Section titled “7.3 训练时最容易踩的几个坑”DDPM 训练循环虽短,但有几个”不报错却训歪”的隐蔽 bug,值得提前记住:
| 症状 | 常见根因 | 怎么查 |
|---|---|---|
| 生成一片灰糊、看不出结构 | 没喂进网络,或时间嵌入接错层 | 打印网络对不同 的输出,看是否随 变化 |
| loss 降到很低但采样全是噪声 | 采样用的课表系数与训练不一致 | 核对采样代码里的 abar 和训练是同一张表 |
| loss 一直不降或 NaN | 数据没归一化到 ,或学习率过大 | 先确认数据尺度,再降 lr 试跑 |
| 生成质量比训练指标暗示的差 | 采样用了原始权重而非 EMA 副本 | 采样时切换到 ema 权重 |
| 换了 x0/v 预测后训练崩 | 目标换了,但 loss 或采样公式没同步换 | 三处(目标、loss、采样换算)必须一致 |
这些坑的共同点是:它们不会抛异常,只会让结果悄悄变坏。所以扩散模型的调试纪律是——先用一个玩具数据集(比如二维点云)把整条训练-采样链跑通、确认能生成出正确分布,再上真实数据。第 9 章的可运行脚本正是为此设计。
7.4 数据预处理:常被跳过却很关键
Section titled “7.4 数据预处理:常被跳过却很关键”上面伪代码的 dataloader 里藏着一个前提:数据已经归一化到网络和噪声匹配的尺度。DDPM 的标准做法是把数据线性映射到 ,因为前向加的是标准高斯噪声, 的尺度大约在 量级,数据尺度和它对齐,网络才好学。对生物数据这一步尤其要小心:分子坐标、蛋白帧、基因表达的原始尺度千差万别,直接扔进去往往训练不稳。第 8 章会讲每类生物数据各自的归一化惯例。
8. score-based / SDE 视角:另一个模型还是另一种视角?
Section titled “8. score-based / SDE 视角:另一个模型还是另一种视角?”你在论文和社群里会频繁看到”score matching""SDE""Langevin 采样”这些词,容易误以为它们是和 DDPM 并列的另一套模型。它们其实是同一件事的另一种视角:
- DDPM 让网络预测噪声 ;而”分数”(score)指的是对数概率密度的梯度 ,也就是”在数据空间里,往哪个方向走概率密度上升最快”。在高斯前向下,预测 和估计 score 只差一个已知系数——本质上是同一个量。你训了一个 ε-预测网络,就等于训了一个 score 估计器。
- 把 DDPM 的离散”加噪 步”取连续时间极限(让步数趋于无穷、每步趋于无穷小),前向过程就变成一个随机微分方程(SDE),反向也对应一个反向 SDE,或一个去掉随机项的等价概率流 ODE。
理解 score 视角,还能顺带看懂Langevin 采样这个词:既然 score 指向”概率密度上升最快的方向”,那从一个随机点出发,反复”沿 score 方向走一小步、再加一点随机扰动”,就能逐渐走到高概率区(数据所在的地方)。这正是反向去噪在做的事——每一步既朝着”更像数据”的方向修正,又保留一点随机性以覆盖多样性。
这个统一视角的价值不在于换一个模型,而在于它把采样问题变成了数值积分问题。一旦你把反向过程看成”解一个微分方程”,就能套用各种成熟的 ODE / SDE 数值解法器来加速采样:低阶的 Euler、高阶的 Heun、专为扩散设计的 DPM-Solver,本质都是在解同一个反向方程,只是用了精度和步数权衡不同的数值格式。第 6 章讲的这些采样器,全都建立在这个视角上。
入门阶段你只需记住一句话:DDPM 是 score-based / SDE 框架的一个离散特例,它们不是竞争关系,而是同一件事的两种坐标写法。等你需要理解高阶采样器、或读到 Flow Matching 这类”换路径”的方法时,再回来深挖这条线(第 5 章、第 6 章)。
9. 本章 Checklist
Section titled “9. 本章 Checklist”- 能说清前向过程没有可学参数,并写出从 到 的闭式
- 理解闭式跳步为什么让训练能高效跑起来
- 能画出 曲线,说出 linear 与 cosine 的形状差别与适用场景
- 能解释反向单步为什么是高斯,以及这为什么要求 大
- 能讲清 ε / x0 / v 数学等价但 loss 加权不等价,并对一个场景选出首选
- 知道训练用的 和采样 NFE 不是一回事
- 能默画 DDPM 的一个训练步(采 → 采 → 采 → 闭式造 → 预测 → MSE)
- 明白 score-based / SDE 是 DDPM 的另一种视角,不是另一个模型
10. 自测 4 问
Section titled “10. 自测 4 问”Q1. 有人说”训练 DDPM 要先把每张图逐步加噪 1000 次存下来再喂给网络”。这句话哪里错了?
参考要点
错在”逐步加噪 1000 次”。前向有闭式,训练时对每个样本随机采一个 ,一次乘加就得到 ,根本不需要真的滚完整条链,也不需要预存。逐步加噪只是定义这条链,不是训练的实现方式。
Q2. 你训练一个 256×256 的病理图扩散模型,用了 linear 课表,发现生成图整体发灰、细节糊。可能是什么问题?
参考要点
高分辨率下 linear 课表在中段就把信号砸掉太多,网络在大 处面对近乎纯噪声硬拟合,细节学不出来。优先换 cosine 课表(把学习难度更均匀铺开)。同时检查末端 是否足够小——发灰有时也来自 分布偏离 。
Q3. 既然 ε / x0 / v 数学上完全等价,为什么蛋白骨架生成常用 x0 而不是图像默认的 ε?
参考要点
因为 loss 加权不同。蛋白任务里”整体折叠拓扑”(大 决定)比”局部细节”(小 决定)更关键,而 x0-prediction 的 loss 恰好在大 处主导,把网络的学习容量导向结构生成。ε 则相反,loss 集中在小 (细节),更适合图像。
Q4. 同事说”我要把 T 从 1000 改成 20,这样采样快 50 倍”。这个想法的问题在哪?
参考要点
混淆了训练 和采样 NFE。把训练 直接砍到 20 会让单步跨度过大、反向高斯假设失效、课表被迫陡峭,训练直接垮掉。想要采样快,正确做法是保持训练 ,在采样时用 DDIM / DPM-Solver 等在少数步上积分(第 6 章)。训练网格密和采样步数少并不矛盾。
11. 与其他章节的关系
Section titled “11. 与其他章节的关系”- 第 1 章 生成直觉:本章把第 1 章 §7 的最小公式展开成完整的前向 / 反向机制。
- 第 3 章 DDPM 三式精讲:把本章的前向闭式、、反向采样收敛成三个方程,讲它们如何咬合成一个坐标系。本章是底座,第 3 章是精讲。
- 第 6 章 训练与采样旋钮:把本章埋的”采样 NFE ≠ 训练 T""高阶采样器”展开成 DDIM、DPM-Solver 的实战调参。
- 第 8 章 生物读者轨道:本章讲的 x0-prediction、cosine 课表在蛋白骨架扩散里的具体应用。
12. 延伸阅读
Section titled “12. 延伸阅读”| 文献 / 资源 | 为什么看 | 阅读深度建议 |
|---|---|---|
| Ho et al., DDPM, 2020 | 前向闭式、、固定方差的原始出处 | 精读方法节 |
| Nichol & Dhariwal, Improved DDPM, 2021 | cosine 课表、可学方差的来源 | 读课表与方差两节 |
| Salimans & Ho, Progressive Distillation, 2022 | v-prediction 的出处与动机 | 读 v-prediction 定义 |
| Song et al., Score-based SDE, 2021 | 理解 DDPM 与 SDE / score 的统一视角 | 先看综述图,再按需深挖 |
说明:本章聚焦机制与参数取舍;具体采样器与生物落地在后续章节按主题展开。
主题色
字体
字号
视觉效果
即将离开本站
你将前往外部网站:
该网站与本站无关,本站不对其内容、安全性或可用性负责。确定后将在新标签页打开。