生成模型 / 条件生成 原理笔记进阶 11 分钟阅读 查看源文件 ↗

条件生成与 Guidance#

本页内容4 个部分

1. 从无条件到有条件生成#

1.1 发展脉络#

2014

cGAN 条件生成起点

Mirza & Osindero 在 GAN 上加入类别标签 yy,训练时把 yy 拼到生成器和判别器输入。有条件生成的思路首次出现,但 GAN 训练不稳定、模式崩塌,无法做到"任意文本→图像"。

2020

DDPM 扩散模型登场

Ho et al. 提出 DDPM,训练稳定、生成质量高,但完全是无条件生成 p(x)p(x)——给噪声只能生成随机图,无法控制内容。扩散模型的时代开始,但还不实用。

2021 · 上半年

CLIP 文本-图像桥梁

OpenAI 用 4 亿图文对训练对比学习模型,把文本和图像映射到同一个 embedding 空间。这是"文本→图像"生成的关键基础设施——有了 CLIP,才能把文字条件转化为模型能理解的向量。

2021 · 下半年

Classifier Guidance 第一个条件扩散

Dhariwal & Nichol(OpenAI)在扩散模型上加入噪声分类器,用分类器梯度引导采样方向,第一次让扩散模型做到有条件生成并在 ImageNet 上超过 GAN。但需要单独训练分类器,且不能处理文本等连续条件。

2022 · 初

CFG 无需分类器

Ho & Salimans 提出 Classifier-Free Guidance:同一个网络训练时随机丢弃条件,推理时用"有条件预测 − 无条件预测"的差值放大条件效果。不再需要额外分类器,且天然支持文本条件,成为此后所有主流模型的标配。

2022 · 中

Latent Diffusion / Stable Diffusion 1.x 效率突破

Rombach et al.(LMU Munich)把扩散过程从像素空间移入 VAE 的隐空间,计算量压缩约 48 倍。结合 CLIP 文本编码器 + Cross-Attention 条件注入 + CFG,组成了完整的文生图技术栈,并开源。Stable Diffusion 时代正式开始。

2022 · 下 — 2023 · 中

DALL-E 2 · Imagen · SDXL 能力跃升

DALL-E 2(OpenAI)引入 unCLIP,先生成 CLIP 图像 embedding 再解码;Imagen(Google)用大型语言模型 T5-XXL 做文本编码器,效果更好。SDXL 增大 U-Net 并引入双文本编码器和微调流程,生成质量大幅提升。

2023 · 10

DALL-E 3 数据工程突破

OpenAI 用 LLM 为训练图像重写高质量 caption(详细、准确的描述替代短标签),prompt following 能力大幅超越前代。核心洞察:数据质量 > 模型架构——更好的 caption 比更大的模型更有效。深刻影响了后续所有模型的数据工程策略。

2024

SD3 · Flux.1 架构革新

SD3(Stability AI)用 MM-DiT 替换 U-Net,三路文本编码器(CLIP×2 + T5),切换到 Flow Matching。Flux.1(Black Forest Labs,SD 核心团队出走创建,12B 参数)采用单流+双流混合 Transformer,通过 Guidance Distillation 实现单次前向推理(schnell 版本)。U-Net → DiT、DDPM → Flow Matching 两条主线完成切换。

**一条主线读懂演进:**无条件(DDPM)→ 需要外挂分类器(Classifier Guidance)→ 用同一网络隐式做引导(CFG)→ 搬到隐空间省算力(LDM)→ 用 Transformer 替换 U-Net(DiT/SD3)。

1.2 无条件生成 vs 条件生成#

无条件生成建模的是数据的边缘分布 p(x)p(x):给模型一段纯高斯噪声,它会随机生成某张图像,你无法控制生成的内容。DDPM、Score-based 模型的原始版本都属于这一类。

条件生成建模的是条件分布 p(x∣c)p(x|c):给模型噪声 加上 一个条件 cc,让它生成符合条件的图像。例如"一只坐在沙滩上的猫"——这才是实际产品需要的能力。

1.3 条件 cc 的类型#

条件类型 示例 典型编码方式
类别标签 ImageNet 1000 类("金毛犬"=207) one-hot / embedding lookup
文本描述 "a cat sitting on a beach" CLIP / T5 文本编码器
图像 img2img、风格参考 CLIP 图像编码器 / VAE 编码器
语义图 / 边缘图 ControlNet 输入 额外卷积编码器
深度图 / 姿态 ControlNet depth/pose 同上

