Diffusion Model 的基本原理与模型架构

Diffusion Model 的基本原理与模型架构

如果需要简洁地说明扩散模型的基本原理,可以沿着刚才的顺序表达:

扩散模型先定义前向加噪过程,把真实数据逐渐变成接近高斯分布的噪声,再学习对应的反向生成过程。以经典 DDPM 为例,训练时随机采样时间步,通过闭式公式直接构造带噪样本,再训练网络预测加入的噪声。生成时从高斯噪声出发,反复调用同一个网络,并根据采样公式逐步更新样本,最终得到图片。网络骨干可以采用 U-Net,也可以采用 DiT 等 Transformer 架构。

如果继续介绍 Stable Diffusion,就接着解释它怎样降低图像生成的计算开销:

经典 Stable Diffusion 把扩散放在自编码器的潜空间中。训练图片先编码成 latent,扩散模型在 latent 上学习;生成时从潜空间噪声开始,逐步生成干净 latent,最后通过解码器恢复图片。文生图时,文本编码器提供条件特征,并通过交叉注意力等机制参与去噪预测。

Diffusion Model(扩散模型)是一类生成模型。理解它时,可以先抓住这样一个整体过程:

逐渐加噪 → 学习去噪 → 从噪声逐渐生成数据。

其中,"怎样加噪、怎样学习、怎样一步步生成"描述的是生成方法;"用什么神经网络完成预测"描述的是网络架构。经典 DDPM 经常使用 U-Net,DiT 则使用 Transformer。Stable Diffusion 又把自编码器、文本编码器和潜空间中的生成模型组合成一个完整系统。

这些名称之间的关系,等看完完整流程后再回过头整理会更容易。我们先从最经典的 DDPM 开始,看看一张图片怎样变成噪声,以及模型怎样学会从噪声生成图片。

1 先看 Diffusion 到底在做什么

假设我们希望模型生成图片。训练集中有一张真实图片,记作 x 0 x_0 x0。

训练时,我们向这张图片加入不同程度的噪声,得到带噪图片 x t x_t xt,再让模型学习如何去噪:

真实图片 x 0 x_0 x0 → 加噪得到 x t x_t xt → 让模型学习去噪

生成时,从一张随机高斯噪声开始,反复执行去噪更新:

x T    ⟶    x T − 1    ⟶    ⋯    ⟶    x 0 x_T \;\longrightarrow\; x_{T-1} \;\longrightarrow\; \cdots \;\longrightarrow\; x_0 xT⟶xT−1⟶⋯⟶x0

在这条生成路径中, x T x_T xT 是起始噪声, x 0 x_0 x0 是最终生成的图片。下标 t t t 表示当前处于哪个噪声水平;在这里采用的 DDPM 记号中, t t t 越大,通常意味着噪声越强。

先保留这个整体认识:训练时利用真实图片构造去噪任务,生成时把学到的去噪能力反复用起来。 下面分别展开这两个过程。

2 第一步 Forward Process 逐渐加噪

从真实图片 x 0 x_0 x0 开始,我们不断加入高斯噪声:

x 0 → x 1 → x 2 → ⋯ → x T x_0 \rightarrow x_1 \rightarrow x_2 \rightarrow \cdots \rightarrow x_T x0→x1→x2→⋯→xT

开始时,图像只受到一点干扰,仍然能看出物体。随着加噪继续,结构和细节越来越难辨认。噪声累计足够多以后,末端样本的分布就接近标准高斯分布,图像看起来基本只剩下噪声。

在经典 DDPM 中,每一步写成:

q ( x t ∣ x t − 1 ) = N ( 1 − β t   x t − 1 , β t I ) q(x_t \mid x_{t-1}) = \mathcal{N}\left( \sqrt{1-\beta_t}\,x_{t-1}, \beta_t I \right) q(xt∣xt−1)=N(1−βt xt−1,βtI)

这个式子表示:给定上一步的图片 x t − 1 x_{t-1} xt−1,下一步 x t x_t xt 从一个高斯分布中采样。实际操作可以写得更直观:

x t = 1 − β t   x t − 1 + β t   η t , η t ∼ N ( 0 , I ) x_t = \sqrt{1-\beta_t}\,x_{t-1} + \sqrt{\beta_t}\,\eta_t, \qquad \eta_t \sim \mathcal{N}(0,I) xt=1−βt xt−1+βt ηt,ηt∼N(0,I)

也就是先把原来的信号适当缩小,再加上一份新采样的高斯噪声。 β t \beta_t βt 控制这一步加入的噪声方差;每一步取多大的 β t \beta_t βt,由噪声调度决定。

