文章目录

本文通过直观的比喻和极简的 PyTorch 代码,彻底拆解扩散模型里最常被提到、也最容易“会背公式但没真正懂”的技巧之一:Classifier-Free Guidance(CFG)。看完你应该能真正回答一句话:为什么一句提示词,真的能把扩散采样轨迹“拉向”你想要的图像?


一、为什么模型光会“生图”还不够?它还得“听话”

假设你已经训练好了一个扩散模型。

它确实会从噪声里生成图片,但这时你会立刻遇到一个现实问题:

我不只是想让它生成“某张图”,我还想让它生成“我指定内容的图”。

比如:

  • “一只戴墨镜的柴犬”
  • “赛博朋克城市夜景”
  • “白底产品图,一只蓝色马克杯”

如果模型只是会从图像分布里随机采样,那它可能生成:

  • 狗,但不一定戴墨镜
  • 城市,但不一定赛博朋克
  • 杯子,但不一定是蓝色

所以我们不只需要 生成能力,还需要 服从条件的能力

这就是 Guidance 想解决的问题:

让采样过程不只是“往真实图片方向走”,还要“往符合条件的真实图片方向走”。


二、先建立直觉:CFG 本质上是在做“方向修正”

你可以先把扩散采样粗暴理解成一句话:

模型每一步都在回答:“从当前这张带噪图出发,往哪个方向去噪,会更像真实图像?”

而 CFG 在这个基础上,多加了一句:

“不仅要更像真实图像,还要更像‘符合你这句提示词’的真实图像。”

1. 核心比喻:两个修图师,一个讲“像真图”,一个讲“更像提示词”

想象你有两个修图师。

第一个修图师只关心一件事:

  • “这张图怎样修,会更像一张自然真实的图片?”

第二个修图师除了关心真实,还额外知道你的提示词:

  • “这张图怎样修,会更像‘一只戴墨镜的柴犬’?”

于是每一轮采样时,你不再只听第一个人的意见,而是把第二个人的意见放大一点:

  • “真实”很重要
  • 但“贴合提示词”也要更强一点

这就是 CFG 的本质:

用条件预测和无条件预测之间的差值,去构造一个更强的“朝条件靠拢”的修正方向。


三、先回顾一个前提:条件扩散模型到底在学什么?

在条件扩散里,模型输入通常不只是带噪图 x_t 和时间步 t,还包括条件 c

  • 文本提示词 embedding
  • 类别标签
  • 图像条件
  • 其他控制信号

于是模型学的是:

ϵ θ ( x t , t , c ) \epsilon_\theta(x_t, t, c) ϵθ(xt,t,c)

也就是:

“给定当前带噪图、当前时间步和条件信息,请预测这次混进来的噪声。”

如果 c = "a dog",模型就会朝“更像狗”的方向去噪。
如果 c = "a cat",模型就会朝“更像猫”的方向去噪。

这就是条件扩散的基本能力。


四、那为什么还需要 Guidance?直接条件生成不够吗?

理论上,直接用条件模型就已经能生成和提示词相关的图了。

但实际中经常会有一个问题:

它会听,但听得不够死。

比如你提示:

  • “红色小汽车”

模型可能给你:

  • 一辆车,但颜色偏橙
  • 或者是一辆很小的红卡车
  • 或者背景和主体都对,但“红色”不够明显

也就是说,普通条件模型更像:

“我知道你的意思,我尽量往这个方向靠。”

而 Guidance 想做的是:

“不只是靠,而是更用力地往这个方向靠。”


五、先讲历史前身:Classifier Guidance 是怎么来的?

在 CFG 出现前,先有一个更早的思路:Classifier Guidance

1. 它的想法很直接

除了去噪模型外,再单独训练一个分类器:

p ϕ ( y ∣ x t ) p_\phi(y|x_t) pϕ(yxt)

这个分类器做的事是:

输入一张带噪图 x_t,告诉你它更像哪个类别。

