6.5 扩散模型(三)DiT、Flow Matching与视频生成

1.从U-Net换到Transformer:DiT想要的是什么

说起来,前两篇我们讲扩散模型,一直默认它的去噪网络是U-Net。U-Net这种结构,3.4 节讲语义分割的时候我们提过,它的招牌是一条先下采样再上采样的对称路径,中间用跳着接的捷径(shortcut)把细节从浅层直接递给深层。这个设计在图像任务上确实好用,对局部细节也格外敏感,所以DDPM(Denoising Diffusion Probabilistic Models,去噪扩散概率模型)一路走来,几乎都是把它当骨干。

可是U-Net有一个绕不过去的短板,它不太容易靠堆规模变强。你想让它的通道数翻倍、层数加深,性能是会涨一点,但涨得不那么痛快,而且显存和计算的代价涨得比性能还快。这一点和语言模型那边的情形很不一样,3.4 节里我们讲过Transformer,它在大语言模型那边已经被反复验证过,参数加到几十亿、几百亿,能力还能继续往上走,这种放大就能变强的特性,英文里有个专门的说法叫scalable,可缩放。

DiT(Diffusion Transformer,扩散Transformer)做的就是这件事,把扩散模型里那个去噪网络从U-Net直接换成了Transformer。它的做法和ViT(Vision Transformer,视觉Transformer)很像,先把输入的隐图(latent image,潜空间里的图)切成一小块一小块的小图,每一块叫一个patch(图像块),每个patch再拍扁成一条向量塞进Transformer。Transformer里头就是一层一层的自注意力和前馈层,把所有patch当作一串token来处理。和DDPM原来的设定一样,它要预测的也还是每一步要去掉的那点噪声(或者说速度场,下一节会细讲),只是骨架彻底换了。

这里还有一个关键的小细节,就是条件怎么喂进去。扩散模型去噪的时候,得知道现在在第几步去噪,我们用时间步 tt 来表示这个步号,tt11 一路走到 TTTT 是总去噪步数。还得知道要生成什么样的图,也就是文本条件,比如一段提示词。DiT用的是一种叫adaLN(adaptive Layer Normalization,自适应层归一化)的技巧,把这些条件先融合成一个向量,再用这个向量去调制每一层归一化的缩放和偏移。这么一来,整张网络每一层都能清楚地知道现在在第几步、要往什么方向去。

DiT的论文(Peebles和Xie在2023年发的那篇)最打动人的结论,就是它拿实验数据明明白白地告诉大家,扩散模型的性能也服从缩放规律(scaling law)。模型变大、计算变多,生成质量就稳定地往上走,Gflops(十亿次浮点运算,这里指模型做一次推理总共要执行的浮点运算量)和样本质量之间有一条相当干净的曲线。说穿了,这一下就把扩散模型从精心调一个U-Net那种手艺活,带到了堆规模放大Transformer的赛道上,后面的故事基本都从这里展开。

2.Flow Matching:把生成看成一次平滑的流动

讲完骨干,我们换一个角度,看看训练目标这一边。前一篇我们讲DDPM,它的训练目标是让网络预测每一步加进去的那一点噪声 ϵ\epsilon,这里的 ϵ\epsilon 就是从标准高斯分布里采样出来的随机噪声。这个推导在数学上是严谨的,但路径走起来稍微有点绕,要先把前向过程定义成一串马尔可夫链,再借助变分推断把目标倒推出来。

Flow Matching(流匹配)给了一个更通用也更利落的角度。它的想法说起来很简单,就是把生成过程看成一次平滑的流动。我们手上有两个分布,一个是我们熟悉的简单分布 p0p_0,通常是标准高斯噪声,另一个是数据分布 p1p_1,也就是我们想要的图所在的地方(更准确地说,是隐空间里的图所在的地方)。我们想象在这两个分布之间搭一条连续的路径,用时间变量 tt 来描述走在这条路上的位置,这里的 tt 和上一节的时间步意思相通,只不过取值范围换成了从 00 平滑地走到 11t=0t=0 的时候还在噪声那头,t=1t=1 的时候就到了数据那头。