不过实际训练不会真的一步一步执行:

x 0 → x 1 → ⋯ → x t x_0 \rightarrow x_1 \rightarrow \cdots \rightarrow x_t x0→x1→⋯→xt

例如,这次训练需要第 500 步的带噪图片,并不需要先把前面 499 步全部算出来。因为这个加噪过程有一个很方便的性质:可以从原图直接采样任意时间步的带噪图片。

具体公式是:

x t = α ˉ t   x 0 + 1 − α ˉ t   ϵ ϵ ∼ N ( 0 , I ) x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1-\bar{\alpha}_t}\,\epsilon \qquad \epsilon \sim \mathcal{N}(0,I) xt=αˉt x0+1−αˉt ϵϵ∼N(0,I)

这里:

α t = 1 − β t , α ˉ t = ∏ s = 1 t α s \alpha_t = 1-\beta_t, \qquad \bar{\alpha}t = \prod{s=1}^{t}\alpha_s αt=1−βt,αˉt=s=1∏tαs

α ˉ t \bar{\alpha}_t αˉt 把前面各步对信号的保留程度累计起来。因此,可以把 x t x_t xt 直观地理解为:

一部分原始图片,加上一部分随机噪声。

随着 t t t 增大, α ˉ t \bar{\alpha}_t αˉt 通常越来越小,原始图片的成分逐渐减弱,噪声的成分逐渐增强。

所以,在一次训练中,我们只需要拿到原图 x 0 x_0 x0,随机抽一个时间步 t t t,再采样一份噪声 ϵ \epsilon ϵ,就能直接构造这次要用的 x t x_t xt。它与逐步加噪到第 t t t 步得到的样本服从相同的条件分布;训练不必真的沿着整条加噪路径走一遍。

这也为下一步提供了一个很重要的条件:这张带噪图片是我们自己构造的,因此我们知道这次用了哪一份噪声 ϵ \epsilon ϵ。

Forward process基本上是人为规定好的数学过程,没有什么需要学习的参数。真正需要神经网络学习的是 Reverse Process

Diffusion 有一个很典型的特点:
训练时可以随机抽一个 (t) 一步训练;生成时却通常需要进行多步迭代。
这也是 Diffusion 推理速度长期以来比 GAN / VAE 一次前向生成慢的重要原因之一。

这个生成包括训练时候的去噪生成吗?训练的时候去噪生成也需要多步迭代吗

不需要。经典 Diffusion 训练时的"去噪训练"通常只做一步网络预测,不会真的从 (x_t) 一路迭代生成到 (x_0)。

这里的"生成"容易把训练推理混在一起。

训练时:只训练某一个随机时间步

假设真实图片是 (x_0)。

先随机采样:

t = 700 , ϵ ∼ N ( 0 , I ) t=700,\qquad \epsilon\sim\mathcal N(0,I) t=700,ϵ∼N(0,I)

直接构造:

x 700 = α ˉ 700 x 0 + 1 − α ˉ 700 ϵ x_{700} = \sqrt{\bar\alpha_{700}}x_0+ \sqrt{1-\bar\alpha_{700}}\epsilon x700=αˉ700 x0+1−αˉ700 ϵ

然后只进行一次模型前向

x 700 , 700 → U-Net/DiT ϵ ^ \boxed{ x_{700},700 \xrightarrow{\text{U-Net/DiT}} \hat\epsilon } x700,700U-Net/DiT ϵ^

计算:

L = ∥ ϵ − ϵ ^ ∥ 2 L=\|\epsilon-\hat\epsilon\|^2 L=∥ϵ−ϵ^∥2

然后反向传播、更新参数。

到这里这一条训练样本就结束了。

不会继续:

x 700 → x 699 → x 698 → ⋯ → x 0 x_{700}\rightarrow x_{699}\rightarrow x_{698}\rightarrow\cdots\rightarrow x_0 x700→x699→x698→⋯→x0

因此训练过程更准确地叫去噪目标训练,而不是实际完成一次完整的去噪生成。


推理/生成时:才需要多步迭代

真正生成一张新图片时,没有真实 (x_0) 给你。

只能先随机采样纯噪声:

x T ∼ N ( 0 , I ) x_T\sim\mathcal N(0,I) xT∼N(0,I)

然后:

x T → M o d e l x T − 1 → M o d e l x T − 2 → ⋯ → x 0 x_T \xrightarrow{Model} x_{T-1} \xrightarrow{Model} x_{T-2} \rightarrow\cdots\rightarrow x_0 xTModel xT−1Model xT−2→⋯→x0