1.4 两个先后发生的问题#

把条件注入去噪过程,要回答两个顺序发生的问题——不是"选哪条路",而是"第一步怎么做,第二步怎么做":

问题一:网络怎么接收条件 c?(架构 / 训练阶段)

这解决的是:怎么让 ϵθ(xt,t,c)\epsilon_\theta(x_t, t, c) 和 ϵθ(xt,t)\epsilon_\theta(x_t, t) 产生差异。Cross-Attention 是主流答案——文本 embedding 通过 K、V 进入网络,图像特征通过 Q 去查询文本,让网络每一层都能读到条件信息。这是网络结构层面的事,训练和推理时都在发生,和"引导"无关。

其他方式:拼接(concat c 到输入通道)、加法(AdaGN/AdaLN 用 c 调制归一化层)。

问题二:推理时怎么让条件影响足够强?(采样阶段)

只有 Cross-Attention,网络只是"看到了"条件,但采样出来的图可能依然模糊、不够贴合 prompt。需要在采样时额外放大有条件预测和无条件预测的差距:

  • Classifier Guidance:在噪声预测上叠加外部分类器的梯度
  • CFG:ϵ~=ϵuncond+w⋅(ϵcond−ϵuncond)\tilde{\epsilon} = \epsilon_\text{uncond} + w \cdot (\epsilon_\text{cond} - \epsilon_\text{uncond}),放大两者的差值

这是采样层面的事,不改变网络结构,只在推理时操作网络输出。

**依赖关系:问题一是问题二的前提。**没有 Cross-Attention,ϵcond\epsilon_\text{cond} 和 ϵuncond\epsilon_\text{uncond} 就没有差别,CFG 的差值为零,放大也没有意义。先让网络能理解条件,再谈如何放大条件的影响。

Stable Diffusion 对两个问题都给出了答案:Cross-Attention 解决问题一(让 U-Net 读取文本 embedding),CFG 解决问题二(推理时用 ww 控制贴合强度)。本章先讲问题二的两种方案(Classifier Guidance → CFG),再讲问题一的实现(Cross-Attention),最后串联成完整推理流程。

2. Classifier Guidance(分类器引导)#

来自 Dhariwal & Nichol, 2021(OpenAI 的 "Diffusion Models Beat GANs" 论文)。这是第一个让扩散模型在 ImageNet 上超过 GAN 的方法。

2.1 训练方式:分开训练,完全独立#

Classifier Guidance 由两套完全独立的训练组成,互不干扰:

第一步:正常训练扩散模型(无条件,不需要标签)

for each step:
    x_0 = 真实图像(不需要标签 y)
    t, ε ~ 随机采样
    x_t = sqrt(ᾱ_t)·x_0 + sqrt(1-ᾱ_t)·ε
    loss = MSE(ε_θ(x_t, t),  ε)
    反向传播更新 U-Net

分类器全程不参与,U-Net 学的是无条件 p(x)p(x)。

第二步:单独训练噪声分类器(输入必须是带噪声的 x_t)

for each step:
    x_0, y = 带标签的真实图像
    t ~ 随机采样(覆盖所有噪声程度 1…T)
    x_t = 用前向公式加噪到 t 步
    loss = CrossEntropy(p_φ(y | x_t, t),  y)
    反向传播更新分类器

关键:分类器输入是 (xt,t)(x_t, t),因为推理时它要对各个噪声程度的中间图分类。用干净图像训练的普通分类器在这里完全不管用。

推理时:两个网络组合,但没有任何训练在发生

for t = T, T-1, ..., 1:
    ε_θ  = U-Net(x_t, t)                      # 无条件噪声预测(U-Net 冻结)
    grad = ∇_{x_t} log p_φ(y | x_t, t)       # 分类器梯度(分类器冻结)
    ε̃   = ε_θ - s · sqrt(1-ᾱ_t) · grad      # 合并:贝叶斯公式
    x_{t-1} = 用 ε̃ 做去噪步骤

分类器梯度不是训练信号,不更新任何权重。它只是在每步采样时给去噪方向加一个"指向类别 yy 的偏转"。