比如:

  • 这张带噪图有多像“狗”
  • 有多像“猫”
  • 有多像“汽车”

2. 为什么分类器能提供 guidance?

因为分类器的梯度:

∇ x t log ⁡ p ϕ ( y ∣ x t ) \nabla_{x_t} \log p_\phi(y|x_t) xtlogpϕ(yxt)

告诉了你一件很重要的事:

如果想让当前图更像类别 y,应该朝输入空间的哪个方向改。

所以在采样时,你可以把这个梯度加到去噪方向里,相当于给模型一个“朝目标类别靠拢”的外力。

3. 但它有个明显麻烦

你得额外训练一个分类器,而且这个分类器还得能处理不同噪声级别的图。

这带来了几个问题:

  • 训练更麻烦
  • 系统更复杂
  • 分类器和去噪模型之间可能不匹配

于是大家就想:

能不能不要额外分类器,直接让扩散模型自己同时扮演“有条件”和“无条件”两个角色?

这就是 Classifier-Free Guidance 的出发点。


六、Classifier-Free Guidance 的核心妙招:让模型学会“两种说话方式”

CFG 的关键设计极其巧妙:

训练时,不是永远把条件喂给模型,而是有时候故意把条件拿掉。

1. 训练时怎么做?

对于每个训练样本,我们有条件 c,比如一句文本提示词。

训练时随机做两种情况:

  • 大多数时候:正常喂条件 c
  • 少数时候:把条件置空,或者替换成 null token

于是同一个模型就被训练成同时会做两件事:

  1. 有条件预测
    ϵ θ ( x t , t , c ) \epsilon_\theta(x_t, t, c) ϵθ(xt,t,c)
    它表示:“在知道提示词的情况下,我觉得噪声是什么。”

  2. 无条件预测
    ϵ θ ( x t , t , ∅ ) \epsilon_\theta(x_t, t, \varnothing) ϵθ(xt,t,)
    它表示:“什么提示词都不给时,我觉得噪声是什么。”

2. 这一步的直觉是什么?

无条件预测更像在回答:

  • “怎样去噪,能更像一张自然真实的图?”

有条件预测则在回答:

  • “怎样去噪,能更像一张符合提示词的真实图?”

于是两者之间的差值,就会暴露出一个非常关键的量:

条件信息到底把去噪方向往哪里拉偏了。


七、CFG 最重要的一条公式:它到底在算什么?

Classifier-Free Guidance 最经典的写法是:

ϵ ^ c f g = ϵ θ ( x t , t , ∅ ) + w ⋅ ( ϵ θ ( x t , t , c ) − ϵ θ ( x t , t , ∅ ) ) \hat{\epsilon}_{cfg} = \epsilon_\theta(x_t, t, \emptyset) + w \cdot \left(\epsilon_\theta(x_t, t, c) - \epsilon_\theta(x_t, t, \emptyset)\right) ϵ^cfg=ϵθ(xt,t,)+w(ϵθ(xt,t,c)ϵθ(xt,t,))

也常写成等价形式:

ϵ ^ c f g = ( 1 − w ) ϵ θ ( x t , t , ∅ ) + w   ϵ θ ( x t , t , c ) \hat{\epsilon}_{cfg} = (1-w)\epsilon_\theta(x_t, t, \emptyset) + w\,\epsilon_\theta(x_t, t, c) ϵ^cfg=(1w)ϵθ(xt,t,)+wϵθ(xt,t,c)

其中:

  • ϵ θ ( x t , t , ∅ ) \epsilon_\theta(x_t, t, \emptyset) ϵθ(xt,t,):无条件噪声预测
  • ϵ θ ( x t , t , c ) \epsilon_\theta(x_t, t, c) ϵθ(xt,t,c):有条件噪声预测
  • w w w:guidance scale,引导强度

1. 这条式子怎么翻译成人话?

先看这部分:

