← 返回笔记列表
🎨 学习笔记 · 视觉生成模型 · 完全新手向

视觉 Diffusion Model:从零开始完全图解

DDPM / Stable Diffusion / U-Net / Cross-Attention / CFG / ControlNet — 每个概念都有类比 + 具体例子,不需要任何生成模型背景

前置知识
只需要知道"神经网络可以做回归任务"即可
涵盖模型
DDPM · Latent Diffusion · Stable Diffusion · DALL-E 2
核心问题
怎么让AI从"噪声"中"雕刻"出一张图片?
阅读时长
约 50–70 分钟
💬
一句话总结
Diffusion model 就是在做一件事情:故意把图片加噪声弄模糊,再训练AI学会如何一步步把模糊的图"复原"回去。

训练时:让AI学会"洗图"(预测噪声位置);
推理时:从纯噪声开始,逐步"雕刻"出清晰的图片。
🎨
§1 核心直觉:故意弄脏再洗白

Diffusion model的核心思想可以用一个简单的类比来理解:

🧽 类比:污渍去除法

想象你有一张干净的画:

  • Step 1: 故意弄脏 - 你拿橡皮擦在上面涂抹,一次比一次重,最终变成完全看不清的白噪声
  • Step 2: 学会清洗 - 训练一个AI:"如果图片现在这么模糊,应该怎么恢复上一步?"
  • Step 3: 逐步复原 - AI从完全模糊的状态开始,一步步去掉噪声,最终变回清晰的画
🔑 为什么这样设计?

直接生成太难了!让AI一步到位从"虚无"中生成一张清晰的图,难度极大。但让AI学会"每步只去掉一点点噪声",这个任务就简单多了。

类比:雕塑家从一块大理石开始,每次只凿掉一点点,最终雕刻出作品。而不是直接让AI"凭空变出雕塑"。

DDPM前向扩散与逆向去噪过程示意图
Figure 1(Ho et al. 2020 原图):Markov Chain of forward (reverse) diffusion process — 前向(蓝)每步加噪声,逆向(绿)每步去噪
➡️
§2 前向扩散:一步步加噪声

前向扩散的目标很简单:把清晰的图 $x_0$ 变成纯噪声 $x_T$

x_0 (原图)
x_1
x_2
...
x_T (纯噪声)

每一步加一点点高斯噪声

2.1 数学公式

$$x_t = \sqrt{1 - \beta_t} \cdot x_{t-1} + \sqrt{\beta_t} \cdot \epsilon$$
符号说明
  • $x_t$:第 $t$ 步的图片(越来越模糊)
  • $\beta_t$:噪声强度调度($t$ 越大,噪声越多,通常从 0.0001 增到 0.02)
  • $\epsilon$:随机高斯噪声(就像电视雪花屏,从 $\mathcal{N}(0, I)$ 采样)
  • $\sqrt{1-\beta_t}$:保留原信息的比例
📌 重要性质

通过重参数化技巧,可以直接从 $x_0$ 跳到任意步 $x_t$:

$$x_t = \sqrt{\bar{\alpha}_t} \cdot x_0 + \sqrt{1 - \bar{\alpha}_t} \cdot \epsilon$$

其中 $\bar{\alpha}_t = \prod_{s=1}^t (1 - \beta_s)$,表示累计保留的原始信息比例。

2.2 举例说明

💡 举例:前向扩散过程

假设我们有一张猫咪图片:

  • x_0:清晰的猫咪照片(像素值如 [0.8, 0.2, 0.5, ...])
  • x_{250}:猫咪轮廓还在,但细节模糊,像雾里看花
  • x_{500}:只能隐约看到有个物体,已经看不出是猫
  • x_{1000}:完全看不出是猫,像老电视的雪花屏(纯噪声)

如果 $\beta_t=0.01$,那么每一步保留 99% 的原图信息,添加 1% 的噪声。

数学上:$\bar{\alpha}_{1000} \approx 0$(信息几乎完全扩散),$x_{1000} \approx \epsilon$(纯噪声)。

⬅️
§3 逆向去噪:训练AI"洗图"

逆向去噪的目标:让AI学会从 $x_t$ 预测"刚刚加了什么噪声"

x_T (纯噪声)
x_{T-1}
x_{T-2}
...
x_0 (清晰图)

每步预测并去掉噪声

3.1 Loss函数

$$\mathcal{L} = \mathbb{E}_{t,x_0,\epsilon} \left[ \| \epsilon - \epsilon_\theta(x_t, t) \|^2 \right]$$
符号说明
  • $\epsilon$:真实加的噪声(训练时已知)
  • $\epsilon_\theta(x_t, t)$:AI预测的噪声(U-Net输出)
  • $\|\cdot\|^2$:均方误差(像素级对比)
🔑 训练流程
  1. 采样:从数据集随机取一张图 $x_0$
  2. 采样时间步:随机取 $t \in [1, T]$
  3. 加噪声:用公式生成 $x_t = \sqrt{\bar{\alpha}_t} x_0 + \sqrt{1-\bar{\alpha}_t} \epsilon$
  4. 预测:让U-Net看 $(x_t, t)$,输出 $\epsilon_\theta(x_t, t)$
  5. 计算Loss:$\|\epsilon - \epsilon_\theta\|^2$,反向传播更新参数
DDPM训练和采样算法流程图
Figure 2(Ho et al. 2020 原图):DDPM 训练算法(Algorithm 1)与采样算法(Algorithm 2)伪代码

3.2 举例说明

💡 举例:逆向去噪过程(推理时)