**grad 是一个向量,和 xtx_t 形状完全一样。**分类器本身输出的是标量概率("这张噪声图属于金毛犬的概率是 0.23"),但对 xtx_t 求梯度之后,得到的是和 xtx_t 同维度的向量——每个位置的值告诉你"把这里往哪个方向动一点,分类器会觉得更像目标类别"。

数字例子:假设 xtx_t 只有 2 维#

x_t = [0.5, -0.3]           # 当前带噪声的图(简化成 2 维)

# 分类器前向:输出标量概率
logit = classifier(x_t, t)   # 比如 [金毛犬: -1.2, 猫: 0.8, ...]
prob_y = softmax(logit)[金毛犬]  # = 0.23   ← 这是个标量

# 对 x_t 反向传播,得到梯度(和 x_t 同形,是个向量)
grad = ∇_{x_t} log(0.23)    # = [+0.1, +0.4]
# 含义:x_t[0] 往正方向动 → 金毛犬概率升高
#        x_t[1] 往正方向动 → 金毛犬概率更高

# 假设 ε_θ = [0.6, 0.2],s = 3,sqrt(1-ᾱ_t) = 0.5
ε̃ = [0.6, 0.2] - 3 · 0.5 · [0.1, 0.4]
  = [0.6, 0.2] - [0.15, 0.6]
  = [0.45, -0.4]    ← 去噪方向向"金毛犬更集中"的区域偏转

为什么加了分类器梯度不会破坏扩散模型?U-Net 的权重完全冻结,不被修改。分类器梯度修改的是每步的去噪轨迹(走哪条路),而不是 U-Net 学到的能力(怎么走路)。数学上这正好对应贝叶斯分解:无条件 score + 分类器梯度 = 条件 score,完全合法。

2.2 核心思路#

训练一个单独的噪声分类器 pϕ(y∣xt)p_\phi(y|x_t)——注意它的输入是带噪声的图像 xtx_t,而非干净图像。然后利用它的梯度来引导去噪方向,使生成图像属于目标类别 yy。

2.3 数学推导#

我们想采样自条件分布 p(xt∣y)p(x_t|y),需要条件 score:

∇xtlog⁡p(xt∣y)=∇xtlog⁡p(xt)+∇xtlog⁡pϕ(y∣xt)\nabla_{x_t} \log p(x_t|y) = \nabla_{x_t} \log p(x_t) + \nabla_{x_t} \log p_\phi(y|x_t)

贝叶斯公式取 log 求梯度:log⁡p(xt∣y)=log⁡p(xt)+log⁡p(y∣xt)−log⁡p(y)\log p(x_t|y) = \log p(x_t) + \log p(y|x_t) - \log p(y),log⁡p(y)\log p(y) 与 xtx_t 无关

引入引导强度 ss(guidance scale):

∇xtlog⁡p(xt∣y)=∇xtlog⁡p(xt)⏟无条件 score(预训练扩散模型)+s⋅∇xtlog⁡pϕ(y∣xt)⏟分类器梯度\nabla_{x_t} \log p(x_t|y) = \underbrace{\nabla_{x_t} \log p(x_t)}_{\text{无条件 score(预训练扩散模型)}} + s \cdot \underbrace{\nabla_{x_t} \log p_\phi(y|x_t)}_{\text{分类器梯度}}

  • s=0s = 0:退化为无条件生成
  • s=1s = 1:标准贝叶斯条件生成
  • s>1s > 1:放大分类器梯度,生成更"典型"但多样性更低的图像

Classifier Guidance 的三大缺点

  1. 需要额外训练一个能在噪声图像上工作的分类器,训练成本不低
  2. 每步采样需要额外做一次分类器前向 + 反向传播(算梯度),推理速度慢
  3. 只能处理离散类别条件(有多少类就训练多少类的分类器),无法直接用于文本等连续条件

**面试要点:**Classifier Guidance 的核心贡献是证明了"guidance scale s>1s > 1 可以用多样性换质量"。这个 quality-diversity tradeoff 的思想被 CFG 继承并发扬光大。

3. Classifier-Free Guidance (CFG)#

来自 Ho & Salimans,NeurIPS 2021 Workshop。CFG 是当前所有主流文生图模型的标准配置。

3.1 原论文实际在做什么#

CFG 原论文演示的是类别标签条件(ImageNet 分类),而不是文本。条件 cc 就是一个整数类别,注入方式和时间步 tt 完全一样——转成 embedding 向量后直接加到 U-Net 的特征上,不需要 cross-attention。