也就是说同一个 U-Net / DiT 会被调用很多次:

text 复制代码
纯噪声 x_T
    ↓ Model
x_{T-1}
    ↓ Model
x_{T-2}
    ↓ Model
   ...
    ↓ Model
生成图片 x_0

所以我们说:

训练:随机一个 t ,通常一次模型预测 \boxed{\text{训练:随机一个 }t\text{,通常一次模型预测}} 训练:随机一个 t,通常一次模型预测

推理:多个 t ,多次模型预测 \boxed{\text{推理:多个 }t\text{,多次模型预测}} 推理:多个 t,多次模型预测

那为什么只训练一步,推理却能连续去噪?

因为训练过程中,每个 batch 都会随机抽不同的 (t)。

比如:

t = 13 , 487 , 920 , 231 , ... t=13,\quad 487,\quad 920,\quad 231,\ldots t=13,487,920,231,...

训练足够久以后,模型实际上学会了各种噪声程度下应该怎么处理

( x t , t ) → 去噪方向 (x_t,t)\rightarrow \text{去噪方向} (xt,t)→去噪方向

因此推理时就可以把这些能力串起来:

x 1000 → x 999 → ⋯ → x 1 → x 0 \boxed{ x_{1000}\rightarrow x_{999}\rightarrow\cdots\rightarrow x_1\rightarrow x_0 } x1000→x999→⋯→x1→x0

可以类比成:训练时随机抽一道"第 (t) 阶段怎么去噪"的题来练;推理时把各阶段的能力连续使用,完成整条生成过程。

3 第二步 Reverse Process 学习去噪

加噪的规则是事先规定好的。真正需要学习的是反方向:给你一张带噪图片 x t x_t xt,怎样得到噪声更少的 x t − 1 x_{t-1} xt−1?

从概率模型的角度,我们希望学习:

p_\\theta(x_ {t-1}\\mid x_t)

其中, θ \theta θ 表示神经网络的参数。这个分布描述了:在当前样本为 x t x_t xt 时,反向生成的下一步可能是什么样子。

经典 DDPM 中有一种很巧妙、也很容易实现的做法:

让神经网络预测构造 x t x_t xt 时加入的噪声。

回到刚才的加噪公式:

x t = α ˉ t   x 0 + 1 − α ˉ t   ϵ x_t = \sqrt{\bar{\alpha}_t}\,x_0 + \sqrt{1-\bar{\alpha}_t}\,\epsilon xt=αˉt x0+1−αˉt ϵ

训练时, x 0 x_0 x0 是已知的训练图片, ϵ \epsilon ϵ 是程序自己采样的噪声, x t x_t xt 是计算出来的结果。于是我们把 x t x_t xt 和 t t t 输入网络:

ϵ ^ = ϵ θ ( x t , t ) \hat{\epsilon} = \epsilon_\theta(x_t,t) ϵ^=ϵθ(xt,t)

ϵ θ \epsilon_\theta ϵθ 是这个噪声预测网络, ϵ ^ \hat{\epsilon} ϵ^ 是它的输出。我们希望网络的预测接近已知的 ϵ \epsilon ϵ:

ϵ ^ ≈ ϵ \hat{\epsilon} \approx \epsilon ϵ^≈ϵ

为什么还要输入时间步 t t t?因为模型需要知道这张图片目前受到了多强的噪声干扰。在轻噪声和重噪声状态下,图像中可利用的信息不同,网络需要据此调整预测。

有了已知的目标噪声,就可以直接比较"真实加入的噪声"和"网络预测的噪声"。最经典的简化训练目标是:

L s i m p l e = E x 0 , t , ϵ ∥ ϵ − ϵ θ ( x t , t ) ∥ 2 2 L_{\mathrm{simple}} = \mathbb{E}_{x_0,t,\epsilon} \left \\left\\\| \\epsilon-\\epsilon_\\theta(x_t,t) \\right\\\|_2\^2 \\right Lsimple=Ex0,t,ϵ∥ϵ−ϵθ(xt,t)∥22

也就是:你加入了什么噪声,就让模型把这份噪声预测出来。

这项损失会惩罚预测误差。随着模型看过越来越多图片,以及同一类图片在不同噪声水平下的样子,它逐渐学会根据带噪状态和时间步估计噪声。这里的监督目标来自加噪程序本身,无需人为标注。