场景:无条件生成一张猫咪图(先不考虑"告诉AI画什么",那是后面 §5 的内容)

  1. 起点:随机生成一张纯噪声图 $x_{1000}$(雪花屏)
  2. 第1000步→999步
    • U-Net看 $x_{1000}$ 和 $t=1000$,预测噪声位置
    • 去掉预测的噪声:$x_{999} = x_{1000} - \epsilon_\theta(x_{1000}, 1000)$
  3. 第999步→998步
    • 图稍微清晰了点,U-Net继续预测并去噪
  4. 重复1000步:最终从雪花屏变成清晰猫咪

类比:就像雕塑家从一块大理石开始,每次凿掉一点多余的石头,最终雕刻出作品。

❓ 等等,这里没有说"画猫咪",AI怎么知道生成的是猫?
因为训练集里全是真实图片(包括猫)。模型学到了"真实图像的分布",逆向去噪就是沿着分布走——最终落点是真实图像空间里的某个点。至于如何控制生成内容,继续看 §3.5 和 §5。

⚠️ 为什么不能一步到位?

你可能会问:为什么不直接训练一个模型,输入噪声直接输出清晰图?

答案:一步到位的难度太大了!

❌ 一步生成

纯噪声→清晰图
难度:😱 极难

像让小学生直接写博士论文

✅ 渐进去噪

每步去掉一点点噪声
难度:😊 可行

像让小学生每次只改一个错别字

🌉
§3.5 关键跨越:为什么去噪 = 学会了生成?
⚠️ 你可能有的困惑

前面讲了前向加噪、逆向去噪,训练时用的是真实图片……但我想生成一张从没存在过的新图,这两件事有什么关系?

先搞清楚:生成模型在做什么

图像生成的本质是:从一个概率分布中采样

想象世界上所有猫咪照片构成一个分布,每张猫咪图都是这个分布里的一个点。生成模型要做的事,就是学会这个分布的"形状",然后从里面随机采一个新点出来。

🗺️ 类比:学地图 vs 画地图

把"所有猫咪图像"想象成一块地形图,猫咪图聚集的地方是山峰,不像猫的图是山谷。

  • 传统方法:需要直接描述这个地形的形状(非常复杂)
  • Diffusion的思路:不直接描述地形,而是学习"地形的引力场"——知道了任意一点的引力方向,就能从随机位置顺着引力"爬山",最终落在山峰上

去噪 = 学习数据分布的"引力场"

这是 Diffusion 最核心的数学洞察,用人话来说:

🔑 核心等价关系

训练一个"预测噪声"的网络 ≈ 学习了"如何从任意噪声位置,往真实图像方向走一步"

换句话说:模型在训练时看了无数张真实图片的"各种模糊程度",学会的不只是"去噪"这个动作,而是所有真实图像组成的分布长什么样

为什么?因为训练时给模型看的 $x_t$ 是从真实图片加噪声来的。所以模型学到的每一步"去噪方向",都指向真实图像分布。

推理时发生了什么(这才是生成!)

训练结束后,你完全不需要任何真实图片。推理时:

1
随机采一个纯噪声 $x_T \sim \mathcal{N}(0, I)$

这是一个完全随机的点,不对应任何真实图片

2
用去噪网络预测:从这里应该往哪个方向走一步?

模型输出"这个噪声点里有多少噪声",等价于"真实图像方向在哪里"

3
走一小步,得到 $x_{T-1}$

往真实图像分布的方向靠近了一点点

4
重复1000步,最终落在真实图像分布里的某个点 $x_0$

这个点是训练集里没有的全新图片,但它符合真实图像的规律

💡 举例:从噪声到猫咪的完整推理

类比LLM:你作为LLM背景的人可以这样理解——

  • GPT 的训练目标是"预测下一个 token",但推理时它能生成从没存在过的句子
  • Diffusion 的训练目标是"预测加了什么噪声",但推理时它能生成从没存在过的图片

两者的共同点:通过预测任务学到了数据分布,采样时就能从分布里生成新内容。

具体过程(以生成猫咪为例):

  1. 随机噪声 $x_{1000}$:像一团乱码,不像任何东西
  2. 去噪50步后 $x_{950}$:开始有了一些纹理,但还不清晰
  3. 去噪500步后 $x_{500}$:隐约有个动物的轮廓
  4. 去噪900步后 $x_{100}$:能看出是猫,细节逐渐清晰
  5. 去噪完成 $x_0$:一张从未存在过的、全新的猫咪图片

每次随机采样不同的 $x_T$,就会生成不同的猫咪。这就是生成的随机性来源。

前向扩散的作用:它只在训练时用!

📌 很多人忽略的关键

前向扩散(§2)只在训练阶段使用,推理时完全不用它。

  • 训练时:用前向扩散给真实图片加噪声,制造训练样本 $(x_t, \epsilon)$
  • 推理时:直接随机采样纯噪声,用逆向去噪生成图片

前向扩散是"制造训练数据的工具",不是推理流程的一部分。

✅ 总结:三步理解 Diffusion 生成
  1. 训练阶段:见过海量真实图片 → 学会了"真实图像分布的形状"(体现为去噪能力)
  2. 推理起点:随机采样纯噪声(任意起点)
  3. 推理过程:用学到的分布知识,逐步把噪声"拉向"真实图像分布 → 输出全新图片
🏗️
§4 U-Net:去噪网络的主力

明确一下 U-Net 在 Diffusion 里的输入和输出

📥 输入(两个)

  • 含噪图片 $x_t$:一张被加了噪声的图,形状和原图一样(如 64×64×3)
  • 时间步 $t$:一个整数,告诉网络"现在噪声有多严重"(如 $t=500$)

📤 输出(一个)

  • 预测的噪声 $\hat{\epsilon}$:和输入图片形状完全相同(64×64×3),表示"刚才加的是什么噪声"

用输入减去输出噪声,就能还原上一步的图片

