0%

近期何恺明团队的论文提出了一种叫做 Just image Transformers (JiT) 新式 DiT (Diffusion Transformer)。它的核心思想是:如果让扩散模型的预测目标从速度变成清晰图像,我们就能成功训练出一个像素空间 (pixel space) 的高分辨率 DiT,且无需对 DiT 结构做复杂的改进 。我这段时间也在做像素空间的 DiT,对这篇文章很感兴趣,立刻在我的实验环境下复现了 JiT。结果发现,我没能正确理解文章的贡献:JiT 论文表明,仅仅在 Transformer 的 patch size 较大 时,预测清晰图像才比预测速度更好。

在这篇博文中,我不会按照原论文的叙述逻辑,而是会根据我对这个领域的理解和实验过程,来逐步讲解 JiT 论文的发现,并给出我自己的分析。

高分辨率扩散模型的探索

最早的扩散模型

自从被提出以来,扩散模型最遭人诟病之处就是它的计算效率:无论是训练和推理,扩散模型都比之前的 GAN 要慢很多。这可以从早期的 ADM 模型的实验表格中反映出来。ADM 模型出自大名鼎鼎的论文 “Diffusion Models Beat GANs on Image Synthesis”,这篇论文在扩散模型奠基之作 DDPM 的基础上对 U-Net 去噪网络略加优化,并提出了 Classifier Guidance 这种优化带约束生成 (conditional generation) 质量的方法。基于这些改进,论文在 ImageNet-256 上训练了一个进阶版 DDPM,也就是 ADM。它的结果如下,其中 Compute 的单位是 1 个 V100 运行一天能完成的计算量。

我们可以主要看 Total Compute 和 FID 这两列。最好的 ADM 要花 962 个 V100 天才能训练出一个 FID = 5.25 的模型。而现在,有了 latent space 的 DiT 后,哪怕是学校实验室的研究者也可以用一个多卡主机在一周内训练出一个 FID = 2 左右的模型。可见,早期扩散模型的学习效率是很低的。

LDM

为了提升扩散模型的推理和训练效率,Latent Diffusion Models (LDMs) 将之前 VQVAE, VQGAN 的两阶段生成方法引入了扩散模型中。LDM 会先训练一个能够压缩和复原图像的 VAE,再训练一个生成 VAE 潜空间 (latent space) 里的潜图像的扩散模型。由于潜图像的元素数远少于像素图像的元素数,LDM 的训练十分高效。

后续的 DiT 工作将 LDM 里的 U-Net 升级成了 Transformer。DiT 的名字虽然叫 Diffusion Transformer,但这篇论文依然沿用了 LDM 的两阶段设计,准确来讲它是一个 latent Diffusion Transformer。

在 DiT 论文的 ImageNet-256 benchmark 表格中,我们能看到 LDM 比像素空间的 ADM 更好,而用了 Transformer 的 DiT 比用 U-Net 的 LDM 更好。

像素空间扩散模型的后续研究

LDM 虽然大大提升了扩散模型生成高分辨率图像的效率,但它并没有解决用扩散模型生成长序列这件事——因为 LDM 是通过减少潜图像序列的长度来提升效率的。但当输入序列变长,比如要生成视频时,我们仍然绕不过长序列生成这个问题。因此,继续研究像素空间的扩散模型仍有价值。

为什么像素空间的 ADM 的生成质量不够好呢?后续研究发现,为了让扩散模型每个时刻的信噪比不随序列长度变化,随着输入序列长度的增加,应该逐步增强噪声。如下图所示,同样添加标准高斯噪声,观察第一行 $64 \times 64$ 的带噪图像和第二行 $128 \times 128$ 带噪图像 average 下采样 2 倍后的输出,我们发现 $128 \times 128$ 明显看起来噪声更少,信息更多。这时,给噪声 $\times 2$ 后,它的信噪比就和 $64 \times 64$ 时差不多了。

像素空间扩散模型 Simple Diffusion (SD) 以及 Simple Diffusion 2 (SiD2) 基于这一观察,调整了加噪的方式。此外,它们也把 U-Net 升级成了和 Transformer 更像的 U-ViT。最终,SiD2 在 ImageNet-256 benchmark 上取得了很不错的表现。

现在主流扩散模型主要参考了 Stable Diffusion 3 (SD3) 的噪声调整方式,会使用 logit-normal 采样而不是均匀采样来获取训练时的 t。

Pixel DiT

在前面的对比实验中,我们发现,在潜空间里 Transformer 比 U-Net 好。而之前像素空间的工作都用的是 U-Net,能否在像素空间里也用 DiT 呢?实际上,在 2025 年 10 月之前,研究 Pixel DiT 的工作非常少。这是因为 Transformer 的计算复杂度很大,我们必须用某种方式来压缩输入序列。但这些压缩往往会严重影响生成质量。

说起压缩序列,最常见的做法是 ViT 里的 patchify 操作:输入时,对图像做步长为 $p$ 、卷积核大小 $p \times p$ 的卷积,即把每 $p \times p$ 个像素过一个线性层压缩成一个 token (这里的 $p$ 被称为 patch size)。在输出时,用一个线性层让每个 token 的输出通道数为 $p \times p \times 3$,再把一个 token 还原成 $p\times p$ 个像素。这个操作是否可行呢?

DiT 论文发现,当参数 $p >= 4$ 后,DiT 生成质量会出现明显下降。因此,自 DiT 之后,所有的大型扩散模型几乎都将 $p=2$ 作为默认设置。

然而,仅将输入序列压缩 $2\times 2$ 倍,高分辨率像素图像的元素数还是太多了,DiT 的运算速度会非常慢。此前尝试在像素空间训练 DiT 的文章有 PixelFlow 和 PixelNerd。PixelFlow 照搬了 f-DM,PyramidFlow 的多阶段加噪方式,让扩散模型在生成时从低分辨率图像开始,一边去噪,一边做上采样。基于这一设计,PixelFlow 成功训练了一个 $p=4$ 的 DiT。PixelNerd 则认为,patchify 对输入的处理没问题,但将 token 还原成 pixel 的过程可以优化。因此,PixelNerd 用了一个类 Nerf 的网络来解码像素值,而 DiT 仅作为一个 encoder。最终 PixelNerd 训练出了一个 $p=16$ 的 DiT。

这两个工作都对原来的 DiT 做了不少改进。能不能进一步简化,直接在 ImageNet-256 上训练一个 $p=16$ 的普通 DiT 呢?这就是 JiT 要解决的问题。

Pixel DiT 动机总结

早期像素空间的 ADM 效果不够理想。LDM 通过加入潜空间来提升训练效率与生成质量,但它只是绕过而不是解决了长序列生成问题。ADM 的改进方向有两个:1)改进长序列下的加噪方法;2)从 U-Net 升级成 DiT。前者已经被成熟研究并广泛用于当前的大型扩散模型了。而 Pixel DiT 的研究还不够多,其瓶颈在于 patch size 过大时 DiT 生成质量会严重下降,必须加入一些额外的设计。而 JiT 试图训练一个不带任何额外设计,且 patch size 较大的 pixel DiT。

扩散模型预测目标

JiT 做的事情可以用一句话概括:把 DiT 的预测目标从 $v$ 换成 $x$。熟悉扩散模型的研究者可能一眼就能看懂这句话是什么意思。当然,为了让人人都能看懂,在这一章里,我们将在如今最常用的 rectified flow 噪声调度器下,回顾扩散模型的三种预测目标及其相互转换方式。

目前最常用的 rectified flow 加噪公式为

其中,$x$ 是清晰图像,$\epsilon$ 是高斯噪声,$z_t$ 是 $t$ 时刻的带噪图像。注意,和早期的 DDPM 相反,这里时刻 0 时图像为纯噪声,时刻 1 时图像为清晰图像。而早期我们用 $x_t$ 来称呼带噪图像,并用 $x_0$ 指代清晰图像。这个公式非常简单,就是清晰图像和噪声之间的线性插值。

为了方便理解,我们将所有图像画成一维数轴上的点。但实际上它们是在高维空间里的。扩散模型的学习目标可以简单解释为:我们现在有一个高维空间里的点 $z_t$,该怎么找到终点 $x=z_1$ 呢?

扩散模型的神经网络主要有三种预测目标:噪声 $\epsilon = z_0$,清晰图像 $x = z_1$,以及两者之间的速度 $v = x - \epsilon$。因为两点确定一条直线,而我们又知道了当前点在哪,所以只需要再知道直线上的一个量,就知道了直线的所有信息。以论文中用到的方法为例,我们来看已知 $z_t, x$ 时该如何求 $v$。

已知 $z_t, x$,我们就能求出它们之间的位移 $v’=x-z_t$,并知道该向量的模长为 $1-t$。而 $v$ 的方向相同,模长为 $1$。因此,我们可以求出 $v=(x-z_t)/(1-t)$。

JiT 方法实现

尽管我们知道扩散模型的三种预测目标之间可以转换,但神经网络学习预测三种目标的难度是不同的。JiT 认为,在设计预测目标时,有两个设计空间:1)让神经网络输出哪个预测目标;2)让哪个预测目标求 l2 loss。由于网络输出的目标之间可以互相转换,所以第一步和第二步可以用不同的预测目标。还是拿刚刚的例子,假设我们预测 $x_\theta$,但是要用 $v_\theta$ 求 loss,我们就先让网络输出 $x_\theta = \text{net}(z_t, t)$,用 $v_\theta=(x_\theta-z_t)/(1-t)$ 求出预测的速度,再对 $v_\theta$ 和 $v$ 求 loss。

如下面的消融实验结果所示,预测 x,使用 v-loss 是最优的。

JiT 的主要改动就是以清晰图像为预测目标,其他改动的影响相对没那么大。我简单列举一下其他的改动。

噪声强度偏移。如前文所述,对高分辨率图像得加更多的噪声。JiT 使用了 SD3 的 logit-normal t 采样技术。这一改动也能大大降低 FID 指标。

Bottleneck 嵌入层。原来 DiT 在将输入通道数变成模型通道数时,只会用一个普通的线性层。而 JiT 把它换成了一个双层 bottleneck 结构:先降维,再升维到模型通道数。这个模型设计上的小改动也能提升生成质量。

现代 DiT 结构。JiT 参考之前的 LightningDiT (即提出了 VAVAE 的论文),对 DiT 的模块进行了改进,使用了 SwiGLU, RMSNorm,并将位置编码换成了 RoPE,还加入了 qk-norm。

针对 class condition 的优化。 JiT 参考同组工作 MAR,将单个类别 token 拓展成了 32 个类别 token。此外,JiT 还用了一种叫做 CFG interval 的技术,能够提升 CFG 的采样质量。

最终训练出来的 JiT 在 ImageNet-256, ImageNet-512 上都取得了不错的结果。

实验分享

到目前为止,我仅仅是重述了 JiT 论文的内容,并没有对其内容做进一步分析。在这一章,我会分享我复现论文时一些有趣的经历,并基于我的实验结果进行分析。

代码实现

在我的训练环境里,我已经准备好了 FFHQ-128 数据集及一个加入了 RoPE 的流匹配版 DiT。我想快速验证一下预测清晰图像这件事能带来多大的提升。恰好,JiT 论文正文给出了 Python 风格的伪代码简明实现,我就直接把它搬进我的代码了。如果已经准备好了 v-prediciton 的训练环境,只需要按照下图红框所示,稍微改几行代码,就能预测清晰图像并启用 v loss 了。

改完之后,我碰到的第一个问题是 loss 出现 NaN。我敢保证这个代码库没有问题,那么出问题的应该是数据范围。我仔细审视了被改动的代码,发现将 x-prediction 转成 v-prediction 时,会出现 / (1-t) 这个操作。假设取 1000 个扩散模型训练步数,那么 t 的范围是 [1/1000, 1]。这就会让某些 t 的 loss 出现乘 1000 倍的操作,进而导致数值爆炸,出现 NaN。

经验告诉我,应该像梯度裁剪一样,把这个权重设一个上限才行。我只好去翻看了 JiT 的 PyTorch 官方实现代码,果然看到了下面的操作:

1
/(1-t).clamp_min(5e-2)

也就是说,分母最小是 5e-2,乘的权重最大是 20,这样梯度不会炸掉。关于这样改动的合理性及其背后的影响,我会在后文分析。

改完这个 bug 后,模型总算训起来了。但是,模型在采样时永远只能生成纯黑的图片。这又是哪错了呢?为了确保论文里的速度和我代码库的速度的定义一致,我自己推导了一遍 x 和 v 的转化公式。最后发现,速度的定义没错,论文里 t 的定义和我这里是反过来的!我用的 Diffusers 库坚守 DDPM 的老传统,把 t=0 当成清晰图像,t=1 当成纯噪声。不知道哪个发明流匹配的人硬生生把这个定义反了过来。太烦人了!

改完这两个 bug,模型总算是成功训出来了。

实验结果分析

实验结果显示,x-prediction 比我之前用的 v-prediction 差得多得多!这是论文有问题吗?我只好回头认真阅读了几遍论文。我在粗略地看了一遍论文后,认为论文的主要主张是「高分辨率像素 DiT 用 x-prediciton 更优」。于是,我在 $128\times128$ FFHQ 数据集上训练了一个 p=1 的 DiT-S 。既然没有复现出论文的结果,那多半是我的配置有点问题。比对过后,我发现我配置上的主要区别是 p。按照论文里将输入序列缩减到 $16 \times 16$ 的做法,我在边长 128 的数据上采用了 p=8 的配置。这下总算复现出了论文的结果。

如下图所示,_base 指的是用 v-predition 的 baseline,_x0 指的是 JiT 最终采用的 x-prediction + v loss。我这里输出的是 1000 个样本的 FID 指标 (越低越好)。训练一共执行 200 个 epoch,batch size 为 256。

这样看来,我对论文的结论理解似乎有误。论文的真正结论应该是「大 patch size 的 DiT 用 x-prediciton 更优」,和分辨率究竟多大,以及是否是像素 DiT 无关。

为了进一步验证我的结论,我做了 p = [1,2, 4, 8] 在 baseline 和 JiT 配置下的 8 个实验。各个实验的 Batch Size 及训练量如下所示:

首先,我们先来复现一下 DiT 的结论:p=2 时,模型的质量尚可接受。再增加 p 则会大大降低模型质量。相关的图表如下所示。(由于我在 p=2,4 时训练了两个阶段,图表会比较杂乱,还望见谅)

先看一下 p=1,2 时的对比。从曲线上看,二者几乎是重合的。但由于 p=2 时 batch size 是 p=1 时的两倍,所以训练的数据量相同时,p=1 还是最优的。我之前有一个训了更久的 p=1 的模型,FID 差不多就是 43 左右,而图中训了 40 个 epochs 的 p=2 模型 FID 为 43.94。也就是说,充分收敛时,p=2 确实不太会影响生成质量。

再增加 patch size 的话,情况就不一样了。p=4 训 80 个 epochs 还比不过 p=2 训 20 个 epochs 的质量。而 p=8 时,几乎看不到能收敛的希望。

接着,我们来对比 baseline 的 v-prediciton 和 JiT 的 x-prediction + v-loss。仅在 p=8 时,JiT 比 baseline 更优。在 p 更小时,还是 baseline 更优。而且,在 p=8 时,x-prediction 也挽救不了大 patch size 带来的质量下降。哪怕它训练了 200 个 epochs,最终的 60 多的 FID 也比不过小 patch size 下训练 epoch 数更少的模型。

通过这些实验,我可以断言,JIT 提出的扩散模型预测目标仅在大 patch size 下有效。这个方法仅仅是不得不用大 patch size 时的无奈之举。如果计算资源足够,用原来 v-prediction 的小 patch size 模型还是更好的。

解释实验结果

流形假设基础

为什么 JiT 在大 patch size 时有效呢?JiT 论文用流形假设 (manifold assumption) 理论来解释这个现象。在探讨 JiT 为什么有效前,我们先简单认识一下流形假设。由于我也没有系统学习过这个概念,只能用一些不太严谨但非常直观的例子来解释它。

流形假设表示,高维空间的数据集里的数据并不是均匀分布在整个空间里,而是在一个低维流形上。我们可以用一个简单的例子来说明:假设我们有一个灰度值构成的数据集,可能的灰度值是 [0, 255]。但是,我们存储这些颜色的数据集用的是 3 通道的 RGB 颜色。虽然 RGB 颜色空间有 $256^3$ 种可能,但实际上灰度值只有 $256^1$ 种,且它们分布在一条直线上。这条直线就是高维 3D 空间里的 1D 流形。

JiT 还提出了另一个命题:符合流形假设的数据更容易被神经网络预测。而在扩散模型的预测目标中,纯噪声 $\epsilon$ 是不符合流形假设的,因为它均匀分布在整个高维空间。因此,由纯噪声算得的 $v$ 也是不符合流形假设的。只有来自真实数据集的清晰图片符合流形假设。

为了验证该命题,JiT 开展了一个迷你实验:为了构造出符合流形假设的数据集,作者将一个 2D 图形用一个维度为 D 的随机投影矩阵投影到了 D 维。接着,作者训练了三个预测目标不同的扩散模型,观察哪个模型能够成功预测这个投影后的 D 维数据。结果发现,随着 D 增加,只有 x-prediction 维持不错的预测效果,预测 $\epsilon$ 和 $v$ 都不行。

这个实验证明,我们对神经网络拟合能力的理解是正确的:神经网络更擅长拟合符合流形假设的数据集。

大 patch 与流形假设

如果神经网络与流形假设的理论是对的,那么 x-prediction 应该总是更优的,为什么我们在 JiT 中发现只有大 patch size 时更优呢?作者在论文里没有详细讨论这一点,而我通过之前的知识大概想出了原因。这涉及神经网络的更底层的概念:一个 Transformer 到底预测了什么?

在学习神经网络的时候,我们会先学全连接网络,再学 CNN, RNN, Transformer。一般教程会说,全连接网络更容易过拟合,而其他网络泛化性更好。但仔细思考后,我们可以更具体地指出全连接网络和其他高级网络的区别:全连接网络用一套参数建模了所有输入到所有输出的关系,换句话说,对于每个输出元素,它用到的参数是不同的。而其他高级网络实际上是在用同一组参数输出一个元素,只不过输出某元素时,输入还包含其它元素的信息。

以 CNN 和 Transformer 为例,我们来验证这个概念。CNN 对每个元素都用同样的卷积核,只不过每个卷积核的输入不同;Transformer 的注意力操作是一个无参数的信息融合操作,其他所有投影层、MLP 全是逐元素生效的。

神经网络其实只负责输出一个数据元素,而现在的扩散模型 loss 或者交叉熵 loss 都是逐元素计算的。所以,看上去神经网络学习的是整个数据集的分布,但它只需要学到整个联合分布的分解 (factorization),也就是其中某一项数据的规律即可。

根据这个假设,我们来尝试解释 patch size 对 DiT 的影响。不加 patch size 时,图像的每个数据元素是一个三通道的像素。单个像素的分布可能非常容易学,不管它是清晰图片,还是由纯噪声计算出的速度。这时,是否符合流形假设不影响学习难度,因为数据本身的维度就低。哪种预测方式更好需要用另外的理论解释。

而增加 patch size,其实是让单个元素的分布更加复杂了。我们可以忽略 patchify 里的线性层,把 patchify 看成是把 $p \times p$ 个像素在特征维度上拼接,把三通道数据变成 $3pp$ 通道的数据(事实上,FLUX.1 的 patchify 就是这么做的)。这个通道数为 $3pp$ 的数据才是真正的「高维数据」,Transformer 要预测的输出通道数是 $3pp$。这时,就可以根据前面迷你实验的结论,用流形假设来解释为什么 $p$ 较大时 x-prediction 更好。

x-loss 和 v-loss

正如 JiT 论文所说,扩散模型的预测目标和求 loss 的目标是解耦的。论文表格显示,v-loss 总是好于 x-loss。这里我将针对 JiT 的代码实现来简单讲一下解释该现象的思考方向。

在代码中,如果要用 x-prediction + x-loss,会这样写:

1
2
3
4
input x

x_pred = net()
loss = mse(x_pred, x)

如果换成 v-loss,会改成这样:

1
2
3
4
5
6
7
8
9
input x, eps, t

z = add_noise(x, eps)
v = (x - z) / (1 - t).clamp_min()

x_pred = net()
v_pred = (x_pred - z) / (1 - t).clamp_min()

loss = mse(v_pred, v)

观察两组 loss,我们发现,其实 v-loss 里那个减去 z 是没用的,因为不管的预测值还是 GT 都带了 -z。因此,x-loss 和 v-loss 的唯一区别就是后面的 /(1-t)。越是靠近清晰图像,1-t 越靠近 0,loss 权重更高;反之,越靠近噪声,loss 权重越低。所以,不同的 loss 其实就是在不同的 t 时用了不同的权重而已。哪种 loss 最优很难用理论解释,现在大家都是从调参实验中获取结论。

我们再来讨论一下代码里为什么可以对分母加 .clamp_min(5e-2)。训练时每个 t 的权重不影响训练的正确性,为了数值稳定,加这个没问题。但采样时,如果算速度时还加了这个,按理来说采样算法是错误的。但换算过来,只有 t < 0.05 时采样公式才不对。如果采样总步数是 50,只有最后两步是不对的。可能这个微小的误差对于采样算法来说是可以接受的吧。

总结

此前大家没能成功训练出 ImageNet-256 上 p=16 的 DiT。JiT 用 x-prediction 取代 v-prediction 解决了此问题。这一做法背后的理论基础是流形假设和神经网络的 factorization: 神经网络将预测复杂分布分解成了预测每一个简单元素的分布,而 patchify 把原本低维的元素变成了高维的元素。此时,如果在预测目标中加入噪声,就会违反流形假设,让模型要学习的高维数据分布过于复杂。

虽然论文最终也把 JiT 在 ImageNet-256 的 FID 训到了 2 以下,比 DiT 要好,但 JiT 用了更多训练和采样的 trick,完全相同的环境下不见得能比得过 VAE + patch size=2 的 DiT。在我自己的实验里也发现,patch size 较小的 v-prediction 仍然是最好的。正如作者在 conclusion 中所写,JiT 的意义可能是用于 tokenizer (或者说压缩数据的 VAE) 不好获取的场合,这时我们能够用大 patch size 直接对输入数据做压缩。另外,我认为 JiT 做的高分辨率像素图片生成和隐空间图片生成没啥区别。隐空间图片分辨率上去了,一样会面临难以训练的问题。因此,JiT 的贡献或许和是否有隐空间无关,它是一种适用于任何数据的,提升大 patch size DiT 生成质量的方法。

就论文写作上,我认为作者虽然写了一套看起来很有逻辑的故事,但没有把核心贡献讲清楚,而仅仅是在方法部分分析了 pathchify 过后维度变大导致了数据不符合流形假设。如果不是亲手做实验,我根本想不到 x-prediction 有效的场景不是 「高分辨率像素图像生成」,而是「大 patch size DiT 生成」。为了让读者能够更好理解论文,作者最好能在 introduction 里花更多的文字讲清楚是 patchify 导致了高维数据的产生,再讲高维数据与流形假设的关系。论文也最好能够提供本文所展示的同一分辨率不同 patch size 下模型的生成质量,以清楚地说明 patch size 决定了 x-prediction 是否有用。当然,我认为文章提出流形假设这个理论还是很有启发性的。此前我从来没有仔细想过为什么 patchify 会让 DiT 变得难训,但把它和流形假设以及神经网络的逐元素预测结合起来后,一切就清晰起来了。

看完这篇论文后,我的第一感是,patchify 对于输入的处理没有问题,但是在输出阶段还原数据尺寸时的做法过于简单。那么,是不是可以用另一个网络来专门负责解码像素级输出,而大 patch size 的 Transformer 仅作为编码器?比如再用一个像素 Transformer,但是注意力层只看自己的像素级特征和之前的 patch 级特征。这个 idea 或许很常见,之前隐空间里的 DDT 、像素空间的 PixelNerd 都用了类似的做法。但没想到,就在前两天,陆陆续续有好几篇像素空间 DiT 生成工作发表了出来,做法跟我这个想法都差不多。看来像素 DiT 这个领域能做的空间也越来越少了。

个人感想

最后谈一点和本文不是很相关的感想。一直以来,我觉得多数人对于扩散模型的学习方式存在误区,好像弄完一堆数学推导,知道 DDPM 和 Flow Matching 是怎么建模的才是最重要、最高大上的。但实际上,除非是专门做与理论紧密相关的研究,比如采样加速,否则理解这些公式对调优扩散模型的结果毫无帮助。从本文的结果也能看出,仅用数学理论完全无法解释要用哪种 loss,以及为什么如何不同 t 时设置不同的权重。究竟怎样的噪声公式最好,其实取决于神经网络的性质以及常见数据集的分布规律,而和预定义的扩散模型公式无关。是扩散模型公式去适应神经网络,而不是让神经网络预测某个预定义的公式变量。所以,在研究扩散模型或者其他生成方法时,必须要像物理一样从现象中归纳,而不是像数学一样基于演绎推理。而且,研究过程中也必须涉及对神经网络的分析。现在 AI 的发展很多都是经验、实验指导的,但要长期发展的话,必须建立某种理论模型,不论这个模型是否与传统的数学模型相容。

参考文献

(JiT) Back to Basics: Let Denoising Generative Models Denoise

(ADM) Diffusion Models Beat GANs on Image Synthesis

(VQVAE) Neural Discrete Representation Learning

(VQGAN) Taming Transformers for High-Resolution Image Synthesis

(LDM, Stable Diffusion) High-Resolution Image Synthesis with Latent Diffusion Models

(ViT) An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale

(DiT) Scalable Diffusion Models with Transformers

(Stable Diffusion 3) Scaling Rectified Flow Transformers for High-Resolution Image Synthesis

(SD) simple diffusion: End-to-end diffusion for high resolution images

(SiD2) Simpler Diffusion (SiD2): 1.5 FID on ImageNet512 with pixel-space diffusion

(Diffusion Noise SNR 研究) On the Importance of Noise Scheduling for Diffusion Models

(f-DM) f-DM: A Multi-stage Diffusion Model via Progressive Signal Transformation

(PyramidFlow) PyramidFlow: High-Resolution Defect Contrastive Localization using Pyramid Normalizing Flow

(PixelFlow) PixelFlow: Pixel-Space Generative Models with Flow

(PixelNerd) PixNerd: Pixel Neural Field Diffusion

(VAVAE, LightningDiT) Reconstruction vs. Generation: Taming Optimization Dilemma in Latent Diffusion Models