把一次训练更新连起来,就是:

  1. 从训练集中取真实图片 x 0 x_0 x0。
  2. 随机采样时间步 t t t 和高斯噪声 ϵ \epsilon ϵ。
  3. 直接计算 x t = α ˉ t x 0 + 1 − α ˉ t ϵ x_t=\sqrt{\bar{\alpha}_t}x_0+\sqrt{1-\bar{\alpha}_t}\epsilon xt=αˉt x0+1−αˉt ϵ。
  4. 把 ( x t , t ) (x_t,t) (xt,t) 输入网络,得到 ϵ ^ \hat{\epsilon} ϵ^。
  5. 比较 ϵ ^ \hat{\epsilon} ϵ^ 与 ϵ \epsilon ϵ,反向传播并更新网络参数。

实际通常按一批样本计算。反复抽取图片、时间步和噪声,使同一个网络能够学习不同噪声水平下的去噪任务。

4 生成图片时 把学到的预测能力反复用起来

到这里,训练出了一个怎样的网络就清楚了。对于刚才这个 DDPM 例子,单次网络调用完成的是:

( x t , t ) ⟶ ϵ ^ (x_t,t)\longrightarrow\hat{\epsilon} (xt,t)⟶ϵ^

可以把它理解为:给我"当前时间步的带噪图片",我来估计其中的噪声。

那预测噪声为什么有助于生成图片?因为加噪公式把原图、带噪图和噪声联系在了一起。如果知道噪声,就可以把公式移项,恢复原图;把真实噪声换成网络的预测,就得到对干净图片的估计:

x ^ 0 = x t − 1 − α ˉ t   ϵ ^ α ˉ t \hat{x}_0 = \frac{ x_t-\sqrt{1-\bar{\alpha}_t}\,\hat{\epsilon} }{ \sqrt{\bar{\alpha}_t} } x^0=αˉt xt−1−αˉt ϵ^

这说明了噪声预测与去噪之间的联系。不过在噪声很强时,网络的一次预测还不够准确。经典生成过程会先依据当前预测,按采样公式把样本更新到更低的噪声水平,再重新预测。

因此,生成一张图片时,先从标准高斯分布采样起始噪声:

x T ∼ N ( 0 , I ) x_T \sim \mathcal{N}(0,I) xT∼N(0,I)

然后把 ( x T , T ) (x_T,T) (xT,T) 输入网络,根据预测结果计算下一步 x T − 1 x_{T-1} xT−1;再把 ( x T − 1 , T − 1 ) (x_{T-1},T-1) (xT−1,T−1) 输入同一个网络,继续得到 x T − 2 x_{T-2} xT−2。这样不断重复:

x T → x T − 1 → x T − 2 → ⋯ → x 0 x_T \rightarrow x_{T-1} \rightarrow x_{T-2} \rightarrow \cdots \rightarrow x_0 xT→xT−1→xT−2→⋯→x0

整个过程中,同一个去噪网络会被反复调用很多次。 每一步都使用当前的样本和当前时间步,网络参数在生成时保持固定。

这里也就能区分训练和生成了:训练时有真实图片,可以直接构造随机时间步的训练样本;生成时从噪声开始,需要依靠模型把当前样本一步步推进到图片。

负责"根据预测结果算出下一步"的部分,通常称为采样器。DDPM 和 DDIM 可以采用不同的采样构造;DDIM 能在兼容的训练目标下使用不同的生成轨迹和较少的采样步数。先理解网络给出预测、采样器利用预测更新样本,后面再看具体采样公式就容易对上各个部分。

5 去噪网络怎样实现 先看 U-Net

前面一直用 ϵ θ ( x t , t ) \epsilon_\theta(x_t,t) ϵθ(xt,t) 表示网络,还没有规定它内部长什么样。

经典图像扩散模型中,最常见的选择之一是 U-Net。于是单次预测可以画成:

x t ⟶ U-Net ⟶ ϵ ^ x_t \longrightarrow \text{U-Net} \longrightarrow \hat{\epsilon} xt⟶U-Net⟶ϵ^

时间步也要进入网络,通常先变成一个时间步嵌入:

t ⟶ E m b ( t ) t \longrightarrow \mathrm{Emb}(t) t⟶Emb(t)

两部分合起来,就是下面的表达式,其中 UNet 表示 U-Net:

ϵ θ ( x t , t ) = U N e t ( x t , E m b ( t ) ) \epsilon_\theta(x_t,t) = \mathrm{UNet}\left(x_t,\mathrm{Emb}(t)\right) ϵθ(xt,t)=UNet(xt,Emb(t))

U-Net 的基本结构,是先逐层下采样,再逐层上采样:

text 复制代码
带噪图片 x_t
      │
      ▼
高分辨率特征 ──────────────────► 高分辨率特征
      │                               ▲
    下采样                          上采样
      ▼                               │