⚠️ 注意:不是输出"清晰的图片"!

很多人以为 U-Net 直接输出最终清晰图片——不是。它输出的是"噪声"(即加进去的那部分),然后用输入减去噪声才得到去了一步噪的图片。这个去噪过程要重复1000次,最终才得到清晰图。

4.1 结构详解

U-Net 完整数据流:从含噪图 → 预测噪声
输入
含噪图 x_t (64×64×3)
+ 时间步 t
编码器
64×64 → 32×32 → 16×16
↑每层都注入时间步
瓶颈层
最抽象特征
(8×8×512)
输出
预测噪声 ε̂ (64×64×3)
形状与输入完全相同
解码器
16×16 → 32×32 → 64×64
拼接编码器的跳跃连接
瓶颈层
+跳跃连接

x_{t-1} = x_t - ε̂ (一步去噪)

三个核心机制

  • 编码器(下采样):用卷积逐层压缩空间尺寸(64→32→16→8),同时提取语义特征
  • 解码器(上采样):逐层恢复空间尺寸,但需要知道细节在哪里
  • 跳跃连接:把编码器每层的特征图直接拼接给对应的解码器层——这样解码器既有抽象语义(来自瓶颈),又有精确位置(来自跳跃连接)
U-Net架构图
Figure 3(Ronneberger et al. 2015 原图):U-Net 完整架构——蓝色方块为特征图(上方标通道数),灰色箭头为跳跃连接

4.2 举例:完整走一遍

💡 举例:U-Net 处理一张含噪猫咪图(t=500)

输入:$x_{500}$(一张模糊的猫咪,噪声很重,隐约能看出轮廓)+ $t=500$

  • 编码器第1层(64×64):检测到"有一些模糊的毛发纹理",同时把 $t=500$ 的时间信息加进去(详见4.3节)
  • 编码器第2层(32×32):检测到"有一个模糊的圆形轮廓(头部)"
  • 瓶颈层(8×8):最抽象的理解:"这大概是一个动物"
  • 解码器第2层:用瓶颈层的语义 + 编码器第2层的跳跃连接,推断出"猫耳朵这里有多少噪声"
  • 解码器第1层:用更精细的跳跃连接,推断毛发纹理处的噪声分布
  • 输出:一张 64×64×3 的"噪声图" $\hat{\epsilon}$,表示"这张图里加了这么多噪声"

去噪计算:$x_{499} = x_{500} - \hat{\epsilon}$,得到稍微清晰一点点的猫咪图

4.3 时间步编码:怎么告诉网络"现在有多模糊"

U-Net 要处理1000种不同程度的噪声图($t$ 从1到1000),同一张图在 $t=100$ 和 $t=900$ 时需要完全不同的去噪策略

  • $t=100$:噪声很少,图片基本清晰 → 要细心保留细节,小幅度去噪
  • $t=900$:噪声极多,几乎全是杂乱信号 → 要大胆"猜"出大致内容,忽略细节

但时间步 $t$ 只是一个整数,怎么让神经网络理解它?和 LLM 的位置编码一模一样的思路:正弦编码。

$$e(t) = \left[\sin\!\left(\frac{t}{10000^{0/d}}\right), \cos\!\left(\frac{t}{10000^{0/d}}\right), \sin\!\left(\frac{t}{10000^{2/d}}\right), \cos\!\left(\frac{t}{10000^{2/d}}\right), \ldots\right]$$
符号说明
  • $t$:时间步整数(1 到 1000)
  • $d$:编码维度(如 512 维,和 U-Net 特征维度相同)
  • $e(t)$:最终的时间步向量,长度为 $d$,每个分量都是不同频率的正余弦值
📌 时间步编码怎么"注入"到 U-Net 里?

这是关键——不是只在输入层加一次,而是在 U-Net 的每一个 ResBlock 里都加进去

  1. 把 $t$ 转成 $d$ 维向量 $e(t)$(如 512 维)
  2. 再过一个小 MLP,得到 scale $\gamma$ 和 shift $\beta$ 各一个向量
  3. 在每个 ResBlock 内部,对特征图做:feature = feature × γ + β(相当于 LayerNorm + 条件调制)

效果:每一层都"知道"现在是第几步,从而调整自己的行为。这和 Transformer 中位置编码注入到每层 Attention 是同样的道理。

💡 举例:时间步编码如何改变网络行为

关键澄清:DDPM 每步要预测的噪声 $\epsilon \sim \mathcal{N}(0, I)$,分布与 $t$ 无关,幅度并没有"越大越小"之分。时间步 $t$ 告诉网络的是当前输入 $x_t$ 的信噪比(SNR),进而影响网络提取特征的策略:

$t = 50$(SNR 高,图片清晰)

$x_{50}$ 已经很清晰,图片结构清晰可见

→ 网络可以看清细节,做精细、局部的噪声预测(如毛发纹理处的微小修正)

$t = 950$(SNR 低,几乎全是噪声)

$x_{950} \approx \epsilon$,几乎看不出任何图像结构

→ 网络几乎没有可用信号,只能依赖全局先验猜测噪声(任务更难,误差更大)

类比 LLM:就像 Transformer 里的位置编码让模型知道"这是第几个 token",时间步编码让 U-Net 知道"当前输入有多'脏'(信噪比多低)",从而调整用什么特征来做预测。

🎯
§5 条件生成:告诉AI画什么

无条件生成

输入随机噪声 → 输出随机图片(不可控,只知道"生成符合训练集的图")

条件生成

输入噪声 + 文本条件 → 输出符合文本描述的图片(可控)

5.0 两种训练,两种数据

⚠️ 常见困惑:DDPM 训的 U-Net 和条件生成 U-Net 是同一个模型吗?

