文生图模型是如何把文本注入扩散过程的?
简化版
文生图的核心是「让每一步去噪都参考提示词」。流程是:先用一个文本编码器(如 CLIP text encoder)把提示词编码成一串向量;再在去噪网络(U-Net)的多个层里插入交叉注意力(cross-attention)——图像特征作为 Query,文本向量作为 Key/Value,让每个空间位置都能「查询」文本,决定该处该长成什么。文本条件通过这种方式持续参与每一步去噪,从而控制生成内容。此外时间步 t 也会作为条件注入网络。
详细版
从文本到图像的完整链路
- 文本编码:提示词 → tokenizer → 文本编码器(CLIP/T5)→ 一串 token 嵌入
c(如 77×768)。 - 条件注入去噪:U-Net 在每一步预测噪声时,把
c通过交叉注意力融合进图像特征:ε_θ(x_t, t, c)。 - 引导强度:配合 Classifier-Free Guidance,用 guidance scale 控制对文本的服从度。
交叉注意力怎么工作
在 U-Net 的注意力层里:
Q = W_Q · (图像潜特征) # 来自当前被去噪的图像
K = W_K · c, V = W_V · c # 来自文本嵌入
Attention = softmax(Q·Kᵀ/√d) · V
- Query 来自图像:每个空间位置发出「我该参考文本的哪部分」的查询。
- Key/Value 来自文本:提供「文本里有哪些语义、对应什么内容」。
- 结果是每个位置按与各文本 token 的相关度,加权吸收文本信息。
为什么是交叉注意力而不是简单拼接
- 交叉注意力是空间自适应的:图像不同区域可以关注文本的不同词(“red car on green grass” 里车的区域关注 red/car,草地区域关注 green/grass)。
- 简单把文本向量加到特征上做不到这种「按位置、按词」的精细对齐。
文本编码器的选择
- SD1.x:CLIP ViT-L/14 text encoder。
- SDXL:CLIP ViT-L + OpenCLIP ViT-bigG 双编码器。
- Imagen / SD3:引入 T5 等大语言模型编码器,长文本与复杂语义理解更强。
完整版教学
一、条件生成的一般框架
无条件扩散学的是 p(x),随机生成;文生图要学的是 p(x|c)——给定文本 c 时图像的分布。技术上只需把去噪网络从 ε_θ(x_t, t) 扩展成 ε_θ(x_t, t, c),让它「看着条件去噪」。
问题就归结为:c 这个条件,用什么方式喂进网络最有效? 常见有三种注入方式,文生图主要用第三种:
- 相加/拼接(用于标量或全局条件):把条件编码成向量,加到特征或时间嵌入上。适合类别标签、时间步这类全局、无空间结构的条件。
- 自适应归一化(AdaLN/FiLM):用条件生成缩放和偏移参数去调制特征。适合全局风格类条件,DiT 用得多。
- 交叉注意力(用于序列条件):适合文本这种变长、有语义结构的条件,能做空间自适应对齐。文生图的主力。
二、为什么文本必须用交叉注意力
文本有两个特点决定了它适合交叉注意力:
- 变长且序列化:一句提示词有若干 token,长度不固定。交叉注意力天然处理变长序列。
- 需要空间对齐:图像不同区域要响应不同的词。交叉注意力让每个像素位置独立地对文本做加权,实现「哪块区域听哪个词」。
举例:“a cat wearing a red hat”。生成猫头顶区域的位置,其 Query 与 “red”、“hat” 的 Key 相似度高,于是这块区域强烈吸收「红帽子」的语义;而猫身体区域更关注 “cat”。这种逐位置、逐词的动态路由,是简单相加无法实现的,也是文生图能「精确听懂空间描述」的技术根基。
一个有意思的推论:正因为交叉注意力图记录了「每个词影响了哪些像素」,它可以被拿来做注意力可视化和基于注意力的编辑(如 Prompt-to-Prompt:改一个词、只动它对应的注意力区域)。
三、时间步条件:另一路不可忽视的注入
除了文本,时间步 t 也是必须注入的条件——网络得知道「现在是去噪的第几步、噪声有多大」,才能给出合适的预测。t 的注入走的是「相加」路线:
- 把整数 t 用正弦位置编码变成向量(和 Transformer 位置编码同理);
- 过一个小 MLP 得到时间嵌入
t_emb; - 在 U-Net 每个残差块里,把
t_emb加到特征上(或用它生成 scale/shift 调制特征)。
面试常把「文本条件」和「时间条件」一起问,记住:文本走交叉注意力(空间自适应),时间走嵌入相加/调制(全局)。
四、CLIP 文本编码器的作用与局限
SD 用 CLIP 的文本编码器,是因为 CLIP 在图文对比学习中已经把文本和视觉语义对齐到同一空间,其文本嵌入天然「懂视觉」。但它也有局限:
- CLIP 文本编码器上下文短(77 token)、对长文本、复杂逻辑关系、计数、空间关系理解有限,导致 SD 有时「数不清个数」「搞不定谁在谁左边」。
- 改进方向:换/加更强的语言模型编码器(Imagen 用 T5-XXL,SD3 用 CLIP+T5 组合),显著提升长提示词和复杂语义的服从度。
五、把整条链路串起来(文生图一次前向)
- “a red car on green grass” → tokenize → CLIP → 文本嵌入
c; - 当前潜图
z_t进 U-Net; - U-Net 每个残差块注入时间嵌入
t_emb;每个注意力块用交叉注意力融合c; - U-Net 输出噪声预测
ε_θ(z_t, t, c); - 配合 CFG:再算一次无条件
ε_θ(z_t, t, ∅),外推放大; - 采样器据此得到
z_{t-1},循环若干步 →z₀→ VAE 解码 → 图像。
六、面试拆解算例
扩散题最好用一次加噪和去噪的小推演讲清楚。假设训练图像像素归一化后是 x0,第 500 个时间步的噪声强度很高,模型看到的是混合样本 xt,目标通常是预测噪声 epsilon。如果预测噪声误差很小,就能从 xt 反推出更接近干净图像的估计;如果误差在早期步骤积累,后面细节会一起漂。
xt = sqrt(alpha_bar_t) * x0 + sqrt(1 - alpha_bar_t) * epsilon
model(xt, t, condition) -> predicted_epsilon
x0_hat = (xt - sqrt(1 - alpha_bar_t) * predicted_epsilon) / sqrt(alpha_bar_t)
| 维度 | 训练阶段 | 采样阶段 | 面试要点 |
|---|---|---|---|
| 输入 | 干净图 + 随机噪声 | 随机噪声或潜变量 | 起点不同 |
| 目标 | 学会预测噪声/速度 | 逐步还原样本 | 目标一致 |
| 条件 | 文本、边缘、姿态等 | CFG/ControlNet 引导 | 控制方向 |
| 代价 | 大量图像训练 | 多步迭代推理 | 速度质量权衡 |
干净图 x0 -> 加噪 xt -> 模型估计噪声 -> 反推 x0_hat -> 下一步更清晰
| | | |
训练目标 时间步 t 条件控制 误差累积
所以回答「文生图模型是如何把文本注入扩散过程的?」时,不要停在“从噪声生成图片”。要说明训练时为什么要加噪、模型到底预测什么、采样器怎样反推、条件信号如何改变方向,以及少步采样为什么会牺牲一部分稳定性。
七、常见误区与追问
- 误区:文本只在开头喂一次。 不是,文本通过交叉注意力参与每一步、每个注入层的去噪,全程在起作用。
- 误区:文本向量直接加到图像上就行。 简单相加做不到空间自适应对齐,效果远不如交叉注意力。
- 追问:Q/K/V 分别来自哪? Q 来自图像特征,K、V 来自文本嵌入。这是交叉注意力和自注意力的关键区别(自注意力 QKV 全来自图像自身)。
- 追问:SD 为什么常数不清物体个数、搞错空间关系? 主要受限于 CLIP 文本编码器的语义理解能力和训练数据的图文对齐粒度;用更强语言编码器可缓解。
- 追问:负面提示词怎么注入? 走 CFG 的无条件分支位置,把
∅换成负面提示嵌入,让生成远离它。
八、加强记忆
文生图注入记「文本走交叉注意力、时间走嵌入相加」:提示词经 CLIP 编成向量 c,在 U-Net 各层用交叉注意力融合——图像出 Query、文本出 Key/Value,让每个像素位置按相关度吸收对应词的语义,实现”哪块区域听哪个词”的空间自适应控制;再叠加 CFG 放大服从度。 抓住「Query 来自图像、KV 来自文本」这一句,交叉注意力的本质就通了;而 SD 数不清个数、搞错方位,根子在文本编码器的语义能力,这也是换 T5、上双编码器的动因。