(MAR) Autoregressive Image Generation without Vector Quantization

最新 Pixel DiT 论文 (除此之外,JiT 表格里对比的所有 baseline 论文都值得阅读):

Advancing End-to-End Pixel Space Generative Modeling via Self-supervised Pre-training

DiP: Taming Diffusion Models in Pixel Space

DeCo: Frequency-Decoupled Pixel Diffusion for End-to-End Image Generation

PixelDiT: Pixel Diffusion Transformers for Image Generation

近两年来 LLM 越来越猛,在 IMO,IOI 等竞赛中屡创佳绩。一直以来,我都是抱着围观的态度,看个热闹也就过去了。但是,最近又传出了 LLM 在算法竞赛 ICPC 2025 中超越了人类的新闻。作为前 ICPC 选手,看着社区里热烈的讨论,我可坐不住了,非得仔细地探一探 AI 的虚实才行。在这篇文章中,我会对 AI 在 ICPC 2025 的解答做深度分析,并给出我对 AI 思考方式以及未来发展趋势的看法。

背景简介

先简单介绍一下 ICPC 的规则,方便圈外人理解。ICPC 是国际大学生算法竞赛(International Collegiate Programming Contest)的缩写。竞赛中,若干支三人小队共用一台电脑,在五小时内尝试用编程解决数道算法难题。解题越多,且解题所花时间越短,则成绩越好。这些算法题的原型都是有着清晰定义的数学题,一般很容易想到朴素的「暴力搜索」解法。然而,算法竞赛要求所有程序必须在数秒内算完,哪怕正确的程序也可能会因为超时而被判定解题失败。算法竞赛的魅力,正在于根据题目的特性(如数据范围),在所有可行算法中找出一个能够在几秒之内快速算完的最快算法。

本次 AI 战胜人类的比赛为 ICPC 2025 世界总决赛。作为全年里最具含金量的比赛,总决赛的参赛队伍都是来自全世界各个赛区的佼佼者。比赛官网为:https://worldfinals.icpc.global/2025/ 。我们可以在 https://worldfinals.icpc.global/problems/2025/finals/index.html 查看所有题目,并在 https://worldfinals.icpc.global/scoreboard/2025/finals/index.html 回顾比赛中各个队伍在比赛中的过题记录及排行榜。

前四名队伍的过题情况及总的过题情况如下图所示。最难的三道题是 B, C, G 题。其中,C 题没有队伍做出来。

本次宣称战胜了人类的公司有两个:OpenAI 和 Google。相关信息来源为 OpenAI 在 X 的发帖:https://x.com/MostafaRohani/status/1968361268475215881 及 Google DeepMind 的博文:https://deepmind.google/discover/blog/gemini-achieves-gold-level-performance-at-the-international-collegiate-programming-contest-world-finals/ 。国内主流媒体报道的内容都是从上面两个信源中整理而成。

简单总结一下 OpenAI 和 Google 的报告内容。OpenAI 使用一个内部推理系统,成功答出了全部 12 题,超越了所有人类选手。值得注意的是,这个推理系统是若干个通用推理模型的集成 (ensemble),没有仅针对 ICPC 竞赛训练。此外,仅用 GPT-5 也能答对 11 题,战平人类最强水平。Google 的 Gemini 则略逊一筹,答对了 10 题,在人类排行榜中能够位居第二。不过,Gemini 也解出了没有人类队伍通过的 C 题,证明其实力也不容小觑。热心的 Google 将 Gemini 的解题代码开源了:https://github.com/google-deepmind/gemini_icpc2025

竞赛题深度分析

以往有 AI 达成某某成就的新闻时,我只能泛泛地分析一下。但在这次 ICPC 中,可以分析的信息多了很多:首先是 Google 开源了他们的解题代码,且有着不俗表现的 GPT-5 是人人可用的,我们能够更加深入地了解 AI 的水平;另外,虽然我的算法竞赛水平不足以解出最难的几道题目,但我能够理解题目的意思,大致看懂题解,并能揣测人类选手的解题思路。基于这些信息,我将深度分析在解答最难的几道题目时,人类和 AI 的区别在哪。

从排行榜可知,对人类来说,最难的题目从难到易依次为 C, G, B,其中无人通过 C 题。而 Gemini 解出了 C 题,却没有解出 B 题和 G 题。我简单扫了遍题,G 题太复杂了懒得想,就去仔细看了 B 题和 C 题。随后,我借助 GPT-5 的帮助,并参考了 Youtube 上的官方视频题解及 GitHub 上某大神的解答 https://github.com/SnapDragon64/ACMFinalsSolutions ,勉强是搞懂了这两题的大致解法。

C 题

我们先看一下人类没解出来但 AI 通过的 C 题。这道题的题意可以对着下面的样例图解释。一些水会从 1 号水站流入下游的水库。水站中间还有一些分水管。水站、分水管、水库构成一张图,其中,水站用绿色表示,水库用蓝色表示,分水管用灰色表示。水站和分水管都会以一定比例将上游的水分流。不过,分水管的分流比例是固定,且可能会存在损耗(分流比例已在图中标出)。作为水站管理人员,我们可以任意指定每个水站的分流比例,因此水站的分流比例没有在图中标出。现在,我们要决定每个水站的分流比例,使得最终所有水库的最少水量尽可能大。假设 1 号水站流出了 1 单位的水,程序只需输出最优情况下上述问题的解,不需输出方案。

比如,在示例中,如果我们让 1 号水站的分流比例为 50% : 50%,则我们可以逐步计算每个管道及每个分水管的流量,最终算出三个水库的水量分别为 0.4, 0.2, 0.2。我们要求解所有水库的最少水量,因此我们这个方案的价值是 0.2。我们要从所有这样的方案中,选择一个价值最高的方案。

这道题的主要数据范围如下:水站、分水管约有 $10^4$ 个,但水库至多有 3 个。

这题看得我一头雾水,我只好向万能的 GPT-5 请教了这道题。结果它淡然地回答我,这个问题其实和另一个更简单的子问题相关:假设三个水库都向水库买水,出价分别为 $a, b, c$, 且满足 $a+b+c=1$。这时,该怎么设置每个水站的分流比例,最大化利润呢?这个问题就简单很多了,由于一开始已经知道了底部水库的价值,我们这次自底向顶计算,算出每个水管和分水管的价值。在每个水站处,我们只需要贪心地让 100% 的水流向价值最高的分水管即可。对于多数竞赛选手来说,这个子问题并不难解。

之后,GPT-5 又告诉我若干个炸裂的结论:如果将此时的可选方案变成指定三个水库的比例 $a:b:c$,而不必再考虑水库的分流方案,那么上面这个子问题的最小值等价于我们求原问题的最大值。并且,这个子问题的解是一个凸函数。针对输入变量数小于等于 3 的凸函数,有十分成熟的三分算法可以求解这个问题。

GPT-5 给我说了一大堆内容,我都被绕晕了。过了一会儿后,我才整理出了这题的解题逻辑:

  1. 原来指定水站分流比例的问题和一个指定水库价值比例的问题相关。题目里问的原问题的最大值,等于子问题的最小值。
  2. 方案已知时,一个子问题可以用动态规划(DP)算法求解。
  3. 不同方案的子问题的解构成凸函数。
  4. 凸函数最优值的问题可以用三分算法求解。

为什么人类选手没能在比赛中做出 C 题呢?对于顶级竞赛选手来说,做到第二、第四步都是轻而易举的事。但是,第一步这个问题转化实在是太难想了,本来求最大值的,怎么会联想到一个要求解最小值的任务。此外,哪怕想到了第一步这个子问题,也猜不到这个子问题的具有第三步中的凸函数性质。

那为什么 AI 如此漂亮地解出了这道题呢?我询问 GPT-5 是怎么想出最关键的那一步问题转化的,它则煞有介事地回复了我一堆数学定理,看起来似乎很有道理。但以我浅薄的积累,这些数学定理全都不能在短期内看懂。我又问它是否这道题用到的知识在数学竞赛中很常见,而在算法竞赛中不常见。它告诉我这些知识在算法竞赛中很常见,但又好像完全没有理解这些知识一样,给了我一份不太相关的「相关题目表」,和这道 C 题用到的核心解法完全无关。最终,GPT-5 并没有教会我它是怎么想的。我只能猜测它的数学知识确实很渊博,比顶级竞赛选手们更快地找到了解决此问题的相关知识。

B 题

我们再来看 B 题。赛场上有 8 支队伍通过了此题,且最快的队伍在第一个小时里就解决了此题。但是,Gemini 并没有通过这道题。我问了 GPT-5,它装模做样地给了一个解答,虽然方向对了,但显然它的解法会超时。

这道题是这样说的:两个人在黑板上写下了 $1 \sim N$ 所有数字。随后,二人轮流选择数字。第一个人在第一步必须选一个偶数。随后,每一步中,每个人必须选上一个数乘以一个质数,或者上一个数除以一个质数(必须保证能整除),随后擦掉上一个数。如果有人选不了下一个数,则这个人就输掉了。题目输入 $N$ $(2 \leq N \leq 10^7)$,输出先手胜利还是后手胜利。如果先手胜利,还要输出先手应该第一步选哪个数。

这个问题很容易用数学模型表达:我们可以把每个 $1 \sim N$ 里的数字看成图里的节点,把 「能从数字 a 选到数字 b」 看成数字 a 和数字 b 之间连了一条边。根据题目,如果当前在数字 $x$,我们就能向 $x \cdot p$ 或者 $x / p$ ($p$ 是质数)连边。这样,我们就能画出一张无向图。那么,从黑板上擦掉数字,等于从图中删掉一个点。所以,问题就变成,两个人在无向图上轮流走一步,并删去上一步所在节点。谁不能动了谁就输了。

下面是 $N=5$ 对应的图。这个情况下,先手必输,后手必赢。假如先手选 2,则后手选 4,先手无路可走;如果先手选 4,则后手选 2,先手选 1,后手选 5,先手同样失败。由于先手只能从偶数,而无论从 2 开始还是从 4 开始都是输,所以先手必输。

GPT-5 告诉我,这个在地图上走路的博弈问题已经在学术界被研究过了,叫什么 Dulmage–Mendelsohn。研究的结论是,把图看成二分图,如果设置 $s$ 为起点,$s$ 在某个最大匹配里不被匹配,则先手必胜……。讲了一大堆我啥也听不懂,能得到的结论是,这道题的数学模型已经被人研究过了,早就有了明确的算法。

可问题是,这个算法要求的计算量很大。在 $N$ 为 $10^7$ 这个量级时,用已知算法求解一定会超时。有没有办法能够绕过这些复杂的计算呢?

解法就出在这个图的构造方法上。上述通用解法是针对一般的地图博弈问题。但在这道题中,这个图是根据「乘除素数」得到的。想必这种构造方法一定存在某些能够简化问题的特性。官方题解讲到,当 N 足够大(大于 80 多)时,我们总能找到三个满足条件的素数 p, q, r,它们能构成一张子图。在这张子图上,有着简单的策略让先手必胜。

所以,这道题的解法分两块:

  1. 如果 N 很小,用现有的成熟算法求解。
  2. 如果 N 较大,只需要输出先手必胜,再轻松找到那个符合条件的起点即可。

这道题属于算法竞赛里那一类解法十分巧妙的题目:用常规做法显然会超时,但如果灵机一动,发现题目在某些情况下有一个很直观的解,那这道题一下子就做出来了。甚至我都敢说,如果我知道这道题用到的成熟算法,连我都很可能在几个小时里把这道题的第二步想出来。当然,从某种角度来说,这道题的第一步也是很难的:如果你从来没有学过类似的定理,在赛场上是难以自己把定理重新发现一遍的。

在我看来,B 题的难度是远小于 C 题的。首先,这题涉及的数学定理不是那么冷门,不少人都知道;其次,第二步那个巧妙的想法对于选手们来说并不难想。可 AI 有着和人类不一样的表现。在我的测试中,GPT-5 确实给出了第一步的正确思路,但它完全没思考清楚是否会超时,也没有发现第二步那个巧妙解法。

人类与 AI 在算法竞赛的对比

如果耐心看完了上一节,相信完全没接触过算法竞赛的读者也能对人类和 AI 解答算法题的方式略知一二。在这一节,我会基于上一节提供的信息,详细对比人类和目前 AI 思考方式上的区别。

在分析之前,我想先给出我看待这个问题的方式。很多人看到 AI 在算法竞赛中战胜了人类,会把「在算法竞赛中表现更好」当成一件完整的事来分析,或许会因感觉 AI 比人类更聪明了而感到焦虑,又或许会以算法竞赛本身意义不大为由认为其不足为虑。而在我看来,解答算法竞赛是一个由若干步骤组成的复杂思维过程,详细地探究其中每一步中人类和 AI 的思维区别,才能帮我们更清晰地认识当前 AI 的实力。

在我看来,算法竞赛选手解题时需要经过以下思维过程:

  1. 读懂自然语言,将其转换成脑中的数学语言。
  2. 回忆自己学过的算法原型,思考这道题的数学语言所表示的模型能够被哪种算法原型解决。
  3. 写出正确的程序并提交。

其中,最具挑战性的是第二步。在不同的题目中,执行第二步思考的方式也不同。以前面的 C 题为例,为了想出正确答案,选手或许需要经过以下思考过程:

  1. 由于这道题的数学模型和「网络流」模型很像,选手会仔细思考网络流算法是否能够解决这道题。但稍微想了一下发现网络流算法解不了这题。
  2. 选手突然灵光一闪,发现这道题可以转化成一个子问题。不同子问题的最小值就是答案。
  3. 找到不同子问题的最优解可以用三分算法,没问题。
  4. 解决单个子问题可以用动态规划算法,没问题。这个问题最后就解出来了。

解答 B 题也会经过这样的思考过程:

  1. 通过回忆与比对,选手发现这道题的本质是一道地图博弈问题,可以用成熟算法解决。
  2. 但题目数据范围太大,套用算法只能解决部分问题。
  3. 根据以往解题经验,这种博弈题在数据大的时候可能有一个很简单的解。简单尝试一下后,果然,选手发现了一个简单解法。
  4. 合并数据量大时的简单解法和数据量小时的成熟算法,得到最终解法。

虽然每道题的思考过程都不同,但我们可以总结出选手解题时共通的思考过程:

  1. 在平时学习时,选手记忆了足够多的算法原型。我们不妨把每个算法原型看成一块「拼图」。
  2. 看完题目后,选手会在记忆中搜索与题目的数学模型最像的那些算法原型。
  3. 接着,选手会判断当前想到的这块「拼图」能不能和数学模型对齐,或者多块「拼图」拼在一起能不能凑出这个数学模型。
  4. 如果当前想到的算法原型不对,那就重新尝试新的算法原型。选手既可能灵光一闪地顿悟出解答,也可能根据套路推理出解答的方向。

在这些加粗的动作中,「顿悟」的原理比较复杂,这里不详细展开。剩下的动作可以清晰地分析两类:

  • 「非理性」的记忆和搜索:我们无法讲清楚我们在脑子里是怎么记东西的,又是怎么搜索出与眼前事物最契合的抽象概念的。

  • 「理性」的判断和推理:我们能够讲清楚为什么一个算法是对的,又或者为什么一个算法会超时。如果碰到了一个套路类似的题目,我们可以直接根据套路不经搜索直接推理出正确解答方法(尽管识别套路时用到了搜索)。此外,知晓一个题目由几个子算法组成,也算是理性思维的一种。

将思考时的动作分成非理性和理性后,再回头看 AI 的解题过程,我们能发现 AI 明显在非理性功能上远胜人类。

  • 在做 C 题时,AI 能够将数学知识融会贯通,一眼看出这道题可以变换成另一个更好解的问题。而人类选手没怎么见过把这种数学知识用到算法题里的先例,在比赛中没能想出来。(如果见过一次这种套路的话,我相信顶级选手是能够在比赛里做出这道题的)
  • 在做 B 题时,AI 轻松找到了正确的算法。

而在理性思考上,我觉得 AI 做得还不够好。比如在做 B 题时,AI 没有注意到直接套用算法会超时,更不用谈思考该如何针对超时做优化了。这对于一个能做出 C 题的同水平的人类选手来说是不可能的事。在人类视角来看,B 题远比 C 题简单。

我们再来讨论一下 AI 和人类的思考方式之间为什么会有这样的差异。所谓非理性思考,其实就是统计学习的结果:从大量的经验中学习,碰到问题时直接凭直觉得出结论。人类在学习语言、重复生活习惯时,其实都用到了这种思考方式。然而,相比之下,现在的 AI 模型都是基于统计学习的,学过的数据比人类多得多,在非理性思考上优于人类也无可厚非。

既然 AI 在学习时只用到了统计学习,它就不能进行需要推理的理性思考了吗?当然不是。现在的 LLM 是用 CoT (思维链)的方式学习推理的。具体来说,思考的过程,比如数学公式的每一步推导过程,被当成了一种文本数据,和其他死知识混在一起,供 AI 学习。这样,仅使用统计学习的方式,AI 既能记住知识,也能输出推理的过程。我们不能说 AI 不会理性思考,正确的说法是只有人类会将思考区别成理性的和非理性的,而 AI 自始至终都是在用同一种方式思考。不管是记忆、搜索,还是判断、推理,在 AI 看来都是大量数据中存在的规律而已。

当下,我们难以断言 AI 的这种统一的思考方式是否最终能够全面超过人类。但可以确定的是,理性思考目前还是人类独属的利器,使得人类能够用相比之下更少的脑容量高效地完成复杂任务。

AI 的下一步

攻克算法竞赛这一项具有挑战性的任务后,AI 下一步要解决的问题是什么呢?如前所述,我认为当前 AI 在算法竞赛中的表现并不能说明它有和人类一样的理性思考水平,即在需要大量推理、严谨关联抽象概念的任务上的水平比不过人类。我将分享三个有价值的任务,它们对现在 AI 来说有望在一两年内有所突破,不至于太难,且能够反映 AI 的理性思考水平。

第一个任务是科研。在我们的认知里,创造新知识的科研是难度最高的思考任务。但直接让 AI 创造新知识恐怕太难了,我觉得一个更简单的科研任务是审稿——清楚认知现有的知识体系,并准确判断一篇新论文的创新性有多少。现在确实有不少辅助审稿、辅助解读论文的 AI。但在我看来,它们都只是从浅层的文本方面分析文章,没有对知识的深刻认识。但如果是稍有科研训练的人类研究者,他们能很快剥开论文表面那些精美的外壳,迅速理解文章究竟提出了哪些新的内容。如果哪一天 AI 也能给出犀利且正确的审稿意见,那就能证明现在的 AI 不是死记硬背,而是确实深刻理解了知识并且知道新论文的知识和现有知识的关联。

第二个任务是实现长思考链。深度学习时代的棋类 AI 一般由两大模块组成:判断网络,用于粗浅判断当前局势及下一步棋怎么下更好;搜索算法,用于模拟下完了几步棋以后的结果,以进一步确认当前每一步棋的好坏。也就是说,第一部分的网络只是凭借棋感大致想出了怎么下棋,而要严谨地确认哪步棋更好,需要搜索算法的帮助。棋感的部分其实是非理性思考,AI 能从大量数据里学会;而搜索算法代表了理性思考的部分,它用严密的程序逻辑告诉 AI 该怎么得到更正确的判断结果。那么,现在的 LLM 能否不靠人类编写的算法,自行领悟出这种思考过程呢?通过 CoT 技术,AI 确实会输出一些中间结果来帮助后续思考。但显然,它们的效率比不过预定义的算法,难以执行非常长的思考。研究仅由 LLM 构成的下棋 AI 同样很有价值。今年其实出了一个叫 InternThinker 的围棋 LLM,和我描述的任务一致,但我觉得这个产品还有很大的提升空间。

第三个任务是输出人类可理解的思考过程。很多时候,知道过程比知道答案更有价值。比如,要检查一个学生是不是在抄答案,我们会问他的解题过程。同理,对于给出了比人类更好的答案的 AI,我们也希望它输出思考过程,反过来教育人类。现在的 AI 可以输出一些思考过程,但做得还不够好。如前文所述,我曾让 GPT-5 教我做 C 题,并告诉我它的思考过程。但 GPT-5 只是列了一些知识点,然后像一本枯燥的数学教材一样,一板一眼地讲着推导过程,根本做不到用三言两语就能快速教会我。从这里也能看出,AI 能输出思考过程,其实只是把训练集里的思考过程,即数学教材的推导方法学了过来。而我认为,真正有价值的思考过程,是把非理性思考的结果用理性思考严谨复述的内容。一旦能做到这一点,AI 就能把从大量数据里学到的新知识教给人类。当然,如何把这种更加复杂的思考过程与现在 LLM 能输出的思考过程做区分,且用一个具体的任务表现出来,同样比较困难。我认为这个任务可以和上一个任务结合起来。如果一个 LLM 的围棋水平很高,且能准确讲出自己每一步棋的想法以指导人类,那这样的 AI 在其他领域一定会有更加亮眼的表现。

总结

通过深度分析 AI 在 ICPC 2025 的解答结果,我们发现 AI 还是在非理性思考,即从大量数据中寻找规律这一点上远胜人类,而在推理、判断等理性思考上不如人类。在我看来,当前 AI 的本质并没有发生什么变化。它取得的一系列成就,只能进一步说明统计学习的有效性——如果 AI 的能力不受内存、算力等资源的限制,学过了世界上所有可能的数据,它就能在一切事情上超过人类。但在资源有限的前提下,人类的理性思考能力还是一项非常高效率的功能。

以 Attention 计算为核心的 Transformer 模型是当今深度学习的基石。虽然 Attention 计算十分有效,但其高昂的计算成本往往成为了模型性能优化的瓶颈。为了在 GPU 上高效执行 Attention 计算,现在开发者们普遍都使用了 FlashAttention——一种高效的 Attention 并行实现算法。

相信有不少 AI 研究者都想学习一下 FlashAttention,却往往因其较高的学习门槛望而却步:理解 FlashAttention 需要高性能计算知识,它和大家平时学习的 Transformer、大模型等深度学习知识截然不同。而我最近在自学 FlashAttention 时,凭借以前稍微学过的一点并行编程知识,成功地在没有完全弄清细节的前提下学懂了 FlashAttention 的核心思想,并就此明晰了后续的学习路线。在近期的几篇博文中,我想分享我学习 FlashAttention 的过程,并涉及尽可能少的基础知识,让没有 GPU 编程基础的读者轻松学会 FlashAttention

在这篇博文中,我会介绍理解 FlashAttention 所需的最简 GPU 编程知识,并通过逐步改进伪代码的方式,介绍 FlashAttention 的算法原理。在后续的文章中,我会继续介绍 FlashAttention 的前向传播、反向传播实现等进阶内容。为了方便读者的学习,我不会完全按照 FlashAttention 的论文的逻辑来介绍知识,也不会严谨地按论文里的算法来介绍,不使用 CUDA 编程术语(因为我也不是很懂),而是介绍一种尽可能简明的 FlashAttention 实现,帮助完全没有相关知识的读者入门 AI 高性能计算领域。

底层 GPU 编程模型

程序是由若干原子操作组成的。比如,对于高级语言而言,原子操作包括四则运算、if-else 构成的判断语句、函数定义等;而对于汇编语言而言,原子操作则由从地址读数据、写数据、程序跳转等操作组成。越是偏底层的语言,我们能够控制的细节越多,代码优化空间越大,但代价是开发的成本也越高。

FlashAttention 中的部分优化策略需要用比高级语言更底层的 GPU 编程模型来描述。在这篇文章中,我们会使用一个尽可能简单的 GPU 编程模型。我们将从访存、并行计算这两个方面认识 GPU 编程的特点。

存储模型

在学习计算机时,我们一般会将存储分为寄存器、内存、硬盘。它们的容量依次递增,读写速度依次递减。硬盘一般只负责存储数据,上面的数据不能做直接运算。内存存储了程序能直接「看到」的数据。使用高级编程语言时,内存是我们存储数据和对数据做运算的地方。但在最底层的运算实现中,程序实际上是先把数据从内存搬到寄存器上,再做运算,最后把数据搬回内存。只有在编写更底层的汇编语言时,我们才需要知道寄存器这一层。

当然,实际上在寄存器和内存之间还有缓存(cache)这一层,但这属于硬件上的实现细节,它在编程模型中是不可见的,硬件会自动处理缓存的逻辑。

类似地,在 GPU 上,也有类似的存储模型。CPU 内存 (DRAM) 上的数据不能直接用 GPU 运算,必须要放到 GPU HBM 里,就像对 CPU 中硬盘和内存的关系一样。GPU HBM 就是我们常说的「显存」。使用高级语言(如 PyTorch)编写 GPU 程序时,我们可以认为数据全是在 HBM 上运算的。同样,在更底层,我们需要先把数据从 GPU HBM 读取到 GPU SRAM (类似于 CPU 中的寄存器)上,做运算,再把数据写回 GPU HBM。

下图的存储模型及命名方式出自 FlashAttention 论文。同样,下图只是一个逻辑模型,实际硬件中 GPU SRAM 既包括了寄存器,也包括了缓存。但在学习 FlashAttention 时,我们只需要了解这个逻辑模型,而不需要将其与实际的硬件对应。

认识了存储模型后,我们来看 GPU 编程模型相比高级语言的编程模型有哪些变化。

在高级语言中,如果要把两个变量相加得到第三个变量,只需要编写如下代码。

1
c = a + b

而加入了「访存」这一概念后,我们需要在计算前后加入变量的读取和存储指令。此外,如果计算中产生了新的变量,需要为新变量新建空间。如下面的代码所示,a_mem, b_mem, 是在 GPU HBM 上的变量,我们用需要用 load 把它们读入到 SRAM 中,得到 SRAM 上的变量 a, b。之后,我们在 SRAM 上创建新变量 c, 并用它存储加法结果。最后把 c 写回 HBM 的 c_mem 里。

1
2
3
4
5
6
7
8
9
c_mem = new_hbm_memory()

a = a_mem.load()
b = b_mem.load()

c = new_sram_memory()
c = a + b

c_mem = c.store()

可以看出,为了实现一次加法,我们做了两次读取,一次存储,访存带来的时间开销不可忽略。

除此之外,这里为新变量创建空间的操作出现了两次:一次是在 HBM,一次是在 SRAM。上面这个例子比较简单,输入输出都只有一个变量,没有空间不足的问题。但一般来说,算子的输入都是很长的数组。我们默认 HBM 的存储空间一定足够,但 SRAM 的空间不一定足够。因此,我们需要用到「分块」操作,一块一块地把输入从 HBM 读入到 SRAM 并运算。稍后我们会看到一个更具体的例子。

