cv.cm

AI · AI基础

扩散模型(diffusion model)是怎么工作的?

阅读约 9 分钟

简短回答

扩散模型学会的是去除噪声。训练时,真实图片被一步步加上随机噪声,神经网络学习预测这些噪声。生成时,模型从纯噪声出发,在文字提示词的引导下,每一步去掉一点噪声,直到出现一张清晰的图片。目前大多数图像和视频生成器都是这样工作的。

一句话版本:先学会清理噪声,再去清理纯噪声

想象给一张照片加上一点随机的雪花点,再多加一点,一次次地加,几百步之后,画面只剩一片灰色的雪花。这个方向很容易,计算机一行数学公式就能做到。

扩散模型是被训练去走反方向的神经网络:看一张带噪声的图片,估计出加进去的噪声,然后把它减掉。如果网络在每个噪声强度下都做得好,你就可以从纯随机噪声出发,一步步把它清理干净。最后留下的,是一张从未存在过、却像是出自训练数据的新图片。

这一思路在2015年被提出,2020年的 DDPM(Denoising Diffusion Probabilistic Models)论文让它在高质量图像上变得实用。就目前而言,Stable Diffusion、FLUX、Imagen、DALL·E 一类的模型,以及 Veo、Kling、Runway、Seedance 等大多数视频生成器,都建立在这一系列方法或其近亲之上。

训练:前向过程与噪声预测器

训练使用数百万张图片,每张都配有说明文字。对每个训练样本,系统都做同一个小练习:

  1. 挑一张真实图片和它的说明,比如一张配文为“一辆红色自行车靠在砖墙上”的照片。
  2. 随机选一个噪声强度,从几乎清晰到几乎全是噪声都有可能。
  3. 按这个强度把图片和随机噪声混合。这就是前向过程,不需要学习。
  4. 把带噪声的图片、噪声强度和说明文字交给网络,让它预测加进去的噪声。
  5. 把预测结果和真实噪声对比,调整网络的权重来减小误差。

把这个过程重复数十亿次,网络就学会了图像在各种模糊程度下大致是什么样子:边缘通常在哪里,光线怎样落在皮肤上,自行车和砖墙长什么样。它并不会把训练照片当作文件存起来,学到的是关于它们的统计规律,这也是它能把从没见过的东西组合在一起的原因。

这个网络过去通常是 U-Net,一种图像网络。许多较新的模型改用 Transformer(常称扩散 Transformer,diffusion transformer)。一些近期的模型用流匹配(flow matching)来训练,这是一种密切相关的方法,学习从噪声到图像的一条直线路径。面向用户的概念,下面讲的都是一样的。

生成:反向过程,一次一步

点下生成之后,模型并不是画线条或拼贴局部,而是在跑一个循环:

x = random_noise(seed)                  # start: pure static
for t in noise_levels_high_to_low:      # e.g. 30 steps
    predicted_noise = model(x, t, prompt)
    x = remove_some_noise(x, predicted_noise, t)
image = decode(x)                       # latent -> pixels

前几步决定大的形状:主体在哪里,地平线在哪里,主要的颜色是什么。中间几步加上形体和光影。最后几步补上头发、布料、皮肤毛孔之类的细节纹理。这解释了几个实用的现象:步数调得太低,图像会显得平滑而没完成;换一个种子,起始的噪声不同,整个构图也就变了。

把噪声预测变成稍微干净一点的图像的那条规则,叫采样器(sampler)或调度器(scheduler)。DDPM 用的是很多个小步。后来的 DDIM 等方法表明,可以走更大的确定性步子,用少得多的步数得到相近的质量。所以现代工具只需要几十步,而不是一千步。

文字提示词如何引导图像

提示词首先由文本编码器转换成数字,文本编码器是一个经过训练、用来表示说明文字含义的语言模型。在去噪网络内部,一种叫交叉注意力(cross-attention)的机制,让图像的每个区域在每一步都能“看”提示词里的词。一块正在变成脸的区域,会关注“雀斑”或“微笑”这样的词。

光靠这种引导,力度比较弱。无分类器引导(classifier-free guidance)能把它加强:每一步,模型预测两次噪声,一次带着你的提示词,一次用空提示词,最终的预测再沿着两者之差的方向多走一段。走多远由引导系数(guidance scale,常称 CFG scale)决定。值越高,越贴近提示词,但画面可能显得生硬、过饱和;值越低,越自然,但可能无视提示词的某些部分。

如果工具支持反向提示词(negative prompt),它通常会取代第二次预测中的空提示词,图像会被推离这些词,比如“模糊、水印、多余的手指”。

为什么大多数模型在潜空间里工作