中分辨率特征 ──────────────► 中分辨率特征
      │                         ▲
    下采样                    上采样
      ▼                         │
低分辨率特征 ───► 瓶颈层 ────────┘

右侧高分辨率特征 → 输出层 → 预测噪声

横向的连接就是 Skip Connection(跳跃连接):把下采样路径中某个尺度的特征,直接传给上采样路径中相应尺度的层。

为什么这样的结构适合去噪?因为判断噪声时,模型既需要较大范围的图像信息,也需要局部细节。下采样让后续层能够综合更大范围的信息;上采样逐步恢复空间分辨率;跳跃连接则让较早的细节特征能够直接传到后面的层。

例如,模型既要利用整体形状判断这里可能是一只狗,又要处理毛发、轮廓等局部信息。多尺度特征与跳跃连接有助于把这两类信息结合起来。实际扩散 U-Net 中还常包含残差块和注意力模块。

注意,图中的整个 U-Net 只对应一次网络调用。生成图片时,前一节的多步过程会反复调用这个完整网络。

6 从像素空间走到潜空间 理解 Stable Diffusion

现在已经知道怎样在图片上加噪,以及怎样用 U-Net 预测噪声。如果直接在 RGB 图片上执行这些操作,就是 Pixel-space Diffusion(像素空间扩散)

例如,一张图片的形状是:

x 0 ∈ R 3 × 512 × 512 x_0\in\mathbb{R}^{3\times512\times512} x0∈R3×512×512

那么带噪图片 x t x_t xt 仍然是这个大小,网络需要反复处理相应的图像张量。随着图像分辨率提高,这种多步计算的开销会变大。

这就自然引出了另一个想法:能不能先把图片压缩成更小的表示,再在这种表示上做扩散?

这就是 Latent Diffusion(潜空间扩散) 的核心思路,也是经典 Stable Diffusion 的关键组成部分。

先用自编码器的编码器把图片变成 latent:

x ⟶ VAE Encoder ⟶ z 0 x \longrightarrow \text{VAE Encoder} \longrightarrow z_0 x⟶VAE Encoder⟶z0

例如,在经典 Stable Diffusion 的一种常见配置中:

3 × 512 × 512 ⟶ 4 × 64 × 64 3\times512\times512 \longrightarrow 4\times64\times64 3×512×512⟶4×64×64

图片被转换成空间尺寸更小的潜变量张量。接下来,扩散过程发生在这个 z z z 上:

z 0 → z 1 → ⋯ → z T z_0\rightarrow z_1\rightarrow\cdots\rightarrow z_T z0→z1→⋯→zT

加噪、噪声预测和损失的思路,与前面在图片上做扩散相同,只是处理对象从 x x x 换成了 z z z。训练时,同样可以直接构造随机时间步的 z t z_t zt。

生成时,先采样潜空间中的高斯噪声,再逐步生成干净的 latent:

z T → z T − 1 → ⋯ → z 0 z_T\rightarrow z_{T-1}\rightarrow\cdots\rightarrow z_0 zT→zT−1→⋯→z0

最后,把 z 0 z_0 z0 交给解码器,恢复成图片:

z 0 ⟶ VAE Decoder ⟶ x z_0 \longrightarrow \text{VAE Decoder} \longrightarrow x z0⟶VAE Decoder⟶x

这样,前面学过的 VAE 就接上来了:编码器把图片转换成 latent,扩散模型学习生成 latent,解码器再把 latent 转换成图片。

把训练和生成分开画,会更清楚:

text 复制代码
训练潜空间扩散模型

真实图片
   │
   ▼
VAE Encoder
   │
   ▼
干净 latent z_0
   │
   ├── 随机时间步 t
   └── 随机噪声 ε
   │
   ▼
直接构造带噪 latent z_t
   │
   ▼
去噪网络预测 ε
   │
   ▼
与已知噪声比较,更新去噪网络
text 复制代码
生成新图片

随机潜空间噪声 z_T
   │
   ▼
反复调用去噪网络,并由采样器更新
   │
   ▼
干净 latent z_0
   │
   ▼
VAE Decoder
   │
   ▼
生成图片

在经典两阶段方案中,自编码器先训练好,随后固定它来训练扩散模型。纯文生图时没有输入图片需要编码,因此从 z T z_T zT 开始,最后使用解码器即可;图生图任务有输入图片,才需要先用编码器取得它的 latent。

7 让文字参与生成 Text-to-Image 的条件输入

前面描述的流程已经可以从噪声生成图片。但如果希望指定"生成什么",例如:

a black dog running on the beach