FlashAttention 的主要贡献就是减少了 Attention 的内存操作开销(读取、存储、新建空间)。

算子融合与访存优化

通过上面的例子,我们发现,算上了访存后,哪怕是实现一个简单的加法都十分费劲。因此,大多数程序员都只会编写高级语言,并让编译器来自动补全访存的逻辑。比如对于 c=a+b 而言,编译器会自动生成两个读取指令,一个存储指令。

可是,编译器自动生成的 GPU 代码一定是最优的吗?这显然不是。考虑下面这个高级语言中的函数 add_more

1
2
3
4
5
def add_more(a, b, c, d):
a1 = a + b
a2 = a + c
a3 = a + d
return a1, a2, a3

如果让编译器按照最直接的方式翻译这段高级语言,那么翻译出的 GPU 程序中会包含如下的指令(为只关注读写次数,我们不写变量在 HBM 上的名称,默认所有变量都在 SRAM 上,且忽略新建空间操作):

1
2
3
4
5
6
7
8
9
10
11
load a, b
a1 = a + b
store a1

load a, c
a2 = a + c
store a2

load a, d
a3 = a + d
store a3

但仔细观察这些读写指令,我们会发现部分读写指令是多余的:a 只要被读取一次就行了。最优的程序应为:

1
2
3
4
5
load a, b, c, d
a1 = a + b
a2 = a + c
a3 = a + d
store a1, a2, a3

由于我们知道了 add_more 函数的某些特性,我们可以通过手写 GPU 程序,而不是让编译器死板地逐行翻译算子的方式,实现一个更高效的「大型算子」。这种做法被称为 「算子融合」(operator fusion)。由于 GPU 上的函数一般被称为 kernel,所以这种做法也会称为「核融合」(kernel fusion)。

再看另一个例子:

1
2
3
4
def add_twice(a, b, c):
d = a + b
e = d + c
return e

如果使用自动编译,会得到下面的 GPU 程序:

1
2
3
4
5
6
7
load a, b
d = a + b
store d

load d, c
e = d + c
store e

但我们可以发现,d 只是中间变量,不用写进 HBM 又读回去。更高效的程序如下:

1
2
3
4
5
6
load a, b
d = a + b

load c
e = d + c
store e

从上面两个例子中,我们能总结出算子融合提高效率的原理:如果连续的多个运算都要用到同一批数据,我们可以对这批数据只读写一次,以减少访存开销;此外,我们应该将中间结果尽可能保留到 SRAM 上,不要反复在 HBM 上读写。

并行编程

和使用高级语言编程相比,在进行 GPU 编程时,我们除了要考虑访存,还需要编写可以并行执行的程序。我们说 GPU 比 CPU 快,并不是因为 GPU 里的计算单元比 CPU 的高级,而是因为 GPU 里的计算单元更多。用一个常见的比喻,GPU 编程就像是把复杂的数学运算拆成简单的加减乘除,再交给许许多多的小学生来完成。作为 GPU 程序员,我们不仅要决定运算的过程,还需要像「小学老师」一样,知道如何把整个运算拆成若干个更简单、可并行执行的运算。

「计算单元」在不同的硬件模型、编程模型中有不同的所指。这里我们笼统地用「计算单元」来表示一个有独立计算资源(存储、运算器)的单元,可以独立地运行一段程序。

为了快速入门并行编程,我们先通过一个简单的例子来了解一般并行程序的写法,再通过一个反例认识怎样的运算是不能并行的。最后,我们会简要总结并行编程的设计方式。

考虑这样一个向量加法任务:假设向量数组 a, b, c 的长度都是 16,我们要在 4 个 GPU 计算单元上实现 c=a+b 的操作,应该怎么为每个计算单元编写程序呢?

最直观的想法肯定是把向量平均拆成四组,让每个计算单元计算 4 个分量的加法结果。这是因为如果任务分配不均匀,任务完成的总时间会取决于任务最多的那个计算单元,这个时间会比平均分更久。因此,我们可以为每个计算单元各自编写如下所示的程序。

为每个计算单元单独写一段程序太累了,能不能只写一段程序,然后让所有计算单元都执行同一段程序呢?这当然可以,但还有一个小小的额外要求:由于现在所有计算单元共用一段程序,我们需要额外输入当前计算单元的 ID 来告知程序正在哪个计算单元上运行。得知了这个额外信息后,我们就可以自动算出当前计算单元应该处理的数据范围,写出下面的程序。

有了这段通用的程序,我们其实就可以实现任意长向量的加法运算。比如当向量的长度变成 32 时,我们可以分配 8 个计算单元来计算。可见,并行编程的目标就是写一段通用的程序,并根据计算单元的 ID 选取同样数量的数据做计算。

在上面的例子中,我们让每个计算单元都计算 4 个数据。实际情况中,应该给每个计算单元分配多少数据呢?一般来说,一个计算单元的并行计算器和存储空间都是有限的,应该尽可能用满它的计算资源。比如一个计算单元最多能并行算 4 个数据,且内存也只够存 4 个数据,那么我们就给它分配 4 个数据。

在学习和设计并行算法时,我们不需要知道每个计算单元具体分配多少数据,但要设计把数据拆分进每个计算单元的方式。比如对于形状为 $N \times M$ 的二维矩阵,计算单元一次能计算 $d$ 个数据,我们要决定是把数据在两个维度上拆分,得到 $ \frac{N}{\sqrt{d}} \times \frac{M}{\sqrt{d}}$ 组,还是只在第二维上拆分,得到 $N \times \frac{M}{d}$ 组。

向量加法只是一个非常简单的运算,由于每个分量之间的计算是独立的,它天然就支持并行计算。而其他的运算就不一定满足这个性质了。比如向量求和:对于一个长度 16 的向量,我们要求出其 16 个分量之和。如果是串行算法,我们会写成这样:

1
2
3
sum = 0
for i in range(0, 16):
sum = sum + a[i]

在每一步运算中,我们都需要读取当前的 sum,并更新 sum 的值。每步运算之间不是独立的,实现并行计算的方式不是很直观。

用 GPU 编程实现更复杂的算子时,我们要仔细分析运算的过程,区分哪块运算像向量加法一样,是互相独立的;而哪些运算像向量求和一样,不好进行并行计算。之后,我们就要巧妙地对数据拆分,分配到各个计算单元中。比如,我们要求二维矩阵第二维(每一行)的和,我们发现矩阵每行之间的运算是独立的。因此,我们可以在第一维把数据拆分,让每个计算单元串行计算矩阵某一行的和。

GPU 编程新知识总结

相比使用高级语言编程,在 GPU 编程时,我们要多考虑两件事:1)访存开销;2)将可并行的运算拆分。具体的知识点有:

  • GPU 的存储从顶到底分为三层: GPU SRAM, GPU HBM, CPU DRAM,它们的访存速度依次递减。编程时我们一般只考虑前两层之间的读写开销。
  • 通过观察算子本身的性质,我们可以利用算子融合技术减少访存开销。不反复读取同一批数据、不读写中间结果是两个常见的优化场景。
  • GPU 由许多独立的计算单元组成,且每个计算单元本身也可以并行计算多个数据。但每个计算单元一次能并行处理的数据是有限的。如果数据量超过了计算单元的显存,要设法拆分数据。
  • 实现并行编程,实际上就是写一个输入参数包含计算单元 ID 的程序。我们要根据 ID 选取同样长度的一段数据,仅考虑这段数据该如何运算。
  • 并行编程的一大难点在于观察哪些运算是独立的,并把可以独立运算的部分分配仅不同计算单元。

Attention 运算

Attention 运算建模了一个常见的场景:已有数据 $a$,该如何从数据集合 $B=\{b_i\}$ 中提取信息。比如一个像素要从图像中所有像素中提取信息,或者一个句子里的 token (词元)从另一个句子的所有 token 中提取信息。

Attention 具体实现方式如下图所示:我们先算出 $a$ 对 $b_i$ 的相似度 $s_i$,它描述了 $a$ 对 $B$ 里第 $i$ 项数据的 「注意力」。之后,假设 $b_i$ 里存储的值 (value) 是 $v(b_i)$,我们用 $s_iv(b_i)$ 算出从单项数据中提取的信息。对所有提取出的信息求和,就能得到 Attention 操作的输出。

那么,数据间的相似度应该怎么求呢?在标准 Attention 运算中,我们用向量内积来反映数据间的相似度。但下一个问题又来了:该怎么从数据 $a$, $b_i$ 中提取出一个用于计算相似度的向量呢?在实际的 Transformer 模型中,我们一般通过线性层来实现这件事。但在这篇文章中,我们假设每项数据的所有属性已经算好了。我们用 $q(a)$, $k(b_i)$ 来分别表示 $a$, $b_i$ 的用于算相似度的向量 (q 表示 query,k 表示 key),$v(b_i)$ 表示 $b_i$ 中的信息。

这个计算还不完美:假如内积相似度 $s_i$ 之和 $\sum{s_i}$ 大于 1,那么 Attention 输出向量里的数值会越来越大,让神经网络的计算变得不稳定。因此,我们希望用归一化让相似度之和为 1。

最容易想到的归一化方法是线性归一化:先算出每个相似度及相似度之和,再除以相似度之和。

但标准 Attention 运算用了一种更高级的 softmax 归一化:先对相似度求自然指数,再做线性归一化。

最后,我们得到了 Transformer 论文中的标准 Attention 运算。

在多数 Attention 实现中,我们会对 softmax 前的相似度乘一个系数 $1/\sqrt{d}$。在这篇文章的讨论中,我们会忽略这个缩放系数。

为了简化上述公式,我们可以把 key, value 向量的集合合并成矩阵。各项数据的形状及合并后的公式如下所示。

假设现在不止是数据 $a$,而是有 $n$ 个数据 $\{a_i | i \leq n\}$ 要从 B 中查询信息,那么我们可以把上述运算重复 $n$ 次,得到 $n$ 个结果 $Attn(a_i, B)$。如果我们把 $a_i$ 的相关属性 (即 query) 也合并成矩阵,就可以得到我们最熟悉的 Attention 公式。

我们花了不少时间来回顾 Attention 运算。不管读者此前是否熟悉 Attention 运算,我都建议在学习 FlashAttention 前把 Attention 的计算细节回顾一遍。

通过上面的回顾,我们发现 Attention 计算有一些特别的性质:

  • 不同 $q$ 之间的计算是独立的。而对于同一个 $q$,算它的 Attention 输出时最复杂的一步是计算 softmax 相似度。

  • 由于 softmax 归一化的存在,我们只有在算完了 $qk$ 的所有内积相似度后,才能计算 softmax 的输出。

在后文的算法设计中,我们会用到这些性质。

自行设计 FlashAttention

简要了解 GPU 编程和 Attention 运算后,我们已经能够自行设计出一种比较高效的 FlashAttention 了。在这一节中,我们将由浅至深地了解 Attention 的实现细节。我们会先看其 PyTorch 实现,再看加入了访存操作后的 GPU 实现。随后,我们来尝试优化这份实现,最终设计出一版简易版的 FlashAttention。

PyTorch 版 Attention 及其访存操作

PyTorch 版 Attention 的代码如下所示。

光看 PyTorch 代码,我们还看不出哪里还有优化空间。因此,我们可以把访存操作加进去。假设一行 PyTorch 代码对应一个标准库里的 GPU 算子,要加入的 IO 操作如下。

这样,我们就能立刻发现一个可优化项:中间变量 s, p 前脚刚写入 HBM,后脚又被读回了 SRAM。如果能用算子融合技术,把整个 Attention 运算放到同一个 GPU 算子里,就能规避这些额外的访存操作。

需要注意的是,如果中间变量不多,多读写两次并不会浪费多少时间。然而,此处的 s, p 是两个数据量很大的变量。这是因为在当今大模型的 Transformer 中,(多头注意力的)特征维度 D 一般只是 32, 64 这样比较小的数,而序列长度 SL 至少是 $10^4$ 这个数量级。所以,形状为 [SL, SL] 的中间变量 s, p 比形状为 [SL, D] 的输入输出要大得多,它们的访存开销严重拖慢了普通 Attention 的速度。

拆分数据读写

现在,我们来考虑如何把 Attention 都在同一个 GPU 算子里实现。如前文所述,每个 GPU 程序描述了一个计算单元上的运算。而由于计算单元本身的 SRAM 存储是有限的,我们需要根据程序 ID,拆分数据,仅处理部分数据。这里,我们假设每个计算单元能存储量级为 D 的数据,但无法存储量级为 SL 的数据。

基于这一限制,我们来继续修改上面的程序。现在,我们不能一次读写形状为 [SL, D] 的数据了,该怎么拆分任务呢?在前文有关注意力运算的回顾中,我们知道,每个 query 之间的运算是独立的。因此,我们可以在上一份代码的基础上修改,只不过这一次我们只在一个并行程序里处理一个 query 和一个 output 的计算。

当然,除了 Q, O,我们也不能一次性读写全部 K, V 了。既然如此,我们只能使用循环,在每一步迭代里读一个 kv。改写后的程序如下。

可是,程序中还有一处超出了内存限制:通过拆分运算,我们将中间变量 s, p 的形状从 [SL, SL] 降低到了 [SL],但它们依然超过了内存限制。能否优化它们的内存占用呢?这一步优化,正是 FlashAttention 的核心贡献。

拆解 softmax

在进行算子融合时,并不是把几个算子拼接起来就做好了。我们往往要深入原算子的计算过程,看看是否能通过交换计算顺序或结合运算,提升整体的计算效率。这里也是同理。我们在优化和 softmax 相关的 s, p 变量时碰到了瓶颈,那我们就要拆解 softmax 的计算过程,看它和前后的两次点乘操作能否融合到一起以优化性能。

softmax 的定义如下:

它的计算可以拆成三步:

  1. 算 exp,得到分子
  2. 向量求和,得到分母
  3. 分子除以分母

因此,softmax 在 attention 中的实现如下。

拆分了 softmax 之后,我们立刻就能发现一个可优化项:变量 s[i] 被求了一次 exp 后就再也没用过了。既然如此,我们不必再用一个循环求 numerator,只需要求出了 q, k 的点乘 s 后,立刻求 numerator[i] = exp(s[i]) 即可。

类似地,我们也不用在另一个循环里对分母求和,一边算一边求和即可。

做完这些优化后,我们确实消除了 softmax 的部分冗余运算。然而,最关键的问题还是没有解决:中间变量 numerator, p 的长度依然是 SL,该怎么接着优化呢?

消除长度为 SL 的中间变量

刚刚我们把 softmax 的部分操作和 q, k 点乘合并了。能否顺着这个思路,把剩余操作和 p, v 的乘法合并呢?

直观上看,这些操作不能合并。这是因为 p 的分母要在跑完了长度为 SL 的循环后才能算出。算出了正确的 p,我们才能接着算 p, v 的乘法。

可见,问题的瓶颈在 p 的分母上。如果不需要除以那个 softmax 的分母,就没那么多限制了。我们先尝试忽略除法那一行,看看代码能优化多少。这时,可以把后面的循环和前面的循环合并起来,得到下面的代码。

接着,我们来回头纠正输出。这个错误的 O 和之前正确的结果差了多少?其实就是少除以了一个 denominator。并且,修改了代码后,有关 denominator 的计算完全没变过。循环结束后,denominator 也就算出来了。所以,我们完全可以在循环结束后再除以分母。

改完代码后,我们发现,p 不用再算了,只剩最后一个长度为 SL 的变量了——numerator。仔细观察代码,现在我们每次只需要用到 numerator[i],不需要重新访问整个 numerator 向量。既然如此,我们可以把 numerator 向量换成一个临时变量。

终于,这份程序成为了一段满足内存限制的可运行 GPU 程序。相比各个运算用独立算子表示的 PyTorch 版 Attention,这份高效 Attention 实现规避了形状为 [SL, SL] 的中间变量的读写开销,大大提升了运行效率。这版 Attention 就是一种简易的 FlashAttention。

优化思路总结

让我们回顾一下优化 Attention 的过程。

  • 由于 Attention softmax 输出的内存占用过高,我们希望利用算子融合技术,避免将中间变量从 SRAM 写入 HBM。
  • GPU 程序需要设计数据的拆分方式以决定并行计算方式。恰好 Attention 每个 query 的计算是独立的。我们让一个 GPU 程序只处理一个 query 的计算。
  • 一个计算单元无法存下长度高达 SL 的数据。因此,我们只能用长度为 SL 的循环来逐个处理 key, value 的运算。但是,softmax 的输出长度仍为 SL
  • 为了进一步优化,我们需要拆解并优化 softmax 的计算。softmax 的部分运算可以和 query, key 的点乘合并。但由于 softmax 分母需要遍历所有 key 后才能算出,仍需存储长度为 SL 的 softmax 分子。
  • 通过观察,我们发现 softmax 的除法运算不影响后面与 value 的乘法运算。因此,我们可以在一个循环里直接算完 query, key, value 的乘法,并维护 softmax 的分母。循环结束后,我们再除以分母。这样,就不再需要长度为 SL 的中间变量了。

总结

在这篇文章中,我们先了解了学习 GPU 编程的必须知识,并回顾了 Attention 的运算过程。之后,我们通过逐步优化代码的方式,实现了一个没有过长中间变量、可以在 SRAM 上运行的算子融合版 Attention,即简易版 FlashAttention。在这个过程中,我们理解了 FlashAttention 的设计动机和优化方向:普通 Attention 会产生长度为序列长度平方的中间变量,它的访存时间严重拖慢了 Attention 的运算速度。在优化该运算时,我们的关键发现是 softmax 的除法运算并不影响 q, k, v 的矩阵乘法运算。因此,我们可以在同一个循环里算 q, k, v 乘法,并同时维护 softmax 的分母。这样,就不用维护一个过长的中间变量了。

在学习过程中,我们或许能发现,GPU 编程比 PyTorch 编程要复杂得多,可能光看这篇博文还看不太懂。之后有时间的话,我会介绍 FlashAttention 的 Triton 实现,让读者能够亲身体会 GPU 编程方式及其带来的优化效果。这篇文章介绍的并不是真正的 FlashAttention 算法,也欢迎读者去阅读原论文和其他文章来深入学习 FlashAttention。

如果你玩过图像扩散模型,那你一定不会对 “guidance_scale=7.5” 这个参数感到陌生。这个 “guidance” 指的就是 Classifier-Free Guidance (无需分类器指引,CFG)。忽略其背后的数学原理,CFG 的作用和公式其实非常易懂。假设 $F(x, c)$ 是一个输入为图像 $x$ 和约束 $c$ (比如文本) 的神经网络,则使用 CFG 后的结果 $\tilde{F}(x, c)$按下面的公式计算:

其中,$w$ 是指引强度,在 Stable Diffusion 常取 7.5 的强度参数就是这里的 $w$。直观上看,通过增加 $w$ 的大小,我们可以让 CFG 结果更靠近带约束的输出 $F(x, c)$,更远离无约束的输出 $F(x, \emptyset)$。比如 $w=0$ 时,CFG 结果就是无约束输出 $F(x, \emptyset)$;$w=1$ 时,CFG 结果就是带约束输出 $F(x, c)$。在约束 $c$ 为文本的文生图扩散模型中,我们常常可以通过调整这个参数,来提升图像与输入文本的匹配程度。

在 CFG 中,$F$ 可以是任何一个神经网络。比如,它可以是 DDPM 中预测噪声的网络 $\epsilon$,也可以是流匹配中预测速度的网络 $v$。甚至在一些没有用到扩散模型,但是输入中包含 $c$ 的自回归模型中,我们也可以用到 CFG。

但是,上面的 CFG 公式还有没有改进空间呢?近期,以 NTU S-Lab 博士生范洧辰主导的工作探究了一种专门为流匹配 (Flow Matching) 打造的改进版 CFG—— CFG-Zero*。

这个方法可以提升所有流匹配模型的生成质量,比如文生图模型 SD3, FLUX.1,以及视频生成模型 WAN-2.1。以下是 SD3.5 上的实验结果。

由于 CFG 的原理比较简单,在这篇博文中,我会跳过背景介绍,直接讲解 CFG-Zero* 的方法及主要消融实验结果,并给出我对该论文的看法。

项目网站:https://weichenfan.github.io/webpage-cfg-zero-star/

GitHub: https://github.com/WeichenFan/CFG-Zero-star

CFG-Zero* 方法讲解

CFG-Zero* 由两个相对独立的改进组成:

  1. 给 CFG 公式中多乘上一个系数
  2. 在流匹配采样的早期不更新带噪图像

我们来分别学习这两项改动的原理。

改进版 CFG 公式

作者认为,应该在 CFG 中添加一项能够调节无约束和带约束输出相对大小的缩放系数 $s$。按照前文的 CFG 公式,对于输出 $t$ 时刻速度的流匹配模型 $v_t^{\theta}(x, c)$,改进版 CFG 的输出应为:

也就是说,我们在原来 CFG 公式的 $v_t^{\theta}(x, \emptyset)$ 前多乘了一个标量 $s$。

此外,作者还认为,最优情况下,$s \cdot v_t^{\theta}(x, \emptyset)$ 和 $v_t^{\theta}(x, c)$ 应该尽可能接近。即 $s$ 满足

上述两个假设是怎么得出的?在理解公式的原理之前,我们先看一下这个公式的几何意义,再反过头倒推其原理。

我们不妨将 $v_t^{\theta}(x, \emptyset)$ 和 $v_t^{\theta}(x, c)$ 看成平面上的向量。

给 $v_t^{\theta}(x, \emptyset)$ 添加一个系数,就意味着 $s \cdot v_t^{\theta}(x, \emptyset)$ 可以是其所在直线上的任何一个向量。

什么时候向量 $s \cdot v_t^{\theta}(x, \emptyset)$ 与 $v_t^{\theta}(x, c)$ 距离最短呢?当然是 $s \cdot v_t^{\theta}(x, \emptyset)$ 正好位于 $v_t^{\theta}(x, c)$ 在 $v_t^{\theta}(x, \emptyset)$ 上的投影处。

此时 $s$ 的取值 $s^*$ 可以通过求向量内积再除以原向量的模得到。

了解完改进版 CFG 优化目标的几何意义后,我们再来尝试倒推它的两项设计:1)为什么要乘 $s$;2)为什么要令两个向量的距离最短。

CFG 的目的就是让带约束输出能够尽可能远离无约束输出。标准的 CFG 只告诉我们如何让某一个点 (带约束输出)远离另一个点(无约束输出)。现在,假如无约束输出是一条直线,那我们应该以「最快」的方向让带约束输出远离这条直线。这里的「最快」方向其实就是点对直线做垂线所在方向。

根据上述分析,我们解释了第二项设计:令向量距离最短,本质原理是找到一个让带约束输出远离无约束输出所在直线的「最快」方向。

那么,第一项设计又如何解释呢?为什么可以给无约束输出多乘一个系数呢?这就很难给一个严谨的解释了。我们只能猜测,对于输出速度的流匹配模型来说,无约束输出的速度的方向比速度的大小更加重要。因此,我们不仅要远离此时无约束的输出,还要远离无约束输出所在直线(所有速度方向相同的点)。

关于这两项假设,作者在论文中做了一定的解释。

对于为什么要乘 $s$,作者认为这是受到 classifier guidance 的启发。在 classifier guidance 中,无约束项和梯度项(在 CFG 中梯度项即为带约束输出)之间是有一个自定义参数 $s$ 来调节它们的相对比例的。CFG 本来就是 classifier guidance 的一种特殊形式,自然也可以用上这个设计。这样看来,作者也没能从理论上讲清为什么要乘 $s$,只是参照以往工作,尝试性地使用了这项改动。

对于在求解 $s$ 时为什么要令两个向量的距离最短,作者解释如下:假设最优情况下,ground truth 输出应为 $v_t^{*}(x, c)$,那么我们应该最小化改进版 CFG 输出 $\tilde{v}_t^{\theta}(x, c)$ 与其的距离(参数 $s$ 为变量)。

上式其实描述了两个向量之间的距离。根据三角不等式(三角形两边之和不小于第三边),可以估算其上界:

所以问题变成了令 $\tilde{v}_t^{\theta}(x, c)$ 的模尽可能小,也就是令改进版 CFG 里两个向量距离尽可能短。按照我们上文的几何分析,就可以求出最优的 $s$。

我认为上述分析非常牵强。作者引入 GT 输出 $v_t^{*}(x, c)$,只是为了说明模型输出和 GT 的距离的上界包含 $\tilde{v}_t^{\theta}(x, c)$ 的模。可是,优化上界,真的就能优化这个值本身吗?这无法从理论上说明,只能通过实验来验证。应该令 $\tilde{v}_t^{\theta}(x, c)$ 的模尽可能小,同样是一个实验性的结论。

零初始化流匹配早期输出

在简单的高斯混合任务,即从带噪分布 $\mathcal{N}(0, \mathbf{I})$ 生成目标分布 $\mathcal{N}(\mu, \mathbf{I})$ 上,我们可以直接求出流匹配的闭合解。因此,在这种简单任务上,我们可以训练流匹配网络,观察它和流匹配闭合解的误差,进而研究流匹配网络的学习规律。

通过这种研究方法,作者发现了另一个规律:训练刚开始时,在流匹配的开始阶段(即图像为高斯噪声的阶段),网络预测的速度 $\tilde{v}_0^{\theta}$ 非常不准确,甚至不如直接输出 $0$ 向量。只有得到充分训练后,网络的预测值才比输出 $0$ 更好。

在更大的 ImageNet 数据集上,该结论同样有效。

我们可以猜测,现在大型文生图模型或者视频模型都没有充分收敛。因此,我们可以对这些模型做一个非常简单的改进:跳过刚开始几次去噪步骤(即让流匹配输出 $0$ 向量),让纯高斯噪声从某个中间时间步开始去噪。

实验

把 CFG 公式改进,并且加入零初始化后,我们就得到了最终的 CFG-Zero*。作者用大量定性和定量实验证明了 CFG-Zero* 能够从多个指标上提升各类流匹配模型的效果。网上有许多 AI 应用博主分享了 CFG-Zero 的使用效果 (感兴趣的读者可以去 Bilibili 搜索 CFG Zero Star),发现它确实能够增强图像细节。在社区中,CFG-Zero 也广受好评,被加入了各个流匹配模型代码仓库的官方实现中。

在这篇博文中,我们主要关注 CFG-Zero* 的消融实验,并分析它们是怎么支持前文的方法的。