不是。它们目标不同、数据不同、架构也不同。

阶段一:无条件去噪(纯图像)

训练数据:只需要图片,无需文字描述

目的:让 U-Net 学会"什么样的像素排列是真实图像"(学图像分布)

结果:能从随机噪声生成图片,但无法控制内容

这是独立完整的成果,有自己用途(无条件生成、图像补全等)

阶段二:条件生成(图文对)

训练数据:需要 (图片, 文字描述) 对,如 LAION-5B(50亿图文对)

目的:让 U-Net 学会"给定文本条件时,朝符合描述的方向去噪"

架构:新增 Cross-Attention 层,不是原来 DDPM U-Net 的结构

📌 那阶段一的训练有什么意义?

实践上的常见做法:先在纯图像上预训练(无条件),让网络学好图像特征表示;再加入 Cross-Attention 层,在图文对上 fine-tune。好处是收敛更快、图像质量更好,因为图像特征不用从零学。

类比 LLM:先在纯文本上预训练(学语言能力),再用对话数据做指令微调(学遵从指令)——前者的特征表示对后者有帮助,但两个阶段目标完全不同。

当然也可以直接用图文对从头训(跳过阶段一),效果相近,只是需要更多数据和算力。

5.1 端到端流程:文本如何变成图像

条件生成不是"在最后加一个文本",而是在每一步去噪时都把文本信息注入进去。整体流程分三步:

1
文本编码:把文字变成向量序列

用文本编码器(如 CLIP 的 Text Encoder)把 prompt 变成一组向量 $c \in \mathbb{R}^{L \times d}$,其中 $L$ 是 token 数量,$d$ 是向量维度(如 768)。

例:"一只戴着红围巾的猫咪" → [token_1: 一只, token_2: 戴着, token_3: 红围巾, token_4: 的, token_5: 猫咪] → 每个 token 变成 768 维向量

2
U-Net 每步去噪时注入文本:Cross-Attention

在 U-Net 的每个 ResBlock 里,有一个 Cross-Attention 层。图像特征"问" ($Q$) 文本特征"答" ($K, V$),让图像每个位置都能感知文本描述。

3
去噪方向被文本"引导"

经过 Cross-Attention 调制后,U-Net 预测的噪声 $\hat{\epsilon}$ 会偏向"去掉后更符合文本描述的方向"。重复1000步,最终落在符合 prompt 的图像上。

5.2 CLIP 的角色:文图对齐的翻译器

🔑 CLIP 的角色,以及 U-Net 怎么用它

重要澄清:带条件生成能力的 U-Net(如 Stable Diffusion 里的)不是把 CLIP 插到一个已有 U-Net 上,而是从头训练一个专门包含 Cross-Attention 层的新 U-Net,训练目标就是"给定 $x_t$ + CLIP 文本 embedding $c$,预测 $\epsilon$"。

  • CLIP 文本编码器:训练时冻结权重,只做特征提取——把文本变成 embedding 序列 $c$
  • U-Net 的 Cross-Attention 投影矩阵($W_Q, W_K, W_V$):从零训练,专门学"如何把 CLIP 的语义向量和图像特征关联"

训练和推理都用同一个冻结的 CLIP,没有训练/推理不一致。

CLIP vs 普通语言模型(如 BERT)

CLIP 是用图文对训练的,"猫咪"的文本向量和猫咪图像的向量在同一对齐空间里。BERT 没有对齐图像空间,直接用效果差很多。

更新:现代模型用 T5/LLM

Imagen 用 T5-XXL,FLUX 用 T5+CLIP 双编码器。纯语言模型对复杂 prompt 的理解更强,但需要更大的 Cross-Attention 层来桥接。

5.3 Cross-Attention:图像"问"文本"答"

Cross-Attention 在 U-Net 里的位置:编码器和解码器的每个 ResBlock 之后都有一个(不只在瓶颈层)。

$$\text{Attention}(Q, K, V) = \text{softmax}\!\left(\frac{QK^T}{\sqrt{d_k}}\right) V$$
符号说明(关键:Q 和 K/V 来源不同)
  • $Q = W_Q \cdot z$:由图像特征线性投影而来($z$ 是 U-Net 当前层的特征图,展平后)
  • $K = W_K \cdot c$:由文本向量投影而来($c$ 是 CLIP 输出的 token 序列,固定不变)
  • $V = W_V \cdot c$:同样来自文本向量
  • $d_k$:$K$ 的维度,用于缩放防止点积过大
📌 Cross-Attention 做了什么
  1. 图像每个空间位置(展平为 token)生成一个 Query $Q_i$,相当于"我这里是什么区域,应该有什么内容?"
  2. 计算 $Q_i$ 和所有文本 token 的 $K_j$ 的相似度 → 得到注意力权重 $\alpha_{ij}$
  3. 用权重对文本 $V_j$ 加权求和 → 输出"这个图像位置应该关注的文本信息"
  4. 把这个信息加回图像特征,调制 U-Net 的去噪方向

类比 LLM 里的 Cross-Attention:机器翻译里解码器生成每个词时,会 attend 到编码器的输出——原理完全一样,这里换成"图像生成每个位置时,attend 到文本的 token"。

5.4 完整举例:生成"一只戴着红围巾的猫咪"

💡 举例:从 prompt 到图像,第 t=500 步的去噪

输入:$x_{500}$(模糊图)+ $t=500$ + 文本 $c$("一只戴着红围巾的猫咪" 的 CLIP 向量)

Step 1:CLIP 编码文本(只做一次,整个推理过程共享)

  • "一只" → $c_1 = [0.1, 0.3, ...]$
  • "红围巾" → $c_3 = [0.8, -0.2, ...]$(在 CLIP 空间里,和红色、围巾相关的图像特征相近)
  • "猫咪" → $c_5 = [0.5, 0.7, ...]$