还需要让去噪网络知道这段文字的含义。

首先,把文字交给 Text Encoder(文本编码器) 。它把文本转换为一组特征,记作 c c c:

text ⟶ Text Encoder ⟶ c \text{text} \longrightarrow \text{Text Encoder} \longrightarrow c text⟶Text Encoder⟶c

经典 Stable Diffusion 使用过 CLIP 文本编码器;具体文本编码器会随模型版本变化。这里先关注它的职责:把文字转换成后续网络可以使用的条件特征。

于是,采用噪声预测时,去噪网络的输入从 ( z t , t ) (z_t,t) (zt,t) 扩展为:

ϵ θ ( z t , t , c ) \epsilon_\theta(z_t,t,c) ϵθ(zt,t,c)

这三个输入分别告诉网络:

  • z t z_t zt:当前的带噪图像表示是什么样。
  • t t t:当前处于哪个噪声水平。
  • c c c:希望生成什么内容。

这样,同样是从噪声开始,预测过程就可以受到"黑狗""奔跑""海滩"等文本信息的影响。

在经典 Stable Diffusion 的 U-Net 中,文本条件主要通过 Cross-Attention(交叉注意力) 注入。如果已经了解 Q、K、V,可以这样对应:

Q Q Q 来自图像特征的投影, K K K 和 V V V 来自文本特征的投影。

然后计算:

A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V \mathrm{Attention}(Q,K,V) = \mathrm{softmax} \left( \frac{QK^\mathsf{T}}{\sqrt{d_k}} \right)V Attention(Q,K,V)=softmax(dk QKT)V

直观上,每个图像位置会根据自己的特征,去选择当前更需要参考哪些文本信息。生成狗的相关区域可能更关注 "black""dog",背景相关区域可能更关注 "beach"。这些是学习到的注意力关联。

因此,文生图的过程可以连成:

text 复制代码
文字 → 文本编码器 → 文本条件 c
                         │
                         ▼
随机 latent → 反复进行有条件的去噪更新 → 干净 latent
                                             │
                                             ▼
                                        VAE Decoder
                                             │
                                             ▼
                                            图片

文字条件会参与多步生成,影响图像内容逐渐形成的过程。

8 有了整体流程 再理解不同的模型家族

到这里,我们已经能把经典文生图系统串起来了:自编码器提供潜空间,文本编码器提供条件,去噪网络给出预测,采样器推进生成,最后解码为图片。

这时再看 DDPM、DDIM、Stable Diffusion、DiT 等名称,就会发现它们经常描述的是不同层面的选择

理解模型名称时先区分这些维度

维度 回答的问题 常见选择或例子
生成方法 如何连接噪声分布与数据分布 DDPM、Score-based SDE、Flow Matching
数据空间 在哪种表示上生成 像素空间、潜空间
网络架构 用什么网络完成预测 U-Net、DiT 等 Transformer
预测目标 网络具体输出什么 噪声 ε、干净样本 x 0 x_0 x0、v 或速度场
采样方法 如何利用预测推进生成 DDPM 采样、DDIM、ODE 求解器
条件信息 生成结果受什么控制 无条件、类别、文本、其他图像
层次 解决的问题 例子
生成/数学框架 数据怎么从噪声变过来? DDPM、Score/SDE、Flow Matching
预测目标 网络到底预测什么? (\epsilon)、(x_0)、(v)、score/vector field
Backbone 用什么神经网络预测? U-Net、Transformer/DiT
数据空间 在哪里进行生成? Pixel Space、Latent Space

这些维度可以组合。例如,一个模型可以同时属于"潜空间生成""Transformer 架构"和"文本条件生成"。DDPM、Stable Diffusion、DiT 因而不构成互斥且一一对应的架构分类。

从生成过程看,DDPM 给出了经典的离散时间加噪与反向生成框架。Score-based 模型从不同噪声水平下的 score 来描述生成,SDE 则提供了连续时间的随机过程表述。Flow Matching、Rectified Flow 是与这些研究相联系的连续流生成方法,常通过学习速度场,把噪声逐渐转成数据。

从处理空间看,可以在原始像素空间生成,也可以像前面介绍的 Latent Diffusion 一样,在自编码器的潜空间中生成。

从网络架构看,可以用 U-Net,也可以使用 Transformer。DiT(Diffusion Transformer) 就属于后一条架构路线,下一节具体展开。

从采样方式看,训练好的网络需要配合相应的更新规则。DDIM 就是与 DDPM 训练目标兼容的一类生成与采样构造,它与"使用 U-Net 还是 Transformer"是不同的问题。