条件注入方式取决于条件的形态

条件类型 注入方式 Cross-Attention?
类别标签(整数,如 207="金毛犬") embedding → 加到特征(和时间步 tt 一样) 不需要
文本("一只猫坐在沙滩上") CLIP 编码成 77 个 token 序列 → cross-attention 需要

类别标签是一个标量,直接转 embedding 就够了。文本是变长的 token 序列,必须用 cross-attention 让图像每个位置去"查询"文本的每个 token。CFG 本身只是一个训练+推理策略,对两种方式都适用。

同期(2021 年底),OpenAI 的 GLIDE 第一次把 cross-attention 加进 U-Net 做文本条件,并同时应用了 CFG——这才是"文本 + CFG"的首次合体。Stable Diffusion(2022)继承了这套架构并搬到隐空间、开源。所以:

  • CFG 策略本身:Ho & Salimans,2021,类别标签条件
  • Cross-Attention for 文本:GLIDE,2021,同期
  • 两者合体 + 开源:Stable Diffusion,2022

3.2 核心思想#

不需要单独的分类器——用同一个去噪网络同时学习有条件去噪和无条件去噪,然后在采样时利用两者的差值做引导。

3.3 训练技巧:条件丢弃#

训练时以概率 puncondp_\text{uncond}(通常 10%–20%)随机把条件 cc 替换为空标记 ∅\varnothing(null embedding):

  • 80%–90% 的时间:网络学习 ϵθ(xt,t,c)\epsilon_\theta(x_t, t, c)(有条件去噪)
  • 10%–20% 的时间:网络学习 ϵθ(xt,t,∅)\epsilon_\theta(x_t, t, \varnothing)(无条件去噪)

这样一个网络就同时具备了有条件和无条件的能力。

3.4 CFG 采样公式#

ϵ~θ=ϵθ(xt,t,∅)+w⋅[ϵθ(xt,t,c)−ϵθ(xt,t,∅)]\tilde{\epsilon}_\theta = \epsilon_\theta(x_t, t, \varnothing) + w \cdot \big[\epsilon_\theta(x_t, t, c) - \epsilon_\theta(x_t, t, \varnothing)\big]

等价形式:ϵ~θ=(1−w)  ϵθ(xt,t,∅)+w  ϵθ(xt,t,c)\tilde{\epsilon}_\theta = (1 - w)\;\epsilon_\theta(x_t, t, \varnothing) + w\;\epsilon_\theta(x_t, t, c)

3.5 直觉理解#

把噪声预测想象成二维向量:

  • ϵθ(xt,t,∅)\epsilon_\theta(x_t, t, \varnothing):无条件预测——"我觉得这个噪声应该往 (2,3)(2, 3) 方向去"
  • ϵθ(xt,t,c)\epsilon_\theta(x_t, t, c):有条件预测——"加上 prompt 后应该往 (4,5)(4, 5) 方向去"
  • 差值 =(4−2,5−3)=(2,2)= (4-2, 5-3) = (2, 2)——这就是**"条件的影响方向"**

CFG 的做法:从无条件预测出发,沿着"条件影响方向"走 ww 步:

数字例子(w=7.5w = 7.5)#

ϵ~=(2,3)+7.5×(2,2)=(2+15,  3+15)=(17,18)\tilde{\epsilon} = (2, 3) + 7.5 \times (2, 2) = (2 + 15,\; 3 + 15) = (17, 18)

可以看到,w=7.5w = 7.5 把"条件的方向"放大了 7.5 倍。最终噪声预测远远偏离了无条件预测,强烈地朝着条件要求的方向走。

3.6 ww 的取值含义#

ww 值 含义 效果
w=0w = 0 完全忽略条件 无条件生成
w=1w = 1 标准条件生成 不做额外引导
w=7.5w = 7.5(SD 默认) 强引导 图像高度符合 prompt
w=20+w = 20+ 过度引导 颜色过饱和、细节失真

3.7 ww 太大为什么会出问题?#

因为 ϵ~\tilde{\epsilon}(CFG 合成出来的最终噪声预测,不是网络直接输出的,而是 ϵuncond+w⋅(ϵcond−ϵuncond)\epsilon_\text{uncond} + w \cdot (\epsilon_\text{cond} - \epsilon_\text{uncond}) 算出来的)的范数远大于训练时见到的 ϵ∼N(0,I)\epsilon \sim \mathcal{N}(0, I)。训练时噪声服从标准高斯,大部分元素在 [−3,3][-3, 3] 范围内;而 w=20w=20 时 ϵ~\tilde{\epsilon} 的元素可以到几十,大大超出网络训练时的"舒适区"。结果就是颜色过饱和、出现伪影。