Step 2:U-Net 编码器处理 $x_{500}$,某一层的图像特征(局部区域):

  • 脖子区域的特征 $z_{\text{neck}}$ → 投影为 $Q_{\text{neck}}$:"这里是脖子/胸口附近,应该有什么?"
  • 脸部区域的特征 $z_{\text{face}}$ → 投影为 $Q_{\text{face}}$:"这里是头部,应该有什么?"

Step 3:Cross-Attention 计算

  • $Q_{\text{neck}} \cdot K_{\text{红围巾}}$ 相似度高 → $\alpha_{\text{neck, 红围巾}}$ 大 → 脖子位置的输出大量参考"红围巾"的 $V$
  • $Q_{\text{face}} \cdot K_{\text{猫咪}}$ 相似度高 → 脸部区域参考"猫咪"的 $V$

Step 4:调制后的 U-Net 输出噪声 $\hat{\epsilon}$

  • 预测的噪声在脖子位置会"偏向"去除与红围巾不一致的噪声
  • 去噪后:$x_{499}$ 在脖子区域的红色信号比 $x_{500}$ 稍微清晰一点点

重复1000步:每一步都用同样的文本 $c$ 做 Cross-Attention,每步都把图像往"符合描述"的方向推一点。最终 $x_0$ = 一只清晰的、脖子上有红围巾的猫咪。

5.5 一个关键问题:条件在哪一步起作用最大?

⚠️ 不同去噪阶段,条件的作用不同

早期步骤($t$ 大,如 900→700)

图片还几乎全是噪声,条件主要决定整体构图和语义:这是猫还是狗?有没有围巾?

后期步骤($t$ 小,如 100→0)

图片已经大致成形,条件主要决定细节和纹理:围巾的花纹、毛发的颜色深浅

这也是为什么去噪步数不够(如只做200步)时,图像细节会差——早期定了形,后期精修同样重要。

§6 Latent Diffusion:算力优化之道

核心创新:不在像素空间扩散,而是在隐空间扩散。

6.1 核心思想

推理完整流程(VAE Decoder 只跑一次!)
纯噪声 z_T
(64×64×4,隐空间)
↓ U-Net去噪 ×50步
全程 64×64×4
干净隐向量 z_0
(64×64×4)
↓ VAE解码器(只用一次)
最终图片
(512×512×3,像素空间)
⚠️ 常见误区:去噪过程不会变回图像

去噪的每一步输入和输出都是 64×64×4 的隐向量,永远不会在中间变成图像大小。VAE Decoder 只在最后跑一次,把最终干净的隐向量还原成像素图。

❌ 像素空间扩散(DDPM)

  • 每步 U-Net 处理:512×512×3 = 786,432 个值
  • ×1000步 = 极大计算量

✅ 隐空间扩散(Stable Diffusion)

  • 每步 U-Net 处理:64×64×4 = 16,384 个值(少 48x)
  • 省的是每步的计算量,×50步,总省约 960 倍

6.2 隐空间去噪:和 DDPM 完全一样的操作

U-Net 本质上是一个函数:输入一个张量,输出同形状的张量。它不关心输入是"图像像素"还是"隐向量",只做卷积/Attention 运算。

DDPM(像素空间)

x_t (512×512×3)
→ [U-Net]
→ ε̂ (512×512×3)
→ x_{t-1} = x_t - ε̂

LDM(隐空间)

z_t (64×64×4)
→ [U-Net]
→ ε̂ (64×64×4)
→ z_{t-1} = z_t - ε̂

唯一的区别是训练目标变了:DDPM 预测加在像素上的噪声;LDM 预测加在隐向量上的噪声。两者数学上完全等价。

📌 "隐向量"是什么

VAE Encoder 把图像压缩成 64×64×4 的浮点数矩阵,每个数字都是图像语义的抽象编码(颜色、纹理、形状信息)。你可以直接对这些浮点数加高斯噪声、做加减运算——它们是普通数字,不需要解码回图像就能操作。

VAE Decoder 只在最后用:1000步去噪结束,得到干净的 $z_0$ 后,才调用 Decoder 还原成像素图,给人看。

Latent Diffusion Model架构图
Figure 4(Rombach et al. 2022 原图):扩散过程全程在 VAE 压缩后的低维隐空间进行,VAE Decoder 只在最后执行一次

6.3 数字对比

💡 生成一张 512×512 猫咪图:计算量对比
方法每步数据量步数U-Net 总计算量(相对)
DDPM(像素空间)786,432 值1000步1x(基准)
Stable Diffusion(隐空间)16,384 值(少48x)50步(少20x)约 1/960x

节省来自两处:① 每步数据量小 48x;② 去噪步数可以少(隐空间更平滑,50步已足够)。VAE Encoder/Decoder 只各跑一次,开销相比 U-Net 几乎忽略不计。

🚀
§7 Classifier-Free Guidance

问题:普通的条件生成,模型会"偷懒"——只依赖图像自身特征,部分忽略文本条件,生成的图与 prompt 不够贴合。

解决方案:用同一个模型同时学条件和无条件去噪,推理时把条件方向"放大"。

7.1 怎么训练:一个模型,随机 Drop 条件

📌 不是两个分开的模型

"同时训练条件和无条件"听起来像两个模型,实际上是同一个模型,训练技巧如下:

  • 训练时,随机有 10%~20% 的概率把文本条件 $c$ 替换成空($\emptyset$,即 null token)
  • 其余时候正常传入文本条件

这样同一个模型在有条件和无条件两种情况下都被训练到,权重是共享的。