在消融实验一节中,作者首先展示了不同采样配置下,CFG-Zero 相较普通 CFG 的表现。这里的采样配置包括不同的采样步数、不同的 CFG 强度。从图中可以看出,CFG-Zero 在多数情况下都有优势,但数值上不是很明显。

由于 CFG-Zero* 实际上由两个独立的方法组成,我们需要分别验证它们的有效性。作者同样给出了相关表格。可以看出,这两个方法都有用,但数值提升不是很明显。并且,不用零初始化,只加入缩放参数的提升似乎非常微小。

论文里还有一个应该对刚开始多少步做零初始化的拓展消融实验。这个实验和原理验证关系不大,在此略过。

仅从这些实验结果中,我感觉 CFG-Zero 在这几项指标上的提升非常不明显。我猜想 CFG-Zero 的作用可能更需要通过定性结果来反映,在一些普通 CFG 生成得不理想的例子上,CFG-Zero* 或许能够做好,就像论文开头展示的对比结果一样。

以上是论文里展示出的消融实验。但在我看来,为了支撑方法中的假设,论文还需要提供更多的实验结果:

  • 为了证明优化 $|| \tilde{v}_t^{\theta}(x, c) ||_2^2 + || v_t^{}(x, c)||_2^2$ 这个上界,就能优化最后的误差 $|| \tilde{v}_t^{\theta}(x, c) - v_t^{}(x, c)||_2^2$,应该展示一个折线图,说明随着 $|| \tilde{v}_t^{\theta}(x, c) ||_2^2$ 变小,误差也能变小。另外,此时 $\tilde{v}_t^{\theta}(x, c)$ 其实不仅可以是 CFG 结果,还可以是带约束或者无约束的结果。
  • 为了证明 $s=s^*$,即沿着垂线方向远离无约束输出是最好的,应该展示一个折线图,表示不同 $s$ 取值下和和 GT 误差的变化。
  • 文章多次强调这些优化是针对流匹配的,但是没有从原理上讲为什么这些方法用不到 DDPM 上,也没有展示任何相关实验结果。

如果是作为一篇面向应用的论文,文中的实验结果是非常完备的。但从理论贡献上看,如果能够多展示一些支持理论分析的实验,文章就能给读者带来更多启发。

总结

CFG-Zero 是一种针对流匹配设计的即插即用的改进版 CFG。它由两个独立的部分组成:1)给无约束输出添加缩放系数;2)跳过开始几步流匹配去噪步骤。实验表明,CFG-Zero 无论是在文生图模型还是视频模型上都表现得很好。目前,CFG-Zero* 已经加入了 Diffusers 框架,并被各个主流流匹配官方仓库使用。

CFG-Zero 论文的主要贡献是提出了一种实用的流匹配采样增强方法。对于这类方法,用户会希望方法尽可能不需要训练,且效果尽可能好。CFG-Zero 完美契合了这两个条件。可以预见,CFG-Zero* 将成为未来流匹配模型的标配。

CFG-Zero* 论文的另一大贡献是提供了一种分析流匹配模型的方法,即在简单的高斯分布生成任务上,比较深度学习模型和闭合解之间的误差,探索模型的学习规律。基于这种研究方法,论文发现流匹配模型在去噪初期预测结果极其不准这一现象,比巧妙地用零初始化提升了推理的速度和质量。

尽管论文提出了一种 CFG 改进公式,但这套公式背后的原理还没有完全被该论文揭示。后续可能可以探索的点有:

  • 这套方法是否能用到 DDPM 或者其他加噪公式或者预测目标上?如果不能,是哪一个区别导致的?
  • 当前系数 $s$ 的选择真的是最优的吗?除了给无约束项添加系数,有没有其他的 CFG 改进方法?

在分析这篇文章的理论时,我再次感受到了目前深度学习方法面临的窘境:多数有效的方法难以详尽地解释清其原理,很多重要步骤完全是由实验结果决定的。比如 DDPM 中,前面算变分上界算得好好的,到最后一步算损失函数时,突然就把系数省略了。很多方法看上去有一套严密的数学公式,但实际上其中存在若干难以解释的步骤,而往往这些通过实验得到的步骤才是方法成功的关键。所以,在学习这些看起来很复杂的方法时,除了一股脑地接受论文里的推导外,我们也要仔细审视推导中究竟哪些步骤其实是存在逻辑跳跃,是由实验决定的。

前段时间,多模态模型 GPT-4o 推出了新版图像生成功能,又一次点燃了社区的 AI 创作热情。作为一款多模态模型,GPT-4o 不仅有着不输纯图像生成模型的质量,还能借助其内置的强大文本理解功能,打造各种各样有趣的图像编辑应用。

我一直没有写博文介绍 GPT-4o。这是因为 OpenAI 完全没有给出任何技术细节,只能从用户的生成结果中推测模型原理。没有技术报告可以解读,我还不如多去网上看一看网友们的创意呢。

虽然没有任何新技术可以学习,但我一直在关注相关的新闻报道,并从用户的视角思考 GPT-4o:为什么之前的多模态模型没火,这次 GPT-4o 就火了呢?更强的多模态模型又能为用户带来哪些新应用呢?最终,我想把我思考的内容以杂谈的形式分享出来,而不是严谨地去谈某一项技术。

在这篇文章中,我会从多个角度谈一谈 GPT-4o。首先,我会简单展示一下我自己的使用结果,以说明 GPT-4o 新图像生成的功能;之后,我会先概述所有多模态模型的设计空间,再结合其他社区用户的意见,给出我自己对 GPT-4o 图像生成原理的猜测;接着,我会基于最新发表的 GPT-4o 评测报告 (GPT-ImgEval: A Comprehensive Benchmark for Diagnosing GPT4o in Image Generation,后文简称「评测报告」),谈一谈 GPT-4o 的定量分析结果;最后,我会从科研和创业两个角度分享我对 GPT-4o 及多模态模型的未来展望。

新版 GPT-4o 的内置图像生成

此前,比较火热的图像模型,比如 Stable Diffusion, FLUX.1,都是文生图模型。这些模型往往会用一个预训练的文本编码器解读文本内容,再基于解读好的文本内容,只学习图像生成一种任务。这就好比是一个画家突然闭门不出,不再更新自己的沟通能力,一心只磨练画技。而在多模态模型中,模型的输入输出都会包含文本和图像。也就是说,模型要同时学习图像和文本的理解和生成。这就像是一个积极参与社交的画家。

GPT-4o 此前的图像生成功能由 DALL·E 完成。而 DALL·E 是一个独立的图像生成模型。因此,为了实现图像生成,GPT-4o 会解析用户输入中的图像生成命令,输出文本等约束信息,最后把所有约束信息传给 DALL·E。这样看来,旧版 GPT-4o 和图像生成模型的关系不是特别紧密,二者的功能相对独立。而更新过后,GPT-4o 更多地负责了图像生成的功能,更多图像生成的相关知识存储在了 GPT-4o 的模型权重中。

把大语言模型 (LLM) 的知识引入图像生成模型后,有两个显而易见的好处:

  • 提升文本理解力:将预训练文本编码器升级成 LLM 后,图像生成模型对于语言的理解更强了
  • 支持更广泛的任务:由于现在图像既是输出,又是输入,所以多模态模型天生支持各式各样的图像编辑任务。

其实所有多模态模型都有这两个优势,为什么 GPT-4o 就火了呢?在我看来,GPT-4o 成功的关键并不是技术上或者功能上的突破,而仅仅是模型能力上的提升,尤其是图像质量的提升(我简单尝试了目前可以用的在线 demo,此前多数多模态模型都不支持图像输入+图像输出,哪怕支持,生成图像的质量也很差)。之前多模态模型的生成图像质量一直比不过单纯的文生图扩散模型,但 GPT-4o 这次却大放异彩。这种综合能力上的提升从量变引起了质变,进而点燃了社区的热情。

当图像生成的输入从纯文本拓宽成图像+文本后,模型的应用场景一下就变得丰富了起来。按输入输出的格式分类,图像生成应用大体可以归结为以下几类:

  • 纯文本生图
  • 根据一张图像和编辑命令,局部修改/全局重绘图像
  • 根据多张图像和编辑命令,融合多张图像的内容
  • 利用对话机制,对已经生成好的图像做多次编辑

下面,我将展示我自己用 GPT-4o 在各种输入输出格式下跑出来的一些结果。

首先是最热门的风格迁移功能(由于现在 GPT-4o 加上了版权检测,需要想办法让它画出来的东西「不太有名」)。

然后是输入两张图像,对图像中的元素做组合。

最后是多轮图像对话。

可以看出,GPT-4o 确实能实现不少功能,输出图像的质量乍看之下也不错。但仔细一看的话,图像在内容合理度、内容一致性、任务理解力、图像空间理解力上还有很大的提升空间。我还随便想了几个整活的主意,但都实现得很不理想。

GitHub 上已经有人收集并分享了 GPT-4o 的种种应用场景:https://github.com/jamez-bondos/awesome-gpt4o-images 。在此我就不再赘述了。

新版 GPT-4o 的模型架构

多模态图像生成范式回顾

在分析 GPT-4o 的模型架构前,我们先对多模态模型的生成范式做一个回顾。

最早,在用 Transformer 搭建语言模型时,我们要想办法把自然语言转换成神经网络能够理解的数据。由于自然语言可以看成是 token (词元) 组成的序列,而 token 的取值是有限的,我们可以把每类 token 映射成整数。比如,假设 token 从二十六个字母中取,我们就让 a0b1,以此类推。这种把自然语言变成离散 token 的模块叫做 “tokenizer”,把 token 变回自然语言的模块叫做 “detokenizer”。

要把图像加入 Transformer,其实就是要决定怎么把图像翻译成 token (这里 token 的意义从文本的「词元」拓展成了一小块图像,多个小块图像可以像词元一样拼成完整图像),以及怎么把 token 翻译回图像。恰好,图像自编码器的编码器 (encoder) 和解码器 (decoder) 就能完成上述的翻译过程。注意,文本和 token 的转换一般可以用简单的程序规则来描述,而图像的自编码器需要用可学习的神经网络来实现。我们可以把这种经典的架构简称为 “a” 类架构。

这里我们忽略了自编码器的细节。实际上图像自编码器会压缩图像的边长,且有连续和离散自编码器之分。如果读者对这些内容感到疑惑可以先学习图像自编码器的知识。

把 token 变成图像,其实就是在做图像生成。因此,图像解码器理应是一个生成模型。但如果解码器能力太弱,Transformer 在学习图像生成时就要花更多的精力。因此,为了减少 Transformer 学习图像生成的压力,就要让解码器的图像生成能力变强。传统的解码器是一个直接输出图像的神经网络,我们可以将其改造成扩散模型,即让解码过程变成扩散模型去噪过程,解码网络不直接输出解码图像,而是输出扩散模型里的预测值。我们可以把这种解码器升级成扩散模型的架构称为 “b” 类架构。

在上述讨论中,我们其实忽略了一件事:图中的 Transformer 到底输出了啥?其实,这里的 Transformer 的输出取决于我们对文本/图像生成方式的定义。一般来说,我们用自回归的 (AR) 方式生成文本,那么 Transformer 的输出就是已知前 $i-1$ 个 token 时,第 $i$ 个 token 的概率分布(假如词元是二十六个字母,那么 Transformer 的输出就是 26 个概率,即 token 属于每种字母的概率分布)。如果我们也想用同样的方法生成图像 token,就要让自编码器的编码器输出离散 token(即使用 VQVAE)。在上面两张图中,我们默认文本和图像都采用同样的自回归生成方法。

自回归其实不要求模型的输出是概率分布,进而不见得要用离散自编码器。详见 MAR 论文 (Autoregressive Image Generation without Vector Quantization)

这样看来,我们可以对图像的生成方式做一些改进:我们不用自回归一个一个输出图像 token,而是用一个扩散模型一次性建模所有图像 token 的生成(全序列扩散模型)。我们可以把这个混合范式称为 “c” 类架构。

b 和 c 架构都是把扩散模型引入了经典 a 架构,只是在引入时的出发点不一样。事实上,这两项改动是独立的。我们完全可以把 b, c 改动都用上,得出一个使用了两遍扩散模型的 “d” 架构。硬要说 b, c 两个架构有什么区别的话,它们的区别就在于解码器不会受到文本生成任务的干扰,而如果让输出文本 token 分布的 Transformer 也预测噪声,就会影响文本任务的学习。

让我们来尝试把所有多模态模型的设计空间总结一下。在此之前,我必须吐槽几句。我认为现在多模态模型的设计都大同小异,仅仅是某几个互相独立的模块存在着多种选择。但很多人会把相关概念混淆,比如把「自回归」和「扩散模型」看成两个对立的生成方式(「自回归」和一次性生成所有元素的「全序列扩散模型」才是对立的)。很多论文也会把模块上的小变动渲染成大创新,并混淆各类名词的使用。我希望通过下面的总结能够帮助大家理清多模态模型的设计空间。

  1. 文本生成范式既可以用经典下一个词元自回归,也可以预测下 N 个词元 (deepseek),还可以按乱序预测下 N 个词元 (MaskGIT, Block Diffusion,通常会被叫做「离散扩散模型」)
  2. 图像生成范式可以分成下一个词元自回归 (VQGAN)、乱序预测下 N 个词元 (MaskGIT, MAR)、用扩散模型一次性建模整个图像的分布 (Latent Diffusion Model)
  3. 如果在图像生成时用到了词元,既可以是离散词元 (VQGAN),也可以是连续词元 (MAR),其中连续词元的分布是用像素级扩散模型表示的
  4. 图像的自编码器既可以是 CNN, 也可以是 ViT;自编码器的解码器既可以直接输出图像,也可以用扩散模型间接根据 token 输出图像
  5. 图像自编码器可以先按传统自编码器的重建任务单独训练,并在后续训练中冻结权重,也可以用各种各样更灵活的方式,比如使用预训练图像编码器(如CLIP),或让解码器在中间 Transformer 训练好以后再训练

下面是一些现有多模态模型的分类:

  • 以 Chameleon 为代表的经典多模态模型 (a 类架构) 在文本和图像上都使用下一个 token 预测,使用了 VQVAE 以建模离散图像词元,自编码器是经典 CNN 直接输出图像的架构,先单独训练自编码器再训练多模态 Transformer。
  • Emu1, Emu2(b类)在 a 类架构的基础上,把解码器换成了扩散模型,并把词元分布建模成连续分布(但是,这个连续分布不是通过扩散模型而是通过回归任务建模的,详见论文)。此外,解码器会在中间的 Transformer 训练好之后再微调。
  • Show-o 在 a 类架构的基础上,把图像生成任务从下一 token 预测变成随机预测下 N 个 token。
  • Transfusion(c 类)在 a 类架构的基础上,把图像生成任务从下一 token 预测变成全序列扩散模型。因此,网络中不存在离散图像词元了,VQVAE 被自然地换成了 VAE。

新版 GPT-4o 多模态架构猜测

首先,可以确定 GPT-4o 一定包含了扩散模型。多项事实可以印证这一点。

1
2
3
4
5
6
Fixes:
* model compressed representations
* compose autoregressive prior with a powerful decoder"

On the bottom right of the board, she draws a diagram:
"tokens -> [transformer] -> [diffusion] -> pixels"
  • 根据经验,从图片质量上来看,纯自回归模型做不到这么好

为了进一步验证模型中是否含扩散模型,在 GPT-4o 图像生成评测报告中,作者借助了神经网络的帮助——作者先用一个 VAR 和一个扩散模型分别生成大量图片,以训练一个分辨图像是否来自扩散模型的二分类器,再用这个分类器来区别 GPT-4o 生成的图片。结果显示,GPT-4o 的输出更像是扩散模型生成的。

得知 GPT-4o 大概率含有扩散模型之后,下一步我们需要猜测这个扩散模型放在了模型的哪一部分。根据上一节的讨论,我们能够猜测 GPT-4o 里的扩散模型可能出现在以下几处:

  1. 将解码器完全换成扩散模型
  2. 将图像生成任务从自回归换成全序列扩散模型
  3. 仍然使用自回归生成,但是参考 MAR,把离散的类别分布换成连续的像素级扩散模型建模的分布(扩散模型一次只输出一个像素,而不是一次输出整个图像)

由于 1 是 GPT-4o 此前的技术路线,即直接把 DALL·E 当作图像解码器(生成器),我们可以排除可能 1。

