专业书籍精读 · Generative AI System Design Interview · 第 9 章
Generative AI System Design Interview · Ch 9 · Ali Aminian, Hao Sheng & Alex Xu · 2024
你在手机上打一句「一只戴着宇航头盔的柴犬,水彩风」,几秒后出来一张图——这一章讲的就是这条链路。但它的重点不是「怎么把图画得好看」,上一章已经把那件事解决了。这一章从头到尾只追一个问题:怎么让那句话真的管住那张图。
一个只会画好看图的模型,和一个听话的模型,是两回事。你说「戴头盔」,它给你一只特别漂亮、但没戴头盔的柴犬——这种失败最麻烦的地方在于:它不报错、不留白,就是安安静静地漏掉了一半要求。而且自动打分工具还会给它高分,因为那张图确实很像真照片。
关键在于:那句话不是在开头交代一次就完了。模型画图是一遍遍擦、一遍遍改的过程,它每改一次、每改到画面的哪一小块,都会回头把那句话再读一遍——就像一个边做菜边反复看订单的厨子,处理到狗头那一片时去问「头上有什么要求吗」,处理到背景时去问「什么风格来着」。所以「头盔」这个词只会落到该落的地方,而不是糊满整张画布。
光这样还不够听话。真正管用的那一招有点反常识:同一步里让模型画两遍——一遍读着你的要求画,一遍完全不看要求随便画。两张的差别,就是「你这句话到底把画面往哪个方向拽」。然后系统不满足于这点差别,而是顺着这个方向再多推几步。想让它更听话,就把这个「多推几步」的倍数调大。
这个倍数是能实时拧的旋钮,也是整条链路上最值钱的一个设计:不用重训模型,就能在「乖」和「野」之间滑动。
拧小了,图好看但自由发挥,你说的细节它当耳旁风;拧大了,它字字照办,但画面开始发僵、颜色发艳、构图千篇一律——老实到没灵气。大多数产品把它落在偏中间,让用户自己在滑杆上微调。
另外还有个便宜的副产品:既然有一遍是「不看要求」的,那就干脆让那一遍去看一句你不想要的东西(「模糊、多余的手指、水印」),于是那根推力就变成了「远离这些」。这就是很多绘图工具里的「反向提示词」,它不是玄学,就是同一招的背面。
代价也很直白:一步画两遍,算力和电费直接翻倍。
文生图真正的工程难题不是画质,是服从:靠「每画一笔都回头再读一遍那句话」把要求落到正确的位置,再靠「画两遍、朝差别的方向多推几步」把服从度放大成一个能实时拧的旋钮——拧得越紧越听话,但也越僵,而且成本翻倍。
想进到具体机制、记号和示意图? → 切到精读版
上一章解决了「画得快、画得大」,这一章补上另一半:可控。答案是两个动作——交叉注意力(cross-attention)把文本嵌进每一层去噪,让每个位置都能回头查询那句话;无分类器引导(classifier-free guidance, CFG)在采样时把「听话方向」按倍数外推,把服从度变成一个不必重训、能实时拧的旋钮。而最容易被低估的,是提示词在模型之外那几层:安全、改写、负面提示与缓存。
512×512×3 → 64×64×4),去噪在草稿上做完再解码回原尺寸——上一章的核心。Part II 十道真题的第 8 题,也是全书「图像三连」的正中一环:Ch7(GAN 人脸)解决画得像、Ch8(潜空间扩散)解决画得起、本章解决画得对,下启 Ch10——把条件从一句话换成几张自拍照。对应 Stable Diffusion、DALL·E、Imagen、Midjourney 这类产品的完整链路。
上一章那套扩散模型给你的是一张好看但不受控的图。产品要的却是「一只戴着宇航头盔的柴犬,水彩风」——模型得同时对上主体、属性、关系、风格四件事,缺一件用户就重抽。
不解决会怎样?会得到生成式系统里最贵的那种失败:错得流畅——不报错、不留白,只是安静地漏掉「戴头盔」,画质却一流。更糟的是自动指标看不见它:FID 量的是「这批图整体像不像真照片」,一张完全无视提示词的高质量图照样能拿漂亮的 FID。所以这一章的问题是一对:条件怎么进去(机制),和听没听进去怎么量(评估)。
还有一层成本约束把设计空间夹得很紧。一个 512×512、50 步的请求在单张 A100 上是数秒量级;而下面要讲的 CFG 每一步要跑两遍网络,等于单请求成本直接乘 2。在这里,「听话程度」不是学术参数,是一条按倍数计费的旋钮。
第一步是把提示词交给一个文本编码器(text encoder)——通常是现成的、训练时冻结不动的语言模型,输出每个 token 一个向量(Stable Diffusion 一系是 77 个 token 位)。这串向量就是后面所有环节要读的「条件」。不训编码器、让扩散网络学着去读它,既省算力,也让文本侧的能力可以整块替换——所以选哪个编码器是真正的系统决策,三条路:
一个好记的类比:CLIP 文本塔像看过千万张配图的美编,一听就知道大概长什么样,但读长句会串行;T5 像只读过书的文学编辑,句子结构拆得极准,脑子里却没有画面。
拿到文本向量后,最朴素的做法是把它加到网络输入上。效果很差——那是一次性的、全局的交代,网络画到局部时早就记不清了。
真正管用的是在去噪网络(U-Net 或 DiT)的每一个块里插一层交叉注意力:潜表示上的每个位置出 Query,文本 token 出 Key / Value。白话就是——网络在处理左上角这一小块时,会回头把那句话再问一遍:「我这块该长成什么样?」然后按相关度从各个词那里取信息。
这一步解释了很多现象。为什么「头盔」只落在狗头那一片、不糊满整张画布?因为注意力天然是位置各问各的,生成过程中自发长出一张「谁听谁的」软对齐表;帽子那片区域和围巾那片区域,问的是同一句话里不同的词。
代价很小:文本只有几十个 token,这层注意力相对整张图的自注意力几乎不占成本。坑在别处——这张对齐表是软的、没人监督,所以「红帽子蓝围巾」常串成蓝帽子红围巾、「三只猫」常画成两只。属性绑定与计数是结构性硬伤,调参治不好。
光有交叉注意力,模型对提示词的态度更像「参考一下」。要把服从度拉满,本章的主角才登场。
它的前身叫分类器引导(classifier guidance):另训一个能在带噪图上分类的模型,用它的梯度把采样往目标类别推。毛病有两个——要多训一个噪声分类器,而且它只推得动「类别」,推不动任意一句话。
CFG 的点子是把那个分类器彻底扔掉。 训练时随机把条件丢弃(约一成的样本改喂空提示),于是同一套权重同时学会了「读着提示词去噪」和「什么都不读去噪」。采样时各跑一遍,拿到两个预测,然后沿着二者之差外推:
ε̂ = ε_uncond + w · (ε_cond − ε_uncond)
白话讲这个式子在说什么:两个预测之差,就是「这句话到底把画面往哪个方向拽」;w 是把这股推力放大几倍。w=1 等于原样不放大(就是普通条件生成),w=7 就是顺着这个方向多推六倍的距离。直觉上,它等于对模型说:别只是参考,往「更像这句话」的方向再走远一点。
三条必须记住的性质。其一,它是采样期的,不动权重——同一份模型就能把 w 开成一根用户滑杆。其二,代价是每步两次前向,算力与延迟翻倍(把两条分支拼成一个 batch 能摊掉部分开销,但浮点量是实打实的两份)。其三,拧大不是纯赚:贴合度上升,多样性和真实感下降——过饱和、构图套路化,w 极大时出现数值溢出导致的色块(Imagen 的动态阈值就是为压这个)。
这是本章最「系统设计」的一节,也最容易被当成产品细节略过。用户打的那句话不能直接喂模型,中间至少四层:
(提示词, 种子, 步数, w, 模型版本) 定成缓存键:同一组输入必出同一张图。一条设计买到三样东西——可复现(客服能重放用户看到的图)、可审计(追得到是哪个版本出的)、可省钱(命中直接跳过整个去噪循环)。有爆款提示词的产品里,这是最大的一笔省。这一章可落地的决策主要是两个:文本那一路用什么,以及 w 开多大。
表 1 · 文本编码器怎么选
| 选择 | 擅长 | 代价 / 短板 | 什么时候选 |
|---|---|---|---|
| CLIP 文本塔 | 天生带视觉语义,风格 / 主体词命中率高;轻、快、生态成熟 | 上下文短(一系约 77 token),长句、否定、计数弱 | 以短提示、风格化创作为主的消费级产品 |
| 纯文本大模型(T5 系) | 长句、从句、空间关系与否定理解显著更好 | 没见过图,扩散侧训练更吃力;编码器本身就很大,显存与冷启动成本上去 | 提示词长、对「说什么就出什么」要求高的场景 |
| 双编码器拼接 | 视觉直觉 + 语法精度都要;实践中是目前最稳的一档 | 两份权重、两次编码,复杂度和显存都翻上去 | 旗舰模型(SDXL 即走此路),成本能摊开时的默认解 |
表 2 · CFG 强度 w 怎么定
| 档位 | 你得到 | 你付出 | 典型用途 |
|---|---|---|---|
w ≈ 1–3 | 多样性高、画面自然,同一提示词能抽出很不一样的结果 | 提示词里的细节常被忽略,复杂指令基本不跟 | 探索阶段、要「给我几个方向」的创意场景 |
w ≈ 5–8 | 贴合与自然的平衡区,绝大多数产品的默认落点 | 仍有属性错配和计数错误,只是频率降下来 | 通用出图的默认档,通常再暴露成用户滑杆 |
w ≳ 10 | 字面服从度最高,指定的元素几乎一定出现 | 过饱和、构图僵化、多样性塌缩;极端值下出色块 | 必须逐项对上的受控场景,且要配动态阈值一类的抑制手段 |
还有一个权衡进不了表:改写放哪一侧。推理侧扩写改得快、可随时回滚,但每个请求多一跳延迟和一份 token 成本;训练侧(用详细合成标题重训)更彻底,但一次几周起步、短期无法回退。多数团队先上推理侧,验证有效再谈往训练侧搬。
面试里被问「怎么让它更听话」,答「换个更大的模型」等于没答。这一章给的是三层能分别下手的抓手:换文本编码器(贵,要重训)、改条件注入方式(贵,动架构)、调 w 与加改写层(便宜,当天能上)。按成本从右往左排,就是一份能直接复述的行动顺序。
评估同样是考点。只报一个数是错的:FID 量真实感、对「听没听话」近乎失明;CLIP score 量贴合度、却能被「把关键词字面糊进画面」刷高。更要命的是两者会沿 w 反向移动——w 一拧大,CLIP score 上去、FID 掉下来。所以要扫一遍 w、报一条曲线而不是一个点,最后仍靠人评兜底。
w 是不是被调高了,而不是去换模型。w 不再意味着两次前向。但「交叉注意力注入 + 采样期外推」这套骨架至今没变。① 核心命题:文生图的难点不是画质(上一章已解决)而是可控;最贵的失败是错得流畅——不报错、不留白,只是安静漏掉一半要求,而 FID 还给它高分。
② 文本先经一个冻结的编码器变成 token 向量串;选 CLIP 文本塔(视觉直觉)、T5 系(语法精度)还是两个都上(SDXL 的做法),是真正的系统决策。
③ 条件靠交叉注意力注入:每个去噪块里、每个位置各自回头查询那句话——所以「头盔」只落在狗头上。对齐表是软的,属性绑定与计数因此不可靠。
④ CFG 扔掉了分类器:训练时随机丢条件,采样时跑有条件 + 无条件两遍,沿差值外推 w 倍。
⑤ w 是采样期旋钮,不动权重:可做用户滑杆,默认常落在 5–8;代价是每步两次前向,算力 ×2,且拧大牺牲多样性与真实感。
⑥ 负面提示是 CFG 的免费副产品——把无条件分支换成「不想要什么」,外推就变成远离它,零额外算力。
⑦ 模型只占链路中间一格:双侧安全、改写扩写、缓存键 (提示词, 种子, 步数, w, 模型版本) 占掉另一半工程量,并同时买到可复现、可审计与省钱。
⑧ 评估必须成对:FID 与 CLIP score 沿 w 反向移动,要报曲线不是报点,最后仍靠人评兜底——Google 为此另发了 1600 条 PartiPrompts。