ϵ θ ( x t , t , c ) − ϵ θ ( x t , t , ∅ ) \epsilon_\theta(x_t, t, c) - \epsilon_\theta(x_t, t, \emptyset) ϵθ(xt,t,c)ϵθ(xt,t,)

它表示:

“条件 c 到底把去噪方向和无条件情况相比,额外推向了哪里。”

然后乘上一个 w,就表示:

“把这个朝条件靠拢的偏移量,放大 w 倍。”

最后再加回无条件预测,意思就是:

先保证图像仍然往‘自然真实’方向走,再额外更用力地往‘符合提示词’方向拽。

2. 为什么大家常把它叫“拉力”?

因为它真的很像两个力的叠加:

  • 无条件预测:把你拉向“真实图片流形”
  • 条件差值项:把你拉向“更符合提示词的区域”

所以 CFG 的本质不是凭空创造信息,而是:

在原有去噪方向上,加一个“更贴条件”的偏置。


八、为什么 guidance scale 大于 1 会更“听话”?

这是很多人第一次看到 CFG 公式时最困惑的点。

正常线性插值不是权重加起来等于 1 吗?
为什么这里经常用:

  • w = 5
  • w = 7.5
  • w = 12

这种看上去“过头了”的权重?

1. 因为这不是普通插值,而是在“外推”

如果 w = 1,那就是普通条件预测:

ϵ ^ c f g = ϵ θ ( x t , t , c ) \hat{\epsilon}_{cfg} = \epsilon_\theta(x_t, t, c) ϵ^cfg=ϵθ(xt,t,c)

如果 w > 1,那其实是在做一件事:

沿着“从无条件预测指向有条件预测”的方向,继续往前多走一段。

这叫 extrapolation(外推),不是 interpolation(插值)。

2. 直观比喻:导航说往东走 10 米,你故意多走到 20 米

无条件预测像在说:

  • “往这边走,会更像真实图片。”

有条件预测像在说:

  • “往这边再偏一点,会更像提示词要求的图片。”

而当你把 w 调大时,本质上是在说:

  • “我知道提示词给的偏移方向了,那我就沿这个方向走得更远一点。”

所以它会让图更“听话”。

3. 为什么这招有效?

因为很多时候,普通条件模型虽然知道条件,但施加得不够强。

CFG 通过放大条件差值项,相当于显式提升了条件信号在采样中的影响力。

于是:

  • 主体更明确
  • 属性更明显
  • 提示词和图像的对应更强

九、但为什么 guidance scale 太大又容易翻车?

因为“更听话”不是免费的。

当你把 w 调得太大时,模型会越来越像在说:

“我宁可过度迎合提示词,也不能偏一点。”

这常常带来几个副作用:

1. 颜色、对比度、饱和度异常

这是很多扩散模型里非常常见的现象。

因为模型被过度拉向某个条件方向后,容易把某些属性推得过头:

  • 红色更红
  • 高光更亮
  • 阴影更重
  • 纹理更硬

2. 多样性下降

因为 guidance 太强时,模型更倾向于沿一条很窄的“最符合提示词”的轨道走。

结果就是:

  • 图更统一
  • 但随机性和变化性更小

3. 容易产生不自然的伪细节

当条件牵引过强时,模型可能会硬凑出一些“看起来像满足提示词、但其实不自然”的结构。

比如:

  • 手部细节怪异
  • 物体边缘过于锐利
  • 局部出现奇怪重复

所以 guidance scale 本质上是在平衡两件事:

  • 条件一致性
  • 图像自然性

十、为什么说 CFG 本质上是在近似“条件分布 / 无条件分布”的差异?

如果从概率视角看,CFG 背后其实有一个很漂亮的思想。

扩散模型本质上在学习 score / 去噪方向,而条件与无条件之间的差别,近似对应了:

“在满足条件 c 时,图像分布相对于整体图像分布,到底偏向哪里。”