那么,是否 GPT-4o 也像 Transfusion 一样,在图像生成时使用了全序列扩散模型呢?根据用户在 X 上分享的观察 (https://x.com/jie_liu1/status/1905761704195346680 ),使用 GPT-4o 生成图像时,网页会依次传输以下几张图片(网页上的动画是靠前端程序实现的)。可以看出,图像确实是从上到下依次生成的。因此,猜想 2 完全不用自回归也不太可能。

那么,经排除法,只剩下猜想 3 了:GPT-4o 没有使用离散视觉 token,而是在建模单个视觉 token 分布时使用了像素级扩散模型。评测报告的作者也是这样认为的。

我们的探索还没有结束。在思考 GPT-4o 原理时,我突然想到了一个实验:输入一张图片,用 prompt 让模型输出一张一模一样的图片会怎么样?如果让 Gemini 2.5 来做,会得到以下结果:输出图片和输入图片完全不一样。这是因为 Gemini 使用了 Imagen 3 来生成图片(作为解码器),图像生成模型和自回归 Transformer 比较独立,难以维持图片的一致性。

而 GPT-4o 则不同,在相同任务下,GPT-4o 的输出一致性高了很多,起码画风是对的,文字也几乎没变。这也是上述猜想 1(将解码器换成扩散模型)不成立的另一个证明。

上面这样实验其实不止我做过,其他人也尝试过类似的事。比如,在评测报告里,作者在「缺点」一节展示了差不多的例子。

但我的实验还在继续:接着上面的对话,我又再次要求 GPT-4o 画一张一模一样的图片。这次,图像的相似度提高了很多。

为了防止多轮对话导致的测试环境不同,我新建对话并要求 GPT-4o 做了两个重绘任务:第一次输入的是 GPT-4o 自己生成的图像,第二次输入的是一张非常简单的图像。在这两种情况下,GPT-4o 的重绘一致性都很不错。

从这个现象中,能得出哪些结论呢?第一,我认为,GPT-4o 并不是不能做重建任务。GPT-4o 的真正问题是输出图像的多样性较低。这一点可以通过 GPT-4o 能够较好地重建自己生成的图像及简单图像反映。开发者可能用了某些特殊手段,比如在高质量数据集上后训练模型,让 GPT-4o 只能输出高质量图片,代价是牺牲多样性。

第二,GPT-4o 一定使用了某种重建任务,让图像解码器能够重建编码器的输出,即让图像的编码器和解码器构成一个自编码器。如上一节的第 5 个设计维度所示,在多模态模型中,既可以用预训练的自编码器来将图像传入 Transformer,也可以单独用预训练的图像编码器、解码器。用预训练模型的好处在于节约训练成本,比如我们可以复用 CLIP 的图像理解能力和 Stable Diffusion 的图像生成能力。但这样做的弊端在于编码器的「输出语言」和解码器的「输入语言」不是同一种语言,Transformer 无法融会贯通地处理图像数据,也无法对生成的图像做多轮编辑。从 OpenAI 官方透露出来的信息「使用更强大的解码器」(见上文中官方网站里的示例 prompt)中,我猜测 GPT-4o 在编码图像时用到了某种程度的 low-level 编码器(保留图像局部特征,使图像有足够的信息被完美重建),并特意以重建任务重新训练了一个强大的解码器。

我再多猜一点,这个解码器可能是 ViT 架构的。因为在自回归生成的过程中,所有 token 并没有生成完,但我们依然能得到完整的中间图像。在 Transformer 中,如果我们使用经典的 encoder-decoder 架构,无论输入 token 数是多是少,输出的 token 数都是一样多的。

最后再分享一点实验结果。我还测试了 GPT-4o 对同一张图片,不同分辨率下的重绘结果。惊人的是,在输入分辨率是 256x256 左右时,文字的重建结果比 1024x1024 左右的输入还要好。这是不是说明模型原生的分辨率就是 256x256 ? GPT-4o 是否对输入图片都做了预处理?在输出 1024x1024 的图片时是否做了 4 倍超分辨率?

总结一下,我认为 GPT-4o 在处理图像时用到了能够保留图像局部特征的编码器,并以重建任务重新训练了一个解码器。图像以连续 token 的形式传入 Transformer,以经典的下一 token 预测学习自回归图像生成,每个 token 的分布是用像素级扩散模型建模的。模型在高质量图像数据上后训练过,以牺牲多样性为代价,保证输出图像总是高质量的。

评测报告概览

讲完我自己的一些猜想后,我们来看一下 GPT-4o 评测报告 (GPT-ImgEval: A Comprehensive Benchmark for Diagnosing GPT4o in Image Generation) 里的一些内容。

先看一下文生图模型都会测试的 GenEval 指标。这个指标反映了模型在多种任务下的指令跟随度。这些任务包括单个物体、两个物体、指定物体数量、指定颜色、指定位置等。GPT-4o 在这个指标上一骑绝尘,战胜所有纯文生图模型和多模态模型。

再看一下反映图像编辑能力的 Reason-Edit 指标。这个指标要求编辑方法能够理解一些复杂的编辑指令,往往要求模型具有一定的文本推理能力。GPT-4o 同样比之前的方法好了很多。

最后,评测报告还分析了 WISE 指标上的结果。WISE 指标不仅要求模型能够理解文字,还要有一定的常识。比如,如果输入是「章鱼面对危险时的举动」,那么模型应该画出一个正在喷墨的章鱼。

在这个指标上,GPT-4o 也遥遥领先,远强于此前最强的 FLUX.1 模型。

以上指标都不涉及图像质量,评价图像质量的最好指标还是社区反馈。在靠用户打分的文生图模型竞技场里,GPT-4o 目前高居榜首。(https://artificialanalysis.ai/text-to-image/arena?tab=leaderboard)

从上述评测结果中可知,GPT-4o 在几乎所有图像评测指标上都领先于之前的模型。

当然,这些评测指标并不能反映 GPT-4o 在所有任务下的表现。在需要精细编辑的任务中,仍然需要使用专门的图像模型。评测报告分享了 GPT-4o 的一些缺点。其中,a, b, d 都是指输出和输入的一致性不够高,c 说明模型在处理非英文文字时不够好,e 说明 GPT-4o 在笔刷编辑任务上做得还不够好。

当然,我认为这些缺点都不是很严重。我们完全可以通过定制化 GPT-4o 来完成某种特定任务。接下来,我来从科研和应用两个方面谈一谈 GPT-4o 的前景。

多模型图像生成未来畅想

科研方面

很多人认为,新版 GPT-4o 出来了,是不是很多图像编辑工作都没有做下去的必要了?在这类「是否悲观看待新技术取代旧技术」的问题上,我的回答永远是积极的。之前的方法不行了,我们就基于 GPT-4o 开发新编辑方法。新的技术虽然会导致部分旧的方案不再可行,但同时也会带来新的可能。我们应该积极地寻求改变,寻找新的方向。从另一个角度来看,GPT-4o 的效果好,也不代表旧的方法就完全没有可取之处。我认为科研工作并不应该以效果好为唯一目的,更重要的是能否带来科研上的启发。

在讨论 GPT-4o 对科研的影响时,其实我觉得最重要的不是谈论哪些任务会被 GPT-4o 直接解决,而是是否有一个像 GPT-4o 一样强大的开源多模态模型供大家研究。去年 Sora 出来时,大家也担心视频生成任务是否就没有做的价值了。但后来以 CogVideoX 为代表的开源视频模型推出后,还是陆陆续续有不少无需训练的视频生成工作发表的。因此,我们可以根据去年的经验,先积攒一些和多模态模型相关的科研想法。等几个月有开源模型出来后,我们再快速上手做实验。

接下来我再谈一些具体的科研想法。思考新科研方向时,最容易的做法是寻找现有方法的缺陷。在 GPT-4o 图像生成中,最明显的缺陷是无法做精细的(比如像素级)编辑,且模型输入输出的一致性不够高。或许这可以通过加数据来解决,但我觉得这个问题可能涉及视觉神经网络的一些本质缺陷:在下采样过程中,图像的像素级特征不可避免地丢失。我会倾向于从更本质入手,分析这个问题出现在模型的哪一块,并加以解决。

GPT-4o 另一个明显的问题是仅有英文生成得比较好。这应该是在大量数据训练下的结果。其他语言效果不好,仅仅是因为数据不够多。我们能不能单独设计一套文字生成方法,再把文字生成融入到图像中呢?当然,这个问题看起来更偏向工程一些。

还有一些子问题也值得探索。比如,就现在的技术趋势来看,我们无法以相同的方式处理文本和图像,无约束图像生成仍是一个有研究价值的子问题。继续研究扩散模型以及自回归和扩散模型的结合方式,仍能帮助多模态模型的发展。另外,我觉得多模态模型的高性能训练一定是一个有价值的方向。如果以后模型大到只有大公司才能微调,学校实验室都无法做微调实验的话,这个领域一定是发展不下去的。

我还想单独谈谈评测的问题。似乎现在在文本任务和图像理解任务上的指标很多,但是在图像生成方面的指标很少。我觉得这篇 GPT-4o 评测报告里用到的指标还不够全面,多数时候我觉得文生图竞技场里的用户体验排名更有说服力。就像现在大家往往用数学题和编程题来检测大语言模型的思考能力一样,我们也需要提出一些更加全面、公正的指标。另外,就无约束图像生成上,我觉得 ImageNet-256 FID 这项指标已经被大家刷得差不多了,很多时候在这个指标上表现好也不能代表同一个模型在大型文生图任务上就表现好。为了加速技术迭代,我们在简单的无约束图像生成上也需要寻找更有挑战性、不增加太多计算量、不容易被暴力过拟合的指标。

应用方面

在思考一项技术的应用时,我完全不会考虑它能不能发论文,而是会考虑有多少用户喜欢这种应用,以及做出了应用能不能赚钱。就目前 GPT-4o 的表现来看,我认为未来多模态大模型有着广阔的应用空间。

在谈这些之前,我想聊另一件事。从开发难度来看,我会把所有基于大模型的应用分为三类:

  1. 像谷歌、OpenAI 一样从头训练基础模型
  2. 完全不修改模型,仅通过调用 API 和编程来开发应用
  3. 为某一项任务定制数据和方法,微调预训练模型,再开发应用

三类应用的本质区别在于花多少资源去训练模型。如果是要创业的话,在我看来,第一个方向太拥挤了,各个公司的模型同质化严重,且需要耗费大量资源,很没有意思。而剩下两个方向可以集百家之长,让大公司开发出来的大模型给自己打工。这两个方向的核心竞争力都在于应用的创意,以及能否早一步抢占市场,吸引用户,以用户社区为壁垒。如果是我自己的话,考虑到我的技术背景,我会选择赛道不那么拥挤的第三个方向,做一些别人不那么容易做出来,同时对用户来说很有帮助的应用。

谈回大模型应用本身。GPT-4o 能带来哪些新应用呢?

我的第一感是开发更加强大、通用的图像编辑应用,以取代 PhotoShop。目前,PhotoShop 在使用上还是有不少门槛,而 GPT-4o 仅需文本指令即可实现编辑。但 GPT-4o 及现在所有 AI 绘画模型,都在可控性上存在着严重的不足,使得它们在功能上还取代不了 PhotoShop。因此,我们要提升多模态模型的可控性。我的一些初步想法是:像 SAM 一样,先允许用户通过鼠标点击或者文本提示,选中输入图像中的某一物体。之后,我们通过文本提示,指出要修改的物体属性,比如位置、大小、亮度等。模型一次性输出某属性从 0~1 逐渐变化的所有输出,我们最后只需要调整滚动条,从中选择一个效果最好的输出即可。

另外,我们也可以思考多模态模型带来的全新功能。从 GPT-4o 当前的多轮编辑结果中,我们发现 GPT-4o 能一定程度地组合不同图像中的内容,比如实现经典的风格迁移任务,把图像 A 的风格迁移到图像 B 的内容上。这一功能对 2D 游戏美术资源生成来说十分有用。一般 2D 游戏都会进行素材的排列组合,以复用资源,并让玩家产生亲切感。比如在《塞尔达传说》一代中,多数怪物都有红色和蓝色两个版本,两个版本的怪物有着类似的行动模式。如果先画出所有怪物的红色版本,给一组怪物的蓝色版本的示例,GPT-4o 可能就能自动把剩下的怪物也变成蓝色版本。推而广之,不止是颜色,我们可以把角色/怪物的所有组成部分进行拆解,比如拆解成头盔、武器、盾牌、衣服等,先让多模态模型分别生成大量部件,再让模型根据某一种排列组合方案,自动生成最终的结果。在 GPT-4o 之前,或许也有方法能做类似的事,但这些方法难以维持多组输出结果的风格一致性;而多模态模型支持多轮对话,通过参考上下文,模型能够理解多轮编辑都是在做同一件事。可以预见,多模态模型一定是未来图像编辑的研究重点。

从上述这个简单应用中,我们能够提炼出一套设计新应用的思考方式:

  • 从现有方法的角度,思考大模型在哪些地方做得不够好。比如,PhotoShop 可以做精细编辑,而大模型只有粗略的文本提示,缺乏可控性。
  • 从大模型的功能出发,思考能够设计哪些新颖的交互方式,以贴合用户的需求。比如多模态大模型能理解图像内容并对内容进行组合,那么我们就基于已有素材,让模型自动生成素材排列组合后的结果。

欢迎大家从这两个方向思考,探索多模态模型的新的可能。

参考资料

我之前的博文:

速览多模态模型 Transfusion 和 Show-o:用 Transformer + 扩散模型同时处理文本和图像

解读何恺明团队新作:不用向量离散化的自回归图像生成

链接/论文:

  • 评测报告:GPT-ImgEval: A Comprehensive Benchmark for Diagnosing GPT4o in Image Generation

  • GPT-4o 新版图像生成官方公告:https://openai.com/index/introducing-4o-image-generation/

  • Emu 系列多模态模型:https://github.com/baaivision/Emu

  • Chameleon 论文:Chameleon: Mixed-Modal Early-Fusion Foundation Models

  • Tranfusion 论文:Transfusion: Predict the Next Token and Diffuse Images with One Multi-Modal Model

  • Show-o 论文:One Single Transformer to Unify Multimodal Understanding and Generation

  • MaskGIT 论文:MaskGIT: Masked Generative Image Transformer

  • MAR 论文:Autoregressive Image Generation without Vector Quantization

潜扩散模型 (Latent Diffusion Models, LDM) 常因生成过程不稳定而备受诟病:哪怕模型的输入只是受到了一点微小的扰动,模型的最终输出也会截然不同。以视频逐帧风格化任务为例,哪怕对每帧使用同样的 Stable Diffusion ControlNet 图生图编辑方法,同样的随机种子,生成的风格化视频会有明显的闪烁现象。

为了找出这一现象的原因,我们设计了一种配置简单的扩散模型编辑实验:平移扩散模型的初始噪声,观察去噪输出。理想情况下,平移输入噪声,输出图片也应该会平滑地平移。然而,实验结果却显示,直接平移输入噪声会大幅改变输出图片;使用了提升内容一致性的 Cross-frame Attention (CFA) 技术后,虽然图片的主体内容不再变化,可是输出图像在平移时还是有不自然的「抖动」现象。

为什么 LDM 的生成过程这么不稳定呢?为什么 CFA 技术又能提升生成的一致性呢?在我们团队近期发表于 CVPR 2025 的论文 Alias-Free Latent Diffusion Models: sImproving Fractional Shift Equivariance of Diffusion Latent Space 中,我们从平移同变性 (shift equivariance) 的角度分析了 LDM 的生成稳定性,并提出了一种能够提升平移同变性的 Alias-Free LDM (AF-LDM) 模型。我们在无约束人脸生成、视频编辑、超分辨率、法向量估计等多个任务上验证了该模型的有效性。

在这篇博文中,我将系统性地介绍一下这篇论文。我会先简单回顾背景知识,让对信号处理不太熟悉的读者也能读懂本文;再介绍论文的方法、实验、贡献;最后从本工作出发,探讨新的科研方向。

项目网站:https://zhouyifan.net/AF-LDM-Page/

背景知识回顾

本节我会先回顾 LDM,再回顾对平移同变性做了深入研究的 StyleGAN3。由于理解 StyleGAN3 需要了解信号处理的基本概念,我会在尽量不用公式的前提下讲清楚图像频率、混叠等概念。为了简化文字,我会省略理论推导,并使用一些易懂却不见得严谨的叙述。对这些原理感兴趣的读者可以系统性地学习一下 StyleGAN3 论文。

潜扩散模型

扩散模型是一种图像生成模型。生成算法的输入是一张纯噪声图,输出是一张清晰图像。算法执行 $T$ 步,每一步都会调用一个去噪网络来去除图像中的部分噪声。

由于扩散模型运算较慢,我们可以借助一个变分自编码器 (VAE) 来压缩要生成的图像,减少要计算的像素数。简单来讲,VAE 由一个编码器 (encoder) 和一个解码器 (decoder) 组成。编码器负责压缩图像,解码器负责将压缩图像重建。网络的学习目标是让重建图像和输入图像尽可能相似。训练结束后,我们可以单独使用编码器或解码器,实现压缩图像和真实图像之间的相互转换。论文里通常会把压缩图像称为潜图像 (latent image 或者 latent)。

潜扩散模型 (Latent Diffusion Models, LDM) 是一种借助 VAE 加速的两阶段扩散模型。普通的像素级扩散模型会生成一张同样大小的清晰图像。而 LDM 会先生成一张潜图像,再用解码器把潜图像还原成真实图像。我们可以把解码操作简单看成一个特殊的上采样。比如在 Stable Diffusion 中,潜图像的边长被压缩了 8 倍,即解码器会对潜图像上采样 8 倍。

训练 LDM 时,我们需要获取训练图像的潜图像。因此,为了构建训练集,我们会用编码器把训练图像转换为潜空间的图像。

图像的频域表示

在计算机中,图像有很多种表示形式。最常见的形式是空域图像:图像由一个像素矩阵表示,每个像素存储了图像在某个位置的颜色值。此外,还可以把图像表示为频域图像:我们认为图像是由许多不同频率的正弦函数叠加而成的,频域图像的每个像素存储每个频率的正弦函数的振幅和相位。直观来看,图像在空域和频域的可视化结果如下所示:

具体来说,我们可以把空域图像和频域图像都看成二维数组。对于空域图像来说,数组的索引是二维位置坐标,值是此位置的颜色值;对于频域图像来说,数组的索引是横向和纵向的一对频率,值是该频率下的正弦函数的振幅和相位。

为什么我们要大费周章地在频域里表示一张图像呢?这是因为图像的各个频率分量从另一个维度拆分了图像中的信息,这种拆分方式有助于我们分析图像。一张空域图像可以通过 FFT 操作变换成频域图像,而频域图像又可以通过 IFFT 操作变回空域图像。那么,我们可以用如下操作可视化不同频率分量的作用:

  1. 把输入空域图像用 FFT 转换到频域
  2. 对频域图像滤波,分别得到低频、中频、高频三张频域图像
  3. 用 IFFT 在空域中可视化三张频域图像

该操作的结果如下所示。可以看出,图像的低频分量描述了图像的全局结构,而中频分量和高频分量进一步完善了图像的细节。

混叠

假设有一根时针在顺时针匀速旋转。现在,我每秒拍一次照片,一共拍下了时针的三张照片。请问,时针的旋转速度是每秒多少度呢?

从照片中可以看出,时针每秒都旋转了 90 度。因此,你可能会说,时针的旋转速度是 90 度每秒。

下面让我揭晓答案。其实,时针的旋转速度非常非常快。每次拍照时,时针都转了一圈多。也就是说,时针每次旋转了 90 + 360 = 450 度,它的速度是 450 度每秒。如果我们拍照的频率更高的话,将会得到下面的结果。

你可能会觉得这很赖皮:「只给三张照片,谁看得出时针已经多转了一圈啊?」这话确实没错。在相邻两次拍照之间,时针可能已经多转了一圈、两圈……。时针的速度究竟是多少?这其实可以有无数个答案。只有我们强行规定两次拍照之间,时针不能转一圈以上,我们才能得到唯一一种答案。在这种规定之下,如果要表示更快的时针,只能通过增加拍照的频率了。

让我们总结一下从这个示例中学到的规律。在现实中,时针是连续旋转的。而由于存储空间有限,我们往往只能对时针的状态拍照(采样),得到离散的指针状态。采样数相同的情况下,能够表达的信息量是等同的,或者说能够记录的时针最大旋转速度(最大频率)是等同的。要表示更快的时针(更高的频率),就必须要增加采样频率。反过来说,由于采样频率有限,我们有时会错判时针(周期信号)的频率。这种错判现象被称为混叠 (aliasing)。比如把速度 450 度每秒的时针看成 90 度每秒就是一种混叠现象。

类似地,我们可以把图像看成空间中的信号。在现实中,我们眼中看到的图像是处处连续的。为了用计算机显示图像,我们只好在空间中对图像采样,记录有限个位置处的颜色值。如果采样的频率过低,也就是在空间中采样的步长过大,就可能会漏掉某些关键信息,从而造成图像信号的混叠。

而在图像处理中,混叠现象一般出现在高分辨率图像的下采样中。我们来用 matplotlib 中的一个示例复现混叠现象。对于一个包含密集纹理的输入图像,如果我们简单地使用最近邻插值,就会在下采样图像中得到不自然的纹理;而换用抗混叠插值后,混叠现象被大大缓解。

抗混叠的原理是什么呢?我们知道,混叠现象是由于某种采样后,图像的采样率(正比于图像尺寸)过低,导致原图像的高频分量无法正确地在采样后图像中显示。既然如此,我们就先用一个低通滤波器,过滤掉原图像中的高频分量,再做采样。也就是说,抗混叠下采样,等于低通滤波+最近邻下采样。

平移同变性与混叠

通常,我们会为图像处理网络引入一些归纳偏置 (inductive bias),以降低网络的学习难度。CNN (卷积神经网络)就是利用归纳偏置的一个经典示例。由于 CNN 主要由卷积操作构成,而卷积操作在某像素处的输出只取决于邻近像素,因此 CNN 满足平移同变性:平移输入图像,CNN 的输出特征也应该对应地平移。而对于基于 CNN + Softmax 的图像分类网络,按理来说,它满足平移不变性:平移输入图像,输出的类别分布不变。

可是,我们训练出来的 CNN 分类网络真的满足平移不变性吗?在经典论文 Making Convolutional Networks Shift-Invariant Again [2] 中,作者发现,平移输入图像时,普通的 CNN 分类网络的输出概率会发现很大的变化。而这背后的罪魁祸首正是混叠现象。而一个抗混叠的神经网络有着更好的平移不变性。

为什么混叠会和平移不变性关联起来呢?为了方便说明,我们先用公式正式地表示一个简化版 CNN。在一个 CNN 分类网络中,输入 x 会经过若干个由卷积和下采样构成的模块,最后得到二维特征图 f。随后,f 会被展平成一维,并经过 MLP 和 Softmax,输出一个概率分布。

1
2
f = down(conv(x))
prob = softmax(mlp(flatten(f)))

在这个过程中,我们希望 fx 是平移同变的。严谨地说,对于输入 $x$,如果函数 $F$ 满足

其中 $T$ 是平移操作,那么操作 $F$ 是平移同变的。在分类网络中,我们希望分类网络的卷积部分 down(conv(x)) 是平移同变的。一旦这个操作满足平移同变性,后面的 softmax(mlp(flatten(f))) 操作都不会考虑输入像素的先后顺序,整个网络就满足了平移不变性。

那么,这么多步骤中,是哪一步出错了呢?论文指出,通常 CNN 都使用最近邻下采样。这种下采样操作会导致图像出现混叠现象。解决方法也很简单,如上一节所述,我们可以将最近邻下采样换成先低通滤波再最近邻下采样,以缓解网络的混叠。果不其然,换用了抗混叠下采样后,CNN 的平移同变性大大提升,最后输出的概率分布的平移不变性也相应地大大提升。

无混叠的 StyleGAN3

经典图像生成网络 StyleGAN2 可以把一张 $4 \times 4$ 的特征图像不断上采样并转换成一张 $1024 \times 1024$ 的高清图像。由于该生成网络也是一个 CNN,我们希望它满足平移同变性。这样,移动输入特征图像,就能对应地移动输出高清图像。但是,在平移 StyleGAN2 的特征图像时,我们能在输出图像中观察到纹理滞留 (texture sticking) 现象:人物的胡须和头发好像停留在了原地,并没有随着输入移动而移动。而 StyleGAN3 的目标正是解决这一问题。

StyleGAN3 同样指出,混叠现象是造成纹理滞留的主要原因。为了彻底解决这一问题,StyleGAN3 系统性地用信号处理知识分析并改进了 StyleGAN2 的模块。如前文所述,一张图像能够表示的频率分量是有限的。图像尺寸越大,能表示的最大频率越大,图像的细节也就越多。而在对图像重采样(改变图像尺寸)前后,如果我们不能正确地调整图像的最大频率,就有可能产生造成图像内容错乱的混叠现象。所以,要系统性地调整每个模块以防止其出现混叠,其实就是要让每个模块正确地处理图像的最大频率。

经分析,StyleGAN3 主要对 CNN 的以下模块做出了改进以去除混叠:

  • 上/下采样层:早期工作设计抗混叠采样时,只是简单地用同一个模糊卷积来近似低通滤波。而 StyleGAN3 精确地为采样率(边长)不同的特征算出了不同的最大频率,并根据此最大频率设计了不同的低通滤波器,用以修正采样前后的信号频率。
  • 非线性函数(激活函数):StyleGAN3 指出,非线性函数会在信号中引入新的高频分量,从而引起混叠。为此,StyleGAN3 的解决方法是,先临时把信号上采样 $m$ 倍,再让信号过非线性函数,最后将信号下采样 $m$ 倍以使其复原。这是因为,采样率越高,能表示的最大频率越高,引起混叠的可能越小。实验中发现,令 $m=2$ 就有不错的效果。这一模块被 StyleGAN3 称为经过滤的非线性函数(filtered nonlinearities)

除此之外,StyleGAN3 还从抗混叠以外的角度提升了 CNN 的平移同变性:

  • 傅里叶特征输入:为了让生成网络的输入平滑移动,即能够移动非整数个像素,StyleGAN3 将输入的 $4 \times 4$ 离散特征图像修改成了一个在空间上可以任意采样的傅里叶特征。
  • 边缘像素裁剪:此前研究表明,CNN 会从图像边缘处的 0 填充卷积中学习到绝对位置信息,这违反了 CNN 平移同变性的假设。因此,StyleGAN3 在同一尺度的特征图像外都填充了一些额外像素,并在每次上采样后丢弃这些边缘像素。

Alias-free Latent Diffusion Models

设计动机

回顾了潜扩散模型理论基础以及神经网络的平移同变性与混叠的关系后,我们来正式学习 AF-LDM 论文。

如本文开头所述,为了分析 LDM 的生成稳定性为什么那么差,我们用一个更简单的平移任务来定位问题的根源。实验结果显示,LDM 网络的平移同变性也很差。更准确地说,LDM 只对整数平移有较好的同变性。

这里先补充介绍一下整数平移和分数平移。假设我们有一个能把图像 2 倍上采样的平移同变的网络。如果我们对输入移动 $n$ 个像素,那么输出就应该平移 $2n$ 个像素。然而,如果只对输入平移整数个像素,那么输出只能平移偶数个像素。为了平滑地让输出平移 1, 2, 3, … 个像素,我们有时需要令输入图像平移分数个像素。

在分数平移时,我们要通过插值获得图像在非整数位置处的值。后文我们会详细讨论该如何选取插值方法。

回到 LDM 的平移同变性上。实验显示,尽管神经网络主干都是理论上应该平移同变的 CNN,LDM 的 VAE 和去噪 U-Net 都只对整数平移有同变性,而在分数平移时同变性较差。如下图所示,我们测试了潜空间下采样 8 倍的 VAE 和去噪 U-Net 的同变性,每一个平移步数表示平移 1/8 个像素。仅当平移步数是 8 的倍数时,网络的同变性指标(以 PSNR 表示)才比较高。

参考了之前工作后,我们认为 CNN 平移同变性下降是由于混叠现象导致的。如果我们去除了 LDM 的 VAE 和 U-Net 中的混叠,那么 LDM 就会有更好的同变性。总结下来,论文的整套思维链如下:

  1. Stable Diffusion 等 LDM 编辑稳定性差。
  2. 在较简单的输入平移任务上,LDM 的稳定性依然很差。
  3. LDM 的分数平移同变性差。
  4. 混叠现象降低了网络同变性。

为了提升 LDM 的稳定性,我们需要倒着解决问题:

  1. 设计抗混叠模块,去除网络中的混叠。
  2. 验证无混叠 LDM (AF-LDM) 的平移同变性确实有所提升。
  3. 验证提升平移同变性的 LDM 在编辑时稳定性更好。

在这一大节里,我们主要会学习 AF-LDM 论文的方法部分,即如何开发一个无混叠的 LDM。在下一大节里,我们再浏览论文里的实验结果,以验证 AF-LDM 确实能提升 LDM 的稳定性。

引入 StyleGAN3 抗混叠模块

我们希望设计一种无混叠的 LDM。同时,为了尽可能利用预训练 LDM (比如 Stable Diffusion)的权重,我们希望对 LDM 模型结构上的改动尽可能小。因此,我们仅将前文所述的 StyleGAN3 的两个抗混叠模块引入了 LDM 的 VAE 和 U-Net 中:

  • 上/下采样层:让上采样层能够正确处理图像频率。和 StyleGAN3 不同的是,StyleGAN3 使用 Kaiser 卷积来近似低通滤波,而我们参考之前的 AF Convnet [3] 工作,使用了基于 FFT 操作的滤波操作以实现理想滤波(恰到好处地过滤图像中的频率)。
  • 非线性函数:我们也使用了同样的经过滤的非线性函数,以抑制高频分量造成的混叠。

当然,仅做这些改动还不足以实现无混叠的 LDM。还需要解决的问题有:

  • 如何定义分数平移。StyleGAN3 将输入特征图像定义成了傅里叶特征,它可以在任意位置采样,天生支持分数平移。而在 LDM 中,我们往往需要分数平移潜图像。而潜图像是离散的,它在分数平移中的插值方式需要慎重定义。
  • 使用同变损失进一步提升同变性。我们在实验中发现,仅靠抗混叠模块还不足以提升模型的平移同变性,我们通过增加损失函数的方式强制让模型在训练中学习平移同变性。
  • 改进自注意力模块。由于自注意力输入是全局操作,其输出对输入的变化非常敏感,平移同变性差。我们分析并缓解了此问题。

连续潜图像表示

对图像做分数平移,其实就是在图像分数位置处重新采样。比如,假设一维信号原来的采样坐标为 0, 1, 2, …,将其向左平移 0.5 个单位后,采样的坐标变为 0.5, 1.5, 2.5, …。为了求解这些新坐标下的像素值,我们需要使用某种插值方法。

在这个工作中,我们假设 LDM 的 VAE 中的潜图像是一种连续图像,即它可以无损被傅里叶变换转换成连续信号。那么,对这种连续图像做分数平移时,就可以使用理想插值:先用 FFT 把图像转到频域,再将分数平移转换成信号的相位变动,最后用 IFFT 把平移后的信号复原回空域。

值得注意的是,将潜图像假设成连续信号,只是规定了我们在分数平移潜图像时用到的算法。模型在训练时并不知道潜图像满足这种表示。在下一节中,我们会学习如何用损失函数让模型学到这种表示。

同变损失

加入了 StyleGAN3 中的抗混叠模块后,一个随机初始化的 VAE 确实有了更好的同变性。然而,我们发现了一个奇怪的现象:随着 VAE 训练的不断进行,VAE 的同变性开始不断下降(稍后我们会在实验部分看到这些结果)。相同的现象在去噪 U-Net 也可以观察到。我们猜测这是因为我们的网络中一些不够完美的设计让模型始终会产生轻微的混叠现象,而这些混叠现象能够帮助网络的学习。因此,随着训练的进行,网络会倾向于放大混叠现象。这些不完美的设计可能包括:

  • 未使用傅里叶特征:StyleGAN3 将输入定义为连续的傅里叶特征,天生支持连续平移。而我们只是假设 VAE 的潜图像可以由连续信号表示,而没有在训练中让模型感知到这一点。
  • 未使用边缘像素裁剪:边缘像素的卷积会泄露绝对位置信息。我们没有像 StyleGAN3 一样使用这个技术。

StyleGAN3 可以简单看成一个不断上采样低分辨率图像的网络,它在结构设计上有很大的自由。而在由 VAE 和 U-Net 组成的 LDM 里,实现上述两种技术的方法并不是很直观。且由于我们想尽可能减少新设计,并通过微调预训练模型来使之具有同变性,我们没有在 AF-LDM 里加入上述技术。

为了防止 LDM 在训练中同变性下降,我们根据同变性的定义,提出了一个额外的同变损失来规范网络模块的学习。对于不同的模块,我们根据其输入输出设置不同的同变损失。比如,对于 VAE 编码器 $\mathcal{E}$,我们定义以下损失:

其中,$T_\Delta(x)$ 表示将 $x$ 平移 $\Delta$ 个单位,$k$ 表示编码器下采样倍数。由于潜图像 $\mathcal{E}(x)$ 的边长缩小了 $k$ 倍,编码器输入平移 $\Delta$ 对应输出平移 $\Delta/k$。除了直接做差以对齐同变性的定义外,我们还设置了掩码 $M_{\Delta/k}$ 以表示需要计算损失的有效区域。之所以平移时存在「有效区域」,是因为我们将平移定义为裁剪平移 (cropped shift),即最右的像素移出图像边界后,最左侧只会填充全零像素。这些全零像素就属于无效区域,我们应该只在另外的有效区域计算同变损失。

VAE 解码器和 U-Net 的同变损失有着类似的形式。欢迎大家阅读论文以了解细节。

由于在计算同变损失时,我们将平移操作中的插值设置成了理想插值,因此模型能够学到我们在上一节定义的连续潜图像表示。

同变注意力

LDM 的去噪 U-Net 一般会使用自注意力操作:

其中,矩阵 $x \in \mathbb{R}^{HW \times d}$ 是 $H \times W$ 个长度为 $d$ 的特征,三个参数矩阵 $W^Q, W^K, W^V \in \mathbb{R}^{d \times d}$ 为可学习参数。

自注意力会严重降低模型的平移同变性。如文本开头的视频所示,原版 Stable Diffusion 在输入噪声平移后,输出会发生极大的改变。而使用 Cross-frame Attention (CFA) 这种提升自注意力稳定性的操作后,模型的输出才稳定起来。

为什么自注意力的平移同步性较差呢?为什么 CFA 能提升同变性呢?在这篇文章中,我们深入地研究了自注意力的平移同变性。准确来说,我们考虑的是裁剪平移下的同变性。

根据同变性的定义,自注意力满足以下条件时才是同变的:

由于此时 $x \in \mathbb{R}^{HW \times d}$,即 $x$ 不是一张图像,而是一个特征序列,图像里的每一个像素是一个行向量,因此这里的平移操作 $T(x)$ 其实是修改 $x$ 的行向量的排序。我们先记住这个性质。

观察上面等式的右边,我们可以将它看成先有输入 $x$,再做了两次矩阵右乘,再做了一次 Softmax,再做了一次矩阵右乘,最后平移。而矩阵右乘和 Softmax 对行向量都是独立的,所以上面的右式可以化简成 $\text{softmax}(T(x)W^Q(xW^K)^\top)xW^V$。

现在,要让自注意力操作满足平移同变性,只需要满足下面两个式子:

然而,由于此时的平移操作为裁剪平移,上面两个式子无法成立,且随着平移的推进误差会越来越大。通过上述分析,我们得出结论:自注意力对裁剪平移不具有平移同变性。这也符合我们直觉上的理解:自注意力是一种全局操作,一旦输入某处发生了一些微小的改变,输出就会出现较大的变动。

想要重新设计一种同变性更好的自注意力操作并不简单。不过,我们可以采取一种权宜之策来提升现有自注意力的相对平移同变性。假设有参考帧 $x_r$ 和平移后的帧 $x_s$,我们将计算 $x_s$ 时的自注意力定义为同变注意力 (Equivariant Attention)

在实现时,我们先正常算所有注意力特征 $x_r$,并将其缓存下来;而在计算某一层的 $x_s$ 的自注意力时,我们再取出对应的 $x_r$。这样,含 $W^K$ 和 $W^V$ 的那两项不随输入 $x_s$ 而变化,整个注意力操作就是一定是平移同变的了。注意,这里的平移同变是 $x_s$ 相对参考帧 $x_r$ 而言的,我们不能保证其他帧之间,如两个平移后的帧之间,仍然具有平移同变性。

这一操作其实就是之前 Stable Diffusion 视频编辑工作 (如 Text2Video-Zero [4]) 里常用的 CFA 操作。而之前工作并没有对 CFA 做深入分析,只是简单解释成「将参考帧的 K, V 注入其他帧能够提升其他帧的风格一致性」。而在我们这篇论文中,我们发现 CFA 有用的原因是它提升了其他帧对参考帧的平移同变性,这其实是一种同变注意力。为了方便其他研究者的理解,我们在后文还是把这种同变注意力称为 CFA。

为了把 CFA 加入模型中,我们在两处使用了 CFA:

  1. 计算同变损失时
  2. 训练结束后,生成平移后的图片时

方法小结

我们的方法可以用下面的示意图概括。除了像 StyleGAN3 一样加入抗混叠模块外,我们的主要改进是在训练时加入同变损失。而在计算此损失时,需要将平移后图像的自注意力运算改成同变注意力。

实验

做完上述所有改进后,我们将这种同变性更好,无混叠的 LDM 称为 AF-LDM。参照这一简称方式,我们会把改进后的 VAE, Stable Diffusion 简称为 AF-VAE, AF-SD。在实验环节,我们会验证改进后模型的有效性,并展示它的一些应用。

同变性消融实验

根据同变性的定义,我们用先平移、再操作和先操作、再平移的图像之间的重建误差来反映同变性的高低。参考之前的工作,我们用 PSNR 来计算重建误差。这种反映同变性的 PSNR 在论文中被简称成 SPSNR。

我们看一下消融实验的结果。Latent PSNR 表示 U-Net 输出的潜图像的同变性,Image PSNR 表示 U-Net + VAE 解码器的同变性。这个表展示了非常多的结论:

  • 比较第一栏和第二栏的结果,使用 SD VAE 看起来 Latent PSNR 还不错,但由于 VAE 不是同变的,最后的 Image PSNR 还是很差。我们必须把 VAE 和 U-Net 都变成无混叠的。
  • AF-LDM random weights 表示做了模块上的改进 (Ideal Sampling, Filtered Nonlinearity) 之后仅随机初始化参数,不训练模型。将它的同变性和训练过的模型做对比,可以发现模型的同变性在训练中下降。
  • 为了防止同变性在训练中下降,我们需要加入同变损失。
  • 在计算同变损失时,我们需要在自注意力中使用 CFA。
  • 比较不做模块上的改进只加同变损失(倒数第二行)和 AF-LDM (倒数第三行)的结果,可以发现同变损失单独是不起作用的,不仅 FID 差了很多,SPSNR 也变差了。因此,同变损失必须和抗混叠模块一起使用。

上表的结果表明,我们在论文中介绍的所有设计都是有效的。最终的 AF-LDM 可以在几乎不降低生成质量的前提下大幅提升模型同变性。除表格外,我们在项目网站上分享了更直观的消融实验结果。

我们还用一个简单的实验说明,此前模型仅在整数平移(潜图像移动 1 个单位,真实图像移动 8 个单位)时具有较好的同变性。而为了实现平滑的图像编辑,我们最大的收获是提升了模型的分数平移同变性。

仅用光流变换的视频编辑

尽管我们在方法设计中仅考虑了裁剪平移的同变性,但在实验中,我们发现模型对更复杂的不规则变换,如光流变换,也具有更好的同变性。这一性质拓宽了 AF-LDM 的应用场景。为此,我们在 AF-VAE 的潜空间里重新训练了加入了抗混叠模块的 Stable Diffusion 1.5 (AF-SD),并在 AF-SD 上做了光流变换同变性的相关实验。

先简单补充一下光流的相关知识:光流描述了视频两帧之间每个像素的平移。因此,光流是一张 $H \times W \times 2$ 的图片,两个通道分别表示每个像素在横向和纵向上的平移。根据光流,我们能够把视频的前一帧变换到后一帧。当然,这种变换是存在误差的。

在实验中,我们主要观察两张图片在扩散模型的 DDIM 反演 (将真实图片变回纯噪声)和 DDIM 重建阶段对光流变换的同变性(以 SPSNR 来评估)。另外,为了知道在光流变换中「较好的」 SPSNR 应该是多少,我们计算了输入帧之间的光流变换误差,用以提供参考。

结果显示,AF-SD 在反演和生成时的光流变换同变性都有所提升。惊人的是,AF-SD 在生成时的重建效果竟然比直接对输入图像做光流变换还要好。也就是说,在用 AF-SD 时,只要对初始噪声做光流变换,输出视频就会自然做对应的光流变换,且比直接在图像上做更加准确。

受到上述实验结果启发,得益于 AF-SD 在反演和生成过程中的同变性,我们设计了一种非常简单的视频编辑方法:对一个视频的每一帧进行 DDIM 反演和再生成(改变生成时 prompt)。我们做的唯一改动是同时在反演和生成的时候都启用后续帧对第一帧的 CFA。

这种简单的视频编辑方法能够为内容变化不大(相对第一帧而言)的视频输出平滑的编辑结果。由于我们的改进主要体现在分数平移同变性上,输入视频的变化越是细微、平缓,我们的编辑方法的优势就越明显。比如,以下是同一个编辑方法下,SD 和 AF-SD 的结果对比。

小声说一句,由于 AF-SD 需要重新训练所有模型,而我们的数据和计算资源都不够,所以 AF-SD 的生成质量较差。当然,它还是可以完成一些简单的编辑任务的。我们主要用这个模型来验证 AF-LDM 的应用潜力。

其他应用

我们还在其他一些任务上简单验证了 AF-LDM 的通用性。在实现所有任务时,我们都采用了基于扩散模型的方法。欲知细节欢迎阅读原论文和访问项目网站。

通过对输入图像做光流变换和插值,我们能够实现视频插帧。

被平移图像的超分辨率。该应用基于 I2SB 工作 [5]。

被平移图像的法向量估计。该应用基于 ControlNet。

贡献总结与未来展望

读完论文的主要内容后,我们可以总结论文的贡献:

  1. 我们追溯了潜扩散模型编辑不稳定的主要原因:缺乏分数平移同变性。

  2. 我们设计了一种无混叠的潜扩散模型 (AF-LDM),它能够有效提升 LDM 的平移同变性。

  3. 从技术贡献上看,我们提出了简明有效的同变损失,以防止加入了抗混叠模块的模型在训练中损失同变性。此外,我们分析了自注意力运算不够稳定的原因,并通过在同变损失里加入同变注意力来提升模型对参考帧的相对同变性。

  4. 我们在多项任务中展示了 AF-LDM 广泛的应用前景。

其中,我认为第一项贡献是最重要的。潜扩散模型的不稳定性是一个老生常谈的问题,但很少有工作对其做深入分析。而我们提供了一个分析此问题的新视角,并且证明此前常见的 CFA 技术其实和同变性密切相关。第四项贡献也很有趣,我们发现 AF-LDM 也能提升不规则平移的同变性,可能可以拓展到更多任务上。剩下两项技术贡献倒相对来说没有那么重要。

按惯例,我也给论文挑挑刺,列举它的几项不足:

  • 社区用户很多时候会关注一项工作的方法能否直接用起来,能否用预训练模型实现一些好玩的应用。但我们在这个项目中训练的文生图模型 AF-SD 生成质量较差,只能做一些简单的应用。

  • 论文没有进一步分析为什么训练时模型的同变性会逐渐下降,只给了解决方法。

  • 我们并没有完美解决自注意力的低同变性问题,目前的同变注意力必须要给一个参考帧。

总体上来,我个人比较喜欢能够深入解释某一问题的工作,我对这个工作的贡献十分满意。

从这个工作出发,我能想到的未来探索方向有:

  • 帮助视频生成和多视角 3D 生成。平移同变性好,意味着模型能够用同样的形式表达不同位置的同一物体。这一性质在图像生成中难以体现,而在视频生成和多视角 3D 生成中比较重要。
  • 更稳定的视频编辑和图像插值方法。我们在论文仅仅展示了简单的视频编辑和图像插值算法。如果将 AF-SD 和之前的方法结合,再稍微加一点新的设计,就能实现一套不错的方法。当然,由于我们提供的预训练 AF-SD 质量较差,开发图像插值应用更可行一点。
  • 获取像素级精确特征。潜图像的一个像素代表了 $8 \times 8$ 个真实像素。而如本工作所示,目前多数 LDM 的 VAE 存在混叠现象。这会导致我们难以准确获取每个真实像素处的特征,只能大概获取其邻域的特征。而 AF-LDM 可以改善这一点。当然,为了验证 AF-LDM 在这方面的优越性,我们需要找到一个合适的任务去测试。我简单测试了像素级匹配任务 (pixel correspondence),但似乎 AF-LDM 在这个任务上没有明显提升。

除了最直接的应用外,这篇论文还能给我们更宏观的一些启示。比如,现在的神经网络在处理图像时并不是完美的。神经网络的上下采样操作一般是固定的,不管网络的其他参数学得有多么好,不够合理的上下采样总会导致一些问题(比如混叠)。我们不能希望靠加数据来解决一切问题,有时候要从更底层的神经网络设计来解决问题。希望这篇论文能够引发大家在科研上的更多思考。

有读者建议:是否应该把 eqvariance 翻译成「等变」?

我查了一下,按照惯例,CV 里确实翻译成「等变」好一点。我的中文直觉是图像的输出会随输入「共同移动」,而不强调移动距离「相等」(由于输入输出的图像大小可能不一样),在这篇文章的语境下「同变」更好听一点。我在之后的文章里会按照惯例翻译成「等变」。

参考文献

[1] StyleGAN3: Alias-Free Generative Adversarial Networks

[2] Making Convolutional Networks Shift-Invariant Again

[3] AF Convnet: Alias-Free Convnets: Fractional Shift Invariance via Polynomial Activations

[4] Text2Video-Zero: Text-to-Image Diffusion Models are Zero-Shot Video Generators

[5] I2SB: Image-to-Image Schrödinger Bridge

最近,备受瞩目的何恺明团队公布了一篇论文——分形生成模型(Fractal Generative Models)。该论文提出了一种叫做分形生成的全新生成范式。以图像分形生成为例,算法会由粗到精地生成每个像素。

但我仔细读过一遍论文后,发现论文的表述不够准确。这篇文章其实提出了一种基于多叉树的效率更高的视觉 Transformer,以降低普通 Transformer 全像素自注意力的高计算复杂度。这种 Transformer 可以用于任何图像生成任务,甚至是图像生成以外的视觉任务。在这篇博文中,我会按我自己的逻辑介绍论文的核心方法,并简单展示论文中的实验结果。之后,我会批判性分析论文的表述,并探讨一些后续可能的科研方向。

知识准备

视觉 Transformer

Transformer 是一种处理序列数据的神经网络。它的核心是自注意力运算。在这个运算中,序列中的元素会两两交换信息。因此,如果序列的长度是 $N$,则自注意力运算的复杂度是 $O(N^2)$。

具体来说,Transformer 的输入和输出的数据是一个形状为 $N \times C$ 的张量。其中,$N$ 为序列的长度,$C$ 为每个数据向量的长度。实际上,自注意力的运算不仅和 $N$ 有关,也和 $C$ 有关。但由于 $C$ 一般是常数,而复杂度分析一般只关注会不断增长的量,所以我们记自注意力运算关于 $N$ 的复杂度是 $O(N^2)$。

图像可以认为是由像素构成的序列。因此,我们可以用 Transformer 处理图像数据,即使用视觉 Transformer (Vision Transformer)。然而,视觉 Transformer 的一大缺陷是计算复杂度过高。假如图像的边长是 $O(N)$,则一次自注意力的计算复杂度高达 $O(N^4)$。

自回归图像生成

自回归(Autoregressive)是一种直观易懂的序列生成范式:在生成第 $i$ 个元素时,生成模型输入前 $i - 1$ 个元素,输出第 $i$ 个元素。以下是文本自回归生成的一个示例:
|步数 | 输入 | 输出 |
|—-|—-|—-|
1 | (空) | 今
2 | 今 | 天
3 | 今天 | 早
4 | 今天早 | 上

如前所述,图像也可以看成一种由像素构成的序列数据。但在自回归生成图像时,我们要给每个像素编号,表示像素生成的先后顺序。只有定义了先后顺序,才能根据前面的像素生成后面的像素。

给图像编号的方式很多。最直接的想法自然是从左到右、从上到下地编号。其他的编号方式也是可行的。以下是 VQGAN 论文 (Taming Transformers for High-Resolution Image Synthesis) 展示的几种像素编号方案。

何恺明团队之前的论文 MAR (Autoregressive Image Generation without Vector Quantization) 表明,可以完全随机地给像素编号。

提升视觉 Transformer 效率

视觉 Transformer 处理图像的效率本身就偏低,再算上多步图像生成带来的计算量,生成一张图像的速度将慢得惨不忍睹。能否加速视觉 Transformer 的计算效率呢?

在早期的 ViT 工作 (An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale) 中,图像在正式输入 Transformer 前会做一步叫做「图块化」(patchify)的预处理操作。原来 $256 \times 256$ 大小的图像会被下采样 16 倍,转换成 $16 \times 16$ 个图块。输入的元素数变少了,Transformer 的计算时间自然也就降下来了。

后续工作延续了这种压缩输入元素数的思想,但采用了不同的图像压缩方式。VQVAE, VQGAN, Latent Diffusion Model (LDM) 等论文使用自编码器对图像做近乎无损的压缩,再仅用生成模型来生成压缩图像。后续的 DiT (Diffusion Transfomrer, 来自论文 Scalable Diffusion Models with Transformers) 把这种借助自编码器的压缩方案集成到了基于 Transformer 的扩散模型中。

树是一种常见的数据结构,它以从整体到局部的顺序描述某种事物。树可以表示抽象的生活概念或者具体的计算机概念。比如,通常书籍的结构都是树形,我们可以用第一章、第 1 小节、第 1.1 小节这种逐级递进的结构组织书的内容。

和植物里的树不同,数据结构中的树是从上往下生长的。最上面的节点叫做根节点。每个节点相邻的下层节点叫做子节点,相邻的上层节点叫做父节点。没有子节点的节点叫做叶节点。树本身还是一种满足递归性质的数据结构:我们可以忽略某节点的父节点及父节点连接的所有其他节点,从而将其看作是一个新的树。也就是说,每个节点其实都代表一个以这个节点为根的树。这样的树被称为子树

我们也可以用树来组织一个一维数组中的信息。比如,我们把四个数存在树的叶节点里,并让其余每个节点都维护整个子树里所有数据的某种统计信息(这里我们把统计信息定义为求和)。

用这种树表示数据有什么好处呢?由于节点都维护了整个子树的所有信息,在查询整个树里某种统计信息时,我们不必访问每个叶节点,而是可以直接从某个中间节点中直接返回信息,以提升计算效率。比如,在上面的求和树中,我们要查询第 1-3 个元素的总和。我们不必逐个访问三个叶节点,而是可以去访问更少的节点。严格来说,普通查询区间和的复杂度是 $O(N)$,用这种求和树的话查询的复杂度会降为 $O(logN)$

多叉树 Transformer

Transformer 的平方复杂度

我们先以一维数据为例,学习这篇论文是怎么加速 Transformer 的。在正式学习方法之前,我们再次复习一遍为什么 Tranformer 的运算是平方复杂度的。

忽略 Transformer 中注意力运算的实现细节,我们仅关心每个运算的输入输出是什么。在 Transformer 中,由于自注意力运算是一种全局运算,每个元素的输出都取决于其他所有元素。从信息的交换次数来看,如果序列有 $N$ 个元素,每个元素都要至少访问 $N$ 个输入元素的信息,总计算的复杂度是 $O(N \times N)= O(N^2)$。

用多叉树维护区间信息

在前文对树的知识回顾中,我们知道树的某个根节点可以维护整个子树内所有数据的统计信息。那么,我们可不可以用树来减少 Transformer 的信息交换次数呢?比如,我们要让 8 号元素查询 1-4 号元素的信息,我们不去逐个查询叶子节点,而是去查询它们构成的子树的根。

那么,怎么让 Transformer 具有这样的树形结构呢?首先,我们先想办法让某个节点表示一个区间内的所有数据。回忆一下,在 Transformer 中,数据的输入输出形状都是 $N \times C$。这里,我们先假设 $C=1$,即每个数据都是一个实数。这样,我们可以通过通道拼接的方式把多个数据放在一个节点里,并用形状修改操作实现树节点的「分裂」操作。

如下图所示。一开始,根结点处只有一个数据,数据的长度为 $8$,表示八个实数的拼接。树的每一条边表示 reshape 操作,表示把数据从通道维度 $C$ 上拆开,放到序列长度维度 $N$ 上。最后,数据变成了原本的形状 $8 \times 1$。

接着,我们把多个 Transformer 加入树中。我们只允许同一个节点的所有子节点交换信息,而不与同一级的其他子节点交换信息。

要进行多个独立的计算,可以利用数据的 batch 维度:我们把数据的形状从 $N \times C$ 拓展成 $B \times N \times C$,其中 $B$ 表示 batch 的数量。每个 batch 之间的运算是完全独立的。在下图中,一个蓝框表示一个 batch 的运算,不同框内运算是独立的。每次运算中,序列长度 $N$ 始终等于 $2$,这个 $2$ 表示的是一个树节点的子节点数。$C$ 和之前一样,表示数据向量的长度乘以区间里数据的个数。由于我们默认数据向量长度为 $1$,所以这里的 $C$ 还是表示区间里数据的个数。

一个树的节点如果最多有 $k$ 个子节点,则该树被称为 $k$ 叉树。我们这里默认使用的是二叉树。

这样的结构乍看起来很奇怪:这个树的每个节点表示什么意思?为什么只允许同一个节点的子节点之间交换信息?这样真的能加速吗?我们来一一解释这些问题。

多叉树 Tranformer 的原理解释

首先,我们先忽略数据间的信息交换方式,仅考查每个节点的意义。由于更底层(更深层)的节点经过了更多次 Transformer 运算,所以深层的节点拥有的信息更加准确;与之相对,更浅层的节点的信息更加模糊,但概括性更强,能够描述多个节点的统计信息。如下图所示,a, b, c 三个节点的概括性越来越弱,但信息越来越准确。

这个树和我们之前见过的求和树一样,每一个节点都维护了整个子树的统计信息。然而,对于求和操作,我们可以精确地维护一个子树里所有数据的和;但对于结果无法直接统计的 Transformer 运算,节点的信息越往上越模糊。我们在之后的分析中,必须要考虑浅层节点的信息损失。

然后,我们来考查某一个节点能够看到哪些信息。不妨来考查 8 号节点。如下图所示,我们可以找出 8 号节点在整趟运算中「看过」的节点。它看过了总结 1-4 号节点的节点 a,看过了总结 5-6 号节点的节点 b,还看到了它自己以及相邻的 7 号节点。这样看来,8 号节点确实看到了序列里的每一项数据的统计信息。

然而,如前所述,浅层节点的概括性虽强,它的准确性也越低。因此,每个节点在访问其他节点时,对于越邻近的节点,获取的信息越准确;相距越远的节点,获取的信息越模糊。这种设计其实假设了数据具有局部性

  • 数据的输出几乎只取决于局部信息,越远的数据影响越小。

由于图像数据满足局部性,因此用这种结构处理图像时,浅层节点的信息损失是能够接受的。

最后,我们来计算这套模型的计算复杂度,以验证这种模型能够加速 Transformer。我们仅考虑一个元素的运算。为了获取一个元素的输出,我们要做 $K$ 次 Transformer 运算,其中 $K$ 为树的高度。每一轮 Transformer 运算中,数据的序列长度、通道数都是常数。因此,一轮运算的复杂度是 $O(K)$。如何计算树的高度 K 呢?假设我们用的是二叉树,则每加一层,树能表示的数据就乘 2。因此 $K=log_2N$。最终,一轮运算的复杂度是 $O(logN)$。

当我们要处理 $N$ 项数据时,只需要对复杂度乘一个 $N$。最终,这个新网络结构处理整个序列的复杂度为 $O(NlogN)$,这比普通 Transformer 的 $O(N^2)$ 快多了。

小结

为了减少 Transformer 中的信息交换,我们重新定义元素的信息交换方式:元素不会直接看到其他元素的准确信息,而是会看到其他元素的统计信息。我们要求越远的信息概括性越强,但准确度越低。这样,每个元素都只需要访问 $O(logN)$ 个信息节点。

为了产生这种不同层级的信息节点,我们使用了一种树状 Transformer 结构。越浅的节点经过的 Transformer 块越少,信息越模糊。为了在不增加复杂度的前提下进行信息交换,我们只允许子节点之间进行 Transformer 信息交换。由于子节点数是常数,每轮 Transformer 计算的计算量是固定的。

我们完全可以让树的子节点更多,以提升效率。比如,我们可以把二叉树拓展成四叉树。

图像自回归生成实例

这套多叉树 Transformer 可以被广泛地用到各种视觉任务上。我们以论文中的图像自回归生成为例,简单了解一下这种模型的拓展方式。

从一维数据到二维数据

把多叉树 Transformer 用到图像上时,我们只需要修改元素的编号方式,它从逻辑上等价于一维数据。比如,我们可以用如下的四叉树划分二维空间。

应用到自回归图像生成

相比于一般直接预测结果的图像任务,自回归生成有一个额外的要求:后生成的像素无法看到先生成的像素,需要为 Transformer 的自注意力生成一个描述先后顺序的掩码。因此,在把多叉树应用到自回归图像生成时,我们只需要决定每一处 Transformer 的掩码是什么。

决定掩码,其实就是决定元素的先后顺序。现在,Transformer 的运算仅在局部进行,我们其实只要随意为同一组做 Transformer 运算的数据标号。比如,对于二维四叉树,我们可以用下面的顺序对各组元素标号。

从整体上看,我们并没有修改自回归生成的定义。上述过程只是一种自回归生成的特例而已,它等价于某种全局标号的普通自回归生成。

重要实现细节

在附录中,作者提供了两项提升图像自回归生成效果的实现细节。

指引像素 在生成高分辨率图像时,让浅层的 Transformer 输出的颜色值与后续深层的输出颜色值对齐。当然,由于浅层的图块更大,这实际上是让深层输出颜色值的平均值和浅层输出对齐。

临近图块生成 直接用这套 Transformer 生成图像,会导致图块与图块的边缘不一致。为此,作者修改了 Transformer 的输出,让它除了输出当前图块的结果外,还输出上下左右四个相邻图块的结果。

作者在代码中用了一些相对复杂的逻辑,只读论文难以理解方法实现细节。对细节感兴趣的读者欢迎阅读开源代码库里的 models/mar.py 文件。

实验结果

我们简单看一下本文的图像生成结果。由于这种 Transformer 复杂度较低,作者实现了一个像素级生成模型,而没有按照流行的方法使用两阶段潜空间 (latent space) 图像生成。由于模型直接输出的是每个像素取某一颜色值的概率(类似于 PixelCNN),该模型能够准确建模图像的概率。这种概率可以用 NLL (Negative Log-Likelihood) 指标反映,越低越好。

先看最重要的 ImageNet-256 图像生成任务。作者仅比较了其他像素级生成模型。本文的最好的生成模型 FractalMAR 的 FID 并不是很好。现在主流生成模型的在此任务上的 FID 都小于 2。

再看一下 NLL 指标的结果,作者比较了那些能够准确输出图像概率的模型。从最大似然估计的角度看,本文的方法确实很不错。

从支持的任务上看,本文和其他类别约束的自回归模型一样,支持图像内插/外插,且可以用 ImageNet 类别作为指引。

论文表述批判性分析

在初次读文章时,我无论是看示意图还是看公式、文字,都不能理解算法的意思。反复读了几遍后,我才大概明白作者提出的其实是一种多叉树结构。我最后通过阅读代码验证了我的理解是正确的。我认为论文的部分叙述不够严谨,且对于贡献的总结不够准确。具体的分析如下。

是否是分治算法

对于一些朴素算法为 $O(N^2)$ 的序列处理任务,分治 (divide-and- conquer) 算法通过把任务拆成子任务并递归求解子任务的方法,将总算法的复杂度降到 $O(N^2)$ 以下。比如我们熟悉的快速排序就是一种分治算法。论文中反复将分形自回归称为分治算法,但它与传统意义上的分治算法存在较大的差别。

分治算法的核心是「治」这一步。在子问题解决完了之后,我们要用低于 $O(N^2)$ 的时间合并两个子问题的解,产生一个新的当前问题的解。而对于本文介绍的图像生成任务,或者说本文介绍的多叉树 Transformer 模型,模型的输出是一次性决定好的,不存在返回父节点再次修改这一步,自然也没有什么低于 $O(N^2)$ 的合并算法。

如果用分治算法实现图像生成,那么我们应该在不依赖全局信息的前提下生成局部像素,然后在父节点里根据邻近像素的生成结果,修改当前节点里所有像素的值。本文先决定整体再决定局部的方法恰好是反过来的。

与其称为分治算法,本文的算法更加靠近树形动态规划:一个区间内所有元素的统计信息可以被综合考虑,而不必逐个访问每个元素。

分形自回归是否是一种高效的新生成范式

作者声称以自回归模型为分形生成器的分形生成模型相较以往自回归建模方式计算效率更高。但是,在我看来,提升效率的本质原因是 Transformer 模型设计,而非生成范式上的改进。同时,作者的理论分析和方法设计完全对不上,实际上使用的还是传统自回归生成范式。

原文的有关说明如下:假设每个自回归模型的序列长度是一个可控常量 $k$,并让随机变量的总长度 $N=k^n$,其中 $n=\text{log}_k(N)$ 表示我们的分形框架的递归层数。第一个分形框架的自回归层随后将(自回归的)联合概率分布划分成 $k$ 个子集,每个子集包含 $k^{n-1}$ 个变量。

这里 $k$ 可以理解成多叉树的最大子节点数,即 $k$ 叉树。$n$ 表示树的高度。包含 $k^{n-1}$ 个变量表示一个大图块里包含 $k^{n-1}$ 个像素。

正式地,我们将概率分布分解成

这个式子表示,总的概率分布可以拆成若干个条件概率。每个条件概率的已知事件是之前所有大图块里所有像素的概率,条件事件是当前大图块所有像素的概率。

每个含 $k^{n-1}$ 个变量的条件分布 $p(…|…)$ 接着被第二级递归的自回归模型建模。以此类推。通过递归地调用这种分治过程,我们的分形框架可以通过用 $n$ 级自回归模型来高效率地应对 $k^n$ 个变量的联合分布求解问题,每一级只需要处理长度为 $k$ 的序列,且该序列长度可控。

以上是论文原文。我开始读论文的时候没读懂这段话的意思。在我写这篇博文的时候,发现作者的意思其实可以用前文的示意图表示。由于每一个递归级的每个子问题都只需要处理长度为 $k$ 的序列,且这个 $k$ 是常量,所以总的复杂度是 $O(NlogN)$。

但是,作者这段话不是针对 Transformer 来讲的,而是针对概率分布来讲的。用严谨的话描述,作者的意思可能是说,上面的那个概率分布按递归展开,最后只会有 $O(NlogN)$ 项。因此,总的计算复杂度降低了。

计算概率分布的算法大致可以被称为分治算法。但计算概率分布和执行多叉树神经网络是两码事。

这一段推理存在逻辑漏洞:概率公式有 $O(NlogN)$ 项,并不能代表最后的计算效率是 $O(NlogN)$。这中间还欠缺一个前提条件:每一项条件概率的计算时间是常数级。实际上,一轮自回归生成的计算时间取决于神经网络的设计,而跟自回归的建模方式无关。比如,同样是计算经典自回归条件概率 $P(x_i|x_1, …, x_{i-1})$,如果用 Transformer,它的复杂度就是 $O(i^2)$;如果用 CNN,它的复杂度就是 $O(i)$。

另外,上述条件概率的计算和论文方法设计完全无关。论文完全没有提如何用模型估计各个叶节点的条件概率,然后用分治算法合并概率,用一套新损失函数优化联合概率。论文的方法完全是按照经典自回归的定义,用神经网络建模 $P(x_i|x_1, …, x_{i-1})$,再用交叉熵损失优化最新像素的类别分布。只不过这个神经网络是一个使用了多叉树优化的 Transformer。

综上,我认为作者对于方法的分析和论文贡献的描述有误。作者并没有用到论文中提出的递归概率分布,只是用到了一个多叉树 Transformer。论文的核心贡献是加速 Transformer,而不是一种全新的生成范式。

科研方向探讨

正如论文所展示的,本文提出的多叉树 Transformer 可以用到 AR 和 MAR 两种生成范式上。我们也可以考虑把它拓展到其他生成范式,甚至其他视觉任务上。比如,将其拓展到 VAR (Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale Prediction) 上就是一个显而易见的改进方向。 VAR 用同一个 Transformer 处理所有尺度的图像,但这显然不是最优的。结合多叉树 Transformer,我们或许能够让不同层的 Transformer 输出不同尺度下的预测;同时,我们也可以用这种结构提升 VAR 的性能,避免使用全序列注意力。

退一步,从更宏观的角度上看,这篇论文以及 VAR 等论文都是通过利用图像特性来减少计算量。我认为最重要的两个特性有:

  • 局部性:像素受到邻近像素的影响更大,受到远处像素影响更小。
  • 局部连续性:一块像素的颜色、信息是类似的,且变化是平滑的。这使得我们可以用下采样/图块化的大像素块来近乎无损地表示一块像素的统计信息,也允许我们将低尺度信息的线性上采样结果作为当前结果的近似。

基于这两种特性,多数工作采用了如下的优化方案:

  • 降低像素间的依赖关系,较远处的像素与此处的像素可以相互独立地并行生成。
  • 用某种下采样表示一整块像素的信息。
  • 将图像生成建模成从低尺度到高尺度的递进式生成。
  • 使用残差设计,将高尺度图像定义为低尺度图像上采样加上残差图像。

问题的关键就在于,我们应该把哪种优化方案放到算法的哪一步中。这篇论文实际上是把图像的多尺度表示用在了 Transformer 模型上。

实不相瞒,我前段时间也尝试设计了一种使用二维四叉树的自注意力,用于加速所有视觉 Transformer,同时也希望实现一个像素级 Transformer。然而,我发现当下采样的比例超过 2 之后,模型的效果就会出现明显下降。当然,我相信对图像做全注意力是没有必要的,肯定存在着更优的加速方案,这个方向仍有研究价值。

总结

Fractal Generative Models 论文提出了一种用多叉树优化的视觉 Transformer 结构。该 Transformer 将图像表达成多个尺度,浅层信息模糊但概括性强,深层信息准确但概括性弱。每个元素最终仅与 $O(logN)$ 个元素做自注意力,距离越远的元素,使用的信息越浅,访问的节点越少。作者用这个 Transformer 实现了自回归生成任务。特别地,作者实现了一个能够准确计算图像概率的像素级自回归模型。该模型在 ImageNet-64 NLL 指标上超越了以往模型,但在 ImageNet-256 的 FID 指标上不尽如人意。

作者将这套方法称为一种新的生成范式,但我认为作者的表述有误。这种效率更高的视觉 Transformer 可以用在任何视觉任务上,比如 VAR 的生成范式上。我们也可以沿着这篇论文的设计思路,继续思考如何利用图像的自身特性,在不显著降低效果的前提下提升 Transformer 的计算效率。

相关解读文章

解读何恺明团队新作:不用向量离散化的自回归图像生成

NIPS 2024 最佳论文 VAR 深度解读:下一尺度预测为何能超越扩散模型?

大语言模型(LLM)社区近期的一大热点研究课题是推理时扩展 (Inference-time scaling),这一热点也逐渐传播到了以扩散模型技术为代表的图像生成社区。相比以往扩散模型图像编辑方法,这类新方法不是那么追求应用的实时性,反而更关注图像生成质量能否随着推理时间增加而提升。那么,在扩散模型中,该怎么实现推理时扩展呢?

虽然扩散模型天生就有采样步数这一灵活的采样参数——采样步数越长,生成效果越好,但有实验表明,一旦采样步数多于一个值后,再扩增采样步数对生成质量的影响微乎其微。而近期不少工作从另一个角度挖掘了扩散模型的推理时扩展能力:既然扩散模型采样的开始和中间过程都受某些随机噪声影响,那么搜索更好的噪声,是不是就能带来更好的生成结果呢?如下图所示,谷歌近期的一篇论文表明,同样是增加函数调用次数(number of function evaluations, NFE),增加噪声搜索量比增加去噪步数的收益更显著。

在这篇博文中,我会分享我这几天学习的几篇有关扩散模型噪声搜索的论文。具体来说,我会分享 “Golden Noise” [1] 这篇直接输出最优噪声的论文,以及使用噪声搜索的 Inference-Time Scaling for Diffusion Models beyond Scaling Denoising Steps [2] 和 Inference-Time Text-to-Video Alignment with Diffusion Latent Beam Search [3] 论文。我会介绍这些论文的主要设计思想和重要实验结果,并分享一些个人科研观点。由于我也是刚开始学习,暂时不能理解论文里的所有公式,叙述时也可能会有一些纰漏。欢迎大家讨论与补充。

知识回顾

扩散模型简述

扩散模型定义了加噪过程和去噪过程:加噪过程中,训练图像 $x_0$ 会加噪 $T$ 次,最后变成纯高斯噪声 $x_T$;去噪过程中,纯噪声 $x_T$ 会被去噪 $T$ 次,最后变成生成图像 $x_0$ 。去噪过程即图像生成过程。为了让模型学习去噪,我们要通过加噪过程为模型提供训练样本。

对于同一个训练好的去噪模型,我们可以用不同的数学模型建模其去噪过程:使用随机微分方程(SDE)建模时,每一步去噪都会受到某随机噪声的扰动;用常微分方程(ODE)建模时,每一步去噪都是决定性的,或者说无随机性的。从随机性的角度看两种建模方式,SDE 在采样初始噪声 $x_T$ 和中间每一步采样时都有随机性,而 ODE 仅在采样初始噪声时有随机性。

如果我们又想用 ODE 采样,又想在采样时加入随机性,该怎么办呢?这时,我们可以利用扩散模型定义好的加噪过程:比如当前采样到了 $x_t$,我们用加噪过程给它随机加噪两步,得到 $x_{t+2}$,再用 ODE 去噪三步,得到 $x_{t-1}$。这样,我们能在正常去噪的同时,通过加噪过程中的随机噪声引入随机性。

得益于 ODE 的确定性,我们可以使用 ODE 反演 (Inversion) 来把真实图像 $x_0$ 重新变回噪声 $x_T$。相比加噪过程,由于这个反演过程没有任何随机性,我们可以保证再次对 $x_T$ 做 ODE 采样得到的重建图像 $\hat{x}_0$ 和原图像 $x_0$ 非常相似。重建图像的误差大小取决于反演算法的精确度。

在去噪时,我们可以启用 CFG (Classifier-free Guidance) 功能,让输出图像更符合某一约束信息。比如,我们可以用 CFG 让输出图像更符合文本提示词。具体来说,对于一个约束于文本信息 $c$ 的网络 $\epsilon_\theta(x_t, t, c)$,我们让它输出 $\epsilon_\theta(x_t, t, c)$, $\epsilon_\theta(x_t, t, \emptyset)$ 两个值,再令这一轮的最终输出为 $(w - 1)(\epsilon_\theta(x_t, t, c) - \epsilon_\theta(x_t, t, \emptyset)) + \epsilon_\theta(x_t, t, c)$,其中 $w$ 为 CFG 强度。直观上看,当 $w > 1$ 时,这一操作相当于是在原输出 $\epsilon_\theta(x_t, t, c)$ 的基础上,让输出更加远离空约束的输出,更加贴近有约束的输出。

在本文中,除非特别指明,否则默认扩散模型使用 ODE 采样。

搜索算法

搜索算法用于从某数据集合中搜索出最符合要求的数据项。一个最简单的场景是数据库搜索:我们输入某数据,将它与数据库中所有数据逐个比对,以判断它在数据库中是否存在。这个算法可以写成:

1
2
3
4
5
input query
for key in database:
if key == query:
return True
return False

我们可以从两个角度拓展这个算法。第一,我们要搜索的数据集合可能是由某个规则指定的搜索空间,而不是一个具体的数据库里的数据。比如,我们要搜索长度为 10 的由小写字母组成的单词,那么尽管我们没有提前存下所有的单词,我们也知道搜索空间里可能的单词有 $26^{10}$ 种。这种数据的搜索空间往往较大,我们通常不能用算法在较短的时间里搜索出最优解,只能用某些启发式算法搜索出一个较优解。

第二,我们不一定要让搜索成功的条件为「完全匹配」,而是可以设置一个评估函数,并从最终搜索中返回价值最大的那个数据项。

1
2
3
4
5
6
7
8
9
input query, evaluator

best_score = -INF
best_data = None
for data in data_space:
score = evaluator(data)
if score > best_score:
best_data = data
return best_data

根据这个算法结构,在阅读这篇博文时,我们可以从以下几个角度整理每篇论文:

  1. 噪声的搜索空间是什么?(是只有开始的噪声可以修改,还是中间每一步去噪也有随机噪声?)
  2. 搜索算法是什么?
  3. 评估函数是什么?

噪声搜索的早期尝试

如前所述,在扩散模型时,我们会先从高斯分布中采样,得到一个纯噪声图像 $x_T \sim N(0, \textbf{I})$,再逐步对其去噪,得到 $x_{T-\Delta t}, x_{T-2\Delta t}, …$,最后得到清晰图像 $x_0$。在各种图像编辑应用中,由于最开始的纯噪声 $x_T$ 信息过少,我们一般会对中间每一步的带噪图像 $x_{T-i\Delta t}$ 都做编辑。经典的 Classifier Guidance 和 Classifier-free Guidance 都是按照这种方式改进生成图像。

随后,有研究发现,仅优化初始噪声 $x_T$ 也能提升生成质量。较早研究这一性质的论文是 CVPR 2024 的 INITNO [4]。该论文发现,对于同样的提示词,有一些「有效」噪声对应的输出更符合提示词。

基于这个观察,INITNO 使用如下算法搜索最优噪声:

  1. 对于当前某个随机噪声 $x_T$,令它每一轮优化后的值为 $\mu + \sigma x_T$。
  2. 每一轮优化中,将 $\mu + \sigma x_T$ 输入进去噪网络中。根据某个来自于去噪网络的可微评价指标,用梯度下降更新 $\mu$, $\sigma$。
  3. 将最后的噪声 $\mu + \sigma x_T$ 加入噪声池。
  4. 多次采样初始噪声 $x_T$ ,执行上述步骤,以扩充噪声池。
  5. 最后,再次根据评价指标,选出噪声池里的最优噪声。

这篇论文选用的评价指标为去噪网络注意力模块响应程度,这种设计受到了 Attend-and-excite [5] 论文的启发。由于该指标的原理与本文主要介绍的内容无关,此处不对其做深入探讨。我们只需知道 INITNO 使用了一个两步噪声搜索算法:1)优化某个随机噪声;2)多次获取优化后噪声,再次选取一个全局最优噪声。评价噪声好坏的标准是其去噪过程中去噪网络注意力块的中间输出,这是因为这些中间输出与文本匹配度密切相关。

