Guidance:如何让模型听懂 Prompt
把条件变量 $y$ 塞进生成模型很容易,难的是让模型「真的听话」——本讲从贝叶斯分解一路推到 classifier-free guidance。
0. 本讲导读
到上一讲为止,我们手里已经有一台完整的生成机器。Lecture 1 给出了 flow model 与 diffusion model 的定义,Lecture 2 用 flow matching 把边际向量场 $u_t^{\text{target}}$ 学了出来,Lecture 3-A 又把同一件事翻译成 score function $\score{t}$ 的语言,并且用 SDE extension trick 打通了 ODE 与 SDE 两条采样路线。把这些拼起来,我们可以从 $\simple = \N(0, I_d)$ 出发,模拟一条轨迹,让终点 $X_1$ 服从 $\data$。
问题是:这台机器只会做一件事——生成「某一张」图。你不能告诉它画什么。
但现实中我们几乎从不需要「随便生成点什么」。我们需要的是「生成一张柯基犬的照片」「生成一段猫在烤蛋糕的视频」。用数学语言说,我们要采样的不是 $\data(x)$,而是条件数据分布 $\data(x\mid y)$,其中 $y$ 是类别标签、文本 prompt、或者任何别的附加信息。
本讲要回答的问题只有一个,但它有两层:
- 数学上怎么做? 这一层其实很简单,简单到几乎没有新东西——把 $y$ 当成网络的一个额外输入,Lecture 2 的整套推导对每个固定的 $y$ 原封不动地成立。这叫 vanilla guidance。
- 为什么这样做还不够,以及怎么修? 这一层才是本讲的正题。实践中人们发现,理论上正确的 vanilla guidance 生成出来的图「不够像那个类别」。修复它的手段叫 classifier-free guidance(CFG),它是今天几乎所有图像 / 视频生成模型的标配。
本讲的技术核心其实是一行贝叶斯公式:
$$ \score{t}(x\mid y) = \score{t}(x) + \nabla_x \log p_t(y \mid x). $$这行公式把「条件 score」拆成了「无条件 score」加上「一个噪声分类器的对数似然梯度」。第二项是唯一携带 prompt 信息的部分。既然模型对 prompt 不够敏感,那就把这一项人为放大 $w$ 倍——这就是 classifier guidance。而 classifier-free guidance 的聪明之处在于,它把同一个恒等式反过来用,把那个讨厌的分类器梯度整个消掉,换成两次向量场求值之差。
- Vanilla guidance 在数学上完全正确。 固定 $y$,把 $\data$ 换成 $\data(\cdot\mid y)$,Lecture 2 的边际化技巧、连续性方程、CFM 损失等价性全部照搬。训练目标只是把数据加载器从「返回 $z$」改成「返回 $(z,y)$」。
- 但它在实践中不够听话。 原因包括模型欠拟合、网络数据中图文配对本身有大量噪声,以及——即使模型完美,$\data(\cdot\mid y)$ 里本来就有大量平庸样本。
- 贝叶斯分解:$\score{t}(x\mid y)=\score{t}(x)+\nabla\log p_t(y\mid x)$,其中 $\nabla_x \log p_t(y)=0$ 是因为 $p_t(y)=\data(y)$ 根本不依赖 $x$。
- Classifier guidance:把分类器项放大 $w$ 倍,$\tilde u_t(x\mid y)=u_t^{\text{target}}(x)+wa_t\nabla\log p_t(y\mid x)$。代价是要额外训一个能处理各个噪声水平的分类器。
- Classifier-free guidance:代回同一恒等式消掉分类器,得到只含两个向量场的线性组合 $$\tilde u_t(x\mid y)=(1-w)\,u_t^{\text{target}}(x\mid\varnothing)+w\,u_t^{\text{target}}(x\mid y).$$ 两个向量场用同一个网络表示,训练时以概率 $\eta$ 把标签替换成空标签 $\varnothing$(label dropout)即可。
- 几何图像:$w>1$ 时我们在采样一个被锐化的分布 $\tilde p_t(x\mid y)\propto p_t(x)\,p_t(y\mid x)^w \propto p_t(x)^{1-w}p_t(x\mid y)^{w}$。它把概率质量从「无条件模型也会生成的东西」推向「最像 $y$ 的东西」,因此感知质量上升、多样性下降。
- CFG 是启发式。 对 $w\neq 1$,$\tilde u_t(\cdot\mid y)$ 不再是任何合法概率路径的边际向量场,$X_1$ 也不再服从 $\data(\cdot\mid y)$。它被采用纯粹是因为经验效果极好。
1. 问题设定:从 $\data(x)$ 到 $\data(x\mid y)$
术语约定:guided 而不是 conditional
先解决一个几乎必然踩坑的记号冲突。在 Lecture 2 里,「conditional(条件的)」这个词已经被占用了:conditional probability path $p_t(\cdot\mid z)$ 与 conditional vector field $u_t^{\text{target}}(\cdot\mid z)$ 里的「条件」,指的是以某个数据点 $z\sim\data$ 为条件。这是我们构造边际路径时用的内部脚手架,跟用户完全无关。
而本讲要讨论的是以一个 prompt $y$ 为条件,这是暴露给用户的接口。为了不让两个「条件」打架,讲义约定:
本讲一律用 guided(引导的) 专指「以 prompt $y$ 为条件」,而把 conditional(条件的) 留给「以数据点 $z$ 为条件」。于是:
- $p_t(\cdot\mid z)$、$u_t^{\text{target}}(\cdot\mid z)$:conditional path / vector field(对 $z$ 条件)。
- $p_t(\cdot\mid y)$、$u_t^{\text{target}}(\cdot\mid y)$:guided path / vector field(对 $y$ 引导)。
- $p_t(x)$、$u_t^{\text{target}}(x)$:marginal / unguided,两种「条件」都不加。
写代码时这个区分同样重要:$z$ 只在训练循环里出现,$y$ 在训练和推理里都出现。
Guided diffusion model 的类型签名
我们把 prompt 变量 $y$ 想成活在某个空间 $\mathcal{Y}$ 里。$\mathcal{Y}$ 上不加任何约束:
- $y$ 是 ImageNet 类别标签时,$\mathcal{Y}=\{0,1,\dots,999\}$,离散有限;
- $y$ 是文本 prompt 时,$\mathcal{Y}$ 是所有字符串的集合(实践中被一个文本编码器映射成 $\R^{L\times k}$ 的嵌入序列);
- $y$ 是一张分割图、一段音频、一个 3D 姿态时,$\mathcal{Y}$ 就是对应的空间。
一个 guided diffusion model 由一个 guided vector field $u^\theta$ 和一个固定的扩散系数 $\sigma_t$ 组成:
$$ \begin{aligned} \text{神经网络:}&\quad u^{\theta}: \R^d\times\mathcal{Y}\times[0,1]\to\R^d, \quad (x,y,t)\mapsto u_t^\theta(x\mid y)\\[2pt] \text{固定的:}&\quad \sigma: [0,1]\to[0,\infty),\quad t\mapsto\sigma_t \end{aligned} $$和 Lecture 1 里的无引导模型相比,唯一的差别是网络多吃了一个输入 $y\in\mathcal{Y}$。对任意选定的 $y$,采样流程也原封不动:
$$ \begin{aligned} \text{初始化:}&\quad X_0\sim\simple &&\text{(从简单分布,如 }\N(0,I_d)\text{,起步)}\\ \text{模拟:}&\quad \dd{X_t}=u_t^\theta(X_t\mid y)\dd{t}+\sigma_t\dd{W_t} &&\text{(从 }t=0\text{ 积分到 }t=1\text{)}\\ \text{目标:}&\quad X_1\sim\data(\cdot\mid y) &&\text{(希望终点服从 }y\text{ 的条件分布)} \end{aligned} $$当 $\sigma_t\equiv 0$ 时,SDE 退化为 ODE,这样的模型称为 guided flow model。下文为了简洁,主要在 flow model 的语言里推导;一切结论对 diffusion model 都成立(见第 8 节末尾)。
四个密度:把类型理清楚
接下来所有推导都在同一个联合分布上进行,把它一次性写清楚可以避免后面反复迷路。构造如下:
- 从数据集里抽一对 图文对 $(z,y)\sim\data(z,y)$。注意数据分布现在是 $\R^d\times\mathcal{Y}$ 上的联合分布,而不只是 $\R^d$ 上的分布。
- 给定 $z$,按条件概率路径加噪:$x\sim p_t(\cdot\mid z)$。关键:加噪过程只看 $z$,完全不看 $y$。也就是说 $$X_t \perp Y \mid Z. \tag{$\star$}$$ 这个条件独立性是后面每一步的支柱。
于是我们得到一个 $t$-依赖的联合密度 $p_t(x,y)=\int p_t(x\mid z)\,\data(z,y)\ud z$,由它派生出四个我们会反复用到的密度:
| 对象 | 定义 | 类型 / 含义 |
|---|---|---|
| $p_t(x)$ | $\displaystyle\int p_t(x\mid z)\,\data(z)\ud z$ | $\R^d\to\R_{\ge0}$。无引导边际路径,就是 Lecture 2/3-A 里的 $p_t$。 |
| $p_t(x\mid y)$ | $\displaystyle\int p_t(x\mid z)\,\data(z\mid y)\ud z$ | $\R^d\times\mathcal{Y}\to\R_{\ge0}$。引导边际路径:把数据分布换成 $\data(\cdot\mid y)$ 后跑同一套加噪。 |
| $p_t(y\mid x)$ | $p_t(x,y)/p_t(x)$ | $\R^d\times\mathcal{Y}\to\R_{\ge0}$。噪声分类器:看到 $t$ 时刻的带噪样本 $x$,标签是 $y$ 的概率。 |
| $p_t(y)$ | $\displaystyle\int p_t(x,y)\ud x$ | $\mathcal{Y}\to\R_{\ge0}$。下面会证明它恒等于 $\data(y)$,与 $t$ 和 $x$ 都无关。 |
$p_t(y)=\data(y)$,因此 $\nabla_x\log p_t(y)=0$。
$$ \begin{aligned} p_t(y) &= \int p_t(x,y)\ud x &&\text{(i) 边际化定义}\\ &= \int\!\!\int p_t(x\mid z)\,\data(z,y)\ud z\ud x &&\text{(ii) 代入联合密度的构造}\\ &= \int \data(z,y)\left(\int p_t(x\mid z)\ud x\right)\ud z &&\text{(iii) Fubini 交换积分次序}\\ &= \int \data(z,y)\cdot 1\ud z &&\text{(iv) }p_t(\cdot\mid z)\text{ 是概率密度}\\ &= \data(y). \end{aligned} $$其中 (ii) 用了加噪只看 $z$ 这一点(即 $(\star)$),(iv) 用了 $p_t(\cdot\mid z)$ 对 $x$ 积分为 $1$。结论是 $p_t(y)$ 是一个只依赖 $y$ 的常数,既不含 $x$,甚至也不含 $t$。所以
$$ \nabla_x \log p_t(y) = 0 \qquad \text{对一切 } x\in\R^d,\ t\in[0,1]. $$讲义在推导贝叶斯分解时一句话带过「gradient 是对 $x$ 求的,所以 $\nabla\log p_t(y)=0$」。上面这段计算说明这句话背后其实是「加噪过程不改变标签的边际分布」这个物理事实。
$p_t(y\mid x)$ 这个「噪声分类器」值得单独品一下。它在两个端点上的行为特别清楚:
- $t=1$($\alpha_1=1,\beta_1=0$):$x$ 就是干净数据,$p_1(y\mid x)=\data(y\mid x)$ 是一个普通的分类器。
- $t=0$($\alpha_0=0,\beta_0=1$):$p_0(x\mid z)=\N(0,I_d)$ 与 $z$ 无关,于是 $X_0$ 与 $(Z,Y)$ 独立,$p_0(y\mid x)=\data(y)$ 是常数——纯噪声里没有任何标签信息。
所以 $\nabla_x\log p_0(y\mid x)=0$:在 $t=0$ 附近,引导什么也做不了。这也和后面的 CFG 公式一致:$t=0$ 时 $p_0(\cdot\mid y)=p_0(\cdot)=\N(0,I_d)$,两者的向量场相同,$\tilde u_0 - u_0 = w\left(u_0^{\text{target}}(x\mid y)-u_0^{\text{target}}(x)\right)=0$,与 $w$ 取多少无关。引导的力量是随着 $t$ 增大、样本逐渐显形才慢慢生效的。
2. Vanilla Guidance:把 $y$ 直接喂进网络
最朴素的做法是:训练和推理时都把 prompt $y$ 作为网络的一个额外输入,其余一切照旧。这听上去像是在耍赖,但它在数学上是完全站得住脚的。本节把这件事讲透。
固定 $y$ 的视角:Lecture 2 原封不动搬过来
先做一个思想实验:把 $y$ 钉死成某个具体值 $y_0$(比如「柯基犬」)。那么我们面对的就是一个全新的、但形式上一模一样的无引导生成问题——只不过数据分布从 $\data$ 换成了 $\data(\cdot\mid y_0)$。
逐条检查 Lecture 2 的推理链条,看它是不是真的照搬无误:
| Lecture 2 的对象 | 无引导版本 | 固定 $y_0$ 的版本 | 是否需要改动 |
|---|---|---|---|
| 条件概率路径 | $p_t(\cdot\mid z)=\N(\alpha_t z,\beta_t^2 I_d)$ | 完全相同 | 不变——加噪不看 $y$ |
| 条件向量场 | $u_t^{\text{target}}(x\mid z)=\dot\alpha_t z+\frac{\dot\beta_t}{\beta_t}(x-\alpha_t z)$ | 完全相同 | 不变——同上 |
| 边际路径 | $p_t(x)=\int p_t(x\mid z)\data(z)\ud z$ | $p_t(x\mid y_0)=\int p_t(x\mid z)\data(z\mid y_0)\ud z$ | 把 $\data$ 换成 $\data(\cdot\mid y_0)$ |
| 边际向量场 | $\int u_t^{\text{target}}(x\mid z)\frac{p_t(x\mid z)\data(z)}{p_t(x)}\ud z$ | $\int u_t^{\text{target}}(x\mid z)\frac{p_t(x\mid z)\data(z\mid y_0)}{p_t(x\mid y_0)}\ud z$ | 同上 |
| 边际化技巧(连续性方程) | 成立 | 成立 | 不变——证明里只用到「$\data$ 是某个概率分布」 |
| CFM 与 FM 损失等价 | 成立 | 成立 | 不变 |
换句话说:Lecture 2 的所有定理都只依赖「存在某个数据分布」,而完全不关心这个分布是怎么来的。把 $\data$ 替换成 $\data(\cdot\mid y_0)$ 之后,我们立刻得到:ODE $\dd{X_t}=u_t^{\text{target}}(X_t\mid y_0)\dd{t}$ 把 $\simple$ 输运成 $\data(\cdot\mid y_0)$,而且可以用条件 flow matching 损失把它学出来:
$$ \mathcal{L}(\theta; y_0)=\E_{z\sim\data(\cdot\mid y_0),\ t\sim\mathrm{Unif}[0,1],\ x\sim p_t(\cdot\mid z)}\norm{u_t^\theta(x\mid y_0)-u_t^{\text{target}}(x\mid z)}^2 . $$从「每个 $y$ 一个模型」到「一个模型吃所有 $y$」
上面的思想实验有个致命的实践问题:$\mathcal{Y}$ 通常是无穷的(所有可能的文本),我们不可能给每个 prompt 训一个网络。真正的做法是一个网络、$y$ 作为输入,训练时对 $y$ 也取期望:
$$ \mathcal{L}_{\text{CFM}}^{\text{guided}}(\theta)=\E_{(z,y)\sim\data(z,y),\ t\sim\mathrm{Unif}[0,1],\ x\sim p_t(\cdot\mid z)}\norm{u_t^{\theta}(x\mid y)-u_t^{\text{target}}(x\mid z)}^2 . $$这就是讲义的 guided conditional flow matching objective。它和无引导的 CFM 目标唯一的差别是:采样 $(z,y)\sim\data$ 而不是 $z\sim\data$。落到 PyTorch 上,就是数据加载器要同时返回图像 $z$ 和 标签 / 文本 $y$,仅此而已。
但这里有一个不能跳过的问题:把不同 $y$ 的损失平均到一起之后,最优解还是每个 $y$ 各自的边际向量场吗? 直觉上应该是(因为不同 $y$ 之间「不打架」),但我们把它证出来。
引理(二次损失的逐点极小元是条件期望)。 设 $(A,B,C)$ 是任意联合分布的随机变量,$g$ 是取值于 $\R^d$ 的可测函数且平方可积。则在所有可测函数 $f$ 上,
$$ \argmin_{f}\ \E\norm{f(A,B)-g(A,C)}^2 = \E\!\left[g(A,C)\,\middle|\,A,B\right]. $$证明。 用塔性质把期望拆开:$\E\norm{f(A,B)-g(A,C)}^2=\E\Big[\E\big[\norm{f(A,B)-g(A,C)}^2\mid A,B\big]\Big]$。内层期望里 $f(A,B)$ 已被条件固定为某个常向量 $c\in\R^d$,于是内层是 $c$ 的严格凸二次函数 $\phi(c)=\E[\norm{c-g(A,C)}^2\mid A,B]$,其梯度 $\nabla\phi(c)=2\big(c-\E[g(A,C)\mid A,B]\big)$ 在 $c=\E[g(A,C)\mid A,B]$ 处唯一取零。因为可以对每个 $(A,B)$ 取值独立地取到这个极小,整体极小元就是逐点极小元。$\square$
定理(guided CFM 的最优解)。 记 $\theta^\ast$ 为 $\mathcal{L}_{\text{CFM}}^{\text{guided}}$ 在所有可测函数上的极小元,则对 $\data(y)>0$ 的每个 $y$ 与 $p_t(x\mid y)>0$ 的每个 $x$,
$$ u_t^{\theta^\ast}(x\mid y)=u_t^{\text{target}}(x\mid y). $$证明。 取 $A=(X_t,t)$、$B=Y$、$C=Z$、$g(A,C)=u_t^{\text{target}}(X_t\mid Z)$,由引理
$$ \begin{aligned} u_t^{\theta^\ast}(x\mid y) &= \E\!\left[u_t^{\text{target}}(X_t\mid Z)\,\middle|\,X_t=x,\ Y=y,\ t\right] &&\text{(i) 引理}\\ &= \int u_t^{\text{target}}(x\mid z)\,p_t(z\mid x,y)\ud z &&\text{(ii) 条件期望写成积分}\\ &= \int u_t^{\text{target}}(x\mid z)\,\frac{p_t(x\mid z,y)\,\data(z\mid y)}{p_t(x\mid y)}\ud z &&\text{(iii) 贝叶斯公式(对 }z\text{)}\\ &= \int u_t^{\text{target}}(x\mid z)\,\frac{p_t(x\mid z)\,\data(z\mid y)}{p_t(x\mid y)}\ud z &&\text{(iv) 条件独立性 }(\star)\\ &= u_t^{\text{target}}(x\mid y). &&\text{(v) 边际化技巧的定义} \end{aligned} $$其中 (iii) 是在固定 $y$ 的条件世界里对 $z$ 用贝叶斯;(iv) 是全篇最关键的一步:$p_t(x\mid z,y)=p_t(x\mid z)$,因为加噪过程只看 $z$;(v) 就是 Lecture 2 里边际向量场的定义式,只不过数据分布换成了 $\data(\cdot\mid y)$。$\square$
这个定理说明:把不同 $y$ 混在一个 batch 里训练,和分别训练一堆独立模型,在最优解层面是等价的。网络内部的 $y$-嵌入相当于给每个 prompt 分配了一个「槽位」,梯度只会把该槽位往它自己的目标上推。这一点在第 7 节讨论空标签 $\varnothing$ 时会再用一次,那里才是真正巧妙的地方。
Vanilla guidance 差在哪里
理论上到这里就该收工了:我们有一个正确的目标、一个正确的最优解、一个正确的采样器。然而人们很快发现,这样训出来的模型「不够听话」。
讲义给出了三个层次的原因,值得逐条拆开看:
- 模型欠拟合。 我们训出来的其实是 $u_t^\theta$,而不是真正的 $u_t^{\text{target}}(\cdot\mid y)$。上面的定理只在「所有可测函数」这个理想类上成立;真实网络容量有限、训练步数有限、$\mathcal{Y}$ 又极大,网络会倾向于把 $y$ 当成一个弱信号忽略掉——毕竟即使完全无视 $y$,损失也只会小幅上升。梯度下降对这种「性价比低」的信号天然不敏感。
- 数据本身不干净。 大规模图文对是从网页上爬的,alt-text 与图像内容的对应关系充满噪声。这意味着我们估计出的 $\data(\cdot\mid y)$ 本身就被「污染」得比真实的条件分布更宽、更接近无条件分布。
- 更根本的一点:即使模型完美,用户想要的也不是 $\data(\cdot\mid y)$。 网络上「柯基犬」的照片里,绝大多数是随手拍的、构图糟糕的、狗只占画面一角的。从 $\data(\cdot\mid\text{柯基})$ 里公平采样,得到的自然也是这样一张平庸照片。用户真正想要的是这个分布的高密度区域——那些最「典型」「最像柯基」的样本。这不是估计误差,而是目标本身就该改。
「CFG 是为了修正模型的训练误差」——这个说法只对了一部分。上面第 3 条说明,即使给你一个完美的 $\data(\cdot\mid y)$ 采样器,人们依然会想开 guidance,因为「从条件分布公平采样」和「生成一张好看的、贴合 prompt 的图」是两个不同的目标。理解这一点,才能理解为什么讲义反复强调 CFG 是启发式(heuristic)而不是某个更精确估计的近似——它是故意去采样一个和数据分布不同的分布。
3. 贝叶斯分解:条件 score 拆成两半
既然问题出在「$y$ 的信号太弱」,一个自然的想法是:把携带 $y$ 信息的那部分单独揪出来,然后人为放大它。要做到这一点,先得知道向量场里哪一部分才是「$y$ 的贡献」。
这就是本节的任务。为了具体,我们和讲义一样限定在高斯概率路径上:
$$ p_t(\cdot\mid z)=\N(\alpha_t z,\ \beta_t^2 I_d), $$其中噪声调度 $\alpha_t,\beta_t$ 连续可微、单调,且 $\alpha_0=\beta_1=0$、$\alpha_1=\beta_0=1$。
第 1 步:把引导向量场写成引导 score
Lecture 3-A 的 Proposition 1(高斯路径的转换公式)告诉我们,对高斯概率路径,边际向量场和边际 score 之间是一个只依赖调度的仿射关系:
$$ u_t^{\text{target}}(x)=a_t\,\score{t}(x)+b_t\,x,\qquad a_t=\beta_t^2\frac{\dot\alpha_t}{\alpha_t}-\dot\beta_t\beta_t,\quad b_t=\frac{\dot\alpha_t}{\alpha_t}. $$我们现在要用的是它的引导版本:
$$ u_t^{\text{target}}(x\mid y)=a_t\,\score{t}(x\mid y)+b_t\,x. \tag{3.1} $$为什么 (3.1) 成立,而且 $a_t,b_t$ 和无引导版本完全一样?
这一步讲义只写了「recall that we can use Proposition 1」,但值得停一下。Proposition 1 的证明分两段:
第一段是对条件量的恒等式:把 $\score{t}(x\mid z)=-\frac{x-\alpha_t z}{\beta_t^2}$ 和 $u_t^{\text{target}}(x\mid z)=\dot\alpha_t z+\frac{\dot\beta_t}{\beta_t}(x-\alpha_t z)$ 代进去做代数,验证 $u_t^{\text{target}}(x\mid z)=a_t\score{t}(x\mid z)+b_t x$。这一段完全不涉及数据分布,只涉及调度 $\alpha_t,\beta_t$。
第二段是把第一段对后验 $p_t(z\mid x)$ 求平均,用边际化技巧升级到边际量。现在我们把这一段在固定 $y$ 的世界里重做一遍:
$$ \begin{aligned} u_t^{\text{target}}(x\mid y) &= \int u_t^{\text{target}}(x\mid z)\,\frac{p_t(x\mid z)\data(z\mid y)}{p_t(x\mid y)}\ud z &&\text{(i) 边际化技巧(数据分布取 }\data(\cdot\mid y)\text{)}\\ &= \int \big[a_t\score{t}(x\mid z)+b_t x\big]\frac{p_t(x\mid z)\data(z\mid y)}{p_t(x\mid y)}\ud z &&\text{(ii) 代入第一段的条件恒等式}\\ &= a_t\int \score{t}(x\mid z)\frac{p_t(x\mid z)\data(z\mid y)}{p_t(x\mid y)}\ud z + b_t x &&\text{(iii) 线性拆分,后验对 }z\text{ 积分为 }1\\ &= a_t\,\score{t}(x\mid y)+b_t x. &&\text{(iv) score 的边际化恒等式} \end{aligned} $$(iv) 用的是 Lecture 3-A 里的 $\score{t}(x)=\int\score{t}(x\mid z)\frac{p_t(x\mid z)\data(z)}{p_t(x)}\ud z$,同样把 $\data$ 换成 $\data(\cdot\mid y)$。
关键观察:$a_t$ 和 $b_t$ 只由 $\alpha_t,\beta_t$ 决定,与数据分布无关,所以引导版本和无引导版本共用同一组系数。这个「共用系数」是第 5 节 CFG 推导能成立的技术前提——正因为两边的仿射部分 $b_t x$ 完全相同,做差时它才会干净地消掉。
第 2 步:对引导 score 用贝叶斯
现在把注意力放到 $\score{t}(x\mid y)$ 上。$p_t(x\mid y)$ 是一个条件密度,我们可以用贝叶斯公式把「条件在 $y$ 上」翻转成「条件在 $x$ 上」:
$$ p_t(x\mid y)=\frac{p_t(x)\,p_t(y\mid x)}{p_t(y)}. \tag{3.2} $$从 (3.2) 到得分分解,一步不跳。
$$ \begin{aligned} \score{t}(x\mid y) &= \nabla_x\log p_t(x\mid y) &&\text{(i) 记号展开}\\ &= \nabla_x\log\!\left(\frac{p_t(x)\,p_t(y\mid x)}{p_t(y)}\right) &&\text{(ii) 代入贝叶斯 (3.2)}\\ &= \nabla_x\Big[\log p_t(x)+\log p_t(y\mid x)-\log p_t(y)\Big] &&\text{(iii) }\log\text{ 把乘除变加减}\\ &= \nabla_x\log p_t(x)+\nabla_x\log p_t(y\mid x)-\underbrace{\nabla_x\log p_t(y)}_{=\,0} &&\text{(iv) 梯度的线性性}\\ &= \score{t}(x)+\nabla_x\log p_t(y\mid x). &&\text{(v) 第 1 节已证 }p_t(y)=\data(y) \end{aligned} $$其中 (v) 是唯一需要动脑子的一步:$\nabla$ 是对 $x$ 求的,而 $p_t(y)$ 根本不含 $x$(第 1 节我们算出 $p_t(y)=\data(y)$),所以这一项直接消失。注意这里不需要贝叶斯公式里的归一化常数「碰巧」是常数——它是严格与 $x$ 无关的。
于是我们得到本讲的核心恒等式:
$$ \boxed{\ \score{t}(x\mid y)=\score{t}(x)+\nabla_x\log p_t(y\mid x)\ } \tag{3.3} $$第 3 步:翻译回向量场
把 (3.3) 代进 (3.1):
$$ \begin{aligned} u_t^{\text{target}}(x\mid y) &= b_t x + a_t\,\score{t}(x\mid y) &&\text{(i) 转换公式 (3.1)}\\ &= b_t x + a_t\big(\score{t}(x)+\nabla\log p_t(y\mid x)\big) &&\text{(ii) 代入 (3.3)}\\ &= \underbrace{\big[b_t x + a_t\score{t}(x)\big]}_{=\,u_t^{\text{target}}(x)} + a_t\nabla\log p_t(y\mid x) &&\text{(iii) 重新分组}\\ &= u_t^{\text{target}}(x)+a_t\nabla_x\log p_t(y\mid x). &&\text{(iv) 再用一次转换公式} \end{aligned} $$结论写成一行:
$$ \boxed{\ u_t^{\text{target}}(x\mid y)=u_t^{\text{target}}(x)+a_t\,\nabla_x\log p_t(y\mid x)\ } \tag{3.4} $$
(3.4) 是一个非常干净的分解,值得逐项读:
- $u_t^{\text{target}}(x)$:「往数据流形上走」。它只管把噪声变成一张合法的图,完全不管画的是什么。
- $a_t\nabla_x\log p_t(y\mid x)$:「往更像 $y$ 的方向走」。$\nabla_x\log p_t(y\mid x)$ 是「使分类器更确信这是 $y$」的最速上升方向——和对抗样本里那个梯度是同一个东西,只不过这里我们沿着它走而不是防着它。
第一项是与 prompt 无关的,第二项是唯一与 prompt 有关的。既然模型「不够听话」,那么要动的显然只有第二项。这就是下一节的全部内容。
4. Classifier Guidance:把 prompt 分量放大 $w$ 倍
公式与命名
沿着上一节结尾的思路,做一件最粗暴的事:给第二项乘一个大于 $1$ 的系数。
$$ \boxed{\ \tilde u_t(x\mid y)=u_t^{\text{target}}(x)+w\,a_t\,\nabla_x\log p_t(y\mid x)\ }\qquad\text{(classifier guidance)} \tag{4.1} $$这里 $w$ 称为引导强度(guidance scale)。当 $w=1$ 时,(4.1) 退化回 (3.4),即真正的引导向量场;当 $w>1$ 时,我们在刻意夸大 prompt 的影响。
剩下的问题是:$\log p_t(y\mid x)$ 怎么拿到?注意到它就是一个作用在带噪数据上的分类器的对数似然——给定 $t$ 时刻的带噪样本 $x$,输出标签 $y$ 的概率。这可以用普通的监督学习训出来:拿标注数据 $(z,y)$,加噪得到 $x\sim p_t(\cdot\mid z)$,用交叉熵训一个接受 $(x,t)$ 输出类别分布的分类器 $q^\phi(y\mid x,t)$,然后用自动微分对输入 $x$ 求梯度即可。这条路线就叫 classifier guidance。
它在采样什么分布
先回答一个更重要的问题:(4.1) 究竟对应什么?这里有一个漂亮的答案。
命题(引导得分 = 锐化分布的得分)。 固定 $t$ 与 $y$,定义
$$ \tilde p_t(x\mid y):=\frac{1}{Z_t(y)}\,p_t(x)\,p_t(y\mid x)^{w},\qquad Z_t(y):=\int p_t(x')\,p_t(y\mid x')^{w}\ud x', $$并假设 $Z_t(y)<\infty$。则
$$ \nabla_x\log\tilde p_t(x\mid y)=\score{t}(x)+w\,\nabla_x\log p_t(y\mid x). $$证明。 取对数:
$$ \log\tilde p_t(x\mid y)=\log p_t(x)+w\log p_t(y\mid x)-\log Z_t(y). $$$Z_t(y)$ 是对 $x'$ 积掉之后的量,不含 $x$,故求 $\nabla_x$ 时消失,剩下前两项。$\square$
推论(另一种写法)。 用 (3.2) 把 $p_t(y\mid x)=\dfrac{p_t(x\mid y)p_t(y)}{p_t(x)}$ 代入:
$$ \begin{aligned} p_t(x)\,p_t(y\mid x)^{w} &= p_t(x)\left(\frac{p_t(x\mid y)\,p_t(y)}{p_t(x)}\right)^{w} &&\text{(i) 贝叶斯}\\ &= p_t(y)^{w}\cdot p_t(x)^{1-w}\,p_t(x\mid y)^{w} &&\text{(ii) 整理幂次}\\ &\propto\ p_t(x)^{1-w}\,p_t(x\mid y)^{w}, &&\text{(iii) }p_t(y)^w\text{ 与 }x\text{ 无关} \end{aligned} $$于是
$$ \boxed{\ \tilde p_t(x\mid y)\ \propto\ p_t(x)\,p_t(y\mid x)^{w}\ \propto\ p_t(x)^{1-w}\,p_t(x\mid y)^{w}\ } \tag{4.2} $$换句话说,$\tilde p_t(\cdot\mid y)$ 是无引导分布 $p_t$ 与引导分布 $p_t(\cdot\mid y)$ 的几何加权平均,权重为 $(1-w,\,w)$。当 $w>1$ 时权重之一为负,这是一个外插(extrapolation)而非插值。
把这个命题和转换公式 (3.1) 拼起来,(4.1) 可以重写成
$$ \tilde u_t(x\mid y)=a_t\,\nabla_x\log\tilde p_t(x\mid y)+b_t\,x, $$也就是说:classifier guidance 相当于把锐化分布 $\tilde p_t$ 的 score 塞进了高斯路径的转换公式。这就是「guidance 在采样一个被重新加权的分布」这句话的精确含义。
这句话必须加一个重要的限定。上面的命题是逐时刻成立的:对每个固定的 $t$,$\tilde u_t$ 确实由 $\tilde p_t$ 的 score 构造而来。但这不意味着模拟 ODE $\dd{X_t}=\tilde u_t(X_t\mid y)\dd{t}$ 会让 $X_t\sim\tilde p_t$。
原因是:转换公式 $u=a_t s+b_t x$ 之所以给出「生成 $p_t$ 的向量场」,靠的是 $p_t$ 本身是由高斯条件路径 $\N(\alpha_t z,\beta_t^2 I_d)$ 对某个固定数据分布边际化得到的。而 $\{\tilde p_t\}_{t\in[0,1]}$ 一般不是任何单一数据分布的高斯路径——它是逐 $t$ 定义的一族分布,彼此之间未必满足连续性方程 $\partial_t\tilde p_t=-\divg(\tilde p_t\tilde u_t)$。
所以正确的说法是:「$w>1$ 时我们在朝着锐化分布的方向走」是理解 guidance 的正确心智模型,但它不是一个可以证明的采样保证。 讲义直白地说:对 $w\neq 1$,$\tilde u_t(x\mid y)\neq u_t^{\text{target}}(x\mid y)$,因此它不是「真正的」引导向量场,CFG/classifier guidance 是启发式。第 6 节会给一个高斯算例,在那个特例里等式恰好精确成立。
为什么要绕开 classifier guidance
Classifier guidance 在原理上可行,也确实是历史上第一个被大规模使用的方案,但它有两个硬伤:
- 要训两个网络。 除了 flow/diffusion 模型本身,还要额外训一个能在所有噪声水平 $t\in[0,1]$ 上工作的分类器。这个分类器不能拿现成的预训练分类器来用(它们只见过干净图),必须专门在带噪数据上训。工程复杂度直接翻倍。
- 高维 $y$ 上会崩。 当 $y$ 不是 1000 类标签而是一段任意文本时,$p_t(y\mid x)$ 是一个在所有字符串上的分布——这个量既难建模,它对 $x$ 的梯度 $\nabla_x\log p_t(y\mid x)$ 更难可靠地估计。文生图恰恰是最重要的应用场景。
此外还有一个实践上的烦恼:每一步采样都要对分类器做一次反向传播来拿输入梯度,这比一次前向要贵。
下一节的 classifier-free guidance 用一个非常简单的代数把这两个问题一并解决。
5. Classifier-Free Guidance:把分类器反解掉
Classifier guidance 的麻烦全部来自那个 $\nabla_x\log p_t(y\mid x)$。CFG 的想法极简单:恒等式 (3.3) 既然能把 $\score{t}(x\mid y)$ 拆成两项,那也能把 $\nabla\log p_t(y\mid x)$ 用另外两项表示出来。移项即可:
$$ \nabla_x\log p_t(y\mid x)=\score{t}(x\mid y)-\score{t}(x). \tag{5.1} $$右边全是我们已经会算的东西——引导 score 和无引导 score,都可以由训练好的向量场网络经转换公式得到。把它代回 (4.1) 就能把分类器彻底消掉。
完整推导
定理(Classifier-Free Guidance 公式)。 对高斯概率路径,classifier guidance 的向量场 (4.1) 恒等于
$$ \tilde u_t(x\mid y)=(1-w)\,u_t^{\text{target}}(x)+w\,u_t^{\text{target}}(x\mid y). $$证明。 逐行展开:
$$ \begin{aligned} \tilde u_t(x\mid y) &= u_t^{\text{target}}(x)+w\,a_t\nabla\log p_t(y\mid x) &&\text{(i) classifier guidance 定义 (4.1)}\\[3pt] &= u_t^{\text{target}}(x)+w\,a_t\big(\score{t}(x\mid y)-\score{t}(x)\big) &&\text{(ii) 代入 (5.1)}\\[3pt] &= u_t^{\text{target}}(x)-\big(w\,b_t x+w\,a_t\score{t}(x)\big)+\big(w\,b_t x+w\,a_t\score{t}(x\mid y)\big) &&\text{(iii) 同时加减 }w\,b_t x\\[3pt] &= u_t^{\text{target}}(x)-w\,u_t^{\text{target}}(x)+w\,u_t^{\text{target}}(x\mid y) &&\text{(iv) 两次转换公式}\\[3pt] &= (1-w)\,u_t^{\text{target}}(x)+w\,u_t^{\text{target}}(x\mid y). &&\square \end{aligned} $$四步里只有 (iii) 需要解释,它是整个推导的关键技巧。第 (ii) 行的括号里是两个 score 之差,我们希望把它们各自补成一个完整的向量场。转换公式说 $u=a_t s+b_t x$,所以要把 $a_t s$ 变成 $u$,需要补上 $b_t x$。于是我们凭空加一个 $w\,b_t x$ 又减一个 $w\,b_t x$:
- 减去的那个 $-w\,b_t x$ 和 $-w\,a_t\score{t}(x)$ 凑成 $-w\big(b_t x+a_t\score{t}(x)\big)=-w\,u_t^{\text{target}}(x)$;
- 加上的那个 $+w\,b_t x$ 和 $+w\,a_t\score{t}(x\mid y)$ 凑成 $+w\big(b_t x+a_t\score{t}(x\mid y)\big)=+w\,u_t^{\text{target}}(x\mid y)$。
这一步能成功,靠的正是第 3 节强调过的事实:引导版和无引导版的转换公式共用同一组系数 $a_t,b_t$。若两边的 $b_t$ 不同,$b_t x$ 就消不掉,推导会卡死。
写成最终形式(讲义 Summary 27,把无引导向量场记作 $u_t^{\text{target}}(x\mid\varnothing)$,理由见下):
$$ \boxed{\ \tilde u_t(x\mid y)=(1-w)\,u_t^{\text{target}}(x\mid\varnothing)+w\,u_t^{\text{target}}(x\mid y)\ } \tag{5.2} $$等价的 score 版本(把 (3.3) 代入 $\score{t}(x)+w\nabla\log p_t(y\mid x)$,或者直接对 (5.2) 用一次转换公式):
$$ \boxed{\ \tilde s_t(x\mid y)=(1-w)\,\score{t}(x\mid\varnothing)+w\,\score{t}(x\mid y)\ } \tag{5.3} $$(5.2) 与 (5.3) 互相等价。 这一步一行就能验,但它揭示了一个重要的结构性事实。把 (5.3) 代入转换公式:
$$ \begin{aligned} a_t\,\tilde s_t(x\mid y)+b_t x &= a_t\big[(1-w)\score{t}(x\mid\varnothing)+w\score{t}(x\mid y)\big]+b_t x\\ &= (1-w)\,a_t\score{t}(x\mid\varnothing)+w\,a_t\score{t}(x\mid y)+\underbrace{\big[(1-w)+w\big]}_{=\,1}b_t x\\ &= (1-w)\big[a_t\score{t}(x\mid\varnothing)+b_t x\big]+w\big[a_t\score{t}(x\mid y)+b_t x\big]\\ &= (1-w)\,u_t^{\text{target}}(x\mid\varnothing)+w\,u_t^{\text{target}}(x\mid y)=\tilde u_t(x\mid y).\qquad\square \end{aligned} $$关键在第二行那个下花括号:CFG 的两个权重之和恒为 $1$。 正因为 $(1-w)+w=1$,仿射项 $b_t x$ 才能原封不动地保留下来。
CFG 在四种参数化下形式完全一样。 上面那个「权重和为 $1$」的观察有一个非常实用的推论。Lecture 3-A 里我们见过四种彼此等价的网络输出:向量场 $u_t$、得分 $s_t=\score{t}$、噪声预测 $\epsilon_t=-\beta_t s_t$、去噪器 $D_t=\frac{1}{\dot\alpha_t\beta_t-\alpha_t\dot\beta_t}(\beta_t u_t-\dot\beta_t x)$。它们两两之间都是形如 $A\mapsto c_1(t)A+c_2(t)x$ 的关于 $x$ 的仿射映射,且系数与 $y$ 无关。设 $F$ 是任一这样的映射,则
$$ F\big((1-w)A_\varnothing+wA_y\big)=c_1\big[(1-w)A_\varnothing+wA_y\big]+c_2x =(1-w)\big[c_1A_\varnothing+c_2x\big]+w\big[c_1A_y+c_2x\big]=(1-w)F(A_\varnothing)+wF(A_y). $$也就是说,「先做 CFG 再换参数化」和「先换参数化再做 CFG」结果相同。因此实践中可以放心地写
$$ \tilde\epsilon_t(x\mid y)=(1-w)\,\epsilon_t^\theta(x\mid\varnothing)+w\,\epsilon_t^\theta(x\mid y),\qquad \tilde D_t(x\mid y)=(1-w)\,D_t^\theta(x\mid\varnothing)+w\,D_t^\theta(x\mid y), $$它们和在向量场层面做 CFG 完全等价。这就是为什么 DDPM 系代码库在 $\epsilon$ 上做 CFG、flow matching 系代码库在 $u$ 上做 CFG,两者却是同一个算法。
几何图像
(5.2) 还可以整理成一个「基准 + 修正」的形式,这是理解它最好的写法:
$$ \tilde u_t(x\mid y)=u_t^{\text{target}}(x\mid\varnothing)+w\Big(u_t^{\text{target}}(x\mid y)-u_t^{\text{target}}(x\mid\varnothing)\Big). \tag{5.4} $$
(5.4) 说:先按「随便生成点什么」的方向走一步作为基准,然后测量「知道 prompt 之后方向变了多少」,把这个变化量放大 $w$ 倍再叠加回去。$w=1$ 就是老实按条件向量场走;$w=4$ 就是把「因为 prompt 而产生的偏移」夸大四倍。
一个恰当的类比是差分放大器:无引导模型是共模信号(图像的一般结构),条件与无条件之差是差模信号(专属于该 prompt 的特征)。CFG 就是在提高差模增益。图像里那些「所有图都有」的成分(合理的纹理、光照、物体的一般形态)来自共模项,被完整保留;而「只有柯基才有」的成分被放大四倍。这也顺带解释了为什么 $w$ 太大会出问题——差模增益开太高,噪声和伪影一起被放大了。
空标签 $\varnothing$:一个网络干两件事
(5.2) 需要两个向量场:无引导的 $u_t^{\text{target}}(x)$ 和引导的 $u_t^{\text{target}}(x\mid y)$。第一反应是要训两个模型——一个用无引导 CFM 目标,一个用 guided CFM 目标——那我们不过是把「模型 + 分类器」换成了「模型 + 模型」,没省下什么。
CFG 的第二个关键想法解决了这件事:把标签集合扩充一个新元素 $\varnothing$,表示「没有条件」。即令 $\mathcal{Y}^{+}:=\mathcal{Y}\cup\{\varnothing\}$,并约定
$$ u_t^{\text{target}}(x\mid\varnothing):=u_t^{\text{target}}(x). $$于是无引导向量场只是引导向量场在某个特殊输入上的取值,一个网络 $u^\theta:\R^d\times\mathcal{Y}^{+}\times[0,1]\to\R^d$ 就够了。实现上,如果 $y$ 是类别标签,就把 embedding 表从 $|\mathcal{Y}|$ 行扩到 $|\mathcal{Y}|+1$ 行,多出来那一行就是 $\varnothing$;如果 $y$ 是文本嵌入,就用空字符串 "" 的嵌入,或者一个可学习的全零/常数向量。
剩下的唯一问题是:怎么让网络在 $\varnothing$ 这个槽位上学到正确的无引导向量场?这是第 7 节的内容。
上面整个推导是在高斯概率路径上做的——我们用了两次转换公式,而转换公式只对高斯路径成立。但最终结果
$$ \tilde u_t(x\mid y)=(1-w)\,u_t^{\text{target}}(x\mid\varnothing)+w\,u_t^{\text{target}}(x\mid y) $$本身对任何概率路径都是一个合法的定义,因为它只涉及两个向量场的线性组合,不需要任何高斯结构。讲义明确指出:用高斯路径推导只是为了展示这个构造背后的直觉——即「放大一个假想分类器 $\nabla\log p_t(y\mid x)$ 的贡献」。
另外,$w=1$ 时 (5.2) 立刻退化为 $\tilde u_t(x\mid y)=u_t^{\text{target}}(x\mid y)$,这对任何路径都严格成立且不需要任何近似——此时 CFG 就是 vanilla guidance。
6. 引导在采样什么:锐化与外插的几何
第 4 节我们已经知道 $\tilde p_t(\cdot\mid y)\propto p_t(x)^{1-w}p_t(x\mid y)^{w}$。这一节把这个抽象结论落到具体的高斯算例上,把「感知质量上升、多样性下降」这句定性描述变成可以手算的公式。
算例一:等协方差 —— guidance 就是均值外插
设在时刻 $t$,无引导边际与引导边际都是高斯,且协方差相同:
$$ p_t(\cdot)=\N(\mu_t^{\varnothing},\ \gamma_t^2 I_d),\qquad p_t(\cdot\mid y)=\N(\mu_t^{y},\ \gamma_t^2 I_d). $$代入 (4.2):
$$ \begin{aligned} \log\tilde p_t(x\mid y) &= (1-w)\log p_t(x)+w\log p_t(x\mid y)+C_1\\ &= -\frac{1-w}{2\gamma_t^2}\norm{x-\mu_t^{\varnothing}}^2-\frac{w}{2\gamma_t^2}\norm{x-\mu_t^{y}}^2+C_2 &&\text{(i) 代入高斯密度}\\ &= -\frac{1}{2\gamma_t^2}\Big[\norm{x}^2-2\inner{x}{(1-w)\mu_t^{\varnothing}+w\mu_t^{y}}\Big]+C_3 &&\text{(ii) 展开平方,}\norm{x}^2\text{ 系数为 }(1-w)+w=1\\ &= -\frac{1}{2\gamma_t^2}\norm{x-\big[(1-w)\mu_t^{\varnothing}+w\mu_t^{y}\big]}^2+C_4 &&\text{(iii) 配方} \end{aligned} $$其中 $C_1,\dots,C_4$ 都是与 $x$ 无关的常数((ii) 里把 $\norm{\mu}^2$ 类的项吸收进去了)。对照高斯密度的形式立刻读出
$$ \boxed{\ \tilde p_t(\cdot\mid y)=\N\Big(\underbrace{\mu_t^{\varnothing}+w\big(\mu_t^{y}-\mu_t^{\varnothing}\big)}_{\text{均值被外插}},\ \underbrace{\gamma_t^2 I_d}_{\text{协方差不变}}\Big).\ } $$这个结果非常说明问题:在等协方差的情形下,CFG 对分布做的事情,就是把均值沿着「无条件 → 条件」的方向外推 $w$ 倍。注意 $\tilde\mu=(1-w)\mu^{\varnothing}+w\mu^{y}$ 与 CFG 的向量场公式 (5.2) 形式完全一致——这不是巧合,因为高斯的均值和它的向量场都是 $x$ 的仿射函数,而 CFG 是线性运算。
这个算例还提供了一个罕见的精确例子。设 $\data(\cdot\mid y)=\N(m_y,\sigma^2 I_d)$、$\data=\N(m_\varnothing,\sigma^2 I_d)$(同协方差),沿高斯路径 $p_t(\cdot\mid z)=\N(\alpha_t z,\beta_t^2 I_d)$ 加噪,则
$$ p_t(\cdot)=\N(\alpha_t m_\varnothing,\ \gamma_t^2 I_d),\quad p_t(\cdot\mid y)=\N(\alpha_t m_y,\ \gamma_t^2 I_d),\quad \gamma_t^2:=\alpha_t^2\sigma^2+\beta_t^2 . $$两者协方差确实相同,于是 $\tilde p_t=\N\big(\alpha_t[(1-w)m_\varnothing+wm_y],\ \gamma_t^2 I_d\big)$——而这恰好就是数据分布取 $\N\big((1-w)m_\varnothing+wm_y,\ \sigma^2 I_d\big)$ 时的高斯路径!所以在这个特例里,$\{\tilde p_t\}$ 真的是一条合法的高斯边际路径,$\tilde u_t$ 真的是它的边际向量场,CFG 采样精确地给出 $X_1\sim\N\big((1-w)m_\varnothing+wm_y,\sigma^2 I_d\big)$。第 4 节的警告在这里不生效。可惜真实数据分布不是单个高斯,所以这只是一个提供直觉的特例。
算例二:不等方差 —— 多样性是怎么丢的
换成一维、方差不同的情形。设 $p_t(\cdot)=\N(0,\gamma^2)$、$p_t(\cdot\mid y)=\N(m,\tau^2)$,并且 $\tau<\gamma$(条件分布比无条件分布窄——这是合理的:知道「这是柯基」之后不确定性应该减小)。同样取对数配方:
$$ \log\tilde p_t(x\mid y)=-\frac{1}{2}\underbrace{\left[\frac{1-w}{\gamma^2}+\frac{w}{\tau^2}\right]}_{=:\ \tilde\lambda\ \text{(精度)}}x^2+\frac{wm}{\tau^2}x+C . $$这仍是 $x$ 的二次式,故 $\tilde p_t(\cdot\mid y)=\N(\tilde\mu,\tilde\sigma^2)$,其中
$$ \tilde\sigma^2=\frac{1}{\tilde\lambda},\qquad \tilde\mu=\frac{wm/\tau^2}{\tilde\lambda}. $$把精度改写一下,结构就清楚了:
$$ \tilde\lambda=\frac{1-w}{\gamma^2}+\frac{w}{\tau^2} =\frac{1}{\tau^2}+(w-1)\left(\frac{1}{\tau^2}-\frac{1}{\gamma^2}\right). $$结论 1(方差收缩)。 当 $w>1$ 且 $\tau<\gamma$ 时,括号里是正数,于是 $\tilde\lambda>1/\tau^2$,即 $\tilde\sigma^2<\tau^2$。引导后的分布比真正的条件分布还要窄——这就是多样性下降的精确机制。
结论 2(均值过冲)。 令 $w\to\infty$,$\tilde\lambda\approx w\big(\tfrac{1}{\tau^2}-\tfrac{1}{\gamma^2}\big)$,于是
$$ \tilde\mu\ \longrightarrow\ \frac{m/\tau^2}{\tfrac{1}{\tau^2}-\tfrac{1}{\gamma^2}}=\frac{m\,\gamma^2}{\gamma^2-\tau^2}\ >\ m,\qquad \tilde\sigma^2\longrightarrow 0 . $$也就是说,$w$ 越大,质量越集中到一个比真实条件均值更极端的点上,同时方差趋于零。这正是大 $w$ 下「过饱和、对比度爆炸、所有样本长得一样」的数学根源。
三种极限情形
用分类器形式 $\tilde p_t\propto p_t(x)p_t(y\mid x)^{w}$ 看极限,图像更直观:
- $w=0$:$\tilde p_t\propto p_t(x)$,分类器项被完全抹掉,退化为无引导采样。
- $w=1$:$\tilde p_t\propto p_t(x)p_t(y\mid x)\propto p_t(x\mid y)$,正是真正的条件分布。这是唯一有理论保证的取值。
- $w\to\infty$:$p_t(y\mid x)^{w}$ 变成一个越来越尖的指示函数,质量集中到 $\argmax_x p_t(y\mid x)$ 附近——即「分类器最确信是 $y$ 的那个点」。这是彻底的模式寻找(mode seeking)。注意这个点未必是「最像真实柯基的图」,而是「最能骗过噪声分类器的图」;两者的偏离就是伪影的来源。
「$\tilde p_t$ 总是一个良定义的概率分布」——不一定。 归一化常数 $Z_t(y)=\int p_t(x)p_t(y\mid x)^{w}\ud x$ 必须有限,$\tilde p_t$ 才有意义。在算例二里,若反过来有 $\tau>\gamma$(条件分布比无条件分布更宽),则 $\tfrac{1}{\tau^2}-\tfrac{1}{\gamma^2}<0$,当
$$ w\ \ge\ \frac{\tau^2}{\tau^2-\gamma^2} $$时 $\tilde\lambda\le 0$,$\tilde p_t$ 根本不可归一化。这提醒我们:$w>1$ 的外插本质上是在做负权重的几何外推,没有任何东西保证结果仍是概率分布。这是 CFG 只能算启发式的又一个理由,也是为什么实践中 $w$ 不能无限调大。
7. 训练:空标签与 label dropout
回到第 5 节留下的问题:我们约定了 $u_t^{\text{target}}(x\mid\varnothing):=u_t^{\text{target}}(x)$,但网络凭什么会在 $\varnothing$ 这个输入上学出无引导向量场?
困难在于:从数据集里采样 $(z,y)\sim\data(z,y)$ 时,我们永远采不到 $y=\varnothing$——真实数据里每张图都是有标签的。$\varnothing$ 这个槽位在训练中根本不会被触发,它的参数会保持随机初始化的状态。
解决办法出奇地简单:人为地制造 $y=\varnothing$ 的样本。引入一个超参数 $\eta\in[0,1]$,每次取到一对 $(z,y)$ 之后,以概率 $\eta$ 把标签丢掉、换成 $\varnothing$。这就是 label dropout。于是得到 CFG conditional flow matching 目标:
$$ \mathcal{L}^{\text{CFG}}_{\text{CFM}}(\theta)=\E_{\square}\norm{u_t^{\theta}(x\mid y)-u_t^{\text{target}}(x\mid z)}^2 $$ $$ \square=\Big\{(z,y)\sim\data(z,y),\ t\sim\mathrm{Unif}[0,1],\ x\sim p_t(\cdot\mid z),\ \text{以概率 }\eta\text{ 把 }y\text{ 替换为}\varnothing\Big\} $$它和第 2 节的 guided CFM 目标唯一的差别就是最后那句「以概率 $\eta$ 替换」。但这一句话就让同一个网络同时学会了条件模型和无条件模型。下面把这件事严格证出来——这正是讲义一笔带过、而我们必须补上的地方。
定理(label dropout 的最优解)。 设 $\varnothing\notin\mathcal{Y}$,令 $B\sim\mathrm{Bernoulli}(\eta)$ 与 $(Z,Y)$ 独立,定义被污染的标签
$$ \tilde Y:=\begin{cases}\varnothing, & B=1\\ Y, & B=0\end{cases} $$并记 $\tilde p(z,\tilde y)$ 为 $(Z,\tilde Y)$ 的联合分布。则 $\mathcal{L}^{\text{CFG}}_{\text{CFM}}$ 在所有可测函数上的极小元 $\theta^\ast$ 满足
$$ u_t^{\theta^\ast}(x\mid\varnothing)=u_t^{\text{target}}(x) \qquad\text{且}\qquad u_t^{\theta^\ast}(x\mid y_0)=u_t^{\text{target}}(x\mid y_0)\ \ \forall\,y_0\in\mathcal{Y}. $$证明。 第 2 节的定理已经证明:对任意「数据–标签」联合分布,二次损失的极小元是 $u_t^{\theta^\ast}(x\mid\tilde y)=u_t^{\text{target},\,\tilde p}(x\mid\tilde y)$,即以 $\tilde p(z\mid \tilde y)$ 为数据分布的边际向量场。所以只需算出条件分布 $\tilde p(z\mid\tilde y)$。
情形 A:$\tilde y=\varnothing$。
$$ \begin{aligned} \tilde p(z,\tilde Y=\varnothing) &= \Pr[B=1]\cdot\Pr[Z=z\mid B=1] &&\text{(i) }\{\tilde Y=\varnothing\}=\{B=1\}\text{(因 }\varnothing\notin\mathcal{Y}\text{)}\\ &= \eta\,\data(z) &&\text{(ii) }B\perp Z \end{aligned} $$而 $\Pr[\tilde Y=\varnothing]=\eta$,故
$$ \tilde p(z\mid\tilde Y=\varnothing)=\frac{\eta\,\data(z)}{\eta}=\data(z). $$把 $\data$ 代入边际向量场的定义,得到的正是无引导边际向量场 $u_t^{\text{target}}(x)$。
情形 B:$\tilde y=y_0\in\mathcal{Y}$。 此时必有 $B=0$,于是
$$ \tilde p(z,\tilde Y=y_0)=(1-\eta)\,\data(z,y_0),\qquad \Pr[\tilde Y=y_0]=(1-\eta)\,\data(y_0), $$ $$ \Rightarrow\quad \tilde p(z\mid \tilde Y=y_0)=\frac{(1-\eta)\data(z,y_0)}{(1-\eta)\data(y_0)}=\data(z\mid y_0). $$因子 $(1-\eta)$ 在分子分母中约掉了,条件分布完全没被污染。代入即得 $u_t^{\text{target}}(x\mid y_0)$。$\square$
这个证明里最漂亮的一步是 (ii):因为丢标签这个动作与图像 $z$ 独立,所以「被丢掉标签的那些样本」的图像边际分布恰好是完整的 $\data(z)$,而不是某个有偏子集。如果你按某种规则丢标签(比如「只丢罕见类别」),这个论证就崩了,$\varnothing$ 槽位学到的会是一个有偏的分布。label dropout 必须是均匀随机的。
同样值得注意的是:$\eta$ 只影响两个任务各自拿到多少梯度预算,不影响最优解。$\eta$ 太小则无条件分支欠训($\tilde u$ 的基准不准),$\eta$ 太大则条件分支欠训(prompt 贴合度差)。它是一个纯粹的「训练资源分配」超参数。实践中通常取一个较小的值(10% 量级),因为条件分支才是主任务。
训练算法
把它写成明确的伪代码(高斯路径 $p_t(x\mid z)=\N(\alpha_t z,\beta_t^2 I_d)$):
Require: 配对数据集 (z, y) ~ p_data, 网络 u_t^theta, 丢弃概率 eta
1: for 每个 mini-batch do
2: 从数据集采一对 (z, y) # z in R^d, y in Y
3: 采时间 t ~ Unif[0, 1]
4: 采噪声 eps ~ N(0, I_d)
5: 构造带噪样本 x = alpha_t * z + beta_t * eps # x ~ p_t(.|z)
6: 以概率 eta 丢标签: y <- 空标签
7: 计算损失 L(theta) = || u_t^theta(x|y) - (alpha_dot_t * z + beta_dot_t * eps) ||^2
8: 对 L(theta) 做梯度下降更新 theta
9: end for
第 7 行的回归目标用的是高斯路径下条件向量场的闭式解。回忆 Lecture 2:$x=\alpha_t z+\beta_t\epsilon$ 是 $z$ 与 $\epsilon$ 的确定性组合,沿 $t$ 求导得
$$ u_t^{\text{target}}(x\mid z)=\dd{}\!\big/\!\dd{t}\big(\alpha_t z+\beta_t\epsilon\big)=\dot\alpha_t z+\dot\beta_t\epsilon . $$对最常用的 CondOT 调度 $\alpha_t=t,\ \beta_t=1-t$,这就是 $u_t^{\text{target}}(x\mid z)=z-\epsilon$——一个不含网络输出、完全由采样得到的量。
PyTorch:带 label dropout 的训练
import torch
import torch.nn as nn
import torch.nn.functional as F
DIM, NUM_CLASSES = 2, 3
NULL = NUM_CLASSES # 空标签占用第 NUM_CLASSES 号 embedding 槽位
DEV = "cuda" if torch.cuda.is_available() else "cpu"
# ---- 玩具数据:三个模态放在一个圆上,y = 模态编号 -----------------
CENTERS = torch.tensor([[ 2.0, 0.0],
[-1.0, 1.7],
[-1.0, -1.7]], device=DEV) # (3, 2)
STD = 0.25
def sample_data(bs):
y = torch.randint(0, NUM_CLASSES, (bs,), device=DEV) # (bs,)
z = CENTERS[y] + STD * torch.randn(bs, DIM, device=DEV) # (bs, 2)
return z, y
# ---- 网络:u_t^theta(x | y),y 通过 embedding 注入 ----------------
class GuidedVF(nn.Module):
def __init__(self, hidden=256):
super().__init__()
self.y_emb = nn.Embedding(NUM_CLASSES + 1, hidden) # +1 行留给空标签
self.inp = nn.Linear(DIM + 1, hidden) # 把 (x, t) 一起投上去
self.body = nn.Sequential(
nn.SiLU(), nn.Linear(hidden, hidden),
nn.SiLU(), nn.Linear(hidden, hidden),
nn.SiLU(), nn.Linear(hidden, DIM),
)
def forward(self, x, t, y):
# x: (bs, DIM) t: (bs, 1) y: (bs,) long
h = self.inp(torch.cat([x, t], dim=-1)) + self.y_emb(y) # (bs, hidden)
return self.body(h) # (bs, DIM)
# ---- 训练:guided CFM 目标 + label dropout ------------------------
def train(steps=6000, bs=1024, eta=0.1, lr=1e-3):
net = GuidedVF().to(DEV)
opt = torch.optim.Adam(net.parameters(), lr=lr)
for _ in range(steps):
z, y = sample_data(bs) # (bs,2), (bs,)
t = torch.rand(bs, 1, device=DEV) # (bs,1) t ~ U[0,1]
eps = torch.randn_like(z) # (bs,2) eps ~ N(0,I)
# CondOT 调度: alpha_t = t, beta_t = 1 - t
x = t * z + (1.0 - t) * eps # (bs,2) x ~ p_t(.|z)
target = z - eps # (bs,2) u_t^target(x|z)
# >>> 与无引导训练唯一的区别就是下面两行 <<<
drop = torch.rand(bs, device=DEV) < eta # (bs,) bool,独立于 z
y_in = torch.where(drop, torch.full_like(y, NULL), y) # (bs,)
loss = F.mse_loss(net(x, t, y_in), target)
opt.zero_grad(); loss.backward(); opt.step()
return net
请把这段代码和上面的推导逐项对照:x = t*z + (1-t)*eps 是 $x\sim p_t(\cdot\mid z)$;target = z - eps 是 $\dot\alpha_t z+\dot\beta_t\epsilon$;drop 用 torch.rand 独立生成,正是定理里 $B\perp Z$ 的那一条。
8. 采样:CFG 推理流程与 $w$ 的取值
算法
Require: 训练好的引导向量场 u_t^theta(x|y)
1: 选定 prompt y(取空标签则为无引导采样)
2: 选定引导强度 w > 1
3: 初始化 X_0 ~ p_init # 通常 N(0, I_d)
4: 模拟 ODE: dX_t = [ (1-w)*u_t^theta(X_t|空标签)
+ w *u_t^theta(X_t|y) ] dt 从 t=0 到 t=1
$w$ 取什么值
| $w$ | $\tilde u_t(x\mid y)$ | 对应的(逐时刻)目标分布 | 效果 |
|---|---|---|---|
| $w=0$ | $u_t^{\text{target}}(x\mid\varnothing)$ | $p_t(x)$,终点 $\data$ | 完全忽略 prompt,退化为无条件生成 |
| $0<w<1$ | $p_t$ 与 $p_t(\cdot\mid y)$ 的插值 | $\propto p_t^{1-w}p_t(\cdot\mid y)^{w}$,介于两者之间 | 条件信号被削弱;几乎没人用 |
| $w=1$ | $u_t^{\text{target}}(x\mid y)$ | $p_t(x\mid y)$,终点 $\data(\cdot\mid y)$ | vanilla guidance。唯一有理论保证的取值,但 prompt 贴合度不足 |
| $w>1$ | 外插:越过 $u^{\text{target}}(\cdot\mid y)$ | $\propto p_t^{1-w}p_t(\cdot\mid y)^{w}$,被锐化 | prompt 贴合度与感知质量↑,多样性↓。启发式 |
| $w\gg1$ | 强外插 | 趋于 $\argmax_x p_t(y\mid x)$ 的点质量 | 过饱和、对比度失真、伪影、模式塌缩 |
讲义对具体数值给出了两处可引用的说法:几乎所有你看到的 AI 生成图像 / 视频都重度依赖 CFG 且 $w\ge 4$;Stable Diffusion 3 在采样时使用 $50$ 步 Euler 与介于 $2.0$–$5.0$ 之间的引导权重。
扩散版本
Remark 28(Guidance for Diffusion Models)。 讲义指出,从 flow model 推广到 diffusion model 是直接的:把 $u_t^\theta(x\mid y)$ 换成 $\tilde u_t^\theta(x\mid y)$,然后按 Lecture 3-A 的方式用 SDE 采样即可。写全了就是
$$ X_0\sim\simple,\qquad \dd{X_t}=\left[\tilde u_t^{\theta}(X_t\mid y)+\frac{\sigma_t^2}{2}\,\tilde s_t^{\theta}(X_t\mid y)\right]\dd{t}+\sigma_t\dd{W_t}, $$其中两个引导量都用 CFG 组合:
$$ \tilde u_t^\theta(x\mid y)=(1-w)u_t^\theta(x\mid\varnothing)+w\,u_t^\theta(x\mid y),\qquad \tilde s_t^\theta(x\mid y)=(1-w)s_t^\theta(x\mid\varnothing)+w\,s_t^\theta(x\mid y). $$若只训了向量场网络,可以用转换公式反解出 score:由 $u=a_t s+b_t x$ 得
$$ \tilde s_t^\theta(x\mid y)=\frac{\tilde u_t^\theta(x\mid y)-b_t x}{a_t}. $$这个反解与 CFG 组合是可交换的(第 5 节的「四种参数化」结论),所以先组合再反解、或先反解再组合,结果一致。对 CondOT 调度 $\alpha_t=t,\beta_t=1-t$,可以把系数算到底:
$$ b_t=\frac{\dot\alpha_t}{\alpha_t}=\frac{1}{t},\qquad a_t=\beta_t^2\frac{\dot\alpha_t}{\alpha_t}-\dot\beta_t\beta_t=\frac{(1-t)^2}{t}+(1-t)=\frac{(1-t)\big[(1-t)+t\big]}{t}=\frac{1-t}{t}. $$验算:代回转换公式,用 $\score{t}(x\mid z)=-\frac{x-\alpha_t z}{\beta_t^2}=-\frac{x-tz}{(1-t)^2}$,
$$ a_t\score{t}(x\mid z)+b_t x=\frac{1-t}{t}\cdot\frac{-(x-tz)}{(1-t)^2}+\frac{x}{t} =\frac{-(x-tz)+x(1-t)}{t(1-t)}=\frac{t(z-x)}{t(1-t)}=\frac{z-x}{1-t}, $$而直接由定义 $u_t^{\text{target}}(x\mid z)=\dot\alpha_t z+\frac{\dot\beta_t}{\beta_t}(x-\alpha_t z)=z-\frac{x-tz}{1-t}=\frac{z-x}{1-t}$。两者一致。$\checkmark$
9. 可运行的最小实现
接着第 7 节的训练代码,补上采样部分。核心只有三行:拼 batch、算两个向量场、做线性组合。
ODE 采样(Euler)
@torch.no_grad()
def cfg_sample(net, y, w=4.0, n_steps=200):
"""y: (bs,) long,目标标签;返回 (bs, DIM) 的样本"""
bs = y.shape[0]
x = torch.randn(bs, DIM, device=DEV) # (bs,2) X_0 ~ p_init
y0 = torch.full_like(y, NULL) # (bs,) 全是空标签
dt = 1.0 / n_steps
for i in range(n_steps):
t = torch.full((bs, 1), i * dt, device=DEV) # (bs,1)
# 条件与无条件沿 batch 维拼起来,一次前向搞定两遍求值
xx = torch.cat([x, x ], dim=0) # (2bs,2)
tt = torch.cat([t, t ], dim=0) # (2bs,1)
yy = torch.cat([y, y0], dim=0) # (2bs,)
u_cond, u_null = net(xx, tt, yy).chunk(2, dim=0) # 各 (bs,2)
u = (1.0 - w) * u_null + w * u_cond # (bs,2) 式 (5.2)
x = x + u * dt # Euler 前进一步
return x
注意 torch.cat + chunk 这个写法:它把两次网络求值合并成一次前向,不会减少计算量(FLOPs 仍是两倍),但能显著提高 GPU 利用率,也让代码更短。这是所有主流实现的标准写法。
SDE 采样(把 score 一起引导)
import math
@torch.no_grad()
def cfg_sample_sde(net, y, w=4.0, sigma=0.3, n_steps=400):
"""CondOT 调度下的 SDE 采样;sigma 为扩散系数(可调)"""
bs = y.shape[0]
x = torch.randn(bs, DIM, device=DEV)
y0 = torch.full_like(y, NULL)
t0, t1 = 1e-3, 1.0 - 1e-3 # 避开 t=0 处 a_t, b_t 的奇点
dt = (t1 - t0) / n_steps
for i in range(n_steps):
tv = t0 + i * dt
t = torch.full((bs, 1), tv, device=DEV)
xx, tt = torch.cat([x, x], 0), torch.cat([t, t], 0)
yy = torch.cat([y, y0], 0)
u_cond, u_null = net(xx, tt, yy).chunk(2, dim=0)
u = (1.0 - w) * u_null + w * u_cond # (bs,2) 引导向量场
a_t, b_t = (1.0 - tv) / tv, 1.0 / tv # CondOT 的转换系数
s = (u - b_t * x) / a_t # 由 Prop.1 反解得引导 score
x = x + (u + 0.5 * sigma**2 * s) * dt \
+ sigma * math.sqrt(dt) * torch.randn_like(x)
return x
把两者串起来
net = train(steps=6000, eta=0.1)
for w in [0.0, 1.0, 2.0, 4.0, 8.0]:
y = torch.zeros(2000, dtype=torch.long, device=DEV) # 全部要第 0 类
xs = cfg_sample(net, y, w=w) # (2000, 2)
center = CENTERS[0] # 第 0 类的真实中心
print(f"w={w:4.1f} "
f"均值={xs.mean(0).tolist()} " # 应随 w 增大而外插
f"标准差={xs.std(0).mean().item():.3f} " # 应随 w 增大而收缩
f"到目标中心距离={(xs.mean(0) - center).norm().item():.3f}")
这段脚本能把第 6 节的两个结论直接跑出来:随着 $w$ 增大,样本均值沿「无条件中心 → 第 0 类中心」的方向越过目标中心(均值外插),同时标准差单调下降(方差收缩)。$w=0$ 时样本会均匀覆盖全部三个模态;$w=1$ 时集中到第 0 个模态且散布与数据相当;$w=8$ 时会明显缩成一个比数据簇更紧的点团,并且偏到簇的外侧。
10. 实践注意事项与常见误区
推理成本翻倍
CFG 最直接的代价:每一个积分步都要对网络做两次求值——一次喂 $y$,一次喂 $\varnothing$。因此在相同步数下,CFG 采样的 FLOPs 和显存带宽消耗都是无引导采样的两倍。对于 Stable Diffusion 3 那种 $50$ 步的设置,实际是 $100$ 次网络前向。
几个常见的工程手段:
- batch 合并(上面代码里的写法):把条件与无条件拼成一个 $2\times$ batch 的前向。省不了 FLOPs,但省下一半 kernel launch 开销,并让 GPU 跑在更高的算术强度上。
- 区间关闭引导:由第 1 节的直觉,$t$ 很小时 $\nabla\log p_t(y\mid x)\approx 0$,引导几乎不起作用;在这些步上可以只算条件分支。
- 蒸馏:把「带 CFG 的两次求值」蒸馏进一个单次求值的学生网络。这是 Lecture 5 会讲到的方向。
$w$ 太大的失效模式
第 6 节的算例二已经预言了大 $w$ 的两个后果,它们在图像上表现为:
- 过饱和 / 对比度爆炸:均值外插会把像素值推出数据的正常范围(在 $[-1,1]$ 归一化下会顶到甚至越过边界),表现为颜色浓艳、高光死白、暗部死黑。工程上常用的补救是在每一步对预测的干净样本 $\hat z$ 做动态截断(dynamic thresholding)——按分位数把它压回合法范围再继续积分。
- 多样性塌缩:方差收缩意味着同一 prompt 的不同随机种子会给出高度相似的构图。评测上表现为「贴合度指标变好、多样性指标变差」,两者之间存在一个由 $w$ 控制的权衡曲线。
- 结构伪影:$w\to\infty$ 时的目标是「最能让噪声分类器确信是 $y$ 的点」,而不是「最像真实 $y$ 的点」。两者的偏差会以奇怪的纹理、重复的局部结构等形式出现。
讲义只做定性判断,没有给出具体的 FID 等数字,这里也不做数值上的断言。可引用的定量参考只有:Stable Diffusion 3 使用 $2.0$–$5.0$ 的引导权重。
$w$ 的记号约定不统一
这是读代码时最容易踩的坑。本课的约定是
$$ \tilde u_t(x\mid y)=(1-w)\,u_t(x\mid\varnothing)+w\,u_t(x\mid y), $$其中 $w=1$ 表示「不做额外引导」(即标准条件采样),$w=0$ 表示完全无条件。
而 Ho & Salimans 的原始 CFG 论文以及不少代码库写成
$$ \tilde\epsilon_t(x\mid y)=(1+s)\,\epsilon_t(x\mid y)-s\,\epsilon_t(x\mid\varnothing), $$其中 $s=0$ 才表示「不做额外引导」。两者的换算关系是
$$ w=1+s\quad\Longleftrightarrow\quad s=w-1, $$因为 $(1+s)\epsilon_y-s\epsilon_\varnothing=w\,\epsilon_y+(1-w)\,\epsilon_\varnothing$。所以论文里的「guidance strength $s=3$」等于本课的 $w=4$。
还有第三种常见写法,形如 pred = pred_uncond + g * (pred_cond - pred_uncond),展开就是 $(1-g)\,\epsilon_\varnothing+g\,\epsilon_y$——这个 $g$ 与本课的 $w$ 一致($g=1$ 表示不做额外引导)。看到一个 guidance scale 数值时,先确认「无引导」对应的是 $0$ 还是 $1$,否则会整整差一个单位。
$\varnothing$ 该怎么实现
- 类别标签:把 embedding 表从 $|\mathcal{Y}|$ 行扩到 $|\mathcal{Y}|+1$ 行,最后一行专门给 $\varnothing$(上面代码的做法)。
- 文本条件:把空字符串
""送进文本编码器,用得到的嵌入作为 $\varnothing$;或者用一个可学习的常量嵌入。前者更常见,也让「负向 prompt」这类玩法成为可能——把 $\varnothing$ 换成一个你不想要的 prompt 的嵌入,(5.4) 就变成了在「远离该 prompt」的方向上外插。 - 切忌把 $\varnothing$ 实现成某个真实标签的复用,或者全零向量恰好与某个合法嵌入重合——那会让无条件分支和某个条件分支互相污染,定理里 $\varnothing\notin\mathcal{Y}$ 的前提就不成立了。
其他容易忽略的点
- 「训练时也要用 CFG 的加权向量场」——错。 训练目标 $\mathcal{L}^{\text{CFG}}_{\text{CFM}}$ 里只有一个 $u_t^\theta(x\mid y)$,回归目标是条件向量场 $u_t^{\text{target}}(x\mid z)$。$w$ 是纯粹的推理期超参数,训练时根本不出现。这意味着一个模型训完之后可以随意换 $w$,不用重训。
- 「$\eta$ 越大无条件分支越准,所以应该取 0.5」——不划算。 第 7 节证明了 $\eta$ 不影响最优解,它只分配梯度预算。条件分支是主任务且难度大得多(要在整个 $\mathcal{Y}$ 上学),无条件分支只是一个「基准」,不需要那么多预算。
- 「CFG 采出来的还是 $\data(\cdot\mid y)$」——不是。 讲义明确写道:$w>1$ 时 $X_1$ 不再服从 $\data(\cdot\mid y)$。CFG 是一个由经验效果驱动的启发式,而不是一个更好的估计量。
- 「负数 $w$ 或 $w<0$ 可以用来避开某个类别」——要小心。 由第 6 节的归一化讨论,$w$ 取到区间外时 $\tilde p_t$ 可能根本不可归一化,行为不可预测。
本讲小结
| 对象 | 公式 | 说明 |
|---|---|---|
| 引导边际路径 | $p_t(x\mid y)=\int p_t(x\mid z)\data(z\mid y)\ud z$ | 把数据分布换成 $\data(\cdot\mid y)$ 后的边际路径 |
| 噪声分类器 | $p_t(y\mid x)=p_t(x,y)/p_t(x)$ | $t=0$ 时退化为常数 $\data(y)$,$t=1$ 时是普通分类器 |
| 标签边际不变 | $p_t(y)=\data(y)$ | 因此 $\nabla_x\log p_t(y)=0$,贝叶斯分解才成立 |
| Guided CFM 目标 | $\E_{(z,y)\sim\data,\,t,\,x\sim p_t(\cdot\mid z)}\norm{u_t^\theta(x\mid y)-u_t^{\text{target}}(x\mid z)}^2$ | 与无引导 CFM 的唯一差别:采样 $(z,y)$ 而非 $z$ |
| 最优解 | $u_t^{\theta^\ast}(x\mid y)=u_t^{\text{target}}(x\mid y)$ | 二次损失的极小元是条件期望 + 边际化技巧 |
| 转换公式(引导版) | $u_t^{\text{target}}(x\mid y)=a_t\score{t}(x\mid y)+b_t x$ | $a_t=\beta_t^2\frac{\dot\alpha_t}{\alpha_t}-\dot\beta_t\beta_t,\ b_t=\frac{\dot\alpha_t}{\alpha_t}$,与 $y$ 无关 |
| 贝叶斯分解 | $\score{t}(x\mid y)=\score{t}(x)+\nabla_x\log p_t(y\mid x)$ | 本讲的核心恒等式 |
| 向量场分解 | $u_t^{\text{target}}(x\mid y)=u_t^{\text{target}}(x)+a_t\nabla_x\log p_t(y\mid x)$ | 第二项是唯一携带 prompt 信息的部分 |
| Classifier guidance | $\tilde u_t(x\mid y)=u_t^{\text{target}}(x)+w\,a_t\nabla_x\log p_t(y\mid x)$ | 需额外训练一个噪声分类器 |
| Classifier-free guidance | $\tilde u_t(x\mid y)=(1-w)u_t^{\text{target}}(x\mid\varnothing)+w\,u_t^{\text{target}}(x\mid y)$ | 只需一个网络;对任何概率路径都是合法定义 |
| 等价的差分形式 | $\tilde u_t=u_t^{\text{target}}(x\mid\varnothing)+w\big(u_t^{\text{target}}(x\mid y)-u_t^{\text{target}}(x\mid\varnothing)\big)$ | 「基准 + 放大的 prompt 修正」,差分放大器 |
| Score 版本 | $\tilde s_t(x\mid y)=(1-w)\score{t}(x\mid\varnothing)+w\score{t}(x\mid y)$ | $\epsilon$ 版本、$D$ 版本形式相同(权重和为 $1$) |
| 目标分布 | $\tilde p_t(x\mid y)\propto p_t(x)p_t(y\mid x)^{w}\propto p_t(x)^{1-w}p_t(x\mid y)^{w}$ | 逐时刻成立;但 $\{\tilde p_t\}$ 一般不是 $\tilde u_t$ 生成的路径 |
| 高斯算例(等协方差) | $\tilde p_t=\N\big(\mu_t^{\varnothing}+w(\mu_t^{y}-\mu_t^{\varnothing}),\ \gamma_t^2 I_d\big)$ | guidance 就是均值外插 |
| 高斯算例(不等方差) | $\tilde\lambda=\frac{1}{\tau^2}+(w-1)\big(\frac{1}{\tau^2}-\frac{1}{\gamma^2}\big)$ | $w>1,\tau<\gamma\Rightarrow\tilde\sigma^2<\tau^2$:多样性下降 |
| CFG 训练目标 | guided CFM + 以概率 $\eta$ 令 $y\leftarrow\varnothing$ | $\eta$ 不影响最优解,只分配梯度预算 |
| 空标签的正确性 | $\tilde p(z\mid\tilde Y=\varnothing)=\data(z)$ | 成立的前提:丢标签与图像 $z$ 独立 |
| 记号换算 | $w_{\text{本课}}=1+s_{\text{Ho–Salimans}}$ | 本课 $w=1$ / 原论文 $s=0$ 才是「无额外引导」 |
| 扩散版本 | $\dd{X_t}=\big[\tilde u_t^\theta+\frac{\sigma_t^2}{2}\tilde s_t^\theta\big]\dd{t}+\sigma_t\dd{W_t}$ | 两个引导量都用同一个 $w$ 组合 |
贝叶斯把条件 score 拆成「无条件 score + 噪声分类器梯度」,classifier guidance 把后者放大 $w$ 倍,classifier-free guidance 再用同一个恒等式把分类器换成两次向量场求值之差,于是一个带空标签的网络就够了。代价是:推理成本翻倍,并且我们采样的已经不是数据分布,而是一个被锐化到「更典型、更贴合 prompt、但更单调」的分布。
延伸阅读
Guidance 的两篇源头
- Classifier-Free Diffusion Guidance (Ho & Salimans, 2022) — CFG 的原始论文,本讲第 5–7 节的全部内容都出自它。读它主要是为了看清记号约定的差异(他们的 $s=w-1$)与实验设计。
- Diffusion Models Beat GANs on Image Synthesis (Dhariwal & Nichol, 2021) — classifier guidance 的出处,也是扩散模型第一次在 ImageNet 上超过 GAN。想理解「为什么人们一开始愿意多训一个分类器」,看这篇。
理论背景
- Score-Based Generative Modeling through Stochastic Differential Equations (Song et al., 2021) — 条件生成的 score 视角,包括用 $\nabla\log p_t(y\mid x)$ 做各类逆问题求解(inpainting、超分等),是本讲贝叶斯分解的更一般化版本。
- Flow Matching for Generative Modeling (Lipman et al., 2022) — flow matching 的原始论文,本讲第 2 节「固定 $y$ 后一切照搬」所依赖的全部结论都在这里。
- Flow Matching Guide and Code (Lipman et al., 2024) — 一份把理论与实现对齐的长篇指南,适合在读完本讲后核对自己的实现细节。
工业级实践
- Scaling Rectified Flow Transformers for High-Resolution Image Synthesis (Esser et al., 2024) — Stable Diffusion 3。它用的正是本讲的 CFG 训练(丢弃类别标签)与 $2.0$–$5.0$ 的引导权重,是「讲义里的算法如何变成真实系统」的最佳对照。
- Photorealistic Text-to-Image Diffusion Models with Deep Language Understanding (Saharia et al., 2022) — Imagen。它系统讨论了大引导权重带来的过饱和问题,并提出动态截断(dynamic thresholding)作为解法,正好补上本讲第 10 节提到的工程细节。
- Movie Gen: A Cast of Media Foundation Models (Polyak et al., 2024) — 把同一套 flow matching + CFG 搬到视频上,可以看到条件模态(文本、图像、音频)变复杂之后 $\varnothing$ 的设计要怎么变。
- High-Resolution Image Synthesis with Latent Diffusion Models (Rombach et al., 2022) — 潜空间扩散。CFG 在潜空间里的行为与像素空间一致(因为它只是网络输出的线性组合),这一点在下一讲会用到。