对全分辨率的图像去噪几百次会很慢。潜扩散(latent diffusion,Stable Diffusion 背后的方法)先训练一个自编码器,把图像压缩成小得多的一张数字网格,并能再还原回去,扩散模型就只在这张小网格上工作。比如每边压缩8倍,一张 512×512 的图像就变成 64×64 的网格,要处理的位置少了64倍。

每次生成的最后一步是解码器,它把清理好的潜变量网格还原成像素。图像出现奇怪的色斑,或小脸显得模糊时,解码器的压缩往往是原因之一,这也是主体在画面中占比更大时,人脸和小字会改善的原因之一。

视频扩散用的是同样的思路,再加上时间:潜变量是一叠帧,网络对它们一起去噪,使运动在帧与帧之间保持连贯。

常见参数究竟改变了什么

大多数生成器都会开放其中一些控制项。名称各异,机制是一样的:

参数控制什么实际效果
种子(Seed)起始噪声相同种子、相同提示词、相同设置,会得到相同的图像。换一个就能看到新的构图。
步数(Steps)去噪的次数太少会显得发软、没做完。超过某个点后,步数再多只是耗时,质量提升很小。
引导系数 / CFG scale提示词被执行的力度越高越贴合提示词,但可能显得生硬;越低越自然,但容易跑偏。
采样器 / 调度器每一步的规则影响速度和细节纹理。测试其他参数时,保持同一个采样器。
反向提示词要推离的内容适合去除反复出现的瑕疵。写一长串通常没什么用。
强度(图生图)给你的输入图加多少噪声低则保留你的布局;高则只保留大致的意思。
分辨率 / 宽高比潜变量网格的大小与训练尺寸相差太远,可能出现主体重复或身体被拉伸。

好的测试方法是先固定种子,每次只改一个参数。否则你分不清图像变好是因为你的改动,还是碰巧。

扩散与其他生成图像的方法

扩散不是唯一的方法。自回归模型把图像当作一串 token 依次生成,就像语言模型写文字那样,一些近期的多模态模型采用这种做法。例如,cv.cm 的 ai-image-generator 在你的浏览器里用 WebGPU 本地运行 Janus-Pro-1B(一个自回归模型),输出 384 像素的图片。它的设置手感也不同:没有扩散意义上可调的步数。

较早的 GAN(生成对抗网络)一次就能出一张图,速度很快,但更难训练,多样性也较差。扩散之所以成为主流,是因为训练稳定,能覆盖范围很广的图像。它的主要代价是速度,因为每张图都需要网络跑很多遍。蒸馏模型能把步数减少到寥寥几步,代价是多样性有所下降。

常见短板与应对办法

  • 手和手指:手有各种姿势,在训练照片里又常被部分遮挡,所以模型学到的是一个模糊的平均。尽量要求简单、看得清的手势,或者事后对手部做局部重绘(inpaint)。
  • 图片里的文字:模型把字母当作形状来学,而不是拼写。新模型已经好得多,但文字要短,在提示词里用引号括起来,并检查每个字母。重要的文字,事后用编辑器加上去。
  • 计数:“五个苹果”常常出来四个或六个。物体少一些更可靠。
  • 提示词串色:颜色和属性在不同主体之间串了,比如红帽子让衬衫也变红。用一句清晰的话描述每个主体,或者分开生成。
  • 照搬:模型有时会生成与知名或被反复引用的图像非常相近的复制品。如果需要原创作品,避免在提示词里写画家名字或品牌角色。

常见问题

Stable Diffusion 和扩散模型是一回事吗?

不是。扩散模型是一种通用方法,Stable Diffusion 是使用潜扩散的一个具体的开源模型系列。其他很多生成器也用扩散。

为什么同一条提示词每次生成的图都不一样?

每次生成都从不同的随机噪声开始,这由种子决定。如果固定种子,并保持其他设置不变,在同一款软件上就会再次得到同一张图。

扩散模型会保存训练图片的副本吗?

它们保存的是学到的权重,而不是图片文件。不过有研究表明,有些训练图片可以被几乎原样地提取出来,尤其是知名或反复出现的图片,所以在少数情况下确实可能出现近似复制。

为什么AI生成一张图要好几秒?

扩散模型每一步都要把庞大的网络运行一遍,每张图往往要几十次。更快的模型经过训练,只需较少的步数,在压缩的潜空间里运行也能节省时间。

CFG scale 设多少合适?

这取决于模型。许多较早的模型在取值范围的中间位置效果较好,一些蒸馏模型则需要很低的引导。先用工具的默认值,固定种子后,一点点地调整。

全部AI教程