稍晚一些的工作 “Not All Noises Are Created Equally” [6] 也汇报了类似的观察:并非所有噪声本质相同,有些噪声的生成质量更高。这个工作实现了两类搜索算法:

1) 噪声选取:从多个随机噪声中直接选取指标最优的那一个。
2) 噪声优化:从当前噪声开始,根据优化指标用梯度下降优化当前噪声。

从搜索算法上看,这个工作相当于把 INITNO 里的两步搜索算法拆成了两种算法。

这个工作用了一种有趣的评价指标。对于噪声 $x_T$,我们求它先生成,再 DDIM 反演 (DDIM Inversion) 得到重建噪声 $\x’_T$。之后,我们令重建稳定性为 $x_T$ 和 $\x’_T$ 的 cos 相似度。论文指出,重建稳定性更好的噪声具有更高的生成质量。尽管作者并没有严谨地分析这个指标,但实验表明这种指标确实有效。我们在后文中会看到,该团队的后续工作对这个指标的原理进行了一定的解释。

Golden Noise: 直接输出临近最优噪声

“Not All Noises Are Created Equally” 的研究团队后续推出了其改进版 Golden Noise for Diffusion Models: A Learning Framework [1]。这篇论文最大的亮点是不直接使用噪声搜索,而是先用噪声优化方法得到「差噪声-好噪声」这样的数据对作为训练样本,再用一个小网络学习差噪声到好噪声的映射。在阅读这篇论文时,我们主要关注两件事:1)如何为差噪声找到对应的好噪声?2)噪声优化网络有何亮点?