推理时:用这一个模型跑两次——一次传条件 $c$,一次传空 $\emptyset$,分别得到两个噪声预测,再做加权组合。

7.2 公式与直觉

$$\tilde{\epsilon}_\theta = \epsilon_\theta(x_t, \emptyset) + s \cdot (\epsilon_\theta(x_t, c) - \epsilon_\theta(x_t, \emptyset))$$
符号说明
  • $\epsilon_\theta(x_t, c)$:条件去噪预测(传入文本 $c$)
  • $\epsilon_\theta(x_t, \emptyset)$:无条件去噪预测(传入空条件)
  • $\epsilon_\theta(x_t, c) - \epsilon_\theta(x_t, \emptyset)$:条件带来的"额外噪声方向"
  • $s$:引导强度(通常 7.5~15,越大越听话于 prompt)
🔑 直觉:为什么去掉更多"某个方向的噪声",图反而更符合描述?

去噪 = 从图里"抠掉"噪声,抠掉什么,剩下的就是什么。

  • $\epsilon_\theta(x_t, c)$(红猫条件)预测的噪声:抠掉后,剩下红猫信号
  • $\epsilon_\theta(x_t, \emptyset)$(无条件)预测的噪声:抠掉后,剩下普通猫信号
  • 差值 = 让图"变红"需要额外多抠的那部分噪声方向
  • 乘以 $s > 1$:放大这个方向,抠掉更多"红色对应的噪声"→ 剩下的红色信号更强→ 图更红

换个说法:CFG 在"条件方向"上做了线性外推(extrapolation),$s=1$ 是正常条件,$s>1$ 是往条件方向"过冲"。

7.3 举例:生成"一只红色的猫"

💡 举例:CFG 如何让猫更红($s = 7.5$)

第 $t=500$ 步,同一个模型跑两次:

无条件预测 $\epsilon_\theta(x_t, \emptyset)$

传入空 token,模型"自由发挥"
→ 预测的噪声只管把图变成"像真实图片"的方向(可能是橙猫、灰猫、任何猫)

条件预测 $\epsilon_\theta(x_t, c)$

传入"红色的猫"
→ 预测的噪声在无条件基础上,额外去掉了"不是红色"对应的噪声成分

CFG 组合:

$\tilde{\epsilon}$ = 无条件噪声 + 7.5 × (条件噪声 − 无条件噪声)
= 无条件噪声 + 7.5 × (那个"让图变红"的方向)

→ 相当于在"红猫方向"上走了 7.5 倍的步长,最终图里红色信号被大幅放大

你的理解完全对:"噪声里不要红了,那生成的图片就是很红了"——抠掉更多"非红"噪声,剩下的红色信号就更强。

⚠️ 调参建议
  • s = 1:等于纯粹条件模型,不放大
  • s = 7.5:Stable Diffusion 默认值,平衡质量和多样性
  • s = 15+:非常听话于 prompt,但可能过度饱和、颜色失真
基于引导的条件生成DDPM算法
Figure 5(Dhariwal & Nichol 2021):Classifier-Free Guidance 采样——每步用同一模型跑两次,线性外推放大条件方向
📚
§8 架构演进:U-Net → DiT,以及现代文生图/文生视频

8.1 为什么从 U-Net 换成 Transformer(DiT)

你说得对——CV 领域现在基本是 Transformer 天下(ViT、Swin 等)。那为什么早期 Diffusion 还在用 U-Net 这种卷积范式?

U-Net(卷积)为什么曾经是主流

  • 医学图像分割领域早已验证,成熟稳定
  • 跳跃连接天然保留局部细节,适合像素级任务
  • 卷积的归纳偏置(平移等变性)对图像有效
  • 早期(2020-2022)算力不足,Transformer 太贵

U-Net 的问题

  • Attention 只在局部感受野内有效,全局建模弱
  • Cross-Attention 是"后插"的,与卷积特征的融合不够自然
  • 扩展性差:想扩大模型规模,卷积层结构难以统一 scale
  • 视频/3D 场景下时序建模更笨重
🔑 DiT(Diffusion Transformer):2022 年后的趋势

DiT(Peebles & Xie, 2022)的核心想法:把 U-Net 完全换成 Transformer

  • 输入处理:把含噪图片(或隐向量)切成 patch,每个 patch 当成一个 token(和 ViT 一样)
  • 时间步和条件注入:用 adaLN-Zero(自适应 LayerNorm)把 $t$ 和文本 embedding 调制进每个 Transformer block,替代 U-Net 的 ResBlock + Cross-Attention
  • 没有跳跃连接:Transformer 靠 Self-Attention 的全局建模来保留细节,不需要编码器-解码器结构
  • 可扩展性极强:直接 scale 层数/头数,性能随参数量稳定提升(scaling law 成立)

结论:现代主流文生图/文生视频模型(SD3、FLUX、Sora)全部基于 DiT 或 DiT 变体,U-Net 架构基本退出主流。

8.2 现代文生图:SD3 / FLUX / DALL-E 3

模型年份骨干网络文本编码器核心创新
DDPM 2020 U-Net(像素空间) 无条件 奠定数学框架
Stable Diffusion v1 2022 U-Net(隐空间) CLIP ViT-L 开源 LDM,社区生态
DALL-E 3 2023 U-Net(隐空间) T5-XXL + CLIP 重新标注训练数据,prompt 遵从度大幅提升
SD3 2024 DiT(MMDiT) T5-XXL + CLIP×2 文本 token 和图像 token 在同一 Transformer 里做双流 Attention
FLUX.1 2024 DiT(Flow Matching) T5-XXL + CLIP-L Flow Matching 替代 DDPM 训练目标,更快收敛;12B 参数开源
📌 SD3 的 MMDiT:为什么要"双流 Attention"

