初始化图像:扩散模型中被忽视的控制机制
来,我问你个事儿。
你肯定试过——同一个提示词,同一个模型,一模一样的步数和CFG,你连按钮都没多碰一下。结果呢?生成两张图,完全长成了两个样子。
一个把猫端端正正摆在椅子上,另一个直接把猫怼到角落里去了,跟自闭似的。一张色调冷得像冰窖,另一张暖得想泡杯热茶。
我以前一直觉得这事儿纯属玄学。跑图嘛,拼的就是手气。运气好了,一张封神;运气差了,熬到天亮全是废稿。
直到我花了一整个周末,硬啃了一篇全网没几个人读的论文。把代码跑了一遍又一遍,最后才找到问题出在哪儿——
那只被所有人当成“空车位”的初始噪声,根本不是什么空车位。 它是个攥着方向盘的老司机,一上车就决定了这辆车往哪儿开。你要逆着它的脾气来,图像就崩得跟车祸现场似的;顺着它的力道推一把,它指哪打哪,比谁都快。
今天,我就带你看清这场游戏的全部底牌。
1. 那个你以为的“随机噪声”,到底藏了什么?
2. 为什么换个种子,看起来就像换了个世界?
3. 图崩了的时候,我能不能给那个噪声“动个手术”?
4. 那些绕来绕去的“反转”技术,到底在逆天改什么命?
来吧,坐稳了。
一、你以为它空无一物?里面藏了一张完整的“草图”
先给结论,省得你没底:那个噪声,根本就不是空的。 它肚子里装的信息,多到让你怀疑人生。
我第一次复现论文实验的时候,手都有点抖。
很简单,我固定了一张随机初始噪声(就那64×64的小矩阵),然后用五个不同的提示词去跑。一句“a cat and a chair”,一句“a dog and a sofa”,一句“a bird and a table”……名词换来换去。
结果你猜怎么着?
一整行看下来,我直接愣住了。
同一个初始噪声,不管提示词怎么换,生成图片的整体构图和光源分布都呈现出惊人的相似性——猫在左上角,换成狗还在左上角,换成鸟还是蹲左上角。连暗部和亮部的区域都差不多。
然后换一行,换一张初始噪声。同样的五个提示词再跑一遍。这一回,位置全变了,物体一溜烟跑到了右下角,色调也变成了暗绿色。
我当时脑子里只有一个声音:这他妈才叫“随机噪声不是随机”。
它从根本上决定了你的构图、采光和画面重心,甚至每个物体最想落在哪儿。说得直白一点,初始噪声就像一张你看不见的草图,上面早已画满了形状的倾向和位置的偏好。
你以为你在画画?其实你只是在给一张草图上色。
后来我去翻了论文原文,他们的说法是“初始图像的生成倾向”——某些内容天生就更喜欢长在某些区域里。哪怕噪声来自标准高斯,这个倾向也霸道地存在。
用大白话讲,就像你去买一块毛料石头。有的石头适合雕马,马鬃飘逸;有的石头适合雕龙,龙爪虬劲。你要非拿雕马的石头去雕龙,也不是不行,但你得狠下心去掉一大块料子。最后出来的东西,总能看出点别扭来。
二、崩图的真相:是你的提示词,跟初始噪声吵起来了
说到这儿,我自己都心疼。
以前我跑图,一百张里至少有十几张,怪得离谱。猫趴在半空中,人物糊成一团,或者颜色跟中毒了一样,紫一块绿一块。
我一直以为是提示词写得不够好,要么就是模型今天心情不好在抽风。
结果论文告诉我:你错了,大错特错。
当初始噪声里自带的“倾向”跟你写下的提示词不一致的时候,模型当场就会陷入两难的尴尬。就像一个车有两个方向盘,你往左打,它顺畅转弯;你硬往右拽,它要么原地打转,要么直接翻沟里去。
我自己的例子最能说明问题。
提示词写的是“a cat on a chair”。我幻想猫舒舒服服窝在椅子上。结果生成的猫缩在画面左下角,椅子孤零零杵在右上角。
论文解释得清清楚楚:初始噪声里,椅子那块区域(就叫它B区域吧)的倾向根本就不是猫;而左下角的角落(A区域)反而非常倾向于出猫。模型左右为难,最后做了一个“聪明”的决定——把猫搁角落里算了,是椅子不对。
我以前只当是随机崩溃。做完实验后,我专门回去试了一下。固定那个初始噪声,换提示词“a dog on a sofa”。你猜怎么着?狗还是往左下角缩,一动不动。
石头没变,雕出来的位置就根本改不了。
所以我现在跑图的铁律是什么?连续三张都崩?换种子!直接换初始噪声! 不跟它较劲。非要跟一个倔脾气的老司机抢方向盘,那只能是自己遭罪。
三、你敢信?我亲自给噪声“动了个手术”
能,绝对能。但有个前提,你得做好心理准备。
扩散模型对初始噪声挑剔到了极点。它要求你的latent值必须严格服从标准高斯分布。你随便改一个像素值,整个分布就乱套了。模型像不认识你一样,要么生成全黑,要么生成全花。
别问我怎么知道的。我改坏了整整十几张图,那一刻才彻底死心。
那论文里到底是怎么做的?说出来你可能会觉得简单得不可思议——哪儿起了冲突,我就在哪儿重新抽一次奖。
还记得刚才那只猫的例子吗?猫就是喜欢往角落里缩,椅子那块区域怎么都容不下它。问题就出在两个区域“不对付”了。
解决方案呼之欲出:把A区域和B区域的latent值重新从标准高斯分布里抽一次。别的地方保持原状,然后重新跑一遍生成过程。
论文里roll了几次,就成功生成了一张猫稳稳当当坐在椅子上的图。
我当场按捺不住,直接在Stable Diffusion 1.5上,用Diffusers库自己去修改那个latent矩阵。具体怎么玩?先生成一张初始latent,随便跑几步;然后根据attention map(或者更粗暴一点:我直接肉眼观察,人工圈出错误区域)锁定冲突区域;接着对那个区域的latent重新初始化成新的随机高斯;其他地方锁定不动;最后从头开始跑一遍。
试了五次,成功了三次。剩下两次冲突转移到别的地方去了——你这边削掉一个硬疙瘩,旁边又冒出一个新的。
这事儿最让我着迷的地方是:你做的不是“编辑图像”,而是“编辑噪声”。 这比什么Inpainting、修复要底层得多。你在改变生成过程的起点,而不是修补结果的漏洞。
当然,你也别指望次次都成。后来我懒得手工roll了,直接写了个循环:每次出崩图,就让程序自动换种子,只保留那些consistent的。反正算力现在也不是什么稀罕东西。
四、那些“反转”技术,为什么非要绕一大圈不走直路?
你可能听过Null-text Inversion、Negative-prompt Inversion,还有RIVAL。名字一个比一个高深,都号称能把真实图像“反转”成latent,然后你想怎么编辑就怎么编辑。
我一开始觉得这不就一个求DDIM反向过程吗?有什么难的?
后来自己上手一试,气得差点砸键盘。反转出来的latent根本没法直接用——用它生成,结果跟原图总是有明显差距。要么风格走样得厉害,要么结构歪得能扭断脖子。
论文一针见血地点出了要害:分布不对齐。
模型在训练的时候,一向假定起始的latent是标准高斯分布。你一张真实的图,反向推到初始步,得到的绝对是一个奇形怪状的、不服从任何简单规律的复杂分布。这个“异常latent”被丢进U-Net后,模型当场就傻了——它这辈子都没见过这种噪声打底的输入。
RIVAL的方法就更直接了。它直接在推理阶段调整denoising chain,让每一步的latent都更贴近“正常”的反转步骤。我读他们论文的时候,脑子里只有一句话:这不就是我自己手动在那roll噪声吗? 只不过他们用算法来做,而且做得更精细、更高效。
所以现在如果有人让我推荐可控性高的方法,我会毫不犹豫地告诉他:先搞清楚你的初始噪声到底在说什么。如果你不想碰初始噪声,用RIVAL或者Direct Inversion;如果你只是想要控制一个构图,最简单的做法还是——换种子,或者手动换噪声区。零成本,谁都能做。
最后,几个你可能从来没想到过的坑
问:初始噪声里真的能存语义信息?
我猜是的。模型在训练的时候,已经把某些语义特征跟噪声里特定的模式锁死了。这有点像GAN里的“latent space walk”,只不过扩散模型更敏感。你甚至可以拿同一个初始噪声去生成完全不同主题,但你总会发现一些重复的结构——这本质上是一种“概率锚点”。模型在训练时就约定好了,某些噪声模式最适合生成什么。
问:为什么Stable Diffusion尤其吃种子?
因为它在潜空间里做扩散。64×64的latent,比原图小了太多,信息密度高得惊人。你换一个种子,就等于整个潜空间被重新排布了一次。影响不大才怪。
问:如果以后有种模型完全不依赖初始噪声,可能吗?
可能吧。有些非自回归的方法,比如Score-based模型,正在模糊初始条件的边界。但说实话,就目前这个阶段,去掉初始噪声,就等于少了一个控制构图的低成本杠杆。这未必是什么好事。
问:我最后踩的一个坑?
有一次,我用一张超美的初始噪声——是从我最喜欢的一张照片里反推出的——去生成了一组图。前几张都好得让人想哭。我以为自己找到“神种”了。结果到第七张,画面直接掉进恐怖谷,越看越瘆人。
后来我才发现,那个反转过来的latent,在我没注意的时候,被前向加噪声一点点污染了——DDIM反向过程不够精确,误差累积起来了。
所以,别迷信什么“通用种子”。 每一个任务,最好都重新挑一个。
说到这儿,你应该明白了。我之所以花这么大力气写这篇文章,是因为自己在这件事上扎进去折腾了整整一个多月。
初始化图像,就像相机的焦平面。 看起来只是个不起眼的小细节,但它决定了所有东西都落在哪里。你要是连这个都忽略了,那后面调prompt、调model、调sampler,都只是在同一个已经歪了的地基上修修补补。
下次出崩图,别急着骂AI。
先换个种子。
再说话。
读者评论 5