扩散模型:从噪声中显影
Ho, Jain, Abbeel · UC Berkeley · NeurIPS 2020 · arXiv:2006.11239
这篇论文的正文里堆满了吓人的符号——βt、ᾱt、变分下界、马尔可夫链。你一个都不用记。你只需要会做一件坏事:把一张图弄脏。因为这篇论文的全部秘密就是——破坏很容易,而它教会了机器把破坏倒着放。今天 Midjourney、Stable Diffusion、DALL·E 画出的每一张图,都是从一片雪花噪声里一步步显影出来的。这门显影的手艺,就从你亲手毁掉一朵花开始学。
先把这朵花毁掉
这是我们的主角:一朵 20×20、总共 400 个像素的粉雏菊。接下来整篇文章,它(和它的几个亲戚)都会陪着你。现在请你干点坏事——把滑块往右拖。每往右一点,我们就往每个像素里掺一点高斯噪声「就是电视机没信号时的那种雪花」:
注意两件事。第一,破坏得比你想的快——滑到一半,花就快认不出了。第二,没有任何像素被"删除":它们只是被越掺越多的随机数淹没,右边那根"残留信号"的条子一路缩水。拖到头,信号归零——此刻这团雪花,和世界上任何一张图加噪到底的结果,在统计上一模一样,不藏任何"这里曾有一朵花"的密码。
前向过程「加噪」没有任何智能:往图里掺随机数,掺到底,谁来掺都一样。论文管这叫扩散(diffusion)——像一滴墨水在清水里散开,散匀了就再也分不出墨和水。掺噪的节奏由一张事先定好的时刻表控制:每一步只掺一点点,总共一千步。你刚才拖的滑块,就是把这一千步压成了一条轨道。
然而,这篇论文问的是反问题:这条路,能倒着走吗?
倒着走,但不是倒放
你的第一反应可能是:倒放录像不就行了?不行。倒放需要手里有原图,或者每一步的完整记录——可机器拿到的只有那团人人平等的纯雪花。它要做的不是"恢复",是无中生有地长出一张新图。这更像暗房里的显影师傅:药水一遍遍过,影像从空白相纸上一层层浮出来——先有轮廓,后有细节。
把滑块从左(纯噪声)拖到右(成品),看一次显影的全过程:
注意显影的顺序:先是一团模糊的暖色(大轮廓),然后花瓣的结构,最后才是锐利的边缘——和暗房里一样,低频先来,细节殿后。再看右边那朵小小的对照图:显影到头,你得到的不是你毁掉的那朵粉雏菊,是一朵金色的向日葵。
反向过程「显影」不是倒放,是生成:从噪声出发,长出一张前所未见、但同样合理的图。
然而凭什么?每一步,机器怎么知道该把哪个像素往哪边挪?论文的答案简单得让人愣住。
网络的全部工作:找出噪声
玩个游戏你就懂了。下面这张粉雏菊被人动了手脚:12 个像素被偷偷换成了随机颜色。点击你认为被污染的像素(点错了再点一次就能取消),标记完按「揭晓」:
这正是论文最漂亮的一步简化:反向过程本来要学一个吓人的概率分布,作者把它化简到最后,训练目标只剩一句话——给你一张噪图,猜出加进去的噪声 ε。猜噪声,比直接画一幅画容易学得多。
想看这句话对应的真实公式?(可跳过,不影响后面)
前向加噪有个漂亮的闭式解:想直接跳到第 t 步,不用一步步掺,一次到位——
xt = √ᾱt · x0 + √(1−ᾱt) · ε,其中 ε ~ N(0, I)
x0 是原图,ᾱt 是一个从 1 缓缓降到 0 的调度表(§01 里那根"残留信号"条显示的就是 √ᾱt)。训练时随机挑一个 t、随机抽一把噪声 ε 掺进去,让网络 εθ 看着 xt 和 t 把 ε 猜出来,损失函数就是最朴素的均方差:‖ε − εθ(xt, t)‖²。论文推了三页变分下界,最后发现把各种权重系数统统扔掉、只留这一项,效果反而最好——这就是标题里 Denoising(去噪)的含义。
还有一个漂亮的等价关系:把上面的式子倒过来解 x0,得到 x0 = (xt − √(1−ᾱt)·ε) / √ᾱt。也就是说,猜出了噪声,就等于猜出了原图——两种说法在数学上是同一件事,论文选"猜噪声"只是因为这个形式训练起来更稳。
且慢——既然网络能猜出噪声,那从纯雪花直接"减掉全部噪声"、一步跳到成品,不就完了?为什么还要磨蹭一千步?
一步登天,为什么不行
问题出在起点。§01 结尾你已经看到:纯雪花里不藏任何密码——所以从同一团噪声出发,显影下去可能是粉雏菊,也可能是向日葵、紫铃兰。让网络一步给出答案,它拿不准押哪个,只能押"所有可能的花的平均"——而一堆不同的花摞在一起取平均,是一团浆糊。就像让你"一笔画完一幅画"和"先起稿、再勾线、再上色"的区别。
按「开始生成」,让两种走法从同一团噪声出发比一场:
左边瞬间就"完成"了——但那团模糊的粉浆糊,你说得出它是什么吗?右边慢吞吞地走,可每一步只需要回答一个小问题:"当前这张图里,噪声是什么?"每擦掉一小步,可能性就收窄一点:先定下"是朵花",再定下"花瓣朝哪",最后定到每一根边缘。小步稳走赢在每一步都简单:预测一小步的噪声学得会,一步预测整个成品学不会。
为什么"平均"注定是浆糊?一道两像素的小算术(可跳过)
想象图只有 2 个像素,而世界上只有两张合法的图:[黑, 白] 和 [白, 黑],各占一半概率。让网络从纯噪声一步预测成品,用均方差训练时,它的最优答案是所有可能答案的平均——[灰, 灰]。可 [灰, 灰] 根本不是合法的图,它谁也不是。这就是左边那团浆糊的数学本质:均方差的最优解是"期望",而多种可能并存时,期望往往落在所有可能之外。
逐步走没有这个毛病:走第一小步时随便偏向某一边一点点,后面的每一步都会把这个微小的选择越滚越实,最后落在 [黑, 白] 或 [白, 黑] 之一上——落在哪个,由起点噪声决定。§06 的骰子,掷的就是这个。
然而一千步意味着一千次完整的神经网络计算。慢,是扩散模型与生俱来的原罪。这个代价到底多大、能砍到什么程度?
一千步的账单
生成一张图的耗时几乎就是一道乘法:步数 × 每步跑一遍完整网络。想快,只能砍步数。往右拖,把一千步往下砍,看画质和速度怎么讨价还价:
从 1000 砍到 250、甚至 100,画质几乎没掉——后来的加速工作(DDIM 等)正是靠这类观察把采样提速了一个数量级。但砍到 20 步、10 步,麻烦来了:步子太大,每一步"擦过头"和"没擦净"的误差没机会被后面的步子修正,残余的噪点和糊掉的细节就留在了成品里。
步数是画质与速度之间那个可以讨价还价的旋钮——但 2020 年的这篇论文里,它还老老实实停在 1000。
还剩最后一个疑问。模型训练好了、步数也定了,它每次生成的会不会都是同一朵花?
多样性藏在起点里
§02 里那朵意外的向日葵已经剧透了答案。现在把它变成一个你能反复按的按钮——掷骰子,换一团起点噪声:
多掷几次。同一个模型、同一套参数、同样的走法,只因为起点那团雪花不同,落地的花就不同——颜色、花瓣数、姿态全变了。回想 §01 的结尾:任何图加噪到底都汇入同一片统计意义上的纯噪声;反过来,从这片噪声里每随机抽一次样,就是通往一张不同新图的入口。
生成的多样性不来自模型的"心情",来自起点噪声的随机性。Midjourney 里那个神秘的 seed 参数,就是这团雪花的编号——编号一样,花就一样。
零件齐了:加噪(你在 §01 干过)、猜噪声(§03 玩过)、小步显影(§04 看过)、随机起点(刚刚掷过)。拼起来。
组装时刻:两个循环
整篇论文的工程实现,就是两个循环。点「▶ 走一遍」,看你摸过的零件怎么咬合:
看清了吗——训练循环里没有"画画"这回事:拿真图、随机加噪(§01)、让网络指认噪声(§03)、按差距调参数,仅此而已。采样循环里也没有"理解"这回事:把指认出的噪声擦掉一小步,重复一千次(§04 的右边),起点由骰子决定(§06)。两个循环靠同一个网络咬合:训练时学会的每一次指认,采样时都兑现成显影的一小步。
两个循环都转起来之后,剩下的问题只有一个:这台显影机,究竟能开到多大?
从暗房到 Midjourney
2020 年,Ho、Jain 和 Abbeel 在这篇论文(Denoising Diffusion Probabilistic Models,DDPM)里把一个 2015 年就有的想法——用非平衡热力学的思路做生成——修剪到了惊人的简洁:训练目标砍到只剩"猜噪声"的均方差,图像质量第一次追平了当时称霸的 GAN。此后的故事你已经在用了:把这套显影搬进压缩过的潜空间,就是 Stable Diffusion;在显影的每一小步用文字提示去偏置"猜噪声"的方向,就是文生图。你在 Midjourney 里敲下一句咒语时,后台发生的正是你今天拖过的那根滑块:一团带编号的雪花,被一个只会指认噪声的网络,一小步一小步地擦成一幅画。
杠精角落:三个最常见的质疑,每条都值得问
"这么慢,凭什么赢当时的 GAN?"——慢在生成,不慢在训练。GAN 要两个网络互相博弈,训练一言不合就崩(模式坍缩是家常便饭);扩散模型的训练就是 §03 那道猜噪声的回归题,稳得像做习题册。但采样慢确实是软肋,原论文没有解决它——你在 §05 亲手量过这笔账,把它砍下来是之后几年(DDIM、蒸馏)的故事。
"这不就是个去噪自编码器?"——血缘确实近,论文自己也认。区别在于它学的不是"一步擦干净"——§04 你已经亲眼看到那只能得到浆糊——而是全部一千个噪声档位上的"擦一小步",并且把当前档位 t 也告诉网络。一个网络,一千种脏度,各有各的擦法。
"Midjourney 是文生图,文字在哪?"——不在这篇论文里。DDPM 只管"无条件"地长出合理的图,本文也只讲了这条主线;用文字提示给每一小步的方向"带偏",是两年后 classifier-free guidance 的故事。但那套引导恰恰长在你今天摸过的底盘上。
最后留一分钟给这个思想本身,它值得。生成一张"好图"是个没法直接定义的目标——好在哪里?像什么才算像?没人写得出这个损失函数。这篇论文的迂回堪称漂亮:我们不知道怎么定义创造,但我们精确地知道怎么破坏——那就让机器学破坏的逆过程。你在 §01 里随手拖出来的那条毁灭之路,每一小段都自动成了一道有标准答案的练习题(噪声是我们自己掺的,所以答案免费);四百万道这样的题做下来,机器就学会了倒着走完全程。破坏是免费的,而免费的破坏,定义了昂贵的创造。
下一次你看到一张 AI 生成的图,可以想起你亲手毁掉的那朵粉雏菊,和从另一团雪花里长出来的那朵向日葵——从噪声到图像的这条路,你已经双向走过一遍了。