粗暴理解就是:

  • 无条件模型知道“自然图片通常长什么样”
  • 条件模型知道“满足 c 的自然图片通常长什么样”
  • 两者差值就体现了“条件 c 带来的偏移趋势”

所以 CFG 不是乱加,而是利用:

条件分布和边缘分布之间的方向差。

这也是为什么它会这么有效。


十一、把它彻底讲形象:CFG 到底在“拉”什么?

这部分你一定要建立画面感。

想象当前某一步的带噪图 x_t,还很模糊。

1. 无条件模型看到它,会怎么想?

它会说:

  • “这团东西更像一张自然图像的话,应该往这边去噪。”

这个方向可能通向:

  • 某种动物
  • 某种街景
  • 某种人像

但并不特指你的提示词。

2. 条件模型看到同一张图,又会怎么想?

如果条件是:

  • “一只戴墨镜的柴犬”

那它会说:

  • “如果要更像这个提示词,那去噪方向应该再往柴犬、墨镜、特定脸型和颜色分布那边偏一些。”

3. 所以 CFG 真正在拉的,不是像素,而是“去噪方向”

这一点非常重要。

CFG 不是在直接说:

  • “这里加一副墨镜”
  • “那里加一条狗尾巴”

它做的是更底层的事情:

它在每一步微调噪声预测,从而微调整条采样轨迹。

也就是说,CFG 拉的不是最终图片某一块像素,而是:

整张图在每一步应该朝哪个方向变干净。

这就是为什么一条文本提示词,能够在几十步采样后,最终塑造出完整语义和结构。


十二、训练时为什么只需要“丢条件”,不需要额外分类器?

这正是 CFG 最优雅的地方。

1. 训练阶段

你只需要在训练条件模型时,加一个简单操作:

  • 以一定概率 p_uncond
  • 把条件 c 替换成空条件

于是模型被迫学会:

  • 给条件时怎么预测
  • 不给条件时怎么预测

2. 推理阶段

同一张带噪图,在同一个时间步:

  • 跑一次无条件预测
  • 跑一次有条件预测
  • 然后做一次 CFG 组合

整个过程不需要单独的分类器。

这就是“Classifier-Free”这个名字的来源:

不是没有 Guidance,而是不依赖外部分类器。


十三、极简 PyTorch:CFG 推理骨架长什么样?

下面是最经典的 CFG 推理写法。

import torch


@torch.no_grad()
def cfg_denoise_step(model, x_t, t, cond, uncond_cond, guidance_scale):
    """
    model: 预测噪声的扩散模型
    x_t: 当前带噪图
    t: 当前时间步
    cond: 有条件输入(如文本 embedding)
    uncond_cond: 空条件输入(如 null embedding)
    guidance_scale: CFG 强度
    """
    eps_uncond = model(x_t, t, uncond_cond)
    eps_cond = model(x_t, t, cond)

    eps_cfg = eps_uncond + guidance_scale * (eps_cond - eps_uncond)
    return eps_cfg

然后你再把 eps_cfg 交给 scheduler,去更新下一步的 x_{t-1}

所以从工程角度看,CFG 的核心非常朴素:

  1. 跑两次模型
  2. 做一次线性组合
  3. 用组合后的噪声预测继续采样

十四、为什么 Stable Diffusion 里经常用 7.5?

很多人第一次用 Stable Diffusion 时都会看到一个神秘数字:

  • guidance_scale = 7.5

这不是数学定律,而是经验上比较折中的一个默认值。

它通常意味着:

  • 提示词约束已经足够明显
  • 但还没有强到特别容易炸细节

当然,不同模型、不同任务、不同提示词,最佳值会不同。

粗暴经验可以这样记:

  • 较小的 scale:更自然、更松弛、更多样
  • 中等的 scale:通常最平衡
  • 过大的 scale:更听话,但更容易过饱和、失真、僵硬

十五、Negative Prompt 和 CFG 有什么关系?