从 Classifier Guidance 到 CFG 的演进

Classifier Guidance 需要分类器梯度;CFG 用两次前向传播的差值代替了梯度计算。数学上可以证明两者在一定假设下等价,但 CFG 在工程上好得多:

  • 不需要额外的分类器网络和训练
  • 不需要反向传播(只需前向)
  • 天然支持文本等任意形式的条件
  • 一个网络搞定所有事

4. CFG 的实际影响和调参#

4.1 典型 guidance scale 取值#

任务 推荐 ww 范围 原因
文本 → 图像 7 – 12 需要强引导才能准确匹配文本描述
图像编辑 / img2img 1.5 – 3 已有原图约束,过强引导会破坏原图结构
超分辨率 1 – 2 主要靠纹理细节,不需要语义引导
视频生成 3 – 7 帧间一致性需要适度引导

4.2 Quality-Diversity Tradeoff#

  • ww 小 → 多样性高,但可能不符合 prompt("自由发挥"太多)
  • ww 大 → 高度符合 prompt,但所有生成结果趋同、颜色过饱和

可以类比温度参数:ww 越大相当于温度越低,分布越尖锐。

4.3 Dynamic CFG(动态引导)#

不同时间步使用不同的 ww:

  • 前期(tt 大):用大 ww(如 15),确定整体构图和语义
  • 后期(tt 小):用小 ww(如 3),添加自然细节、避免过饱和

直觉是:前期决定"画什么",后期决定"画得多自然"。

⚠️ Dynamic CFG 不是默认行为

你在 Diffusers / ComfyUI / WebUI 里看到的 CFG scale 输入框,给的是一个固定值,整个推理过程全程用这个 ww——这是最标准、最通用的实现。

Dynamic CFG 需要额外的插件或手动改推理代码(ComfyUI 有专门的 CFGScheduler 节点,WebUI 有 Dynamic Thresholding 扩展)。它是社区里的进阶调参技巧,不是主流框架的默认配置,面试时了解原理即可,不需要当成"标准做法"来记。

4.4 Negative Prompt 的原理#

标准 CFG 公式中,无条件预测 ϵθ(xt,t,∅)\epsilon_\theta(x_t, t, \varnothing) 使用空 embedding。Negative prompt 把它替换为负面条件的预测:

ϵ~θ=ϵθ(xt,t,cneg)+w⋅[ϵθ(xt,t,cpos)−ϵθ(xt,t,cneg)]\tilde{\epsilon}_\theta = \epsilon_\theta(x_t, t, c_\text{neg}) + w \cdot \big[\epsilon_\theta(x_t, t, c_\text{pos}) - \epsilon_\theta(x_t, t, c_\text{neg})\big]

cposc_\text{pos} = 正面 prompt,cnegc_\text{neg} = 负面 prompt(如 "blurry, low quality")

具体例子#

正面 prompt = "a beautiful landscape photo",负面 prompt = "blurry, watermark, low quality"

  • ϵθ(xt,t,cneg)\epsilon_\theta(x_t, t, c_\text{neg}):网络预测"如果要生成模糊低质量图,噪声方向是 (1,−2)(1, -2)"
  • ϵθ(xt,t,cpos)\epsilon_\theta(x_t, t, c_\text{pos}):网络预测"如果要生成美丽风景,噪声方向是 (3,4)(3, 4)"
  • 差值 =(2,6)= (2, 6),代表"从低质量走向高质量风景"的方向
  • w=7.5w = 7.5:ϵ~=(1,−2)+7.5×(2,6)=(16,43)\tilde{\epsilon} = (1, -2) + 7.5 \times (2, 6) = (16, 43)

negative prompt 的效果:起点从"什么都不画"变成了"画得差",引导方向变成了"远离差,走向好"。

**面试要点:**Negative prompt 并不是"删除"某些东西,而是改变了 CFG 的参考基线——从"无条件"变成"负面条件"。引导方向变成"远离负面 + 趋近正面"。

相关阅读路线

理解生成模型 ↗