在构建训练样本时,Golden Noise 并没有用噪声搜索技术,而是用规则直接得到更好的噪声。和前作”Not All Noises Are Created Equally” 一样,这篇论文把噪声 $x_T$ 先去噪再 DDIM 反演的重建噪声当成一个更好的噪声。稍有不同的是,这篇文章明确指出,去噪时使用的 CFG 强度大于 1,而反演的时候 CFG 强度等于 1。这样得到的重建噪声 $x’_T$ 能够更加贴近约束文本的描述。

作者用公式推导介绍了这项技术的原理。通过合并去噪和 DDIM 反演的公式,我们能够用下面的式子描述原噪声 $x_T$ 和反演噪声 $x’_T$ 的关系。我们可以忽略多数参数,只看后面 $\epsilon$ 做差的那一项。前面的系数 $w_l - w_w$ 表示去噪 CFG 强度 $w_l$ 减去重建 CFG 强度 $w_w$。可以发现,这个式子和 CFG 类似,也是写成了带约束输出 $\epsilon(\cdot, c)$ 减去无约束输出 $\epsilon(\cdot, \emptyset)$ 的形式。那么,它的作用也和 CFG 类似,可以把噪声「推向」更靠近文本描述的方向。

该团队的同期工作 Zigzag Diffusion Sampling [7] 用了更多示意图来直观解释这项技术的原理。从语义贴合度的角度看,使用 CFG > 1 的强度做去噪会提升噪声的语义贴合度,而使用 CFG = 1 的强度做反演几乎不会改变噪声的语义贴合度。因此,只要反复执行去噪-反演过程,就能让噪声的语义贴合度逐渐提升。

先去噪再反演只能提升噪声的语义贴合度,而不能保证图像的质量提升。因此,在构建好噪声时,Golden Noise 还使用了一种拒绝采样策略,以确保找到的「好噪声」确实能生成高质量图片。具体来说,Golden Noise 用一个基于神经网络的图像质量评估器和原噪声 $x_T$ 对应图像 $x_0$ 和新噪声 $x’_T$ 对应图像 $x’_0$ 分布打分。只有 $x’_0$ 的分数比 $x_0$ 高出一点时,才把 $(x_T, x’_T)$ 加入训练集。

我们再简单看一下噪声预测网络的设计。这个网络会根据输入的差噪声 $x_T$ 输出语义贴合度高且质量更高的噪声 $x’_T$。作者发现,每对噪声的 SVD (奇异值分解) 结果非常相似。因此,Golden Noise 设计了一个两路网络:一个网络根据输入噪声,输出预测噪声的大致 SVD,它决定了最终噪声的主要内容;另一个网络根据输入噪声和文本嵌入,输出一个残差噪声,用于补充细节。

一套完整的噪声搜索基础框架

2025 年 1 月,谷歌谢赛宁团队公布了论文 Inference-Time Scaling for Diffusion Models beyond Scaling Denoising Steps。这篇论文依然是从搜索更优的初始噪声或中间噪声的角度来提升扩散模型采样质量。但相比之前的工作,这个工作作出了两大贡献:

  • 从推理时扩展 (Inference-time scaling) 的角度认识噪声搜索,研究采样计算量与图像指标的关系。
  • 提出了一套系统性的噪声搜索框架,指明了框架的两个设计维度:评估图像质量的评估函数和搜索时使用的算法。这篇博文对搜索算法的建模方式主要参考自这一框架。

下图是论文中的第一张示意图。彩色的线是增加噪声搜索量的结果,灰色的线是增加采样步数的结果。可以看出,不管是哪个评价指标,增加噪声搜索量对图像质量的提升都更加明显。

这篇论文的叙述逻辑十分流畅。让我们按照论文的叙述顺序,看看这个工作用到了哪些搜索算法与图像质量评价指标。

早期验证

为了简单验证是否可以通过增加噪声搜索量来提升图像质量,这篇论文开展了一个简单的验证实验:使用在 ImageNet-256 上训练的 SiT [8] 模型,使用较简单的搜索算法和最直接的评估指标,观察模型按类别生成(额外输入一个类别标签)质量随搜索量的变化趋势。

具体来说,在搜索算法上,作者采用了「随机搜索」(random research) 算法:和 “Not All Noises Are Created Equally” 中的噪声选取一样,算法随机采样大量噪声,然后选择效果最好的那个噪声。在评估函数上,作者采用了简单粗暴的「面向答案」策略:如果最终的测试指标是 Inception Score,就选取 Inception V3 网络的对输入类别的分类概率最大的噪声;同理,如果最终测试指标是 FID,就贪心地选取让 FID 尽可能小的噪声。由于实际应用中,我们不能用这种「作弊」的方法提前知道评测指标,因此这种评估函数仅供概念验证使用。

以下是早期验证实验的结果。由图可知,提升计算量能够明显提升图像质量。比如,左侧 FID 结果中,对于 CFG=1 的曲线,不使用噪声搜索(NFE 最少的那个点)的结果很差;然而,增加噪声搜索量后,CFG=1 的 FID 分数甚至能超过 CFG=1.5 的。

之后,论文测试了两个更加合理的评估函数:使用 CLIP 和 DINO 分类器。和前面的 Inception V3 网络一样,评估函数会找出分类概率最大的输出。

用 CLIP 做类别分类器时,需要把类别转换成文本。

使用更合理的评估函数后,依然能观察到图像 Inception Score 随搜索量增长的现象。

其他搜索算法

随机搜索算法虽然表现不错,但这个算法会导致验证器欺骗 (verifier hacking):算法快速在整个高斯噪声空间中找到了那些验证分数更高的噪声。但是,验证器总是存在偏见的,验证器高分不总是代表图像质量高。因此,验证器欺骗会导致输出图像分数虚高,且多样性下降。

为了缓解这个问题,论文尝试了其他搜索算法。论文先尝试了零阶搜索(Zero-Order Search, ZO)算法 :对于某个输入噪声,仅在其小邻域里搜索更好的噪声。搜索时,我们随机从邻域里取一些噪声,然后选评估分数最高的那一个噪声。之所以把这个算法称为「零阶」,是因为先有一阶搜索算法:让评估函数对噪声求梯度,沿着令评估分数更好的梯度方向优化。但作者发现,一阶搜索算法需要反向传播梯度,速度太慢了,相较零阶搜索并没有明显优势。

“Not All Noises Are Created Equally” 的噪声优化算法是一种一阶搜索算法。

另外,论文还尝试了沿路径搜索(Search over Paths)算法。在这个算法中,作者把原来的 ODE 采样改成了 ODE-重加噪采样:每次去噪几步,稍微加噪几步,又去噪几步。这样,就可以在采样过程中也引入随机噪声。沿路径搜索希望找到一条最优的生成路径,这个路径既涉及初始噪声,也涉及中间噪声。

在搜索时,沿路径搜索采用了 beam search 的策略:维护一个大小为 $N$ 的当前最优带噪图像。每一步,对每个带噪图像(也就是每条采样路径)采样 $M$ 个噪声,得到 $NM$ 个可能的下一轮带噪图像。最后,使用评估函数,从 $NM$ 个图像中挑选最优的 $N$ 个。

在前两种搜索算法中,我们都是得到了最终的生成图片 $x_0$,再用评估函数来评估 $x_0$ 的质量。但在沿路径搜索中,我们在采样过程中途就要决定当前带噪图像 $x_t$ 的质量。为了高效评测 $x_t$ 的质量,沿路径搜索会先对 $x_t$ 执行一步去噪,再根据扩散模型公式算出一个临时预估的 $x_0$,最后评估该 $x_0$ 的质量。

如下图所示,这两个新搜索算法也是有效的。各项实验的详细参数请参考原论文。

文生图模型实验

在较为简单的按类别图像生成任务上验证了想法的有效性后,论文展示了文生图任务上噪声搜索的效果。

将任务拓展成文生图后,不需要重新设计搜索算法,只需要更新评估方法。论文选用的评估方法包括 ASP (Aesthetic Score Predictor), CLIPScore, ImageReward。它们的评估标准如下:

  • ASP 模型为输入图像预测一个美学分数。
  • CLIPScore 表示 CLIP 输出的图文匹配程度。
  • ImageReward 能够从图文匹配度、美学质量、无害度等多个角度评估图像。

除了单独使用上述某个评估方法外,还能够将所有评估方法组合成一个集成(ensemble),更综合地评估图像。

在测试时,论文使用了同样的指标。但是,为了确保对比的公平性,我们应该忽略评估方法和测试指标完全相同时的结果。另外,论文还汇报了多模态大语言模型 (MLLM) 的打分结果,作为补充测试指标。

下图展示了在 FLUX.1-dev 上使用上述评估方法做噪声搜索的实验结果。第一行的实验是不使用噪声搜索,只用 30 次 NFE 做去噪的实验结果。后面的实验都是用了 2880 次 NFE 在搜索上。相比之前 ImageNet 上的 FID 实验,此处指标提升得并不明显。

论文还展示定性实验结果。每一行前三张图像是增加去噪 NFE 的结果,从第四张图像开始是增加搜索 NFE 的结果。

与偏好微调结合

现在 LLM 普遍采用了根据奖励函数微调模型的策略,比如直接偏好优化(Direct Preference Optimization,DPO)。这些微调技术也被用到了扩散模型中,比如 Diffusion-DPO [9]。而噪声搜索的做法和这些微调方法很像,都是基于某一个奖励函数,让模型的输出更符合人类的偏好。那么,对于微调过的模型,噪声搜索还有用吗?

论文展示了在 Diffusion-DPO 中的 SDXL-DPO 上应用噪声搜索的实验结果。可以看出,噪声搜索同样兼容偏好微调模型。

最后,我们来简单浏览近期另一篇使用噪声搜索技术的论文: Inference-Time Text-to-Video Alignment with Diffusion Latent Beam Search [3]。相比前几篇论文,这篇论文主要是把噪声技术拓展到了视频模型上。阅读这篇论文时,我们会简单看一下论文的搜索算法和视频评估函数,并讨论论文中的部分理论推导。

Beam Search 噪声搜索

这篇论文用到的搜索策略和上文中的沿路径搜索完全相同。即一轮去噪中,我们维护 $N$ 个最优带噪视频,并从 $NM$ 个下一轮带噪视频中选取最优的 $N$ 个。一个 $N=2, M=2$ 的示意图如下所示:

同样,在这个搜索算法中,我们无法提前获取清晰视频 $x_0$,需要用某种方法即时评估带噪视频 $x_t$。上一篇论文通过一步去噪并提前获取预测 $x_0$ 的方式实现了在线评估。而这篇论文采取了另一种类似的策略:对当前带噪视频执行一个步数极少(2~3)步的 DDIM 采样,以快速预测当前 $x_t$ 对应的 $x_0$,再评估预测的 $x_0$ 的质量。

视频评估指标

这篇论文将 MLLM 的打分结果作为最终优化目标。但由于此评估方法过于耗时,在搜索时,该论文还是用了一些更高效的评价指标,包括:

  • 主体一致性:用帧间 DINO 特征的相似度表示
  • 运动平滑性:借助视频插帧网络提取视频运动特征
  • 运动程度:用光流表示
  • 美学质量:用 LAION 美学预测器评估
  • 图像质量:用一个能够检测图片是否过曝、模糊的 low-level 质量评估网络评估
  • 文本-视频一致性:用一个视频版 CLIP 评估

论文以上述 6 个指标的线性组合为最终评估指标。为了获取最优的线性组合权重,论文暴力尝试了若干组参数,并根据 MLLM 的打分结果选取最优线性组合。

理论推导

尽管这篇论文最后还是使用了简单粗暴的噪声搜索技术来优化扩散模型生成质量,但论文为这种做法提供了一些理论解释。作者借助了随机最优控制 (stochastic optimal control)中的相关技术,把让采样结果更符合某个奖励函数这一问题,转化成先求奖励函数对带噪图像梯度,再把该梯度加入去噪公式。这一技术和 Classifier Guidance 的思想非常相似:如下图所示,在 Classifier Guidance 中,我们可以对网络输出加上一个对 $x_t$ 求梯度的项,使得 $x_t$ 往某个奖励函数 (此处的奖励函数是一个分类网络,用于让图像更像某类物体)的方向靠近。

但是,求梯度太耗时了。而求梯度的一种高效近似就是零阶搜索:随机搜索附近的一些 $x_t$,找到值最优的那个 $x_t$。所以,我们可以把噪声搜索看成是 Classifier Guidance 的一种近似操作。

