把箭头掉转:从「看」到「造」
本阶到目前为止的一切都朝着一个方向跑:图片进去,标签、框或掩膜出来。卷积网络看出一只猫;视觉 Transformer看出各个部件以及它们之间的关系。生成则把这个箭头反了过来。我们要的不是「图像 → 含义」,而是「含义 → 图像」:把「一只狐狸在雨中读报纸」这个想法交给模型,让它产出与之相符的像素。难就难在没有唯一正确答案——能诚实地匹配这几个字的图,可以有十亿张之多。
所以生成器并不是把一个输入映到一个输出的函数。它是一种从浩瀚的「合理图像」空间里采样的方式——就像掷骰子是在 1 到 6 这些数字里采样一样。早期的尝试用 生成对抗网络,让一个造假者和一个鉴别者对打;也用过 变分自编码器,把图像挤过一个狭窄的瓶颈。两者都能用,但训练起来都很娇气。最终接管这个领域的方法更温和,而且一旦你看懂,几乎是顺理成章的。
扩散:学会把噪声「撤销」
扩散模型背后的把戏是这样的。拿一张真实照片,往里一点点撒入随机噪声——先一点,再多一点,越来越多——经过几百个微小步骤后,它就和电视雪花花屏没什么两样了。这种「破坏」很容易,无非是加噪声。真正巧妙的一步是训练一个网络去倒着跑这个过程:给它一张带噪的图,再告诉它一个数字、说明它*有多*噪,让它预测出当初加进去的那部分噪声,好把它减掉。做到这一点,你就能一层一层把噪声剥下来。
回报来了。要*生成*图像,你根本不从照片开始——你从纯噪声、从全新的随机雪花出发,然后一遍又一遍地向训练好的网络问同一个问题:「你在这里看到了什么噪声?」减掉一小口,再重复。许多步之后,雪花就凝结成一张干净、连贯的图像。网络从没背下这张图;它学到的是「真实图像长什么样」的大致样貌,并用它从随机中雕出秩序。负责预测噪声的主力网络通常是一个 U-Net——一种编码器—解码器,先把图像缩小以抓住整体大局,再把它放大回全分辨率,同时保住细节。
潜在扩散:在一个更小的世界里做这件事
在一张全尺寸图像上跑几百个去噪步骤——每一遍都是几百万像素——代价高得吓人。让图像生成便宜到人人可用的那次突破,叫 潜在扩散。思路是:根本不去扩散像素。先训练一个 自编码器,把一张图像压成一小格数字——一个潜在表示(latent)——它抓住图像的精髓,体积也许只有原来的几十分之一,并且能被解码回一张忠实的图。然后,把整套「从噪到净」的扩散过程统统放进这个紧凑的潜在空间里去跑。
流程于是变成:在潜在空间里放入噪声 → 一步步去噪 → 得到一个干净的潜在表示 → 一次性把它解码成全分辨率像素。因为潜在表示小得多,每个去噪步只需做一小部分工作,模型也得以专注于*含义*,而不必浪费力气去复刻精确的像素纹理(那些交给解码器)。这正是你也许在自己笔记本上跑过的那些开源模型背后的架构。代价是一个微妙之处:解码器会把最细的细节抹糊,这也是为什么招牌上生成的文字、以及小人脸的结构常常出来是乱的。
用文字掌舵:文本生成图像
到目前为止,模型能凭空梦出*某张*连贯的图,却还不是你点的那张。文本生成图像给它装上了方向盘。你的提示词会被转成一个嵌入向量——一串捕捉其含义的数字——通常由 CLIP 这类模型来做,它在训练时学会把相互匹配的图文对在一个共享空间里放得彼此靠近。在每一个去噪步里,这个文本嵌入都会通过注意力机制喂进 U-Net,于是噪声预测就被往「与你的话相符的内容」那一侧轻轻推。整张图,是*以提示词为条件*被雕出来的。
latent = random_noise() # start from static
for t in reversed(timesteps): # e.g. 50 steps
text = encode(prompt) # meaning of your words
eps = unet(latent, t, text) # predicted noise, nudged by text
latent = step(latent, eps, t) # subtract a sip of noise
image = decoder(latent) # latent -> full pixels (once)还有一个值得认识的旋钮:引导强度。你可以告诉模型,是该更紧地贴着提示词,还是更多地听从它自己对「什么样子才自然」的判断。调到很高,图像会死死咬住你的字眼,但可能变得艳俗、过饱和;调低一些,图会更柔和自然,却可能跑题、偏离你的要求。这里没有免费的午餐——它是一个真实的权衡,要凭感觉去调,而不是有唯一正确取值的开关。
编辑与超分辨率:同一个思路,换个条件
一旦你抓住了「去噪,并以某物为条件」这个核心,一整箱工具就打开了——你只需换掉模型*以什么*为条件。给它一张真实照片、把一块抠空,让它把那块区域补上(inpainting,局部重绘)。让去噪不从纯雪花、而是从一张现有图像「加了一半噪」的版本开始,它就会把图往你的提示词那边推、同时保住原有构图(图生图)。以一张边缘图或一具姿态骨架为条件,你就能精确掌控布局。去噪引擎本身从不改变;变的只是条件。
超分辨率又是同一招:让生成器以一张小而模糊的图为条件,请它产出一张更大、更清晰的图。但在这里,诚实非常要紧。模型并不是在*找回*已丢失的细节——那些信息根本就没了。它是在编造与低清输入相符的、看似合理的细节。那清晰的砖墙纹理、那被「锐化」出来的车牌,也许看起来很可信,却可能完全是虚构的。用来把照片修得更好看,没问题;可一旦有人把放大后的图当成「现场真的就是这样」的证据,那就危险了。
诚实的局限、瑕疵,以及炒作避而不谈的部分
这些模型令人惊叹,但它们不是魔法。它们没有任何关于物理或解剖学的模型——只有像素的统计规律。于是它们会画出六根手指的手、违背几何的倒影、打错方向的阴影、以及糊成「像字母的鬼画符」的文字。这些不是补个补丁就能修好的 bug;它们是从方法本身长出来的。模型给每一块区域填上*局部*看起来合理的东西,却没有一本全局账本去核对手指加起来是不是五根。更新的模型在这方面越来越好,但「更好」不等于「解决了」。
还有一个更深的局限。生成器只能从训练数据展示给它的那个世界里采样,因此它会继承那批数据的偏见——你点一个「医生」或「美人」,看看它默认会蹦出哪些面孔。它能混搭、能重组,却不会像营销话术暗示的那样、从无到有地凭空发明出真正崭新的风格。又因为同一套机器也能造出以假乱真的赝品,对图像生成诚实的描述就必须连它的阴影一起讲:深度伪造,以及一个至今悬而未决的活生生的问题——拿谁的图来训练它。
退一步看,整一阶就串起来了。你学过像素如何变成张量,卷积网络如何读它们,Transformer如何把各部件联系起来——而现在,你看到同样的积木倒着跑,就能从噪声里召唤出图像。「看」与「造」,原来是同一种本领的两个方向:一个真正学懂了视觉世界统计规律的模型,既能认出这个世界,也能小心翼翼地、把它梦回来。