来源:Ho, Salimans 2022 · arXiv:2207.12598 §3.2、Algorithm 1、Algorithm 2、论文式(6)。本节是本单元核心。 读法:§2.1 隐式分类器(引导项由生成模型自己给出);§2.2 核心论文式(6) 的推导;§2.3 训练 Algorithm 1;§2.4 采样 Algorithm 2;§2.5 引导项是纯网络之差、与对抗攻击无关;§2.6 一行代码与引导强度的约定。 --- ## §2.1 隐式分类器:引导项不必外挂 §1.4 的 classifier guidance 需要一个外挂分类器 $p_\theta(c\mid z_\lambda)$ 来提供引导项 $\nabla\log p(c\mid z_\lambda)$。CFG 的第一步观察:这个引导项其实可以由生成模型自己表示出来,不必单独训分类器。 办法是用贝叶斯,把分类器 $p(c\mid z_\lambda)$(已知带噪图、求这张图属于类别 $c$ 的概率)写成生成模型两个量的比: > [!danger] 论文 §3.2 · 隐式分类器 > $p^i(c\mid z_\lambda)\propto\frac{p(z_\lambda\mid c)}{p(z_\lambda)}$ 来历:贝叶斯 $p(c\mid z_\lambda)=p(z_\lambda\mid c)p(c)/p(z_\lambda)$,其中 $p(c)$ 是类别先验、不含 $z_\lambda$,对固定的 $z_\lambda$ 只是个常数,吸进正比号,剩下 $p(z_\lambda\mid c)/p(z_\lambda)$。上标 $i$ 标明这是「由生成模型倒推出的分类器」(implicit),区别于 §1.4 那个真去训的分类器。 对这个比值取对数、对 $z_\lambda$ 求梯度,就得到引导项。比值取对数变减法($\log(a/b)=\log a-\log b$),于是引导项是两个 score 之差: $\nabla_{z_\lambda}\log p^i(c\mid z_\lambda)=\nabla_{z_\lambda}\log p(z_\lambda\mid c)-\nabla_{z_\lambda}\log p(z_\lambda)$ 右边两项一个有条件、一个无条件,都是 score。论文在这一步特意用精确 score 的记号 $\varepsilon^*(z_\lambda,c)$、$\varepsilon^*(z_\lambda)$:星号表示这是两个分布真正的 score 翻成 $\varepsilon$ 的样子,不是网络输出。用 §1.2 的翻译器 $\nabla\log p=-\varepsilon/\sigma_\lambda$ 把两项都换成 $\varepsilon^*$(同除 $-\sigma_\lambda$): > [!danger] 论文 §3.2 · 隐式分类器的引导项(精确 score 版) > $\nabla_{z_\lambda}\log p^i(c\mid z_\lambda)=-\frac{1}{\sigma_\lambda}\big[\varepsilon^*(z_\lambda,c)-\varepsilon^*(z_\lambda)\big]$ > $\varepsilon^*$ 是精确 score(真分布的 score 翻成 $\varepsilon$),这条等式只在 $\varepsilon^*$ 上严格成立。 **引导项等于「有条件减无条件」,再除以 $-\sigma_\lambda$;这条等式只对精确 score 成立。** 网络的两路输出 $\varepsilon_\theta(z_\lambda,c)$、$\varepsilon_\theta(z_\lambda)$ 只是这两个精确 score 的估计,两者一减得到的是引导项的估计,外挂分类器就此省掉。这正是 Score-SDE `10_可控生成与逆问题` §10.5 预告的那句「用网络自己的有条件、无条件输出之差,替掉外部分类器的引导项」。 ## §2.2 核心:论文式(6) 把 §2.1 的隐式引导项代进 §1.4 classifier guidance 的修改预测里,$\sigma_\lambda$ 恰好上下约掉、合并同类项。先说清这一步的性质:在精确 score($\varepsilon^*$)的世界里这是恒等推导;换成网络输出后它不再是推导,而是受它启发的定义,CFG 直接规定用网络两路输出照这个形状组合(论文原话:论文式(6) 是 inspired by 隐式分类器的梯度)。得到 CFG 的核心: > [!danger] 论文式(6) · classifier-free guidance > $\tilde\varepsilon_\theta(z_\lambda,c)=(1+w)\,\varepsilon_\theta(z_\lambda,c)-w\,\varepsilon_\theta(z_\lambda)$ **论文式(6) 是有条件预测与无条件预测的线性外推**:$w=0$ 退回普通有条件采样,$w$ 越大、越把预测往「远离无条件、贴近有条件」的方向推。式子里没有任何分类器梯度,两处输入只是同一个网络喂 $c$ 与喂 $\varnothing$。三步代数推导见下折叠。 > [!note]- 从 §1.4 的修改预测推到论文式(6) > 以下在精确 score 层面推(把式里的 $\varepsilon_\theta$ 都读作 $\varepsilon^*$ 即严格成立),推完把 $\varepsilon^*$ 换成网络输出,就是 CFG 的定义。 > > 第一步 · 写下 §1.4 那条 classifier guidance 的修改预测,但把里面的外挂分类器换成 §2.1 的隐式分类器(引导项系数仍是 $w$): > $\tilde\varepsilon_\theta(z_\lambda,c)=\varepsilon_\theta(z_\lambda,c)-w\,\sigma_\lambda\,\nabla_{z_\lambda}\log p^i(c\mid z_\lambda)$ > > 第二步 · 把 §2.1 求出的 $\nabla\log p^i=-\frac{1}{\sigma_\lambda}[\varepsilon_\theta(z_\lambda,c)-\varepsilon_\theta(z_\lambda)]$ 代进去。系数 $-w\sigma_\lambda$ 乘上 $-\frac{1}{\sigma_\lambda}[\cdots]$:$\sigma_\lambda$ 与 $\frac{1}{\sigma_\lambda}$ 相乘约成 $1$、两个负号相乘变正,只剩 $+w[\cdots]$: > $\tilde\varepsilon_\theta(z_\lambda,c)=\varepsilon_\theta(z_\lambda,c)+w\big[\varepsilon_\theta(z_\lambda,c)-\varepsilon_\theta(z_\lambda)\big]$ > > 第三步 · 合并同类项。$\varepsilon_\theta(z_\lambda,c)$ 出现两次,$1$ 份加 $w$ 份共 $1+w$ 份;$\varepsilon_\theta(z_\lambda)$ 是 $-w$ 份: > $\tilde\varepsilon_\theta(z_\lambda,c)=(1+w)\,\varepsilon_\theta(z_\lambda,c)-w\,\varepsilon_\theta(z_\lambda)$ > 即主线的论文式(6)。 > [!example]- 「外推」看得更清楚的写法 > 把论文式(6) 重排成 $\tilde\varepsilon=\varepsilon_\theta(z_\lambda)+(1+w)\big[\varepsilon_\theta(z_\lambda,c)-\varepsilon_\theta(z_\lambda)\big]$:从无条件预测出发,沿「有条件减无条件」这个方向迈 $1+w$ 步。$\varepsilon_\theta(z_\lambda,c)-\varepsilon_\theta(z_\lambda)$ 是「加入条件把预测拉动了多少」,CFG 把这段拉动放大到 $1+w$ 倍。$w=0$ 恰好迈一步、落在有条件预测上。 ## §2.3 训练:一个网络同时学两路(Algorithm 1) 论文式(6) 要网络能给出有条件预测 $\varepsilon_\theta(z_\lambda,c)$ 和无条件预测 $\varepsilon_\theta(z_\lambda)$ 两样。CFG 不训两个网络,而用一个网络兼任:无条件就是把条件位置喂一个空标记 $\varnothing$,即 $\varepsilon_\theta(z_\lambda)=\varepsilon_\theta(z_\lambda,\varnothing)$。**训练时以概率 $p_{\text{uncond}}$ 随机把条件 $c$ 替换成 $\varnothing$,一个网络就在同一套权重里同时学会了两路。** > [!danger] 论文 Algorithm 1 · 联合训练 > 需要:$p_{\text{uncond}}$(无条件训练的概率) > ``` > repeat > (x, c) ~ p(x, c) # 从数据集取一对「图, 条件」 > c ← ∅ with prob p_uncond # 以 p_uncond 丢掉条件,改成无条件 > λ ~ p(λ) # 抽一个噪声水平(log 信噪比) > ε ~ N(0, I) > z_λ = α_λ x + σ_λ ε # 按论文式(1) 加噪到 λ > 在 ∇_θ ‖ε_θ(z_λ, c) − ε‖^2 上做一步梯度下降 > until 收敛 > ``` 和普通条件扩散训练相比,只多了一行「以 $p_{\text{uncond}}$ 把 $c$ 换成 $\varnothing$」。其余(抽噪声水平、加噪、预测噪声的 L2 损失)与已写过的训练循环一字不差。$p_{\text{uncond}}$ 是新的超参数,实验(§3)会看 $p_{\text{uncond}}$ 取多大合适。 ## §2.4 采样:把两路组合起来走(Algorithm 2) 采样时每一步做两件事:先用论文式(6) 把有条件、无条件两路预测组合成 $\tilde\varepsilon$,再拿 $\tilde\varepsilon$ 当作这一步的噪声预测,走一步普通的采样更新。 > [!danger] 论文 Algorithm 2 · 条件采样 > 需要:引导强度 $w$;条件 $c$;递增的 log 信噪比序列 $\lambda_1<\dots<\lambda_T$($\lambda_1=\lambda_{\min}$、$\lambda_T=\lambda_{\max}$) > ``` > z_1 ~ N(0, I) > for t = 1, …, T: > ε̃_t = (1 + w) ε_θ(z_t, c) − w ε_θ(z_t) # 论文式(6):组合两路 > x̃_t = (z_t − σ_{λ_t} ε̃_t) / α_{λ_t} # 由 z 和 ε̃ 反解干净图估计 > z_{t+1} ~ N(μ̃_{λ_{t+1}|λ_t}(z_t, x̃_t), (σ̃²_{λ_{t+1}|λ_t})^{1−v} (σ²_{λ_t|λ_{t+1}})^v) 若 t<T;否则 z_{t+1} = x̃_t > return z_{T+1} > ``` 逐行读。起点 $z_1\sim\mathcal N(0,I)$ 是纯噪声($\lambda_1=\lambda_{\min}$,信噪比最低)。 第一行是论文式(6),把两路组合成 $\tilde\varepsilon_t$。 第二行由加噪关系反解干净图的估计:论文式(1) 是 $z=\alpha x+\sigma\varepsilon$,把 $\tilde\varepsilon_t$ 当作这里的噪声、从 $z_t$ 里减掉 $\sigma_{\lambda_t}\tilde\varepsilon_t$、再除以信号系数 $\alpha_{\lambda_t}$,就解出干净图估计 $\tilde x_t=(z_t-\sigma_{\lambda_t}\tilde\varepsilon_t)/\alpha_{\lambda_t}$。 第三行用这个 $\tilde x_t$ 做一步反向转移,走到下一个噪声水平 $\lambda_{t+1}$;末步($t=T$)直接输出 $\tilde x_T$。 式中 $\tilde\mu_{\lambda_{t+1}\mid\lambda_t}(z_t,\tilde x_t)$ 是反向转移的均值,即 DDPM 那套祖先采样的均值(Score-SDE `04_反向SDE` §4.4.1):吃当前 $z_t$ 和干净图估计 $\tilde x_t$、给出下一步的高斯均值。方差是两个方向的转移方差在 log 空间按 $v$ 插值($v$ 是插值超参),属采样细节、与 guidance 无关,此处不展开。 序列 $\lambda_1<\dots<\lambda_T$ 递增,即采样是噪声水平从高到低、$\lambda$ 从小到大走。 > [!tip] 采样器可以替换 > Algorithm 2 第三行用的是祖先采样(DDPM 那条转移),但 guidance 只发生在第一行「把两路组合成 $\tilde\varepsilon$」这一步,和用哪个采样器无关。论文明说这一步可换成别的采样器,例如 DDIM。所以 CFG 是加在任意采样器之上的一层,凡是「吃一个噪声预测 $\varepsilon$、走一步」的采样器(DDIM、Heun、祖先采样都是),把喂给采样器的 $\varepsilon$ 换成 $\tilde\varepsilon$ 即可。 ## §2.5 引导项是纯网络之差:非保守的向量场 §0.2 提过 classifier guidance 的一个疑点:classifier guidance 把 score 和真分类器的梯度相混,形式上像在对分类器做基于梯度的对抗攻击。CFG 从根上避开了这个疑点。 关键在 $\varepsilon_\theta(z_\lambda,c)-\varepsilon_\theta(z_\lambda)$ 这个差。这个差由同一个无约束网络的两次输出(喂 $c$ 与喂 $\varnothing$)相减而成,一般不是任何分类器的梯度(严格说是「非保守场」,见下框)。§2.2 点破过论文式(6) 对网络输出是定义、不是恒等推导,根子正在这里:网络输出不是精确 score,这个差也就不必是任何分类器的梯度。**$\tilde\varepsilon$ 的构造里没有任何分类器的梯度,采样迈的方向和分类器梯度没关系,自然不能解释成对分类器的对抗攻击。** 于是 §0.2 的疑问在 CFG 里不成立:CFG 把 FID、Inception Score 抬高,是纯生成模型做到的,不靠迎合分类器梯度。 > [!example]- 「保守场」是什么意思 > 一个向量场若是某个标量函数的梯度,就叫保守场(像重力场是势能的梯度)。真分类器的梯度 $\nabla\log p_\theta(c\mid z)$ 天生是保守场(这个梯度就是 $\log p_\theta(c\mid z)$ 这个标量的梯度)。而同一网络喂不喂条件的两次输出之差 $\varepsilon_\theta(z,c)-\varepsilon_\theta(z)$ 没有这层保证,一般不是任何标量的梯度,即非保守场。这个区别正是「CFG 的引导项不是任何真分类器的梯度」的严格说法。 ## §2.6 一行代码,以及引导强度的约定 把两节算法合起来看,**CFG 相对普通条件扩散只有两处一行改动**:训练时一行「以 $p_{\text{uncond}}$ 把 $c$ 换成 $\varnothing$」,采样时一行「$\tilde\varepsilon=(1+w)\varepsilon_\theta(z,c)-w\,\varepsilon_\theta(z)$」。极简是 CFG 最大的实用优势,也是 CFG 成为文生图标配开关的原因。 > [!tip] 引导强度 $w$ 与工程里的 guidance scale 差一 > 论文式(6) 用 $w$,$w=0$ 表示不引导。很多实现(以及文生图界面里的 guidance scale $s$)用的是外推写法 $\tilde\varepsilon=\varepsilon_\theta(z)+s\big[\varepsilon_\theta(z,c)-\varepsilon_\theta(z)\big]$,对照 §2.2 折叠里的重排写法可知 $s=1+w$:论文的 $w=0$(不引导)对应 guidance scale $s=1$,界面上常见的 $s=7.5$ 对应论文 $w=6.5$。同一个旋钮,两套读数差一个常数 $1$,讨论数值时先认清用的是哪一套。 ## 本节一条线 CFG 的两块拼图:其一,隐式分类器 $p^i(c\mid z_\lambda)\propto p(z_\lambda\mid c)/p(z_\lambda)$ 把引导项写成「有条件预测减无条件预测」除以 $-\sigma_\lambda$,于是引导项由网络自己给出、不必外挂分类器;其二,把隐式引导项代进 classifier guidance 的修改预测,$\sigma_\lambda$ 约掉、合并同类项,得核心论文式(6) $\tilde\varepsilon=(1+w)\varepsilon_\theta(z_\lambda,c)-w\,\varepsilon_\theta(z_\lambda)$,即两路预测的线性外推。训练(Algorithm 1)用一个网络、以概率 $p_{\text{uncond}}$ 随机丢条件,同时学会有条件与无条件两路;采样(Algorithm 2)每步先用论文式(6) 组合两路、再走一步任意采样器。这个引导项是两个无约束网络之差、一般不是任何分类器的梯度(非保守场),所以采样迈的方向和对分类器的对抗攻击无关。落到代码只是训练、采样各一行改动。