总结与评价

噪声搜索是扩散模型采样过程中一种通过选取最优初始、中间噪声来提升图像质量的技术。在这篇博文中,我们主要学习了早期利用扩散模型自身性质搜索噪声的 INITNO 和 Not All Noises Are Created Equally,直接用神经网络预测更优噪声的 Golden Noise,系统性建模噪声搜索的 Inference-Time Scaling for Diffusion Models beyond Scaling Denoising Steps,以及将噪声搜索应用到视频生成的 Inference-Time Text-to-Video Alignment with Diffusion Latent Beam Search。我们可以从是否搜索中间噪声、搜索算法、评估函数三个维度描述一个噪声搜索方法。本文的方法可以总结如下:

方法 搜索中间噪声? 搜索算法 评估函数
INITNO 局部一阶搜索+全局随机搜索 扩散模型注意力输出
No All Noise 全局随机搜索/局部一阶搜索 去噪-反演稳定性
Golden Noise 神经网络预测 去噪-反演稳定性+图像质量
beyond Scaling Denoising Steps 仅在沿路径搜索中 全局随机搜索/局部零阶搜索/沿路径零阶 beam search 分类器最大概率/美学打分器/ImageReward
Inference-Time Text-to-Video Alignment 沿路径零阶 beam search 主体一致性/运动平滑性/运动程度/美学质量/图像质量

从任务目标来看,噪声搜索希望模型输出能够满足某个奖励函数,尤其是满足人类偏好的奖励函数。它和相关技术的对比如下:

  • Classifier Guidance: 用奖励函数一阶导数指导生成。
  • 噪声搜索:使用零阶搜索时,可以看成 Classifier Guidance 的高效近似版。
  • 偏好优化 finetune:用奖励函数微调模型参数。

我认为这项技术并不是一个很好的科研方向,原因有:

  • 噪声搜索的做法太简单暴力了。使用过 AI 绘画的用户,应该都尝试过随机生成大量图片,然后从中挑选自己满意的图片。所谓噪声搜索只不过把这个过程自动化了而已。所有这些方法中只有 Golden Noise 的直接预测噪声看起来比较新奇。
  • 不同噪声对应的图像质量不同是一个有趣的观察。但是,这些论文并没有深入分析这个问题的原因,只是用实验去证明哪些做法可以缓解这个问题。从科研上,我们更希望有文章能够深入解释某一个现有问题。
  • 虽然有文章宣称噪声搜索是一种推理时扩展,但仔细浏览实验表格,噪声搜索带来的提升太有限了:网络运算次数从 30 增大到了 2880,是原来运行时间的 96 倍,换来的只是一点微小的指标提升。还不能排除文章中展示的定性图片是精挑细选的结果。

我猜测不同噪声的本质不同在于,当前扩散模型的初始噪声是放在一个二维像素网格里的。在随机采样完成后,像素间的某些关联性就被确定下来了。无论在后续采样过程中怎么干预,一开始的图像结构都难以改变。但我们更希望一开始噪声的每个维度都互相解耦合的,这样噪声的生成质量的方差或许会更小一点。要让噪声的每个维度一开始互相独立,我们可能需要设计一种新的图像表示方法,而不用二维像素结构。

我认为扩散模型的推理时扩展确实是一个有价值的研究方向。但就目前来看,噪声搜索显然不是实现这个目标的最优解。

部分参考文献

对于某些经典论文 (如 CLIP, Classifier Guidance),可以直接通过搜索关键词找到论文。其他一些较新的论文有:

[1] Golden Noise for Diffusion Models: A Learning Framework

[2] Inference-Time Scaling for Diffusion Models beyond Scaling Denoising Steps

[3] Inference-Time Text-to-Video Alignment with Diffusion Latent Beam Search

[4] INITNO: Boosting Text-to-Image Diffusion Models via Initial Noise Optimization

[5] Attend-and-excite: Attention-based semantic guidance for text-to-image diffusion models

[6] Not All Noises Are Created Equally: Diffusion Noise Selection and Optimization Zipeng

[7] Zigzag Diffusion Sampling: Diffusion Models Can Self-Improve via Self-Reflection

[8] Sit: Exploring flow and diffusion-based generative models with scalable interpolant transformers.

[9] Diffusion model alignment using direct preference optimization.

自从 ChatGPT o1 在 2024 年 9 月发布后,人们逐渐把研究重点放在了推理时扩展 (Inference-time scaling) 上。对于扩散模型而言,除了在推理时增加步数外,谷歌今年 1 月的研究 Inference-Time Scaling for Diffusion Models beyond Scaling Denoising Steps 表明,搜索更好的扩散模型噪声也能提升图像质量。但实际上,选取更好的噪声这一想法早在 2024 年 6 月的论文 Not All Noises Are Created Equally:Diffusion Noise Selection and Optimization 中就已提出。可惜的是,这篇论文最后在 ICLR 上被主动撤稿了,详情可参考 OpenReview:https://openreview.net/forum?id=R5xozf2ZoP

在这篇博文中,我会简单介绍「并非所有噪声本质相同」这篇论文。之后,我们来尝试批判性分析这篇论文及其审稿意见,并反思该如何做出高质量的工作。

知识准备

想读懂这篇论文,只需了解 DDPM 和 DDIM 这两篇扩散模型经典论文。

DDPM 定义了加噪过程和去噪过程:加噪过程中,训练图像 $x_0$ 会加噪 $T$ 次,最后变成纯噪声 $x_T$;去噪过程中,纯噪声 $x_T$ 会被去噪 $T$ 次,最后变成生成图像 $x_0$ 。

DDIM 修改了 DDPM 中的部分假设,让扩散模型在去噪时不再有随机性,而唯一的随机性来自于随机噪声 $x_T$ 的采样。保证了去噪过程不再有随机性后,我们就可以通过公式反演 (inversion),找出某个真实图像 $x_0$ 对应的 $x_T$。当然,这个反演过程存在误差。

核心思想:更好的噪声带来更高的图像质量

作者认为,过去的工作仅通过优化网络结构或参数来提升扩散模型生成质量,却忽视了噪声的重要性。作者从两个方向探索了噪声空间(即所有可能的噪声构成的集合):能否用某种定量指标选取更好的噪声?能否优化某一现有噪声?这两个方向的应用如下所示。噪声选取能够提升模型在同一个文本提示下的随机生成质量,而噪声优化能够提升现有某噪声对应图像的质量。

用反演稳定度反映噪声质量

根据以上设计思想,这个工作的重点就落在了噪声质量的评估指标上。只要有了一个这样的指标,我们就能用简单的算法实现噪声选取和噪声优化:

  • 噪声选取:随机采样大量噪声,然后根据指标选出最好的那一个。
  • 噪声优化:把指标变成损失函数,用损失函数优化给定噪声。

作者认为,函数不动点具有某些良好性质。因此,如果一个噪声在做完一轮生成-反演(去噪-加噪)后变化越小,那么这个噪声的质量越好。

所谓不动点,就是令函数 $f$ 满足 $x=f(x)$ 的输入 $x$。这里作者把函数 $f$ 定义成先生成再反演这一整个过程,把 $x$ 定义成某个高斯噪声。

具体来说,作者用 cos 相似度来反映噪声的「变化幅度小」,即对于噪声 $\epsilon$ 和其生成-反演结果 $\epsilon’$,反演过程的稳定度,或者说噪声的质量,等于 $cos(\epsilon, \epsilon’)$。

有了这样一个指标后,我们可以用下面伪代码所示算法实现噪声选取和噪声采样:

1
2
3
4
5
6
7
8
9
10
11
input number of samples K, denoising model M
eps_list = sample_noise(K)
stability_list = []
for i in range(K):
eps = eps_list[i]
img = generate(M, eps)
eps_inversion = inversion(M, img)
stability = cos(eps, eps_inversion)
stability_list.append(stability)
best_idx = argmax(stability_list)
output eps_list[best_idx]
1
2
3
4
5
6
7
input denoising model M, optimization steps n, noise eps
for i in range(n):
img = generate(M, eps)
eps_inversion = inversion(M, img)
loss = 1 - cos(eps, eps_inversion)
eps = gradient_descent(loss, eps)
output eps

实验结果

实验配置

本工作用 SDXL 和 SDXL-turbo 模型做实验。去噪步数分别为 10, 4。

本工作在测试时只需要设置提示词。提示词来自于 Pick-a-pic, DrawBench, GenEval 这三个数据集。

  • Pick-a-Pic 收集了真实文生图应用中用户的输入提示词及相同提示词下不同输出的偏好程度。每项数据包含提示词、一对图像、一个表示用户偏好哪个图像的标签。
  • Drawbench 的每项数据包含提示词、一对图像、一个反映图像质量的偏好标签、一个反映提示词对齐度的偏好标签。这些提示词能从颜色、物体数量等多个角度测试模型生成属性。
  • GenEval 提供了能从单个物体、两个物体、物体数量、颜色、位置等多个角度测试模型的提示词。

为了对比生成图像质量,本工作用了 HPS v2, AES,PickScore, ImageReward 指标。除 AES 只考虑美学分数外,其他几个指标都是通过训练一个匹配人类偏好的模型来评估图像质量。除了给出这些指标的值外,论文还展示了方法的胜率——在同样的提示词下,比较使用/不使用新方法的定量结果,统计使用新方法胜利的频率。

定性定量结果

以下是噪声选取的实验结果。

以下是噪声优化的实验结果。

从定量结果中可以看出,本文的方法一定程度上确实是有效的。但是,这些数值上的提升真的总能反映在视觉效果上吗?这些数值上的提升足够大吗?由于缺乏同类方法的比较,这些实验还是欠缺说服力。

博文开头已经展示了本文的定性结果,这里就不再重复展示了。值得一提的是,本文的方法可以拓展到其他模型上,比如生成 3D 模型的 SV3D。以下是 3D 模型上的可视化结果。

审稿意见分析

在看 ICLR 2025 官方审稿人意见之前,我先给出我的一份简单审稿意见。我把本文的主要内容都在这篇博文里写出来了,读者也可以在阅读下面内容之前尝试给该论文打分。如果读者想着重提升审稿能力,可以先去把这篇论文细读一遍,再去 OpenReview 上审视其他审稿人的意见。

这篇文章发现了并非所有扩散噪声生成质量相同这一问题,并设计了反演稳定度这一衡量噪声质量的指标。定性和定量实验表明该方法确实能提升图像质量。

本文的优点在于新问题的发现:确实之前多数研究者只考虑如何优化模型,而忽视了噪声也是影响图像的重要因素。

本文在叙述和论证上均存在缺陷:

  • 在为何要使用反演稳定性这件事上,作者说是受到了不动点理论的启发。但作者完全没有深入分析反演稳定性的原理,本质上是通过实验来直接验证假设的合理性。哪怕不好从数学原理上解释,作者也应该通过列出相关工作,并补充部分探究原理的实验,来巩固该指标的合理性。
  • 本文的技术贡献并不多:优化噪声是一个非常常见的策略。
  • 在实验中,作者没有和其他方法对比,完全看不出这个方法是否具有优越性。找出一个基准方法其实并不难:将 CFG (classifier-free guidance) 分别设置成 1 和 7.5 就是一个非常容易实现的基准方法。

如果是现在已经知道了优化噪声是一个有潜力的方向,我可能会给这篇论文一个位于接收临界线上的分数。但如果是去年的话,很可能给的是低于临界线的分数。

我们来简单看看官方审稿人的评价。

审稿人 A 给了明确的差评。文章的主要缺陷有:

  • 虽然作者宣称这是首次研究噪声空间的论文,但实际上之前已经至少有三篇工作做过类似研究。因此,文章的创新性是有限的。
  • DDIM 反演稳定性差一部分是因为反演算法不够好导致的,而和扩散模型无关。最好能够展示更好反演算法下的结果。
  • 评估不充分:这篇文章没有展示任何和其他方法的比较。另外,最好能展示诸如 FID,IS 等其他指标。文中的指标提升看起来微不足道,仅有约 1%,感觉不到明显的进步。
  • 每次评估都需要执行一次加噪-去噪过程,方法性能较低。

审稿人 A 是这个方向的专家,他用已有的噪声空间优化工作来质疑本文的创新性。我简单看了一下该审稿人引用的工作,确实已经有不少往期工作做了类似的事,但实现方法还是比本文的方法更复杂一点。所以,不能说这篇论文一点创新也没有,作者必须严谨地比较这篇论文和之前的论文,并强调出创新点在哪。

审稿人 B 给了一份评价略低于临界线的短评。他认为这篇论文提出的「反演稳定性」及其实验结果还是非常合理的。他认为论文的主要缺陷是方法质量受到反演算法的影响,并希望作者给出不同反演策略下的结果。

审稿人 C 也给出了略低于临界线的评价。他认为这种使用反演稳定性来评估噪声质量的想法有新颖性,且实验的设置比较合理。在 3D 上的应用或许很有潜力。但他也列出了几条主要缺陷:

  • 作者认为反演质量与生成质量强相关。但这个假设只是通过一个具体示例来验证,而缺少理论分析或者系统性的研究。一个可能的分析方法是:测试10万个样本,计算图像质量和反演稳定性的相关性。
  • 和上面两个审稿人一样,审稿人 C 也提到了 DDIM 反演本身就不够好的问题。
  • 噪声选取和噪声优化都需要大量计算资源。

审稿人 D 也给出了略低于临界线的评价。他同样认为反演稳定性是一种新颖的指标,作者对于方法设计动机阐述得十分清晰。他提到的主要缺陷有:

  • 研究反演中的不同点并不是一个新颖的想法,之前至少有三篇工作从迭代优化来寻找反演不动点的文章。这篇文章没有与这些工作做对比。
  • 从 K=100 个样本里选取噪声的方法太简单直接了。之前有类似工作用一种更深入的方式选取噪声。
  • 缺乏和其他噪声优化论文的比较。
  • 计算效率太低。

总结与反思

本工作明确指出了扩散模型不同初始噪声质量不同这一设计动机。为了找出更好的噪声,本工作用一种听起来比较有趣的「反演稳定性」来评估噪声质量。基于这个指标,本工作设计了噪声选取和噪声优化两个算法,用于两类生成任务。

多数审稿人都认可该工作的方法有一定的新颖性,但其论文有着诸多缺陷:

  • 没有深入分析反演稳定性的原理,且没有考虑是否应该用更好的反演算法。
  • 噪声优化是一种常见的策略。没有与相关工作做对比。
  • 指标提升的说服力不足。
  • 每次评估反演稳定性都需要执行去噪和加噪过程,运算效率过低。

当然,在目前的眼光看来,如果生成质量足够高,增加推理时间也是可以接受的。但是,论文的前几个缺陷是实实在在的,被评价为低于接收临界线合情合理。作者最后也没有 rebuttal,直接撤稿了。我感觉这篇论文还是比较可惜的,毕竟它的研究方向比较有潜力。

从这篇论文以及最近做推理时扩展的论文可以看出,哪怕对于同一项技术,改变看待问题的角度也算创新。比如同样是更换扩散模型噪声,如果是从推理时扩展的角度来看,那么运算时间长就不是缺陷了;但与之相对,我们需要证明随着运算时间的增加,生成质量会按某种规律逐渐变好,表明花更多的时间是有意义的。

从这篇论文投稿失败的教训中,我们也可以总结出顶会论文应该满足哪些最基本的要求。当论文的方法和之前方法非常相似时,一定要与之前的方法对比,并明确写出本文的创新点在哪。另外,虽然很多时候我们是先有了实验结果再去补充说明方法中的假设,但我们依然可以在论文里尝试解释我们这样做的原因。这种解释可以是通过原理上的推导,也可以是通过解释性实验。

Ave Mujica 第五集一直在沉重的气氛中度过。无言的悲伤透过屏幕,来到我的心里。就像被巨石堵住的水流,我想要做些什么来释放这些情绪,却茫然无措。终于,在这集动画最后,灯的一句「一起组乐队吧!」瞬间击穿了我的心理防线,泪水止不住地流了下来……

在生活中,我一直保持了理性的态度,冷静地看待一切。只有偶尔有闲暇时,才会把感性的一面留给自己。一边哭着,我一边试图分析剧情,分析自己的想法,想要弄清楚现在的我究竟在想什么。可是,泪水就是止不住。本以为是困了,可是两天后在外面吃饭时,我又想起了这段剧情,眼睛又湿润了起来。

前几周,哪怕观点大不相同,我也积极地浏览着网上关于 Ave Mujica 热火朝天的讨论。而看完这集后,稍微看了一下贴吧,我就知道我的感想果然难以在网上找到共鸣。这一次,我害怕了,我不敢再去看别人的评论了。我想去诉说我的想法,传递给人海中的那些同路人,但不被理解的痛苦与恐惧占了上风。所以,这一周,我不敢看,也不敢想 Ave Mujica 的事。

一周快过去了,新的一集要播出了。不把此刻的想法说出来,我好像就会失去什么。最后我打算鼓起最后的一点勇气,在博客上讲一讲我的感想。不管是这篇文章,还是之后有关 Ave Mujica 的文章,很多东西不是在写剧中的角色,而是在写我自己;我也明白,这些文章不怎么会照顾他人的阅读体验,而只是写给我自己看的。不管自己的内心被暴露成了什么样子,我都想坦荡地面对。


在接连不断的事件后,第四集快节奏地结束了。剧终,在队员们的宣言下,Ave Mujica 解散了。

正如那干脆利落的解散宣言,第五集的开头,我们直接看到的是乐队解散后的场景。当红乐队在巡演中途突然解散,观看最后一场演出的观众排队退票。随后,网上布满了乐队解散的流言蜚语。面对事务所的一次次来电,祥子无力地趴在初华家的桌子上。初华想关心祥子,但真正在意的问题却是「我们还能在一起吗?」某日,仅留下一段简短告别便签的祥子,彻底宣告乐队的一切关系都结束了。

就像什么都没有来过似的,队员们的生活重新步入了「正轨」。在海铃看来,不过又多见识了一支解散的乐队,自己雇佣兵的身份并没有改变。初华还留在 Sumimi,和她的好搭档真奈继续着这个组合的活动。喵梦还是当着网红,活跃地出现在人们面前。祥子回到了破碎的家庭,重操客服旧业,赡养老爹,如轮回般过着和之前一样的日子。

可是,真的什么都没改变吗?

初华焦急地寻找着她心心念念的祥子,海铃则断然拒绝了一切有关过去的讨论。以知名演员为梦想的喵梦,也因再怎么努力也无法拥有天才般的演技,而回绝了演戏的良机。睦更是从人们的视线里消失了。

「那个人好像是 Ave Mujica 的 Oblivionis 哦。」

即使是听到了这样的杂谈,祥子依然带着职业般的微笑结束了客服的工作。平常地坐着电车,平常地回到出租屋。

老爹又被带到了警局。领他回家的时候,他又狼狈地坐在了地上。「如果是以前的话,这里是不是应该生一生气比较好呢?」在这一刻,祥子或许这样想过。但最后,她选择了最平常的做法,默默地看着。

对祥子来说,一切平常才是最大的不寻常——她已经不再有激情反抗,而是无奈地接受了一切。

无论是努力学习,努力工作,努力养家,都只是机械般重复地之前的动作,只是自我麻痹与忘却的手段。她不再努力改变自己的命运了。

动画的前半段正是这样如流水般展示主角们的生活片段。虽然没有深刻的剧情,但这淡淡的日常中流露出一股抹不去的哀伤。乐队解散就像还未下雨的乌云一样,笼罩在角色们的心里。


事情到这里还没有结束。很快,祥子的外公在她放学时找了过来。乐队解散的违约金已经全部付清,只需要告别不争气的父亲,回去当大小姐就行了。这一次离开破旧的出租屋时,祥子只是平静地带走了行李。重返大宅的那一刻,那个要强的她也已经死了。

——不,或许比真正的死亡还要痛苦。

作为一个在战争中失利的士兵,最渴求的应该是一次痛快的死亡。可是,如果被带到了敌国,好吃好喝伺候着,甚至连反抗的意识也完全失去了。这不是更大的一场悲哀吗?

只是为了和亲生父亲生活在一起,为了这小小的愿望,她头也不回地告别了大小姐的生活。命运给了和她年龄不匹配的生活压力,让她在学习之余不得不打工养家。只是为了和父亲在一起,只是想要反抗这不对的命运,她摧毁了心爱的乐队,冷酷地斩断了一切。可是,不管身体能够承受住多少劳累,心灵的腐朽只会与日俱增。在心理被压垮之后,她只好把一切押在了一支新乐队上。这或许是无意识间把乐队和幸福联系在了一起,又或许是通过获取名利向世界的一次复仇。为了保护那破碎不堪的心,祥子把自己抽离出来,全部寄托在乐队上——只要乐队做到了世界最好,我是不是就能获得幸福呢?

但很可惜,乐队又一次解散了。连接灵魂和世界的最后的一根弦,最后也断掉了。

「不就是大小姐过家家吗?」

当她放弃父亲,重回大宅的那一刻,她连最初反抗一切的念头也消失了。一切看似都回来了,但她的一切也全部消失了。

「我讨厌我自己」

她也意识到,丰川祥子,在精神上死去了。


在悲伤的镜头之间,穿插着高松灯幸福的回忆。

因为独特的爱好,她总是离人群有些疏远。但她从来没有放弃解读他人的想法,想要尽可能融入进去。

那一天,在随风飘散的花瓣前,她碰到了生命中那个重要的人。

祥子带她加入了乐队,认识了乐队的大家。就像春天的阳光一样,样子为她驱散了身边的寒气。《春日影》的每一个字,每一声调,都是大家共同创作的结晶。那是一段多么美好的日子啊!

后来,CRYCHIC 解散了。几经沉浮,灯用自己的心声,在 MyGO 乐队里与陌生和熟悉的朋友建立了牢固的关系。这一回,她终于融入了自己所属之处。

可是,回头望去,春日的暖阳已经不在了。留下的,只有月光下一个孤寂的影子,就和当年的自己一样。明明同样在弹着曲子,灯却无法从祥子那里再感受到之前的温暖。她敏锐地察觉到了祥子的变化,想要为祥子做点什么。虽然不知道这么做有没有用,她一直用便签试图和祥子沟通。

「祝你幸福」是祥子给她留下的最后的话。向他人送上最诚挚的祝福时,祝福的话语并不是为对方量身定做的考虑,而只是希望对方获得自己最求之不得的东西。可能是想到了这里,灯又一次在便签上写道:「小祥,你幸福吗?」


幸福是什么呢?

最早,祥子的幸福只是简简单单地和家人生活在一起。母亲去世后,幸福变成了用自己双手就可以争取到的东西。而父亲的事业失败,则让幸福变成了牺牲一切也难以把握的东西。

越是缺失,越想追求。越是追求,越是求而不得。幸福就是香气扑鼻的毒药,惹人沉醉,使人沦陷,最后带走一切。又一次经历乐队解散的祥子,终于明白,追求幸福才是一切的元凶。只有忘记一切,忘记幸福,才能「正确地」在世界上活下去。

「幸福是什么呢?」

灯向立希问道。经历了种种后,MyGO 队员间的关系已经牢不可破。望着眼前这个自己在意的人,想着眼前这美好而平凡的日子能够一天一天持续下去,立希害羞地说:「我现在就很幸福……」。

是啊,我们都很幸福。灯虽然不见得理解了立希对她特别的关心,但她能够感觉到,在 MyGO 里,大家都是幸福的。

所以,察觉到了什么的灯,向祥子发出了「是否幸福」的拷问。其他的话语都可以回避,唯有这个可望不可及的词语,一击突破了祥子的心防。她粗暴地回应了这个便签。她只是害怕,害怕这个总是给自己带来痛苦的东西。

祥子又一次逃跑了。只有灯的话,大概永远都追不上吧。而这一次,有行动力极强的爱音在她身边。机缘巧合之下,灯和爱音坐上了祥子回家的车,灯有了和祥子直面对话的机会。

灯又进入了那座豪宅。可是,一切都物是人非。再次来到那个曾经熟悉的琴房后,「你幸福吗」的答案已经显而易见了。现在,在这里的,只是一名楚楚可怜、自我封闭的少女。现在的她,就像当年的自己一样。而现在的自己,又能够说些什么,来表达自己的关心呢?

「我喜欢你」只是压在对方身上的一副重担。

「希望你能一直幸福」只是一句廉价的同情。

「小祥!一起组乐队吧!」

这是高松灯此时能说出的最恰当的话语。

听到这句话后,作为观众的我不禁潸然泪下。


看过 MyGO 的我们,知道「组乐队」对于灯来说有着特别的含义。要组乐队,就是一辈子的事。进乐队,不只是为了演奏,更是希望和关系紧密的朋友在一起,一直,一直,直到走完一辈子。

灯一直在尝试理解他人的心灵。哪怕没有交流,仅仅是通过乐曲,通过行为,通过一架钢琴,灯就体会到了祥子的那份孤独。所以,她下意识地说出要一起组乐队的话。组乐队,不仅是「希望你能幸福」的期望,还是「我会让你一辈子幸福」的承诺,更是「让我们携手共同幸福」的祈求。灯想表达的一切的一切,都浓缩在这句话里了。

如果祥子和我一样,能站在上帝视角理解灯的心意,也会情不自禁地落泪吧?

断绝一切的原因,是不相信会被他人理解。哪怕说出去了,换来的浮于表面的关心,只会让不被理解的痛苦又增一分。所以,对于自己难过的情绪,祥子永远都不会说出去。可是,哪怕只是有一刻,祥子会不会幻想着,有人能跨越一切,真正来到她的身边,为她抚平伤痕呢?

但幻想只是幻想,祥子不会在生活中相信这种事的存在。没有看过对方心路历程的她,或许无法理解灯的心意。这就是另一种悲哀了。


总之,Ave Mujica 第五集对氛围的渲染十分恰当,将细腻的情感一点一点展现出来。我一直把心安在角色们的身上,希望能体会她们每刻的感受。在片尾灯说出要组一起乐队的那一刻,在我的理性理解一切之前,我自然而然地明白到了灯的心意,感受到了祥子的寂寞。我心中暂存的两个灵魂连结到了一起,强烈的情感洪流涌了上来。这一幕着实让我感动。

我知道,和我有同样感受的观众太少了。我也害怕自己的想法无法被人理解。但我在网上,也看到了少数和我一样愿意仔细分析角色心理的人。所以,在新的一集播出之前,我也想分享我此时的感受,分享给同样用心感受动画的观众。