算法可视化与交互学习平台
学习 Diffusion / DDPM:从加噪去噪到图像生成Diffusion / DDPM: From Noising and Denoising to Image Generation
从 DDPM 的前向扩散公式出发,用最小二维数据和 16×16 几何图像理解 forward 加噪、高斯噪声张量 epsilon、噪声预测训练目标、reverse 去噪采样和 scheduler 直觉,并通过 Tiny DDPM 实验观察模型如何从雪花噪声中恢复图像结构。
先抓住 DDPM 的核心直觉
DDPM(Denoising Diffusion Probabilistic Model)是最经典的一类 Diffusion Model。它的核心不是“直接画出图像”,而是学会一件更小、更稳定的事情:
训练时,我们人为把干净数据 x0 加噪成 xt,并且保存真实噪声 epsilon。这里的 epsilon 不是一个标量,而是和图像同形状的噪声张量:每个像素、每个通道都有独立采样的高斯随机值。模型学习预测这整张噪声图。生成时,从纯噪声开始,反复预测噪声、扣掉噪声,结构就会一步步浮现。
严格说,本模块是 DDPM 的教学版骨架:重点讲 DDPM 的 forward 加噪、噪声预测训练目标和 reverse 去噪直觉;最后的 Tiny 实验为了可视化做了最小化处理,不覆盖完整论文里的 ELBO 推导和所有方差参数化细节。
学习主线是:
一张图看 DDPM 算法路径
DDPM 有两个方向相反的过程。Forward process 是人为规定的加噪规则,不需要学习;reverse process 是模型要学习的去噪过程。
为什么不直接训练模型从 x_T 一步生成 x_0?因为这太难。DDPM 把一个困难的大跳跃拆成很多小步,每一步只做一点点去噪。
关键要记住:forward 是我们写死的数学过程,模型不需要学它;模型真正学习的是在给定 x_t 和 t 时,预测混入的那一整份噪声张量 epsilon。这一思想非常适合图像生成:先从随机噪声中恢复大结构,再逐步恢复局部形状、边界与细节。Tiny DDPM 实验会把这个过程缩小到 16×16 简单图案里,让你直接看到结构如何从噪声中浮现。
DDPM Forward Process:一步跳到任意噪声等级
DDPM 的 forward process 是人为定义的加噪规则。训练时可以直接从干净样本 跳到任意噪声等级 ,不必真的连续加噪 t 次。
这个高斯分布公式在说什么
这个式子读作:给定上一时刻的数据 ,下一时刻的数据 是从一个高斯分布中采样出来的。这个高斯分布的均值是 ,协方差是 。这里 是单位矩阵,表示每个维度都加入独立同分布的高斯噪声。
它和采样公式是等价的
从高斯分布采样可以写成“均值 + 标准差乘以标准高斯噪声”。所以这个分布形式等价于把上一时刻信号保留一部分,再加入一部分独立高斯噪声。
从单步加噪开始
Diffusion 的 forward process 先定义一个单步马尔可夫加噪过程。每一步只保留一部分上一时刻的信号,并加入一份新的高斯噪声。
展开两步,看累计保留比例从哪里来
把第一步代入第二步,原始信号 前面的系数会连乘,因此出现累计保留比例 。
把多份高斯噪声合并
多份独立标准高斯噪声的线性组合仍然是高斯噪声。上式里的两项噪声可以合并成一项新的标准高斯噪声,其总方差为 。
推广到任意 timestep
令 表示从第 步到第 步的 连乘,就得到可以直接从 采样到 的闭式公式。
如何理解两个系数
控制原始信号还剩多少, 控制累计噪声混入多少。噪声等级越高,原始信号权重越小,噪声权重越大。
epsilon 不是一个数,而是一整份噪声张量
如果 是一张 的图像,那么 也是 。同一个 timestep 下, 是全图共享的噪声强度系数,但 在每个像素、每个通道上都有自己的随机值。
正态分布曲线里采样到的是横轴值
钟形曲线的 y 值是概率密度,用来说明哪些位置更容易被抽到;真正采样返回的是横轴上的数值。代码里的 `torch.randn_like(x0)` 会返回一整份和 同形状的随机张量,里面的值通常靠近 0,少数会靠近 或 。
最小代码
逐步演算:一个像素 / 一个维度如何被加噪
x0 = 1.0
epsilon = -0.4
alpha_bar_t = 0.64高斯分布观察:epsilon 到底怎么采样
在逐步演算里,我们先看了单个像素或单个维度的计算。但在真正的 DDPM forward process 里,更准确的说法不是“得到一个固定结果”,而是:给定上一时刻 后,下一时刻 来自一个条件概率分布。
这句话的意思是: 会围绕一个中心随机波动。这个中心不是原来的 ,而是衰减后的信号:
扩散范围由协方差控制:
这里 是单位矩阵,表示每个维度都加入独立同分布的高斯噪声。也就是说,如果数据是二维点,两个坐标分别独立加噪;如果数据是图像,每个像素、每个 RGB 通道或 latent 维度都按同样规则独立加入高斯噪声。
容易混淆的一点是:正态分布的钟形曲线里,横轴是可能被抽到的随机值,纵轴是概率密度。采样得到的是横轴上的值,不是纵轴高度。也就是说,torch.randn_like(x) 返回的是很多类似 0.23、-1.51、0.88 的随机数,而不是概率密度。
高斯采样有一个通用写法:
把 DDPM 的均值和标准差代进去:
就得到 forward process 的采样形式:
所以,分布写法和采样写法描述的是同一件事:前者强调“ 来自哪个概率分布”,后者强调“如何真正采样出一个 ”。
一维高斯加噪图解
交互观察:调节 alpha_t 看 DDPM 单步加噪
调节上一时刻数据 x_{t-1}、保留比例 alpha_t 和采样数量,观察理论高斯曲线与实际采样直方图是否重合。这个实验帮助理解:forward process 给出的不是单个确定值,而是一整个条件分布;采样得到的是横轴上的 x_t 数值,曲线高度只是概率密度。
二维高斯加噪观察:每个维度独立扰动
二维情况和一维没有本质区别,只是一个数变成了一个二维向量。给定上一时刻点 ,forward 加噪仍然是: 其中 。这里的 是二维单位矩阵,表示第 1 维和第 2 维分别加入独立同分布的高斯噪声。因为协方差是 ,两个方向的方差相同、相关性为 ,所以采样点会围绕均值 形成近似圆形云团。 这个二维点云就是图像 / latent 加噪的最小版本:二维点 多维向量 图像张量,本质还是同一个公式。
二维加噪过程观察:结构如何逐步变成噪声
这个实验用二维点云模拟图像 / latent 中的“结构”。 是干净数据, 是第 个噪声等级下的数据。 每个 timestep 都按闭式公式直接采样:。 当 较小时, 较大,原始结构仍然清楚;当 变大时, 变大,随机噪声越来越主导。接近最后一步时,点云基本忘记原始结构,逐渐接近标准高斯噪声。
训练目标:预测噪声 epsilon
模型输入带噪样本 和噪声等级 ,输出它认为混入的噪声张量 。训练目标就是让预测噪声接近 forward process 中真实加入的整份噪声 。
先看训练样本从哪里来
训练时, 不是数据集里原本存在的样本,而是我们用干净样本 和随机噪声张量 主动合成出来的。对于图像, 的形状和 完全一样,每个元素独立来自标准正态分布。
真正关键:训练时我们知道真实噪声
虽然 是随机噪声,但它不是未知答案。因为 forward 加噪是我们自己做的,所以生成 时用到的那一份 会被保存下来,直接作为监督信号。
loss 在比较什么
模型要学的不是“这张图是什么”,而是“这个带噪样本里混入了哪一份噪声”。如果预测噪声和真实噪声越接近,MSE loss 就越小。
为什么不是直接预测 x0
直接预测 或 也可以设计成训练目标,但不同 timestep 下数据分布变化很大,学习会更不稳定。预测 的好处是:无论 怎么变,目标噪声都来自标准高斯分布,尺度更统一。
为什么模型能预测随机噪声
神经网络不是凭空预测一份完全不可见的随机数。它看到的是混合结果 和噪声等级 。在给定 与 后,模型可以利用训练数据分布中的结构线索,估计哪部分更像原始信号,哪部分更像噪声。
最本质的一句话
神经网络能预测噪声,不是因为噪声本身可预测,而是因为真实数据有强结构规律,噪声没有结构。模型在大量训练样本中学到“什么像真实数据”,于是面对带噪样本时,就能估计哪些部分更不像真实数据,从而估计混入的噪声。
和 reverse 去噪的关系
训练好以后,生成阶段没有真实 可以看。模型只能根据当前 和 预测 ,再用这个预测噪声反推出更干净的样本。
最小代码
Reverse Sampling:用预测噪声反推出更干净的样本
如果模型能估计 xt 中的噪声,就可以反推出当前 xt 对应的干净样本估计 x0_hat。采样器再根据这个估计把 xt 推向更干净的状态。
采样的直觉
每一步都先问模型:这里面像噪声的部分是什么?然后根据公式把这部分扣掉一点。重复多次后,从随机噪声中恢复出训练数据分布里的结构。
DDIM 风格的最小更新
从雪花噪声中恢复图像:训练一个 Tiny DDPM
这个实验把二维点云换成最小图像:程序生成一批 16×16 的简单图案,让 TinyConvDenoiser 学会在不同 timestep 下预测噪声。它是一个 DDPM 风格的教学实验:forward 加噪和 epsilon 预测目标来自 DDPM,网络和采样器为了能在浏览器里快速跑完而做了极简化。 训练时,我们先用 主动制造带噪图,再让模型学习 。这里的 是和图像同形状的噪声张量,代码里就是 `torch.randn_like(clean)`:每个像素、每个通道都独立采样一个标准高斯随机值。 因此模型不是直接“画图”,而是学会:在一张被雪花噪声吞没的图里,哪些部分更像噪声。训练完成后,就可以从纯噪声开始,一步步扣掉预测噪声,让图像结构重新浮现。 这里的扩散步数 表示把“从干净图像到纯噪声”的 forward 路径切成多少个 timestep。 不是越大越好,而是在生成质量、计算成本和可学习性之间做平衡: 太小,相当于每一步变化很大,结构会突然被破坏,reverse 去噪更难学; 较大,每一步只是小修正,更像沿楼梯下楼,过程更稳定,但训练和采样都要经历更多步,计算会更慢。 可以把 理解成生成路径的分辨率。 大,路径更细,每一步任务更简单; 小,路径更粗,速度更快,但每一步要跨越的变化更难。原始 DDPM 常用 ,因为很多小步更接近连续 diffusion process;但真实推理时,DDIM、DPM-Solver、Euler、UniPC 等快速 sampler 往往只用 20 到 50 步,LCM 或 Turbo 类方法甚至可以用 1 到 4 步。它们的目标都是:用更少步骤,仍然保持可接受的生成质量。 所以观察这个实验时,不要把“扩散步数 T”理解成绝对越大越好。它真正控制的是:把复杂生成拆成多少个小修正。调大 时,注意 forward 行是不是更平滑、reverse 行是不是更稳定;调小 时,注意速度是否更快,但最终结构是否更容易失真。