所以,一个模型完全可以同时具备"潜空间""Transformer""文本条件"这几个特点。Stable Diffusion 或 FLUX 这样的具体模型系列,则要结合版本,看它究竟采用了哪些组件与方法。

这个分类的作用,是帮助我们把每个名称放回刚才的完整流程中:它究竟改变了流程的哪一部分?

9 DiT 用 Transformer 完成去噪预测

前面已经看过 U-Net。如果希望用 Transformer 承担预测任务,可以先把这个变化理解为:

z t ⟶ U-Net ⟶ ϵ ^ z_t \longrightarrow \text{U-Net} \longrightarrow \hat{\epsilon} zt⟶U-Net⟶ϵ^

变成:

z t ⟶ Transformer ⟶ ϵ ^ z_t \longrightarrow \text{Transformer} \longrightarrow \hat{\epsilon} zt⟶Transformer⟶ϵ^

这里为了便于对照,仍然以预测噪声为例。网络输出的具体目标可以另外选择。

Transformer 处理的是 token 序列,因此首先需要把带噪 latent 变成 token。假设:

z t ∈ R C × H × W z_t\in\mathbb{R}^{C\times H\times W} zt∈RC×H×W

将它在空间上切成若干个 patch:

z t ⟶ { p 1 , p 2 , ... , p N } z_t\longrightarrow\{p_1,p_2,\ldots,p_N\} zt⟶{p1,p2,...,pN}

再把每个 patch 投影成一个 D D D 维 token,得到:

X ∈ R N × D X\in\mathbb{R}^{N\times D} X∈RN×D

这一步和 ViT 很相似:把空间上的小块转换成序列中的元素,再用 Transformer 建模它们之间的关系。

完整过程大致是:

text 复制代码
带噪 latent z_t
      │
      ▼
Patchify / Projection
      │
      ▼
Token 序列,加上位置信息
      │
      ▼
Transformer Blocks ◄── 时间步及其他条件
      │
      ▼
输出投影并重排回空间张量
      │
      ▼
噪声或其他指定目标的预测

原始 DiT 在潜空间中用 Transformer 替换常见的 U-Net 骨干,并研究了时间步、类别等条件的注入方式。后续模型还可以发展不同的图文交互结构。

因此,"把 U-Net 换成 Transformer"能说明 DiT 在完整系统中替换了哪个部件;进一步看内部结构,就会看到 patch 划分、token 序列、注意力计算和输出重排这些不同之处。

无论采用哪一种骨干,前面那条联系仍然成立:网络接收当前带噪状态和时间等条件,给出预测,再由生成过程使用这个预测推进样本。

10 再向外扩展 网络也可以预测其他量

刚才一直用 ϵ θ \epsilon_\theta ϵθ 表示网络,是为了把经典 DDPM 的噪声预测讲清楚。但扩散模型也可以使用其他预测目标。

一种选择是直接预测干净样本:

x ^ 0 = x θ ( x t , t ) \hat{x}0=x\theta(x_t,t) x^0=xθ(xt,t)

前面已经看到,给定 x t x_t xt、噪声水平和噪声预测,可以计算干净样本的估计。因此,预测噪声与预测干净样本之间有数学联系。具体模型可以选择不同的参数化,并配合相应的损失和采样公式。

还有一种常见选择是 v v v-prediction。在一种常用定义中,令:

a t = α ˉ t , s t = 1 − α ˉ t a_t=\sqrt{\bar{\alpha}_t}, \qquad s_t=\sqrt{1-\bar{\alpha}_t} at=αˉt ,st=1−αˉt

则训练目标为:

v t = a t ϵ − s t x 0 v_t=a_t\epsilon-s_t x_0 vt=atϵ−stx0

它是信号与噪声的一个特定组合,网络学习预测这个组合。

在 Flow Matching 或 Rectified Flow 中,也经常看到:

v θ ( x t , t ) v_\theta(x_t,t) vθ(xt,t)

这里通常表示沿所定义生成路径的速度场 :告诉当前状态在这个时间应该朝什么方向、以怎样的速度变化,再通过数值求解逐步生成数据。它的具体定义由所选路径决定,不能仅凭都使用字母 v v v 就认为它与前面的扩散 v v v-prediction 完全相同。

第一次学习时,先把 DDPM 的"已知加噪规则 → 构造训练样本 → 学习预测 → 反复更新生成"理解清楚,再扩展到这些目标与生成路径,会更容易看清它们之间的关系。

11 把原理 架构与完整系统放到一起

现在可以回到最开始的问题:Diffusion Model 是否存在不同家族,以及不同的模型架构?