这也是你在实践里非常常见的一个点。

在很多文本到图像系统里,“无条件分支”并不一定真的什么都不给,而是可以喂一个 negative prompt

比如:

  • blurry, low quality, deformed hands

这时公式还是类似的,只不过“uncond”分支不再是完全空白,而是:

“往不要这些东西的方向去。”

于是 CFG 的组合效果就变成了:

  • 一边朝正向提示词靠
  • 一边远离负面提示词

这也是为什么 negative prompt 往往很有效。


十六、CFG 的优点到底是什么?

可以直接总结成 4 点:

1. 不需要额外分类器

系统更简单,训练和部署都更干净。

2. 条件控制很强

对文本、类别、属性等条件的服从度明显提升。

3. 实现简单

本质只是:

  • 训练时做条件 dropout
  • 推理时做双分支预测和线性组合

4. 通用性强

不只文本到图像,很多条件扩散任务都能用。


十七、CFG 的代价和局限是什么?

同样也要看到它的成本。

1. 推理要跑两次网络

最经典的 CFG 推理通常需要:

  • 一次无条件前向
  • 一次有条件前向

所以推理成本大约翻倍。

2. scale 调参敏感

不同 prompt 和模型,对 guidance scale 的最佳值不一样。

3. 强 guidance 容易伤自然性

前面已经讲过:

  • 过强会过饱和
  • 过强会失真
  • 过强会降低多样性

所以 CFG 不是“越大越好”。


十八、把它和你已经学过的扩散公式接起来

如果你已经看懂了前面那篇“为什么扩散模型能从噪声里还原图像”,那现在只需要加上一层理解:

原本采样时,我们用的是:

ϵ θ ( x t , t ) \epsilon_\theta(x_t, t) ϵθ(xt,t)

现在换成:

ϵ ^ c f g = ϵ θ ( x t , t , ∅ ) + w ( ϵ θ ( x t , t , c ) − ϵ θ ( x t , t , ∅ ) ) \hat{\epsilon}_{cfg} = \epsilon_\theta(x_t, t, \emptyset) + w \left(\epsilon_\theta(x_t, t, c) - \epsilon_\theta(x_t, t, \emptyset)\right) ϵ^cfg=ϵθ(xt,t,)+w(ϵθ(xt,t,c)ϵθ(xt,t,))

然后再把这个 ϵ ^ c f g \hat{\epsilon}_{cfg} ϵ^cfg 放进 DDPM / DDIM / 其他 scheduler 的更新公式里。

也就是说:

CFG 并没有改变扩散模型的整体框架,它只是把“每一步的噪声预测”换成了一个更偏向条件的版本。

所以你可以把它看成:

  • 扩散模型:提供去噪主干
  • CFG:给去噪方向加一个条件偏置

十九、你必须真正记住的 6 句话

如果这篇很长,你至少要记住下面 6 句:

  1. CFG 的目标不是让模型更会画图,而是让模型更听条件。

  2. 训练时通过随机丢掉条件,让同一个模型同时学会有条件和无条件预测。

  3. 无条件预测负责把图拉向“自然真实图片”,有条件预测负责把图拉向“符合提示词的真实图片”。

  4. 两者差值表示:条件到底把去噪方向往哪里额外推了一下。

  5. guidance scale 大于 1 不是普通插值,而是在沿条件方向做外推,所以会更听话。

  6. scale 太大时,图会更听话,但也更容易失真、过饱和、缺少多样性。


二十、终极总结:Classifier-Free Guidance 到底在“拉”什么?

现在你可以用一句完整的人话回答了:

Classifier-Free Guidance 不是在直接修改最终图像,而是在每一步采样时,用“有条件预测”和“无条件预测”的差值,构造出一个更偏向提示词的去噪方向,从而把整条生成轨迹逐步拉向你想要的内容。

一句更短的版本:

CFG 拉的不是像素,而是每一步的去噪方向。


Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