📑 本页目录(点开跳转)
06 · 条件控制:文本与 CFG
⏱ 22 分钟 | ⭐ 你在任何 UI 上拖的那个 guidance scale,这一页讲清它在算什么
🎯 一句话
提示词不是一次性的「输入」,而是每一步去噪时都在旁边说话的那个人;而 guidance scale 更奇怪 —— 它让模型同一步跑两次,一次听提示词、一次装作没听见,再朝两者的差外推。 外推多远,就是那个滑块。
前面几章的去噪循环里没出现过一个字的提示词,跑完得到的是「训练分布里的某一张图」—— 哪一张,随缘。这一章把提示词接进去。
📝 一、文本先变成一串向量
第一步和扩散无关:把提示词交给一个已经训好、并且冻住的文本编码器(Stable Diffusion 1.x 用 CLIP 的文本塔)。
⭐ 它吐出来的不是一个向量,是一串。 CLIP ViT-L/14 固定输出 77 个位置 × 768 维,不足补齐、超了截断 —— 早期「提示词写太长后面不起作用」的传说,根就在这个 77 上。
为什么必须是一串?因为下一步要做对齐:「戴红帽子的猫」里「红」该影响帽子那片像素、不该影响爪子;压成一个向量这信息就没了。
🔀 二、交叉注意力:每个位置自己决定听哪个词
条件要在每一层、每一步都参与,靠的是交叉注意力。
| 从哪来 | 有多少 | |
|---|---|---|
| Q(我想找什么) | 当前图像特征,每个空间位置一个 | h × w 个 |
| K / V(能提供什么) | 文本编码器的输出 | 77 个 |
打分矩阵因此是 (h·w) × 77:每个图像位置对 77 个文本位置各打一个分,softmax 成权重后把 V 加权取回 —— 所以「帽子」那片特征会大量取走「红」,爪子那片不会。
⭐ 「提示词塞在哪一层」的答案是:哪一层都塞了,条件不是起点而是全程施加的偏置。⚠️ 时间步 t 不走这条路,它和主干结构一起放在下一章。
🎚️ 三、CFG:同一步跑两次
光靠交叉注意力,服从度往往不够。CFG(classifier-free guidance)在采样时动手:带提示词跑一次得 ε_cond,带空提示词再跑一次得 ε_uncond,然后合成:
$$\tilde{\varepsilon} = \varepsilon_{\text{uncond}} + s \cdot (\varepsilon_{\text{cond}} - \varepsilon_{\text{uncond}})$$
💡 人话:括号里是「有提示词和没提示词,预测差在哪」,也就是条件把画面往哪拽;s 决定沿这个方向走多远。
整理成 (1−s)·ε_uncond + s·ε_cond 更能看出问题:⭐ s = 1 时它就等于 ε_cond,即完全不做引导;s > 1 时 ε_uncond 的系数变负 —— 这不是插值,是越过 ε_cond 往外推。UI 上默认的 7.5,就是沿条件方向走出那么远。
👀 名字里的 free 指什么(可跳过)
前身 classifier guidance 要另训一个看得懂带噪图的分类器;CFG 改成训练时以约 10% 的概率把条件丢掉,同一个网络就兼职学会了无条件预测,不需要额外分类器。
⭐ 另外:「空提示词」不是全零张量,是把空字符串真送进文本编码器得到的那串向量。把它换成负面提示词,那一支就成了「往反面推」—— 负面提示词的全部机制就在这里。
📉 四、s 调大之后坏在哪
用两个假的预测张量,看合成那一行把结果放大成什么样:
# CFG 合成出来的 ε,随 s 被放大成什么样
import torch
torch.manual_seed(0)
D = 256 # 假装是展平的潜变量
eps_uncond = torch.randn(D) # 空提示词那次前向的输出
eps_cond = eps_uncond + 0.35 * torch.randn(D) # 带条件那次
base = D ** 0.5 # 训练时 ε~N(0,I),范数期望 sqrt(256)=16
print(f"训练时见过的 ε:范数约 {base:.1f},几乎没有分量超过 3")
for s in (1.0, 3.0, 7.5, 15.0):
eps = eps_uncond + s * (eps_cond - eps_uncond) # ⭐ 就是 CFG 那一行
n = eps.norm().item()
print(f"s={s:4.1f} 范数 {n:6.2f}(训练尺度的 {n/base:.2f} 倍)"
f" 越过 3 的分量 {int((eps.abs() > 3).sum()):3d} 个")
训练时见过的 ε:范数约 16.0,几乎没有分量超过 3
s= 1.0 范数 15.81(训练尺度的 0.99 倍) 越过 3 的分量 0 个
s= 3.0 范数 22.84(训练尺度的 1.43 倍) 越过 3 的分量 9 个
s= 7.5 范数 47.13(训练尺度的 2.95 倍) 越过 3 的分量 70 个
s=15.0 范数 91.65(训练尺度的 5.73 倍) 越过 3 的分量 152 个
⭐ 关键不是「变大了」,是「变成了模型没见过的东西」:s=7.5 合成出的范数已是训练尺度的 2.95 倍、70 个分量越过 3,s=15 是 5.73 倍 —— 而每一步都要减掉它,误差还逐步累积。
落到图上是三个症状:过饱和(颜色发死、对比拉爆)、构图崩坏(结构变形、纹理反复)、⚠️ 多样性塌缩(换十个种子出十张越来越像的图)。第三条最容易漏掉,因为单看一张图发现不了。
⭐ 「调大一点更听话」只在一段区间里成立,过了那段换来的是一张更响亮的坏图。
💰 五、代价:每步计算量翻倍
CFG 每步跑两次前向,50 步就是 100 次网络调用 —— 不是常数开销,是乘 2。实现上一般把两次拼成 batch=2 一起送:权重只从显存搬一次,省的是访存;乘加实实在在两份,算力那份省不掉。
⭐ 于是很多「加速采样」的比较是不公平的:有的把「一步」算成一次网络调用,有的算成一次去噪步(=两次调用)。看到「20 步出图」先问是 20 次还是 40 次。
🌡️ 六、它和 temperature 是同一类旋钮
语言模型的 temperature |
扩散的 s |
|
|---|---|---|
| 在调什么 | 采样分布的尖锐程度 | 条件方向被外推多远 |
| 更听话往哪调 | ⚠️ 调小 | ⚠️ 调大(方向相反,别记混) |
| 走极端 | 复读、干瘪 | 过饱和、构图崩、多样性塌缩 |
| 额外算力代价 | 没有 | ⚠️ 每步两次前向 |
共同点才是重点:都在「多听话」和「多自由」之间取舍,都没有安全默认值,都得按任务调。
⚠️ 这是类比不是等同:temperature 改的是分布形状,s 改的是预测向量的方向和长度,可迁移的只有那个权衡结构。但正因结构一样,那边的规矩这边也成立:别两个旋钮一起动,出问题先调回默认。
🔗 这一章连到哪里
| 去哪 | 为什么 |
|---|---|
| 大模型全景导论 06c · 解码参数怎么调 | ⭐⭐ 上一节那个类比的另一半:它把 temperature 的数学摊开了(logits 差 2.0 时 T=0.5 把概率比放大到 54.6 倍),并给了一条这里也适用的规矩 —— 和 top_p 只调一个 |
| 大模型全景导论 主线 2 · 模型怎样看懂一句话 | 交叉注意力的底子:那页把 Q/K/V 讲成三个角色(我想找什么/能被怎样匹配/能提供什么内容),本章只是把它们拆到两个东西上 |
| 大模型全景导论 10d · CLIP 与对比学习 | 那个「已训好并冻住」的文本编码器是怎么来的:几亿对(图片,描述)用 InfoNCE 训,一个 batch 的 N 对编成 N×N 相似度矩阵、要求对角线最大 |
| 大模型全景导论 06 · 推理优化:省显存 | 「计算量翻倍」这类账在语言模型那边怎么算:核心是瓶颈分两种(算力密集 vs 访存密集),正是「batch=2 省搬权重、不省乘加」背后的判据 |
✅ 检查点
- 文本编码器输出的是一个向量还是一串?为什么这个区别关键?
- 交叉注意力里 Q、K、V 各来自哪边?打分矩阵是什么形状?
- CFG 的合成公式是什么?
s = 1时会发生什么?为什么说s > 1是外推不是插值? s调得很大会坏成什么样?其中哪一条单看一张图发现不了?- CFG 的算力代价是多少?拼成 batch=2 之后省掉的是什么、没省掉的是什么?
👀 答案
- 是一串:CLIP ViT-L/14 固定输出 77 × 768。因为交叉注意力要做对齐 —— 「红」要影响帽子那片像素、不影响爪子。
- Q 来自图像特征(每个空间位置一个,共 h×w 个),K/V 来自文本编码器输出(77 个)。打分矩阵是 (h·w) × 77。
ε = ε_uncond + s·(ε_cond − ε_uncond),s = 1时等于ε_cond,即完全不引导。整理成(1−s)·ε_uncond + s·ε_cond就看得出s > 1时前一项系数是负数,结果落在ε_cond之外。- 过饱和、构图崩坏、多样性塌缩,第三条单看一张图发现不了。数值上
s=7.5合成出的范数是训练尺度的 2.95 倍、70 个分量越过 3。 - 翻倍(50 步 = 100 次调用)。省掉的是访存,乘加那份省不掉。
🛑 可以停在这里
你已经能解释一张图怎么「听懂」提示词:文本编码器 → 每层每步的交叉注意力 → 采样时的两次前向外推。⚠️ 什么时候回来:图颜色发死、结构反复、换种子也总是那几张 —— 先把 s 调回默认再查别的。
⚡ 走神救援
先记住这几件事
- 条件通过网络影响每一步去噪,而不是只在初始噪声里出现一次。
- CFG 组合有条件与无条件预测,加强条件方向,同时增加计算与偏离训练分布的风险。
- 引导强度不是越大越好,要同时观察匹配程度、细节和多样性。
下一节 👉 07-去噪主干-UNet与DiT.md