SD3(Stable Diffusion 3)的核心架构是 MMDiT(Multimodal DiT),和之前 U-Net 架构最大的区别:

  • 旧方案(U-Net + Cross-Attention):图像特征做 Self-Attention,再 Cross-Attend 到固定的文本 embedding——文本是"旁观者",不随图像更新
  • MMDiT:图像 token 和文本 token 拼在一起进同一个 Transformer block,文本和图像可以相互 Attend——文字和图像信息双向融合,文本理解大幅增强

8.2.1 文生图代表:FLUX 做了什么

FLUX(Black Forest Labs,2024)是目前开源文生图里效果最强的模型之一,12B 参数。它的技术选择几乎代表了当前主流的最佳实践:

🔑 Flow Matching:为什么要替换 DDPM?

DDPM 的核心问题是:噪声调度(noise schedule)定义的扩散路径是曲折的——加噪/去噪都沿着一条弯弯曲曲的概率轨迹走,需要很多步(通常 20~100 步)才能收敛到高质量图像。

Flow Matching 的思路:用"直线路径"替换"曲线路径"

对比维度DDPMFlow Matching(FLUX/SD3 采用)
路径形状曲线(马尔可夫链噪声过程)直线插值:$x_t = (1-t)\,x_0 + t\,\epsilon$
训练目标预测每步噪声 $\epsilon$预测"速度"向量场 $v = \epsilon - x_0$(直线方向)
采样步数通常 20~100 步4~8 步即可(直线更好近似)
理论基础随机微分方程(SDE)常微分方程(ODE),路径确定、可逆

直觉:DDPM 像走迷宫(每步只走一小步,路径弯曲);Flow Matching 像走直线(知道起点和终点,直接连线,速度快得多)。

🏗️ FLUX 的架构:双流 DiT(MMDiT)

FLUX 和 SD3 一样采用 MMDiT 双流架构,但做了进一步优化:

1
图像编码:VAE + patch 化

原始图像经 VAE 压缩到 16× 下采样的隐空间(如 $1024×1024$ → $64×64×16$),再切成 $2×2$ patch → 每张图变成 $32×32=1024$ 个 image token

2
文本编码:T5-XXL + CLIP 双路

T5-XXL(4096维)负责语义理解(长文本、复杂关系);CLIP(768维)负责视觉-语言对齐。两者 concat 后得到 text token 序列

3
双流 Attention(前 19 层)→ 单流 Attention(后 38 层)

前半段:image token 和 text token 各自有独立的参数,但在 attention 时拼在一起——图文信息双向流动,各自保留独立表示。后半段:图文 token 合并成一条序列,共享参数做 Full Attention,深度融合

4
时间步 + 条件注入:adaLN(自适应 LayerNorm)

把时间步 $t$ 和全局 CLIP embedding 用 MLP 映射成缩放/偏移参数,注入每个 Transformer block 的 LayerNorm 中——替代 U-Net 里的 ResBlock 时间嵌入

📊 FLUX 和 SD1.x 的差距:为什么那么明显
  • 文本理解:T5-XXL(110亿参数的语言模型)vs CLIP-ViT-L(4亿参数)——SD1.x 靠 CLIP,写复杂 prompt 经常"读不懂";FLUX 的 T5 能理解长句、多属性、空间关系
  • 全局一致性:双流 MMDiT 的 Full Attention 让每个图像 token 都能看到所有文字 token,文本与图像区域精准绑定;SD1.x 的 Cross-Attention 是"逐层插入",信息流不完整
  • 细节质量:Flow Matching 路径更平滑,梯度估计更准确,手指/文字等细节错误大幅减少

8.3 现代文生视频:从 U-Net 到 3D DiT

视频生成的难点:除了空间维度(H×W),还有时间维度(T 帧),需要同时建模空间一致性(每帧的图像质量)和时序一致性(帧间运动流畅)。

⚠️ 为什么 U-Net 更难做视频
  • 卷积的感受野是局部的,帧间的长距离时序依赖很难捕捉
  • 原始 U-Net 没有时间维度,需要额外加 temporal attention 层,结构复杂
  • U-Net 的跳跃连接在 3D(T×H×W)上显存开销极大

现代文生视频的主流范式:3D DiT + 隐空间

1
3D VAE 压缩