这件事不妨拿滴墨入水来打个比方。一滴墨刚落进清水里的时候,形状是模糊的一团浊(噪声那头),随着时间慢慢散开、流动,最后稳定成水里某种好看的纹路(数据那头)。Flow Matching要学的,就是这股推动墨水从浊到清一路流动的力,也就是这条路径上的速度。

最简单的搭法叫线性插值(linear interpolation),也常被称作最优传输路径。我们记 x0x_0 是从 p0p_0 采样的噪声,x1x_1 是从 p1p_1 采样的真实数据,那么在这条路径上任意时刻 tt 的中间状态 xtx_t 就定义为:

xt=(1t)x0+tx1x_t = (1 - t) \cdot x_0 + t \cdot x_1

这里 xtx_t 就是 x0x_0x1x_1 之间的一个线性混合,tt 越靠近 00 它越像噪声,越靠近 11 它越像数据。

接下来我们对 xtx_t 关于 tt 求导,就得到了沿着这条路径流动的速度:

ut=dxtdt=x1x0u_t = \frac{d x_t}{d t} = x_1 - x_0

这个 utu_t 就是速度场(velocity field),它告诉我们在任何一个中间状态、任何一个时刻,应该往哪个方向、以多快的速度走,才能从噪声平滑地流向数据。注意这里 utu_t 在线性插值下是一个常数(等于 x1x0x_1 - x_0),这正是最优传输路径的好处,路径走的是最直的那条。

Flow Matching的训练目标,就是用一个神经网络 vθ(xt,t)v_\theta(x_t, t) 去逼近这个真实的速度 utu_t,这里的 θ\theta 是网络的参数,vθv_\theta 就是我们学出来的速度场模型。损失函数的形式相当朴素:

L=Et,x0,x1[vθ(xt,t)(x1x0)2]\mathcal{L} = \mathbb{E}_{t, x_0, x_1} \left[ \| v_\theta(x_t, t) - (x_1 - x_0) \|^{2} \right]

这个 L\mathcal{L} 就是预测速度和真实速度之间的均方误差,E\mathbb{E} 表示数学期望,意思是在 ttx0x_0x1x_1 各自从各自的分布里采样后取平均,2\| \cdot \|^{2} 表示向量长度的平方。等到训练完,采样的时候也很直观,就从 x0p0x_0 \sim p_0 出发,这里的 \sim 表示服从某个分布采样,沿着网络预测出来的速度场 vθv_\theta 一路走,解一条常微分方程(Ordinary Differential Equation,ODE),走到 t=1t=1 就得到了一张想要的图。

这个框架最讨喜的地方,是它把扩散模型那一套稍微绕一点的马尔可夫链推导,换成了一个干净利落的最优化目标。而且因为路径可以选最直的那条,采样的时候不用走太多步,几步甚至一步就能跑出一个像样的结果,这点比起经典DDPM动辄要上千步要轻松得多。数学上Flow Matching和扩散其实是相通的,经典DDPM可以看作Flow Matching在某种特殊路径下的特例,只是Flow Matching换了个更顺手的写法。

我记得小张前阵子看了Stable Diffusion 3的技术报告之后跟我感慨,说他以前实现DDPM的采样器(sampler)的时候,被那一堆 αt\alpha_tβt\beta_tαˉt\bar{\alpha}_t 绕得够呛,这里的 αt\alpha_tβt\beta_t 都是DDPM里定义噪声调度(noise schedule,控制每一步加多少噪声的方案)的中间量,αˉt\bar{\alpha}_tαt\alpha_t 从1累乘到t的结果。换成Flow Matching之后,整个采样就只剩解一条ODE这一句话,清爽多了。