可以这样整理已经走过的内容:

text 复制代码
扩散与相关的连续流生成模型
│
├─ 生成过程怎样定义
│  ├─ DDPM
│  ├─ Score-based / SDE
│  └─ Flow Matching / Rectified Flow
│
├─ 在什么空间中生成
│  ├─ Pixel Space
│  └─ Latent Space
│     └─ 自编码器负责图像与 latent 的转换
│
├─ 由什么网络完成预测
│  ├─ U-Net
│  └─ Transformer,例如 DiT
│
├─ 网络预测什么
│  ├─ 噪声 ε
│  ├─ 干净样本 x_0
│  └─ v 或所定义路径的速度场
│
├─ 怎样利用预测生成下一步
│  └─ 与模型兼容的采样器或求解器
│
└─ 如何控制生成内容
   └─ 文本等条件,经编码后参与网络预测

这张图中的各条分支是不同维度,可以组合。对于经典的 U-Net 型 Stable Diffusion,可以把它放回我们已经理解的流程:

图片通过自编码器进入潜空间;扩散模型在 latent 上学习生成;文字通过文本编码器变成条件,参与 U-Net 的预测;生成时从潜空间噪声开始,经过多步更新得到 latent,再由解码器输出图片。

DiT 让我们看到,负责预测的骨干可以换成 Transformer。DDIM 让我们看到,生成时的采样轨迹也可以调整。Flow Matching 等方法则进一步改变了训练所依据的路径和预测目标。

这样,"扩散模型的原理"和"某个具体模型的架构"就能联系起来:前者说明生成为什么按这样的过程进行,后者说明由哪些网络部件把这个过程实现出来。

12 总结

如果需要简洁地说明扩散模型的基本原理,可以沿着刚才的顺序表达:

扩散模型先定义前向加噪过程,把真实数据逐渐变成接近高斯分布的噪声,再学习对应的反向生成过程。以经典 DDPM 为例,训练时随机采样时间步,通过闭式公式直接构造带噪样本,再训练网络预测加入的噪声。生成时从高斯噪声出发,反复调用同一个网络,并根据采样公式逐步更新样本,最终得到图片。网络骨干可以采用 U-Net,也可以采用 DiT 等 Transformer 架构。

如果继续介绍 Stable Diffusion,就接着解释它怎样降低图像生成的计算开销:

经典 Stable Diffusion 把扩散放在自编码器的潜空间中。训练图片先编码成 latent,扩散模型在 latent 上学习;生成时从潜空间噪声开始,逐步生成干净 latent,最后通过解码器恢复图片。文生图时,文本编码器提供条件特征,并通过交叉注意力等机制参与去噪预测。

后续要深入 DDPM 的数学,可以从前面已经出现的三个分布接着看:

q ( x t ∣ x t − 1 ) , q ( x t ∣ x 0 ) , p θ ( x t − 1 ∣ x t ) q(x_t\mid x_{t-1}), \qquad q(x_t\mid x_0), \qquad p_\theta(x_{t-1}\mid x_t) q(xt∣xt−1),q(xt∣x0),pθ(xt−1∣xt)

它们分别对应单步加噪、从原图直接构造任意时间步的样本,以及学习到的反向生成。先把这三个分布与训练、生成的实际步骤对上,再推导损失和反向采样公式。

来源与延伸阅读

正文沿分享对话的介绍顺序整理,关键公式与方法可结合以下原论文阅读。

相关推荐
wabs6664 小时前
关于二叉树【力扣572.另一棵树的子树的思考】
数据结构·c++·算法·leetcode·二叉树
hanlin034 小时前
刷题笔记:力扣第41题-缺失的第一个正数
笔记·算法·leetcode
shehuiyuelaiyuehao5 小时前
算法50,分治归并,数组中的逆序对
java·算法
阳明山水5 小时前
校准分位数驱动智能库存决策
人工智能·深度学习·算法·机器学习·架构
别动我齐刘海7 小时前
ROS2 Jazzy + C++ 实战路线——进阶学习3
c++·人工智能·vscode·python·算法·机器学习·机器人
zhangfeng11337 小时前
《从“人工适配“到“智能生成“:KernelSwift 跨国产芯片算子迁移全栈方案解读》 —— 强调范式跃迁和跨硬件属性,适合偏架构分析的写法
人工智能·算法·华为·ai编程·npu
0+1117 小时前
算法 --滑动窗口
c++·算法·leetcode
reikocao7 小时前
大场景下 Hessian 特征值放大与退化检测
算法
hetao17338378 小时前
2026-09-18 hetao1733837 的刷题记录
c++·算法