用 3D VAE(含时间维度的 VAE)把视频从像素空间 $(T \times H \times W \times 3)$ 压缩到隐空间 $(T' \times H' \times W' \times C)$,大幅降低计算量

2
时空 patch 化

把 3D 隐向量切成时空 patch(如 $2 \times 2 \times 2$ 的小块),每块是一个 token——空间和时间都被统一成 token 序列

3
3D DiT 去噪

Transformer 在所有时空 token 上做 Full Attention(或分解的 Spatial + Temporal Attention),同时建模帧内空间关系和帧间时序关系

4
文本条件注入

和图像生成一样:文本 token(T5 / LLM 编码)通过 Cross-Attention 或双流 Attention 注入,每步去噪都受文本引导

模型机构年份架构核心特点
Sora OpenAI 2024 3D DiT(spacetime patches) 统一图像/视频为 patch token,可变时长/分辨率,60秒高质量视频
CogVideoX 智谱 2024 3D DiT + Expert Transformer 开源;3D VAE + Expert AdaLN;视频文本双流融合
HunyuanVideo 腾讯 2024 3D DiT(双流+单流混合) 开源;13B参数;图像/视频统一训练;full attention
Wan2.1 阿里 2025 3D DiT + Flow Matching 开源;14B;支持文生视频/图生视频;中文 prompt 友好
💡 Sora 的核心思路(一句话)

把视频看成"时空 patch 的序列",和 LLM 把文本看成"token 序列"是同一个范式——生成视频 = 在 token 序列上做扩散,而不是逐帧生成。这样模型天然能建模帧间一致性,也能任意扩展时长和分辨率。

类比 LLM:GPT 不是"逐词独立生成",而是在整个 token 序列上建模上下文。Sora 也不是"逐帧独立生成",而是在整个时空 token 序列上建模一致性。

8.3.1 文生视频代表:Wan2.1 做了什么

Wan2.1(阿里,2025)是目前开源文生视频里效果最强的模型,14B 参数。其架构设计是 3D DiT + Flow Matching 路线的集大成者,也是目前工业界可落地的最佳开源方案之一。

🔑 Wan2.1 的核心架构:3D VAE → 时空 patch → DiT + Flow Matching
1
3D Causal VAE:时间+空间统一压缩

Wan2.1 用因果 3D VAE压缩视频:空间下采样 8×(如 $480×832$ → $60×104$),时间下采样 4×(如 81 帧 → 21 帧),通道扩展到 16 维。"因果"意味着每帧只能看到过去的帧,和自回归 LLM 的 causal mask 思路类似,保证视频可以流式生成

2
时空 patch 化:统一成 token 序列

把 3D 隐向量按 $2×2×1$(空间×空间×时间)切成 patch,每个 patch 是一个 token。$81$ 帧 $480×832$ 的视频最终变成约 $13000$ 个 token——数量远多于图像(一张 $1024×1024$ 约 $4096$ token),这也是为什么视频模型显存开销极大

3
文本编码:umt5-xxl(中英双语 T5)

Wan2.1 专门使用支持中英双语的 umt5-xxl 作为文本编码器,max_length=512,输出 text token 序列通过 Cross-Attention 注入每个 DiT block。这也是 Wan2.1 对中文 prompt 特别友好的核心原因

4
DiT + Flow Matching 去噪

骨干是标准 Transformer(40层,hidden_dim=5120),在所有时空 token 上做 Full Self-Attention——每个 patch token 能"看到"所有帧的所有 patch,天然建模帧间一致性。训练目标用 Flow Matching(直线路径),推理只需 50 步左右即可得到高质量视频

⚠️ 为什么视频生成的 Full Attention 那么贵

以 Wan2.1 生成 81帧 480P 视频为例:

  • 图像 token 数:约 13000 个(每次推理)
  • Full Attention 的计算量:$O(N^2)$,即 $13000^2 \approx 1.7 \times 10^8$ 次 attention 运算/层
  • 40 层 × 50 步 = 大量计算,这就是为什么生成一个视频需要 24GB+ 显存和数分钟时间

一些模型(如早期 AnimateDiff)会把 Attention 分解成 Spatial Attention(只在同一帧内)+ Temporal Attention(只在同一位置的不同帧间),牺牲全局建模能力来换速度。Wan2.1/HunyuanVideo 选择了 Full Attention,效果更好但更贵。

✅ Wan2.1 还支持什么
  • 图生视频(I2V):把第一帧图像作为条件注入,生成以该图像为起点的视频——图像 token 和 noise token 一起输入 DiT
  • 视频续写:给定视频前几秒,续生后续内容——已有帧作为 context token,新帧从噪声中去噪
  • 可变分辨率/时长:因为是 token-based,不需要固定输入尺寸,只需在 position embedding 里编码时空坐标即可支持任意分辨率和时长

8.4 架构总结

Diffusion 骨干网络演进路线
DDPM U-Net
像素空间,纯卷积
LDM U-Net
隐空间 + Cross-Attn
DiT
图像 patch → token
3D DiT
时空 patch → 视频
2020 → 2022 → 2022 → 2024
🎯
§9 应用场景

🎨 文生图

输入文本描述,输出对应图片

应用:艺术创作、游戏原画、广告设计

🖼️ 图生图

输入参考图+文本,输出风格转换后的图片

应用:照片转油画、白天转夜晚

🔧 Inpainting

图片+遮罩+文本,AI重新生成遮罩区域

应用:去除路人、修复破损照片

💡 举例:Inpainting应用

场景:照片里有路人抢镜

  1. 用画笔遮住路人区域
  2. 输入文本:"蓝天白云下的草地"
  3. AI自动填充该区域,完美融合背景
⚖️
§10 Diffusion vs 其他生成模型
对比维度DiffusionGANVAE
生成质量 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐
训练稳定性 ⭐⭐⭐⭐⭐ ⭐⭐ ⭐⭐⭐⭐
生成多样性 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐
生成速度 ⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
可控性 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐
⚠️ Diffusion的最大缺点

生成速度慢:需要逐步去噪(通常50-1000步)

  • Stable Diffusion生成一张图:1-5秒
  • GAN生成一张图:0.1秒以内

解决方案:DDIM(减少到20-50步)、Consistency Models(1-2步)

生成模型全景图
Figure 6(Lilian Weng 2021):四种主流生成模型对比——GAN(对抗博弈)、VAE(变分推断)、Flow(可逆变换)、Diffusion(逐步去噪)
🗺️
§11 总结与学习路线

11.1 为什么Diffusion能成功?

📐 理论扎实

有完善的概率论和统计物理支撑

🏋️ 训练稳定

不像GAN有模式崩溃问题

🎛️ 可控性强

文本、图像、姿态等多种条件可控

11.2 学习路线

三阶段学习路径
1
理解基础

阅读DDPM论文 + 跑通minimist代码 + 理解U-Net架构

2
动手实践

微调Stable Diffusion(用LoRA) + 尝试ControlNet控制生成

3
深入原理

研读Score-based models + 理解SDE/ODE形式化 + 探索采样优化

11.3 推荐资源

📚 经典论文