3.DiT加Flow Matching:新一代生成的标配

把上面两件事拼到一起,就是这两年图像生成的新标配,DiT当骨架,Flow Matching当训练目标。

这条路最早是Stable Diffusion 3蹚出来的。它把原来Stable Diffusion 1和2那套U-Net扔了,换成了一个放大的DiT。训练目标也从预测噪声 ϵ\epsilon 换成了预测速度 utu_t,也就是用了Flow Matching。文本条件那一边,它接的是4.10 节讲过的CLIP和T5这种大规模预训练的文本编码器,把提示词编码成一组向量,再喂给DiT去做条件化。三件东西这么一凑,整张图的生成质量稳稳地上了一个台阶,图片里直接写文字(比如画面里画一块写着HELLO的招牌)也比以前准了很多。

Sora(OpenAI的视频生成模型)走的也是这条路。说穿了,这两年凡是叫得上名号、能产出让人眼前一亮图像或视频的生成模型,基本都在往DiT加Flow Matching这套技术栈上靠。这件事背后是有道理的,我们下面慢慢说。

4.视频生成:把时间也切成patch

讲完图像,我们再进一步,看看视频怎么生成。视频说到底就是一串连续的图,每一帧是一张图,帧与帧之间还有时间上的连贯关系。如果只把每一帧单独生成,出来的视频就会一帧一帧地抖,人物上一秒穿红衣下一秒变蓝衣,根本没法看。所以视频生成真正的难点,是让模型同时理解空间上的内容和时间上的连贯。

Sora给出的做法很优雅,它把视频也变成了patch。3.4 节我们说过ViT把图像切成空间上的patch,Sora做的事情是把视频切成时空上的patch(spacetime patch,时空块),也就是说,不仅在画面的长和宽上切,还在时间维上切。一小段时间内、画面上一小块区域的内容,打包成一个token。一整段视频,就成了一个长长的token序列。这个表示有个好处,它把图像和视频统一了起来,一段视频和一张大图,从模型角度看都是一串token,只不过视频的token更多一些。

有了这个统一的表示,剩下的就好办了。还是DiT当骨干,还是Flow Matching当训练目标,先在大规模的视频和图像上做联合预训练,让模型先把这个世界大概长什么样这件事学个大概,再用少量精标的数据做微调。采样的时候,从一段标准高斯噪声开始,噪声的形状和目标视频的token序列一样,沿着学到的速度场一路走,走到 t=1t=1 就得到了一段完整的视频。

这里不妨打个比方。我之前看过一部讲电影特效的纪录片,里头讲早期的逐帧动画,每一帧都靠动画师一笔一笔画出来,画到后面整个动作的节奏就接不上了,人物的动作一卡一卡的。后来的做法是先把角色的关键动作建模成一个三维的骨架,再让电脑去补中间的过渡帧,节奏自然就顺了。Sora这种时空patch的做法,有点像后者,它学的是整段视频在时空上的流动方式,单帧长什么样反而不重要,所以能产出几秒到十几秒的连贯长镜头,物理上也相对合理,比如一个人走过一面镜子,镜子里还能看到他的倒影。

5.走向统一:和语言模型越来越像

写到这儿,我们不妨站远一点看看这条线的意义。

最早VAE(变分自编码器)和GAN(生成对抗网络)那一拨,每个方法都有自己的专属架构。VAE靠编码器加解码器,再加上1.4 节讲过的KL散度(Kullback-Leibler divergence,衡量两个分布差异的量)来训练。GAN靠生成器和判别器两边对抗来训练。后来DCGAN、StyleGAN把GAN的生成器做得很精巧,DDPM把U-Net推上了王座,每一种生成路线都有自己的专属零件,彼此不太通用。

