专业书籍精读 · Generative AI System Design Interview · 第 7 章
Generative AI System Design Interview · Ch 7 · Ali Aminian, Hao Sheng & Alex Xu · 2024
网上流传过一类照片:一个笑得很自然的人,头发丝、毛孔、耳垂的光都对——而这个人从来没有存在过。这一章讲的就是机器怎么凭空画出一张真脸,以及一个更难的问题:画完了,谁来说它画得好不好。
教机器做别的事,都有标准答案:这张是猫还是狗,对就是对。可「画一张脸」没有标准答案——你没法指着任何一张照片说「你本该画成这样」。没有答案,就没法打分;没法打分,就没法告诉机器下一步往哪改。
早年的办法是让它「照着大家的平均去画」。结果很荒唐:把一万张脸的每个位置取个平均,得到的是一团灰蒙蒙、五官糊在一起的东西——平均一万张脸,不会得到一张好看的脸,只会得到一张谁都不是的脸。要清晰,就不能求平均;不求平均,就又回到没法打分。
真正的解法很反常:既然没人能当裁判,那就再训练一个裁判。
安排两个人对练。一个是仿画者,闭着眼睛瞎涂起步;一个是鉴定师,桌上摆着一摞真照片和仿画者刚交的作品,任务只有一个:指出哪张是假的。仿画者的目标是骗过鉴定师,鉴定师的目标是别被骗。妙处在于鉴定师也在长进——今天靠一团模糊就能蒙混,明天鉴定师学会看眼神了,后天开始挑耳朵和头发的破绽。尺子自己越来越严,仿画者就被一路逼到能乱真。
后来还给仿画者加了一套分层的调色盘:先定大处(脸的朝向、脸型),再定中间(五官、表情),最后才定细处(肤色、发丝、毛孔)。想改发型而不动脸型,就只拧中间那层的旋钮——这才有了「可控」。还有一个很好用的窍门:让它画得离大众脸近一点,出错就少,看上去更真;代价是画出来的人全都有点像亲戚。
还是不看单张。把五万张真照片和五万张画出来的照片各摆一堆,比较两堆的整体气质——真照片里有老人有小孩、有侧脸有戴帽子的,画出来那堆如果也铺得一样开、一样细,就算过关。这是对付「没有标准答案」的通用招数:单张评不了,一群可以。
好处是画得快——学成之后出一张脸只要一眨眼,所以实时头像、素材生成、拿合成脸替真人脸做测试都用得上。代价只有一句,但很硬:这场对练随时可能崩——最常见的崩法是仿画者发现某一张脸屡试不爽,从此只画这一张。
你以为难的是画得像,其实难的是没人能说清「像」是什么。这一章的全部聪明之处,是把「说不清的标准」变成「另一个也在学习的对手」。
想进到具体机制、记号和示意图? → 切到精读版
你以为生成对抗网络(GAN,generative adversarial network)的发明是那个会画画的生成器,其实它真正的发明是把损失函数本身交给另一个网络去学——因为「这张脸像不像真的」写不成公式,那就训练一个不断变严的判别器来充当那把尺子。整章该记住的一句工程结论是:尺子是学出来的,所以它会抖、会被骗、也没法当进度条看;GAN 的三种病(不收敛、模式崩塌、判别器过拟合)和 FID 这类分布级指标,全都是为这个选择买的单。
512 维),是生成一张图的「种子」,同一个 z 永远给出同一张脸。ψ):生成时把潜向量往「平均脸」方向拉一点,越拉越保真、越拉越单调。Part II 十道真题的第六道,图像生成三连(Ch7 人脸、Ch8 高分辨率合成、Ch9 文生图)的开篇。上承 Ch5 图像描述——那里是「图进、文出」,这里反过来是「什么都不进、图出」。本章走 GAN 路线,Ch8 起换成扩散模型,两章连读才看得出这条路线之争。现实对应虚拟形象与素材生成、人脸数据的去标识化,以及 deepfake 那一侧的风险工程。
核心矛盾一句话:判别式任务有标签,生成式任务没有。「这张 X 光片有没有病灶」有唯一答案,可以逐条对;「画一张人脸」没有——给定同一个随机种子,没有任何一张照片是它「本该」变成的样子。没有标准答案,就没有误差,也就没有可以下降的目标。
硬套逐像素误差会怎样?会得到一张糊脸。原因不玄:真实人脸的分布是多峰的(有侧脸有正脸、有长发有光头),而最小化像素均方误差的最优解是对所有可能性取平均——平均一万张脸得到的不是一张好脸,是一团谁都不是的雾。要清晰,就必须放弃求平均。
所以这一章真正要交付的东西是:找到一个可优化的目标,同时逼住两件常常打架的事——保真度(单张经得起看)与多样性(一批铺得开,覆盖得住真实人群)。不解决会怎样?迭代只能靠人眼看图,反馈周期从分钟级掉到天级,而且两个人看同一批图能给出相反结论。
是什么:两个网络。生成器 G 把随机向量 z 变成一张图;判别器 D 看图打分,回答「这来自真实数据集的概率是多少」。两者交替更新:训 D 时固定 G,喂真图和假图让它学着分开;训 G 时固定 D,让它朝「能把 D 的打分推高」的方向改。
直觉:造假者与鉴定师对练。关键不在造假者有多强,在于鉴定师也在进步——一团模糊今天能蒙混,明天 D 学会看眼神对称性,后天开始挑耳廓和发际线。尺子自己在变严,所以生成器没有「达标」的那一天。
记号:常写成 min_G max_D V(D,G),白话是「D 尽力把真假分开,G 尽力让 D 分不开」——注意这不是在求一个函数的最小值,而是在找两个对手的均衡点,这一点决定了后面所有麻烦。
为什么这样设计:因为「像不像真脸」没人能写成公式:手写指标(像素差、边缘相似度)都能被一团符合指标却不像脸的东西骗过去。写不出来就学一个——这是 GAN 最核心的一步棋,也是它全部代价的来源。
不收敛 / 振荡。普通训练是下山,看 loss 降就知道在进步;对抗训练是拔河,G 的 loss 降往往只说明 D 这一刻弱了。由此得到 GAN 最反直觉的一条实践纪律:损失曲线不能当质量进度条看,判断好坏只能靠定期采样出图 + 算分布级指标。
模式崩塌。如果某一类脸总能骗过当前的 D,G 就会一头扎进去,把所有 z 都映射到那几张脸上。致命之处在于它对保真度无害——出的图张张清晰好看,只是全都长得像,只看 demo 完全发现不了。
判别器过拟合。数据少的时候,D 会转而去「背」训练集里的具体图片而不是学「真实感」,尺子一旦失效,训练随即发散。
怎么救(每条一句):非饱和损失——改写 G 的目标,让它在被 D 碾压时还有梯度可用;WGAN-GP 的梯度惩罚与谱归一化——限制 D 变化的陡峭程度,别让尺子一步跳太远;TTUR(两个不同的学习率)——让 D 学得稍快,维持一个「有用但不碾压」的对手;判别器数据增强——给 D 看到的每张图(真的假的都要)随机加变换,逼它学特征而不是背图。
朴素 GAN 的 z 是纠缠的:动其中一个数字,脸型、发色、朝向会一起变,等于给了你一个只能整体摇的盒子。StyleGAN 的改法分三步。
先解耦:z 不再直接进画图流程,而是先过一个小的映射网络变成 w。这一步的作用是把原本挤在一起的属性在新空间里摊开,让「只改发色」成为可能。
再分层注入:图像从 4×4 逐级放大到 1024×1024,w 在每一级各注入一次(通过 AdaIN——用 w 去定这一层特征的均值和方差,等于定这一层的「风格」)。于是控制天然分了粗细:低分辨率层管姿态与脸型,中间层管五官与表情,高分辨率层管肤色与发丝。「换个发型但保持这张脸」之所以能做到,就是因为它们本来就由不同层负责。
最后分离随机性:毛孔位置、碎发走向这类「换一次就该不一样、但不影响这是谁」的细节,走一条独立的逐层噪声通道,不占用 w 的表达力。
截断技巧:生成时把 w 往训练集的平均 w 拉一点,拉的力度写作 ψ。ψ 越小越靠近平均脸,出错率显著下降、看着更真,代价是大家越来越像亲戚。这是全章最该记住的一个旋钮——保真度与多样性之间没有开关,只有一根连续的滑杆,而网上那些惊艳的人脸 demo 几乎都开着一个偏低的 ψ。
既然单张没有正确答案,评估就只能上移一层:不比图,比分布。
机制(白话):取 50000 张真图和同样多的生成图,各自送进一个现成的图像分类网络(Inception),在中间层取出 2048 维特征;把两堆特征各自当成一个高维高斯分布,拟合出均值和协方差;算这两个高斯之间的距离。数值越小,说明两堆图在这个特征空间里「长得像同一群」。
为什么这样设计:这个指标同时惩罚两种失败——图糊了,特征均值就偏;多样性塌了,协方差就缩。一个数字,两头都管住。
代价与坑:正因为一个数字管两头,它坏的时候你分不清是哪一头坏了。所以生产里通常再拆一层:用精确率 / 召回率分别量保真度与覆盖度(精确率低=出怪图,召回率低=漏掉了人群里的某些类型)。另外它依赖一个在 ImageNet 上训的网络当尺子,对人脸的细节未必敏感;样本数和实现细节一变,数值就不可比——FID 只在同一套评测流程内部横向比较才有意义,跨论文抄来的数字不能直接对齐。
第一层选型是路线之争。面试里问「为什么选 GAN」,答的就是这张表。
| 路线 | 出一张图 | 训练稳定性 | 覆盖 / 多样性 | 什么时候选它 |
|---|---|---|---|---|
| GAN | 1 次前向,1024² 人脸在单张现代 GPU 上几十毫秒 | 最差:要调稳,三种病都要防 | 偏弱,模式崩塌是常态风险 | 延迟和单价是硬约束:实时头像、超分、端上生成 |
| 扩散模型 | 20–50 步迭代去噪,慢一到两个数量级 | 好:本质是回归任务,训练稳 | 最好,天然覆盖得开 | 质量与可控性优先、能接受几秒延迟:文生图主力(Ch8–9) |
| VAE | 1 次前向,最快 | 最好 | 好,但倾向于取平均 | 要的是紧凑表示而非顶级画质;也常给扩散当潜空间压缩器 |
代价都写在第二、三列:GAN 用「训练难」换「推理快」,扩散反过来。
第二层选型发生在同一个模型内部——拧 ψ 这根滑杆。它不是调参细节,而是产品决策:
| 场景 | ψ 取向 | 得到什么 | 代价 |
|---|---|---|---|
| 官网 demo / 营销图 | 低(偏保守) | 几乎不出怪图,张张能看 | 人脸同质化,长得都像亲戚 |
| 合成训练数据 / 数据增强 | 高(偏多样) | 覆盖住长尾人群,下游模型才不偏 | 废片率上升,需要自动筛选兜底 |
| 论文刷 FID | 中间调优 | 指标最好看 | 那个 ψ 未必是产品该用的 ψ |
同一份权重换个 ψ 就是两种产品——这也是「论文 FID 漂亮、上线体感一般」的常见来源。
最出名的落地是 NVIDIA 的 StyleGAN 系列与那个「这个人不存在」式的演示页——它让「合成人脸已过肉眼关」成了公共常识。工程上真在用的有三类:虚拟形象与素材生成(游戏、电商模特、头像,省掉拍摄与版权);人脸数据去标识化(用合成脸替真人脸做演示与测试,绕开同意与合规);数据增强(给下游模型补长尾样本)。而真实感本身就是风险面:越逼真,冒用身份的成本越低,所以来源可证(provenance)与水印是必须提前设计进流程的一环,不是事后补丁。
面试里这一章最常被问的不是「GAN 怎么训」,而是「一个没有标准答案的模型,你怎么证明它变好了」——答案是分层:分布级指标(FID)看整体、精确率/召回率拆保真与覆盖、人工双盲对比做最终裁决,三者缺一不可。
70,000 张 1024×1024 的高质量 PNG 图像组成」,图片「从 Flickr 抓取,因而继承了该网站的全部偏见」,并用 dlib 自动对齐裁剪、最后靠 Amazon Mechanical Turk 人工剔掉雕像与画作。三句话说尽数据侧:规模、对齐,以及偏见随数据原样继承。NVlabs/ffhq-dataset ↗ψ 和人工挑选。评估要看未经挑选的随机批次,这是尽职调查里最省事也最有效的一问。① 这一章真正的发明不是生成器,是把损失函数交给另一个网络去学——因为「像不像真脸」写不成公式。
② 生成任务没有标准答案;硬套逐像素误差的最优解是对所有可能取平均,得到一张谁都不是的糊脸。
③ 目标是两件常打架的事同时成立:保真度(单张经得起看)与多样性(一批铺得开)。
④ G 与 D 交替更新、找的是均衡而非最低点,所以 GAN 的 loss 不能当质量进度条。
⑤ 三种病:不收敛、模式崩塌(只砍多样性,demo 看不出)、判别器过拟合(数据少时发散)。
⑥ 稳定手段各管一段:非饱和损失保梯度、梯度惩罚与谱归一化限制尺子的陡峭度、TTUR 调快慢、判别器增强防背图。
⑦ StyleGAN 三步把控制还给人:映射网络解耦、w 逐层注入(粗管姿态、细管发丝)、噪声单走一路。
⑧ 截断 ψ 是保真度与多样性之间的连续滑杆,不是开关;demo 好看多半是 ψ 偏低的功劳。
⑨ FID 比的是分布不是单图:两堆图各拟合一个高斯、量距离;一个数字管两头,坏了却分不清哪头坏,且跨实现不可比。
⑩ 选型一句话:GAN 用训练难换推理快(几十毫秒 1 次前向),扩散用几十步的慢换稳定与覆盖;真实感越高,来源可证与水印越要提前设计进系统。