可走到DiT加Flow Matching这一步,事情悄悄变了。骨干网络变成了Transformer,这和大语言模型是同一套东西。训练目标变成了回归一个连续的速度场,采样变成了解ODE,整套数学和大语言模型预训练那种预测下一个token的方式,在工程上可以共享很多基础设施,连条件输入用的CLIP、T5也是和语言、多模态那边共用的。说穿了,生成模型正在从一套专门为图像调出来的手艺活,慢慢长成Transformer大家族里的一个分支。

这件事的工程意义非常大。以前做一个图像生成团队,得自己维护U-Net的工程、自己调DDPM的采样器、自己写噪声调度的代码。现在这些东西都可以和大语言模型的训练栈共用,注意力怎么算、Transformer怎么并行、显存怎么切,这些底层问题的答案在两边是通用的。所以这两年大家常说的统一架构(unified architecture),说穿了就是这个意思,不同的生成任务,最后都收敛到了同一套Transformer加Flow Matching的组合上。

我记得看过一本讲工业革命的书,里头说早期的工厂每家都自己造机器、自己定零件规格,后来螺纹、齿轮、螺栓全行业统一了标准,整条产业链一下子就起来了。生成模型这两年走的,大概也是这样一条路,从各自为战的手艺活,慢慢走向一套通用的底座。

今天的DiT、Flow Matching和视频生成就先讲到这儿,下一篇我们再聊聊这条统一架构线往前走会遇到什么新的难题。

练习

Q1. DiT为什么把扩散模型的去噪网络从U-Net换成Transformer?换完之后最大的好处是什么?

因为U-Net不太容易靠堆规模变强——通道翻倍、层数加深,性能涨得不痛快,显存和计算代价却涨得比性能还快。Transformer在大语言模型那边已被反复验证过,参数加到几十亿、几百亿能力还能继续往上走(scalable,可缩放)。DiT把隐图切成patch当token塞进Transformer处理,最大的好处就是让扩散模型也服从缩放规律:模型变大、计算变多,生成质量就稳定往上走,从"精心调一个U-Net的手艺活"带进了"堆规模放大Transformer"的赛道。论文用Gflops和样本质量之间那条干净曲线证明了这一点。

Q2. Flow Matching把生成看成一次"平滑的流动",线性插值路径下 xt=(1t)x0+tx1x_t=(1-t)x_0+tx_1 对应的速度 utu_t 是什么?训练目标长什么样?

线性插值下对 xtx_t 关于 tt 求导,ut=dxtdt=x1x0u_t=\frac{dx_t}{dt}=x_1-x_0,是个常数(这就是最优传输路径,路径走最直的那条)。训练目标就是用一个神经网络 vθ(xt,t)v_\theta(x_t,t) 去逼近这个真实速度,损失是均方误差 L=Et,x0,x1[vθ(xt,t)(x1x0)2]\mathcal{L}=\mathbb{E}_{t,x_0,x_1}[\|v_\theta(x_t,t)-(x_1-x_0)\|^2]。训完采样时从噪声 x0p0x_0\sim p_0 出发,沿着学到的速度场 vθv_\theta 解一条常微分方程(ODE)走到 t=1t=1,就得到想要的图。

Q3. 易错点:Flow Matching和经典DDPM是不是两套完全不相干的方法?

不是不相干,数学上两者是相通的,经典DDPM可以看作Flow Matching在某种特殊路径下的特例。区别在于表述角度:DDPM把前向过程定义成一串马尔可夫链、再借变分推断把目标倒推出来,路径走起来稍微绕,采样动辄上千步;Flow Matching换了个更通用利落的写法,把生成看成两个分布(噪声 p0p_0 和数据 p1p_1)之间的连续流动,路径可选最直的最优传输,采样时解ODE、几步甚至一步就能出结果,比经典DDPM清爽得多。所以Flow Matching没有推翻扩散,而是给了一套更顺手的统一框架,新一代生成模型(Stable Diffusion 3、Sora)基本都换成了DiT+Flow Matching这套组合。

相关标签
深度学习生成模型DiTFlow Matching