0%

最近,备受瞩目的何恺明团队公布了一篇论文——分形生成模型(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 第五集对氛围的渲染十分恰当,将细腻的情感一点一点展现出来。我一直把心安在角色们的身上,希望能体会她们每刻的感受。在片尾灯说出要组一起乐队的那一刻,在我的理性理解一切之前,我自然而然地明白到了灯的心意,感受到了祥子的寂寞。我心中暂存的两个灵魂连结到了一起,强烈的情感洪流涌了上来。这一幕着实让我感动。

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

Transformer 中平方复杂度的注意力运算一直是其性能瓶颈,该问题在序列长度极大的视觉生成任务中尤为明显。为了缓解此问题,并生成分辨率高至 4K (4096x4096) 的图像,英伟达近期推出了文生图模型 Sana。Sana 不仅使用了线性注意力的 Transformer,还通过增加 VAE 压缩比等方式,极大提升了超高分辨率图像生成的性能。

Sana 论文示意图如下,生成的图像看起来还不错。值得注意的是,在 1K 图像生成上,Sana-0.6B 的生成速度是 FLUX-Dev 的 25 倍。由于采用了线性注意力机制,这一速度优势会随着图像尺寸增加而越发明显。

在这篇博文里,我们来着重学习 Sana 相较标准 DiT 文生图模型 (SD3, FLUX.1) 做了哪些提升性能的改进。

本文中,计算机术语「性能」表示运行速度。

线性注意力真的是「免费午餐」吗?

在看完论文摘要后,我的第一反应不是去细读论文,而是立刻去网上搜索社区用户对于 Sana 的评价。我一直坚持一个观点:「天下没有免费的午餐」。线性注意力比标准注意力快了那么多,那么它的质量一定会有所下降,不然所有人都会立刻把标准注意力换成线性注意力。

有网友在 Reddit 上分享了 Sana 的生成结果并对此开展了讨论:https://www.reddit.com/r/StableDiffusion/comments/1hzxeb7/it_is_now_possible_to_generate_16_megapixel/ 。有关图像质量的讨论有:

  • 楼主:「Sana 的 4K 模型生成出的图片没有 2K 的真实」。
  • 社区用户:「生成结果看起来更靠近抽象艺术,但这些效果已经能够通过 SD 1.5 + 超分辨率达到了。能否用 Sana 生成照片级图片?」楼主:「它不太擅长生成照片级图片。」
  • 社区用户:「4K 图片质量太差了,没有比 1K 图片更多的细节。许多上采样算法的结果会比这个更好。论文应该宣传其生成速度而不是丢人的 4K 图像质量。」
  • 楼主:「手画得不是很好。」

另一个帖子 (https://www.reddit.com/r/StableDiffusion/comments/1h5xujr/sana_nvidia_image_generation_model_is_finally_out/ )里的评论有:

  • 「考虑模型大小和速度的话,它的效果非常惊人。第一感看起来艺术感比 FLUX 好,但文本生成能力不太行。」
  • 「有 SD 1.5 的质量,但很快。再训练它可以达到 SDXL 的质量。」同楼里另一个用户则认为,Sana 质量在 SDXL 基础版和 FLUX 之间。

简单看下来,根据社区用户的反馈,Sana 的质量没有显著好于 SDXL。它的 4K 图像生成效果跟先生成较低分辨率再使用超分辨率算法的结果差不多。我们应该着重关注 Sana 的加速方式而不是其生成质量。

以往工作

潜扩散模型(Latent Diffusion Models)

扩散模型能够在多次迭代中生成高质量图像。而有研究发现,扩散模型在生成时早早就生成完了图像结构,后续时间都浪费在完善图像细节上。为此,潜扩散模型 (Latent Diffusion Models, LDM)使用了一个两阶段方法来提升扩散模型的性能:

  • 先用一个自编码器 VAE 把图像压缩成尺寸更小、信息更丰富的潜图像 (latent images)。
  • 用标准扩散模型生成潜图像。

目前主流的扩散模型几乎都属于 LDM。其中,最经典的 LDM 是 LDM 论文作者实现的 Stable Diffusion (SD)。根据 LDM 论文的实验结果,令 VAE 的压缩比 f 为 4 或 8 比较好。SD 采用了 f=8 的 VAE。后续多数 LDM 都使用了这样的压缩比。

Diffusion Transformers

早期扩散模型是用 U-Net 实现的,而后来大家逐渐把 U-Net 替换成了 DiT (Diffusion Transformers)。基于 DiT 的著名文生图模型有 SD3, FLUX。这些模型的核心仍是标准 Transformer 中的多头注意力运算。

线性注意力

设矩阵 $Q \in \mathbb{R}^{n \times d}, K \in \mathbb{R}^{n \times d}, V \in \mathbb{R}^{n \times d}$,其中 $n$ 为序列长度,$d$ 为特征长度,则注意力操作可以简写成:

对于矩阵 $A \in \mathbb{R}^{a \times b}, B \in \mathbb{R}^{b \times c}$,不做加速的前提下,朴素的矩阵乘法 $A B$ 的复杂度是 $O(a \cdot b \cdot c)$。

根据这个结论,注意力操作的复杂度为 $O(n^2d)$。这是因为 $Q \in \mathbb{R}^{n \times d}, K^T \in \mathbb{R}^{d \times n}$,第一步 $QK^T$ 的复杂度是 $O(n^2d)$。类似地,后一步矩阵乘法也是同样的复杂度。总复杂度不变,仍是 $O(n^2d)$。

由于模型特征长度 $d$ 是常数,我们只考虑序列长度 $n$ 的变化,所以可以认为标准注意力操作的复杂度是 $O(n^2)$。

但假如注意力运算中没有 softmax 操作的话,注意力运算就是两次矩阵乘法。

由于矩阵乘法满足结合律,通过改变矩阵乘法的顺序,我们能够神奇地改变注意力运算的计算复杂度。

由于 $K^T \in \mathbb{R}^{d \times n}, V \in \mathbb{R}^{n \times d}$,$K^TV$ 操作的复杂度是 $O(nd^2)$。由于 $Q \in \mathbb{R}^{n \times d}, K^TV \in \mathbb{R}^{d \times d}$,第二步矩阵乘法的复杂度还是 $O(nd^2)$。因此,总复杂度变为 $O(nd^2)$。不考虑 $d$ 的增长的话,这种注意力运算就是线性复杂度的。

我们再回头看去掉 softmax 对注意力运算有什么影响。softmax 函数同时做了两件事:1)保证 QK 的输出非负,以表示相似度;2)保证对于一个 query,它对所有 key 的相似度权重之和为 1,使得输出向量的范数(向量的「大小」)几乎不变。所以,线性注意力都会设置一个非负相似度函数 $sim(q, k)$,并用下面的注意力公式保证权重归一化。

根据 NLP 社区的反馈,线性注意力的效果比不过标准注意力。

相比之下,CV 社区对线性注意力的探索没有那么多。Sana 主要参考的早期工作为 Efficientvit: Lightweight multi-scale attention for high-resolution dense prediction。

Sana 模型架构改进

在模型架构上,Sana 主要做了三大改进:增加 VAE 压缩比、使用线性注意力、使用轻量级文本编码器。

深度压缩 VAE

在基于 LDM 的 DiT 中,和图块数(参与 Transformer 计算的元素个数,类似于 NLP 的 token)相关的超参数有:

  • VAE 压缩比例 f
  • DiT 图块化 (patchify) 比例 p

此外,VAE 输出的潜图像通道数 c 决定了重建质量与学习难度:c 越大,自编码器的重建效果越好,但扩散模型的学习难度也变大。

经过 VAE 后,图像会从 $H \times W \times 3$ 压缩成 $\frac{H}{f} \times \frac{W}{f} \times C$。又经过图块化操作后,图像大小会变成 $\frac{H}{fp} \times \frac{W}{fp} \times d$,其中 $d$ 是 Transformer 的特征长度。决定 Transformer 运算量的是图像尺寸 $\frac{H}{fp} \times \frac{W}{fp}$。标准 Transformer 一般至多处理 $64 \times 64$ 大小的图像。

此前的文生图 DiT 一般采用 f8 c4 p2f8 c16 p2 的配置。而 Sana 直接把 f 设置成了 32,实现了一个 f32 c32 的 VAE。

其实,LDM 论文尝试用过一个 f32 c64 的 VAE,但生成效果并不好。为什么这次 Sana 的 VAE 就好了不少呢?论文对此没有做深入分析,只是简单列举了一些 Sana 的 VAE 做出的改进:

  • 从模型设计与训练策略上:此前 f32 VAE 效果不好的一大原因是模型没有充分收敛。为此,Sana VAE 将模型中的标准自注意力换成了线性注意力。另外,为了提升在高分辨率图像上的生成效果,Sana VAE 先在低分辨率上训练,之后在 1K 图像上微调。
  • 从通道数上:作者比较了 f=32c=16, 32, 64 的实验结果,发现将 c=32 改成 c=64 会显著提升扩散模型收敛速度。

尽管 VAE 是卷积网络,里面还是包含了自注意力运算。

除了调整 f, c 外,作者还认为 p=1,即不使用图块化操作,是最好的。论文展示了总压缩比 fp 不变的前提下, p 提升、 f下降后扩散模型的学习进度。结果发现,不用图块化而让 VAE 全权负责压缩是最好的。

线性 Transformer 块

为了降低注意力操作的复杂度以提升性能,Sana 使用了线性注意力操作。如前所述,线性注意力会去掉 softmax 并通过矩阵乘法的结合律来降低计算复杂度,但需要通过额外设计一个相似度指标。

Sana 对线性注意力的定义如下:

其中,$O_i$ 是某一条 query $Q_i$ 的输出。这其实是让相似度函数为:

ReLU 函数用于让相似度非负。

在上面的线性注意力公式中,不管是分子还是分母,都可以通过结合律来优化计算复杂度。此处细节可参见原论文。

根据之前的经验,线性注意力会降低注意力运算的效果。为了弥补这一点,Sana 参考 EfficientViT,把前馈网络 (FFN) 从 MLP (即 1x1 卷积网络)换成了带 3x3 逐深度卷积的网络。这个小卷积网络不仅提升了整个 Transformer 块的拟合能力,还省去了位置编码——由于卷积网络天然能够建模相对位置关系并打破 Transformer 的对称性,不需要再加入位置编码了。

轻量级文本编码器

之前的 SD3 和 FLUX 都用 T5 作为文本编码器,但 Sana 为了提升模型性能,使用了速度为 T5-XXL 6 倍的 Gemma-2-2B。

定量实验

最后,我们简单看一下论文的主要实验结果。论文用到的实验数据集为 MJHQ-30K,包含三万张 Midjourney 生成的图像。

从定量指标上看,Sana 确实好过不少此前的文生图模型。但是,这些指标无法如实反映人类的审美偏好。如前文所述,社区用户认为 Sana 并没有明显好于 SDXL,但指标无法反映这一点。这些指标参考价值不大的另一个证据是 FLUX-dev 和 FLUX-schnell 的比较结果——作为一个被进一步蒸馏出来的模型,schnell 显然是比 dev 的生成质量更差的,但它的 FID, GenEval, DPG 竟然比 dev 还好。因此,在比较文生图模型质量时,我个人建议不要参考文生图的定量指标,而是去参考社区用户的反馈。

另外,虽然 Sana-1.6B 比 FLUX-dev 快了很多,但它比 FLUX-schnell 只快了一倍。或许 Sana 也可以通过蒸馏获得进一步的推理加速。

总结

Sana 是一个以降低运算开销为主要目标的高分辨率文生图模型。它主要通过增加 VAE 压缩比例、使用线性注意力来提升 DiT 的效率。为了弥补线性注意力的能力损失,Sana 将 FFN 改成了 3x3 卷积网络,在提升模型能力的同时免去了位置编码。除了这两大主要设计外,Sana 还通过使用轻量级文本编码器等诸多细节改进提升了模型的训练与推理效率。整体上看,这个工作主要在工程上作出了贡献,线性注意力的设计几乎照搬了之前的工作,没有使用比较新颖的模块设计。

从生成效果上看,尽管 Sana 论文给出的定量指标还不错,但这些指标是否能如实反映文生图质量还存疑。据社区用户反映,Sana 的质量没有明显好于 SDXL。另外,虽然论文一开头就宣称 Sana 能够生成 4096x4096 的图片,但这种图片的细节很差,和 1024x1024 的差不多。这是因为不管是 VAE 还是 DiT 都只在 1024x1024 上训练过。在加大生成尺寸后,图像的清晰程度没有变,只是看起来像素变多了。这篇论文真正应该强调的是生成 4K 图像的速度会更快,而不应该去强调 4K 图像的质量有多高。

从生成速度上来看,Sana 确实比最强开源文生图模型 Flux-Dev 要快很多。但尴尬的是,在 1024x1024 图像生成上,Sana 的速度仅仅是精心蒸馏的 Flux-schnell 的两倍。当然这个对比可能不是很公平,因为 Sana 还没有经过蒸馏。但就目前来看社区用户在生成 1024x1024 的图像时难以感受到 Sana 性能优势。

这篇文章很好地指明了 DiT 的一个发展方向:我们能不能将线性注意力更好地引入 DiT 呢?按我目前的理解,线性注意力就是通过牺牲自注意力全局依赖关系来提升模型计算速度。它的本质和 MAR (Autoregressive Image Generation without Vector Quantization)、VAR (Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale Prediction) 很像,都是通过减少计算像素间的依赖关系来提升速度。这个假设在视觉任务中是很合理的:在确定了图像的主要结构后,理解细节只需要局部像素信息。然而,这些加速方法都不可避免地降低模型的能力。在完全不用和完全使用全局信息之间,我们或许要找到一个平衡点,来使 DiT 具有最佳性能和效果。

最近一篇论文因其吸引眼球的标题而刷屏科技自媒体:”The GAN is dead; long live the GAN!
A Modern Baseline GAN (GAN 已死?GAN 万岁!一个现代 GAN 基模)”。我不喜欢这种浮夸的标题,因为真正有价值的论文不必靠标题吸引人。带着怨气通读完论文后,我发现这篇论文果然没有做出特别大的创新。

这篇论文提出了一种叫做 R3GAN (读作 “Re-GAN”)的 GAN 基准模型。R3GAN 综合使用了 RpGAN 损失函数和特殊的梯度惩罚 (Gradient Penalty, GP) 损失函数,并基于前沿卷积网络 ConvNeXt 重新设计了一套 GAN 网络。实验表明 R3GAN 在 FFHQ 和低分辨率 ImageNet 图像生成上有着比肩扩散模型的 FID 分数。该工作主要是在工程实验上做了贡献,没有提出太多科研创新。在这篇博文里,我会简单介绍 R3GAN 的主要实现细节,并为各项细节提供参考文献而不做深入讲解,感兴趣的读者可以查阅文末总结的参考文献。

GAN 回顾

在这一小节里,我们会回顾读懂 R3GAN 必备的和生成对抗网络 (GAN) 相关的知识。

GAN 基础知识

和其他多数生成模型一样,GAN 的训练目标是建模一个好采样的分布(高斯分布)到一个不好训练的分布(训练数据集)的映射方式。具体来说,GAN 会用一个生成器 (Generator) 把来自高斯分布的噪声 $z$ 设法变成图像 $x$。其他生成模型大多有自己的一套理论基础,并根据某理论来设置生成器的学习目标。而 GAN 用另一个神经网络——判别器 (Discriminator) 来学习生成器的训练目标。

两个模型的学习是通过一种博弈游戏实现的:判别器试图分辨图片是否是「假」的,或者说是否是生成出来的,而生成器通过提升生成图像质量来让判别器无法分辨图片真假。二者共用一套优化目标,但一方希望最小化目标而另一方希望最大化目标。

在上面的损失函数中,$f$ 有很多种选取方式。R3GAN 选用了 softplus 函数,如上图所示。

两大经典结构 DCGAN 和 StyleGAN

GAN 的开山之作是用全连接网络实现的。在 GAN 的后续发展过程中,有两个经典的网络结构:2016 年 的 DCGAN 和 2019 年的 StyleGAN。

DCGAN 是一个生成器基于卷积神经网络 (CNN) 的 GAN。它的特点是对低通道特征逐渐上采样并逐渐减少通道数,直至生成目标大小的三通道图像。

StylGAN 是一个训练较稳定且适合做图像编辑的 GAN。和传统 GAN 生成器相比,StyleGAN 从一条「旁路」输入被映射网络 (Mapping Network) 预处理过的噪声 $z$,此处信息注入的方式是风格转换 (Style Transfer) 中的 AdaIN 操作。由于输入噪声的方式变了,原来的低分辨率特征图输入被换成了一个常量。

两大难题:难收敛和模式崩溃

相比其他生成模型,GAN 常被诟病「难训练」。这种难训练体现在难收敛、模式崩溃 (Mode Collapse)。难收敛即意味着模型对数据集拟合效果不佳,我们可以用 FID 来评估模型输出与训练集的相似程度。模式崩溃指的是对于一个多类别数据集,模型只能生成其中少数类别,示意图如下所示(图片来源)。为了检测是否出现模式崩溃,我们既可以让网络随机生成大量图片并用另一个分类网络统计其中出现的类别数,也可以用生成召回率 (recall) 来大致评估模型的采样丰富度。

R3GAN 实现方法

R3GAN 在引言里把 StyleGAN 中的各种提升 GAN 稳定性的小技巧批判了一通,并主张应该使用尽可能简洁的 GAN 生成器。虽然论文是这样写的,但实际上 R3GAN 是在更早的 DCGAN 的基础上,更新了损失函数,并用上了最新的 CNN 结构,和 StyleGAN 结构几乎无关。我们来从这两个方面来学习 R3GAN:损失函数和模型结构。

损失函数

在描述博弈游戏的 GAN 损失上,R3GAN 把标准 GAN 损失换成了 RpGAN (relativistic pairing GAN) 论文中的 GAN 损失。相比之下,RpGAN 损失用一对真假样本的判别器输出之差送入激活函数 $f$,而不是分别把真假样本的判别器输出送入 $f$。

根据之前的研究结果,作者从直觉和理论上简单解释了 RpGAN 的好处:

  • 以前的 GAN 损失只要求判别器区分真假样本,而不要求真假样本之间的距离要尽可能大。通过把一对真假样本的差输入损失函数,RpGAN 损失可以让真假样本之间的差距尽可能大。
  • 根据之前论文的理论分析,在一些简单的配置下,标准 GAN loss 有数量指数增长的较差局部极小值,而 RpGAN loss 的每个局部极小值都是全局最小值。

R3GAN 还重新对最佳的梯度惩罚(Gradient Penalty, GP)损失函数做了消融实验。$n$-GP 表示让模型对输入的梯度尽可能靠近实数 $n$,从而使得训练更加稳定。常用的 GP 有 0-GP 和 1-GP:

  • 0-GP:最优情况下,模型对任意输入都给出完全一样的结果。
  • 1-GP:最优情况下,模型的输出对输入平滑变动:输入张量的范数变 1,输出张量的范数也变 1。

作者认为 0-GP 对 GAN 判别器是较好的。因为当生成器的输出完全和训练集一样时,判别器是无法区分任何输入的,对任何输入都会给出一样的输出。

对判别器的 GP 有 $R_1$ 和 $R_2$ 两种形式,分别表示对真/假数据采取 GP。作者发现同时用 $R_1$ 和 $R_2$ 更好。

总结一下,R3GAN 使用的损失函数为 RpGAN + $R_1$ + $R_2$。作者用简单的实验证明这是最优的。如下图所示,在一个有 1000 种类别的简单数据集上,最佳损失配置能够生成所有类别的数据,且有更小的分布距离 $D_{KL}$ (和 FID 指标类似,越小越好)。不用 RpGAN 损失会同时降低输出多样性和收敛度,不用 $R_2$ 会使训练完全无法收敛。

现代化的卷积网络

找出了一个简洁而有效的损失函数后,R3GAN 论文接着探究了更优的卷积网络结构。文中提及了五套配置:

  • A:原版 StyleGAN2
  • B:把 StyleGAN2 里的绝大多数设计删掉,让模型和 DCGAN 几乎相同。
  • C:换用上一节里发现的新损失函数
  • D:把类似 VGG 的神经网络加上 ResNet 中的残差连接
  • E:用 ConvNeXt 里的模块更新 ResNet

我不明白作者为什么要强行从 StyleGAN2 开始做实验,然后把 StyleGAN2 中的设计批评一顿,删掉全部设计,再换成一个更早期的 DCGAN。直接用 DCGAN 不是更加简洁吗?我猜测是因为作者用了 StyleGAN2 的代码做开发,花很多精力把 StyleGAN2 删成了 DCGAN。既然代码都改了,不写进论文就太浪费了。

我们跳过配置 A,直接看配置 B 和早期的 DCGAN 有什么区别。经作者总结,配置 B 中比较重要的几项区别有:

  • a) 用 $R_1$ 损失。
  • b) 用较小的学习率且关闭 Adam 优化器中的动量
  • c) 所有网络中均不使用 Normalization 层
  • d) 用 bilinear 上采样代替反卷积

其中,不改 a), b), c) 会使训练失败。d) 是当今神经网络上采样的标准配置,可以防止出现棋盘格 artifact。

配置 C 中的新损失函数我们已经在上一节中讨论过了。

包括 StyleGAN 在内,此前 GAN 的神经网络多采用了类 VGG 结构,没有残差块。而配置 D 将标准 ResNet 中的 1-3-1 残差块引入了网络。

配置 E 则是进一步更新了卷积层的设计。该配置首先引入了 group convolution 操作(将通道分组,同组通道相互连接。group=1 即 depthwise convolution)。由于该操作更加高效,网络能够在总运行时间不变的前提下加入更多参数。此外,配置 E 还用到了 ConvNeXt 中的反瓶颈(inverted bottleneck)块,该模块的设计灵感来自于 Transformer 中的全连接层。

我们再看一次各配置的简单消融实验结果。看起来新损失函数并没有多大的提升,最后比较有效的是网络架构的改进。最好的配置 E 模型能够略优于 StyleGAN2。

定量实验结果

最后,我们来看论文中的定量结果。如前所述,我们主要关心 GAN 的两个指标:多样性与收敛度/图像质量。前者能够通过数类别或者召回率反映,后者能够通过与训练集的 FID(以及本文使用的 $D_{KL})$反映。

多样性

在小型多类别数据集上,R3GAN 能够生成出所有类别,且有最好的训练集相似度。而 StyleGAN2 无法生成少数类别。

另一个能够反映图像多样性的指标是召回率,它大致表示了训练集有多少内容能够在生成集里找到。论文没有提供表格,只简单说了一下 CIFAR-10 上 StyleGAN-XL 是 0.47,R3GAN 0.57。但总体来看 R3GAN 的召回率总是会低于扩散模型。

收敛度

本工作宣传时的一大亮点是它在部分数据集的 FID 分数超过了扩散模型。我们看一下本工作在单一、多样数据集上的 FID 结果。

先看经典的 FFHQ 人脸数据集。在这种多样性较低的数据集上,GAN 的表现一直很不错。R3GAN 的 FID 好于 StyleGAN2 和多数扩散模型,且只需要一次推理 (NFE=1)。但它的 FID 并没有优于此前最好的 GAN 模型。当然,此前的 GAN 用了一种提升 FID 而不提升图像质量的技巧,R3GAN 没有用。

再看类别比较丰富的 CIFAR-10 和 ImageNet 数据集。R3GAN 的表现也比所有扩散模型和大部分 GAN 强。但 R3GAN 没有在更大分辨率的 ImageNet 上测试。现在前沿生成模型一般都会测试 ImageNet-256,而 R3GAN 并没有提供相关实验结果。

总结与评论

R3GAN 是一种现代版的 DCGAN。它从损失函数和模型结构两个方面做了改进。损失函数方面,DCGAN 用了 RpGAN + $R_1$ + $R_2$ 损失函数;模型结构方面,R3GAN 用 ConvNeXt 中的最新卷积结构代替了原来的 VGG 结构。实验表明 R3GAN 在 FFHQ-256 和 ImageNet-64 的 FID 分数上超过了全部扩散模型和多数 GAN,略差于此前最强的 GAN。在生成多样性上,R3GAN 依然没有扩散模型好。

从科研贡献上来看,这篇文章并没有提出新理论或新想法,完全复用了之前工作提出的方法。这篇文章主要提供了一些工程上的启发,有助于我们去开发更好的基于 CNN 的 GAN。从结果来看,R3GAN 并没有在目前主流指标 ImageNet-256 上测试,没有迹象表明它能好过扩散模型。我们可以从其他数据集上的实验结果推断,R3GAN 的最佳表现和之前的 GAN 差不多,没有对 GAN 作出本质的改进。综上,我认为这篇文章是质量满足顶会要求的平庸之作,被 NIPS 2024 选为 Poster 合情合理。

参考文献

DCGAN: Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks

StyleGAN: A Style-Based Generator Architecture for Generative Adversarial Networks

StyleGAN2: Analyzing and Improving the Image Quality of StyleGAN

GP (WGAN-GP): Improved Training of Wasserstein GANs

RpGAN: The relativistic discriminator: a key element missing from standard GAN

RpGAN Landscape Explanation: Towards a Better Global Loss Landscape of GANs

ConvNeXt: A convnet for the 2020s

ImageNet FID Trick: The role of imagenet classes in fréchet inception distance

最近,我在网上看到了一个专门介绍深度学习源代码的网站(https://nn.labml.ai/index.html ),各类流行网络架构一应俱全。这个网站最吸引我的,是它的双列式结构。如下所示,每个页面右边显示代码,左边显示每段代码对应的注释。

一直以来,我在博客中介绍代码时,都是先写描述文字,再贴一段代码。这种方式对作者和读者来说都十分低效。受到上面那个网站的启发,我决定以后也采用这种方式介绍源代码。很可惜,上面那个网站是由 labml.ai 这个组织维护的,似乎并没有提供开源的、可定制的注释网站搭建方式。为此,我找到了一个替代品:Pycco。它可以方便地为 Python 代码生成双列带注释的静态页面。

Pycco 安装与使用

Pycco 是页面生成工具 Docco 的 Python 实现版。它们都是「快而脏」的文档生成器:源代码只有几百行,没有多余封装,直观而暴力地生成 HTML 页面的所有内容。它们为初学者只提供了一个文档页面,这个文档页面讲的是它们的源代码,且文档页面就是由它们本身创建出来的。Pycco 的官方文档页面如下所示。一开始介绍完 Pycco 的背景信息和安装方式后,文档就会直接开始介绍源代码。

根据文档的指示,我们可以通过下面的命令在 pip 里安装 Pycco:

1
pip install pycco

在使用 Pycco 时,我们完全不用去理解其源代码的意思,只需要准备一个带注释的 Python 源文件就行。Pycco 提供了一键式命令,帮我们把源文件里的注释和代码分离,并生成左侧为注释,右侧为代码的静态文档页面。这里的注释既包括了 # 开头的单行注释,也包括了 """ """" 包裹的多行注释。注意,三个单引号构成的多行注释 ''' ''' 不会被该工具识别。

我们来看一个示例。假设我们有下面一个名为 hello.py 的 Python 源文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
"""
Hello
World
"""
import torch
import pycco

# Hello
print("hello world")

"""
End of file
"""

我们用下面的命令为其生成文档页面。

1
pycco hello.py

页面会生成在目录下的 docs 子目录里,子目录包含一个 hello.html 文件和一个 pycco.css 文件。我们可以用浏览器打开 .html 网页,看到下图所示内容。

注释默认使用 Markdown 语法。如果平时就习惯用 Markdown 写博客的话可以无缝切换。但是,默认情况下网页无法渲染公式。

页面跳转

除了普通的 Markdown 语法外,Pycco 还支持一个特殊的功能:文档跳转。我们可以把文件名写在 [[ ]] 内,实现源文件内部或源文件间的跳转。特别地,我们还可以在页面某处打上标签,并跳转到某页面的标签处。以下是一个示例。为了给「注释」加上注释,我别出心裁地把注释写进了代码部分。

让页面渲染 LaTeX 公式

刚才我们发现,目前的 Pycco 页面并不支持公式渲染。而在解释深度学习代码时,很多时候不得不用到公式。因此,我决定给 Pycco 加上渲染公式的功能。

Pycco 这种直观暴力的实现方法让网页开发者能够快速地修改页面生成逻辑。然而,我已经把 HTML 的知识快忘光了,配不上「网页开发者」这个名号。因此,我让 ChatGPT o1 来帮我开发这一功能。

经指导,我认识了 MathJax 这个在网页上渲染公式的工具。只需要在 HTML 的 head 里导入一些包,网页就可以自动识别单行公式 和多行公式 $$$ $$$。我不记得 head 是什么了,但大概能猜到这个是一个相当于声明全局变量的语句块。

我在 pycco_resources\__init__.py 文件里找到了设置 head 的地方。这个文件提供了生成网页的模板,包括了写死的 CSS 文件和部分 HTML 代码。打开这个文件的最快方式是在某处写 import pycco_resources,之后用 IDE 的代码跳转找到这个包在本地的位置。

我们在该文件下图所示的位置插入和 MathJax 相关的代码。

1
2
3
4
5
6
7
8
<script>
MathJax = {
tex: {
inlineMath: [ ["$","$"] ]
}
};
</script>
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>

修改模板后,重新生成网页,可以发现现在公式能够正确渲染了。

高亮新增/删除代码

在以后讲解代码的时候,我想高亮新增的或者删去的代码,就像 GitHub 里显示代码的更改一样。由于 Pycco 非常容易做二次开发,我又去请教 ChatGPT o1 该如何实现这样的功能。

经指导,我了解到代码高亮可以通过设置背景颜色 style 来实现。为此,我需要做两件事:

  1. 新增有关背景颜色的 CSS style
  2. 想办法指定要高亮的代码块

第一件事很简单,只需要打开模板文件 pycco_resources\__init__.py,添加背景颜色 style 即可。我添加了两种背景颜色,分别表示删去的和新增的代码块。我是在 VSCode 里找到想要的颜色值的。随便打开一个 CSS 文件,输入一个大概的颜色值,VSCode 就会弹出一个选择颜色的小窗口。

1
2
3
4
5
6
.highlighted-line-1 {
background-color: #fa53208c;
}
.highlighted-line-2 {
background-color: #68fc5d;
}

第二件事就比较难了。我需要先看懂目前高亮源代码的逻辑,再在其基础之上添加背景高亮的功能。Pycco 的主函数在文件 pycco/main.py 里,我们可以用导入 Python 包的方式快速找到这份源文件。原来的高亮关键字的逻辑如下,我在其中加入了一些代码用于输出中间结果。

函数的主要输入是列表 sections,函数的输出存储在列表项 section"docs_html", "code_html" 字段。

sections 内容如下,可见其中是过了解析器的注释块和代码块。每一段注释都会对应一段代码。

1
[{'docs_text': '=== BeGin ===\r\n\n', 'code_text': 'import torch\r\nimport pycco\r\n\r'}, {'docs_text': '# Hello\r\n## World\r\nThis is a **Python** [code](https://www.python.org/).\r\nTry formula $\\epsilon$ .\r\n$$\r\n3 = 1 + 2\r\n$$\r\n\n\n', 'code_text': 'print("hello world")\r\n\r'}, {'docs_text': 'End of file\r\n\n', 'code_text': '\n'}]

函数的输出是完整 HTML 文件的一部分。

1
2
3
4
5
6
7
8
9
10
11
12
13
<h3><span id="begin" href="begin"> BeGin </span></h3>
<div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">torch</span>
<span class="kn">import</span> <span class="nn">pycco</span></pre></div>
<h1>Hello</h1>
<h2>World</h2>
<p>This is a <strong>Python</strong> <a href="https://www.python.org/">code</a>.
Try formula $\epsilon$ .
$$
3 = 1 + 2
$$</p>
<div class="highlight"><pre><span class="nb">print</span><span class="p">(</span><span class="s2">&quot;hello world&quot;</span><span class="p">)</span></pre></div>
<p>End of file</p>
<div class="highlight"><pre></pre></div>

那么,我的目标就是修改这个文件。我需要先根据输入的原始代码块,判断这段代码是否要高亮,再修改 HTML 代码块的内容。

首先,从用户的角度考虑,应该怎么指定要背景高亮的代码呢?既然现在代码被拆成了一块一块的,且每块代码对应一段注释,我决定用一些特殊注释来高亮一整块代码,就像前面的设置标签和跳转标签的特殊注释一样。我加入了以下判断:如果注释前几个字符是 '===ADD===''===DEL===',就用对应的颜色高亮这段代码。

判断了是否要高亮后,我还需要做对应的修改。我不仅要在 HTML 代码块里高亮代码,还需要把注释块里的特殊命令删掉。通过观察相关代码,我忽然回忆起了 HTML 的部分实现原理:背景高亮就是把一段 HTML 字符串封进一个带有背景高亮样式的标签 <div></div> 里。那剩下的删除注释也很简单,只需要对字符串做一点简单操作就行了。代码修改过程及使用示例如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
# Add following code

delete_background_start = '<div class="highlighted-line-1">'
add_background_start = '<div class="highlighted-line-2">'
background_end = '</div>'

if section["docs_text"].startswith('===ADD==='):
section["docs_text"] = section["docs_text"][9:]
section["code_html"] = add_background_start + section["code_html"] + background_end
elif section["docs_text"].startswith('===DEL==='):
section["docs_text"] = section["docs_text"][9:]
section["code_html"] = delete_background_start + section["code_html"] + background_end

修正多行注释缩进

在写这篇博文的时候,我又发现 Pycco 的一个 bug:在多行注释带缩进时,HTML 页面上的注释也会缩进,导致页面布局完全乱套。

我找到了 pycco/main.py 里处理多行注释的代码。我把旧代码全部删掉,换了一种暴力的字符串处理方式:删除多行注释左侧所有空格及制表符。

1
docs_text += line.lstrip('\t ') + '\n'

改完之后 bug 就修好了。

总结

在这篇文章中,我介绍了 Pycco 这个为 Python 代码生成双列注释-代码静态页面的 Python 工具,并分享了我对其的三个修改:支持 MathJax 公式、支持背景高亮、修复多行注释缩进 bug。相比介绍开源项目的 readthedocs 等文档构建工具,Pycco 能够为每行 Python 代码写注释,尤其适合详细讲解深度学习代码。对于熟练的网页开发者,Pycco 的源代码很短,改起来很方便;但另一方面,Pycco 似乎比较小众,多年都没人维护,可能有各种 bug。主要推荐想在个人博客里讲解代码的朋友使用这个工具。我以后都会用它来讲解代码。

ChatGPT 小插曲

ChatGPT 在指导我添加 MathJax 时,先叫我下载 python-markdown-math 这个 pip 包,让 Python 脚本里的 Markdown 解析器能够解析公式。但我在实践中发现不解析 $$$$ 符号,在正确导入 MathJax 包后,网页依然能够正确渲染。

ChatGPT 一开始提供的 MathJax 导入代码是 MathJax V3 的。经过 python-markdown-math 解析后,双行注释被转换成了 <script type="math/tex; mode=display"></script> 包裹的内容。这些公式没法成功渲染。我把添加双行公式的详细过程提供给 ChatGPT 后,它分析出这种 <script> 的写法是 MathJax V2 的,让我把 head 里的包改成 MathJax V2。修改过后,双行公式果然渲染成功了。然而,如上一段所述,我发现哪怕不用 python-markdown-math 也行。于是我又用回了 MathJax V3。可见 ChatGPT 有功有过,给我制造了一些麻烦,也算是能够帮我解决。

在求助 ChatGPT 添加背景高亮功能时,它非常出色地分析了问题:先理解 Pycco 生成 HTML 的过程,再决定用户如何指定要高亮的内容,最后根据不同的方案做实现。但它给的三个信息输入方案都不尽如人意:(1) 在命令行里指定要高亮的行;(2) 在每行要高亮的代码前都加特殊注释;(3) 用另一个配置文件来指定要高亮的行。这些方法的用户体验都不好,且难于实现。当然,由于我没有把所有源代码给它,它或许没有发挥完整的实力。最后我还是靠自己理解了 Pycco 的页面生成逻辑,选了一种好实现且好用的方案。

我从来没有用 ChatGPT 做过特别复杂的编程任务,这次稍微体会了一下。感觉它的能力有时候会出乎意料地强(比如发现 HTML 的风格是 MathJax V2 的),但不见得次次都靠谱。它的能力主要还是基于大量数据的「搜索」,加上一点浅显的思考。只是因为看过的数据过多,所以很多时候能从历史经验中直接给出很好的答案。当然,作为语言模型,它对于语言的理解能力极强,哪怕描述不完全也能准确理解用户的意图。做为使用者,我们要在用之前就想好能从 ChatGPT 那里获取到哪些帮助,并提供充足的信息,而不能全盘接受它的输出,就和我们日常和别人交流一样。

年底难得有闲暇,我打算首次写一下年终回顾。写这样的文章总是很害羞,我现在不好意思去看我以前写的「随笔」类文章了。但是,今天,我就是有一股冲劲,想要实现心中那小小的想法,不想被生活的洪荒冲走我那鲜活的热情。不去思考为谁而写,不去思考是否有人会看,不去纠结于遣词造句。只求能够纯粹地表达。

人的思考有时非常奇怪。有时会对未来产生过分的期待,期待过后又是更深的失落。小的时候,盼望长大。可自从大学毕业以后,见过了周围人的种种言谈,我又害怕起了变老。明明二十多岁,正值人生中精力最鼎盛的时期,一向乐观的我也时常害怕起了年龄变大,害怕像周围人一样慢慢失去对未来的期盼。就是在这样一种心理下,我在 2024 年却碰到很多令人惊喜的事,让我继续有了向前看的动力。


先说游戏吧。我一直觉得这几年新游戏都没什么创新,但从今年年初开始,我见到了非常多有意思的游戏。「小丑牌」将自走棋的经济系统与爬塔类游戏结合,创造出了一款机制简明却不失趣味与深度的游戏,挖掘出了 Roguelike 类游戏好玩的本质。《背包乱斗》拓展了以前背包类游戏的机制,通过 PVP 自走棋的游戏形式让游戏自带了平衡性与挑战性,从而让背包类游戏的魅力得以绽放。但成也自走棋败也自走棋,做成 PVP 后,游戏的趣味性必然会大打折扣。作者也没能深刻理解自走棋类游戏该如何设计,不去思考怎么做平衡和简化游戏机制,不停地试图加新内容。游戏一下就玩腻了,非常可惜。年中出的《动物井》和《海天岛传奇》我没玩,但我很高兴能见到这些优秀的解谜类游戏。《风暴之城》是今年最令我惊喜的游戏。我从小就很喜欢玩《主题医院》、《龙之崛起》这类模拟经营游戏,但这些游戏的特点是趣味性大于挑战性,战役的每一关的玩法都大同小异,很容易玩腻。而《风暴之城》把近年来的 Roguelike 设计思路引入了模拟经营游戏,并精心设计了会让玩家游戏失败的「危机」,玩游戏时能体会到玩即时战略游戏的那种刺激感。最终,《风暴之城》兼具了 Roguelike、 模拟经营、即时战略等多种游戏的优点,对于喜欢二十多年前的游戏的老玩家来说非常新鲜又亲切。在我心中,《风暴之城》已经代替《英雄无敌3》,成为了综合游戏体验最佳的游戏。另一个我今年才挖掘出来的游戏是《幸运房东》,这个脱胎于爬塔机制的游戏成功开创了「幸运房东类」这一新型游戏。这类游戏操作简单,只需要每次从新的「卡牌」中三选一,最终组建出一套成型构筑。这类游戏把构筑类游戏复杂的「测试构筑」环节(比如暗黑类游戏用当前装备打怪,《杀戮尖塔》里用当前卡组战斗)大幅简化,只单独考验玩家的组建构筑能力,充分把一项游戏机制做到了极致。除了本体外,我还尝试了许多后续「幸运房东类」游戏,最终认识了《轮作法》这个游戏。这个游戏把自走棋玩法融入「幸运房东类」游戏,同时把《炉石传说:酒馆战棋》里的卡牌空位管理机制加入了游戏,让一个有诸多随机机制的游戏充满了思考深度。《轮作法》是我继《岛民》(islander) 以来见过我最像棋类的游戏(信息公开,需要玩家做运算,搜索当前已知最优解),我非常喜欢这类有思考深度的游戏。《流放之路》我也稍微玩了下,但游戏机制没怎么大改,我稍微回味了一下就没玩了。倒是新暗黑类游戏《最后纪元》也让我很惊喜。由于游戏是新出的,攻略很少,我第一次享受了在暗黑类游戏里自己组构筑的快乐。可惜这个游戏重玩体验没有《流放之路》高,第二个赛季我就不太想玩了。去年年底到今年年初我还认识了《战场兄弟》这个游戏,我也没想到这几年来还有类似于《英雄无敌》的以战棋为子玩法的游戏,我很开心能见到这类游戏。

剩下我的日常游戏时间都主要投入在了重玩性强的挑战类游戏上。我从去年下半年开始打《雀魂》,年初被打到道心破碎。后来抽时间稍微玩了一下,总算上了雀豪2,暂时没有继续玩的打算。上半年我又反复提升了《亿万僵尸》的技术,最高难度不暂停的胜率大幅提高。只要我完全认真玩,就很少有过不了的地图。下半年压力很大,我又开始玩《杀戮尖塔》,对游戏的理解越来越深,近期随随便便打出了猎手7连胜。我甚至开始重新捡起了围棋,下的盘数可能快超过了小时候的。但我只和星阵 AI 下,大概能打平 3 段,所以我现在一直在挑战准 4 段。

跟我有类似游戏品味的人太少了,所以十多年来我很少有机会和别人深入交流游戏攻略。而我玩完游戏就忘。所以这两个月我一直在反思我是不是失去了探索新游戏的胆量,只敢玩老游戏了。但看了 Steam 的年终回顾我才发现,原来我今年的游戏之路是这么丰富多彩。我并不想跟随潮流,玩最新最热门的游戏。看到好玩的就玩,不管是几年前出的。顺其自然地玩,才是真正地享受游戏。


今年年中的时候我被直播弹幕引流,去看了「MyGO」。本以为只是消遣,没想到这部动漫彻底改变了我的生活。「MyGO」讲述了几个美少女组乐队的故事。少女们性格各异,因巧合凑到了一起,因矛盾而散开,最终又凭借着人与人之间的牵绊又走回到了一起。动漫对感情的描写非常细腻,且擅长用特色鲜明的场景、台词来展现角色间的冲突。可能是某些场景乍看之下非常滑稽,这部本来仅属于少部分情感细腻的观众的作品被涌入的各式各样的观众玩梗、做二创、引流,形成了别具一格的二创文化。也得益于这些引流,我一个平时不怎么看动漫的人能看到这样一部温馨的作品,我为今年能认识「MyGO」而感到惊喜与感动。

关于「MyGO」的观后感,不管是有关剧内的剧情、剧外的同人创作,还是结合我个人经历得出的评价,我有太多太多想说的话。但是,今天时间有限,我不能快速把它们全部表达出来。我只能想到什么说什么。

作为一部动漫,「MyGO」的表现能力很强,其对于感情的描写甚至能够达到视觉小说的程度(毕竟小说由大量文字组成,更容易表达深刻的思想)。故事中的每个人看似有着各种各样的毛病,但在二次元这个理想的世界里,她们每个人的本质都是纯洁善良的。所以,在矛盾过后,少女们能够把人性中最美好的那些情感展示出来。哪怕大家性格各异,无法简单地用语言达成共识,但是,只要有歌声,有了想要表达自己的冲动,有了想要和他人建立连结的念头,那么演唱过后,那些无法用言语描述的情感会连在一处,并自然地流入每个人的心中。剧中的高松灯并不是我最喜欢的角色,但是她在剧中的做法让我非常感动与向往:作为一名不太敢于他人交流,略有心理障碍的人,她能为了留住和他人的友谊,去忘我地、不计后果地在台上念诗,尽自己一切努力,勇敢地表达着自己。最终,她成功地把队友找回来了。「诗超绊」的名场面,我看一次哭一次。作为极端理性的人,我知道这些事在现实生活中是不可能的。没有耐心的观众,没有愿意追求真挚友情的朋友,自然也没有敢于忘我地表达自己的人。是作者的温柔,让理想的二次元世界里诞生了这样的故事。我知道这样的事是不可能的,不存在的,不应该去梦想的。但是,我羡慕这种能够忘我地追求目标的人。我开始不断反思自己前进的步伐还不够大。我一直说自己有理想,现在我却分不清这到底是真正有想做的事,还是仅仅虚伪地创造一个引诱自己前进的「胡萝卜」了。我不想忘记我的理想。我也想不计后果地去追求!

「MyGO」的二创作品也是盛况空前。歌曲、剪辑、小故事……,催泪向、搞笑向……。看着这么多人都和我有着类似的喜好,都分享着自己的喜好,我感到非常幸福,一度想起了十年前认识「东方」时的感动。如果只有作品本身,「MyGO」对我来说只不过是和优秀 Galgame 一样的存在。但是「MyGO」的二创给我带来了各种全新的体验。比如我开始了解角色的声优,了解所谓的 2.5 次元偶像企划。为了现场见声优,我甚至年底久违地去了次漫展。本来几乎不唱歌的我,也开始努力把「MyGO」的歌曲唱得好听。这些新的体验对我来说也仅仅是调剂,我不会像某些过分热情的粉丝一样花太多精力在这上面,但我很高兴能够认识这些全新的体验,去看到生活中我不曾见过的风景。

看过「MyGO」后我又自然而然地看了「Grils Band Cry」(GBC)。GBC 也是讲少女乐队的故事,但风格更偏现实,更沉重一些。剧中的人物,一直在强调一个观点:要创作自己的心声,而非迎合观众。这同样也是我一直以来的信念。这个世界不断在教人们做「正确」的事情,强迫人们放其自己本来想做的事情。不知道是幸运还是不幸,我从来就没有从迎合世界中获取过恩惠。等回过神来的时候,我的心中只剩下了对世界的复仇之情。我不想被任何世俗的负担左右,我只想做我想做的事情,我想证明我是对的。我想做的事情并不是真正意义上从我自己出发,只会有利于我的事情。就像 GBC 中的女主角被一首歌鼓舞了一样,我也是在种种鼓舞中走过来的人。我想做的,是再现这些对他人的鼓舞。所以,我所追求的,并不是只有我在追求,是很多人想追求,却因种种原因难以伸手把握的事物。既然如此,我会从我开始,斩断这些世俗的枷锁。

我今年看的这两部动漫助长了追梦的热情。我对它们的感谢无以言表,所以只能用实际行动来表达。就像现在写这篇文章的时候一样。我不想思考是不是太晚了要睡觉,不去害怕会不会写不完。只要心中还有一丝冲动,我就会继续诉说,直到心满意足了为止。


最后聊今年玩的视觉小说类游戏。由于今年「逆转裁判 4 5 6 」上架了 Steam,所以我把之前没能在模拟器上玩的《逆转裁判5》玩完了,还顺便玩完了《大逆转裁判》两部曲。感叹于巧舟的才华后,我又玩了他的《幽灵诡计》。这些作品质量都还不错,但由于我早就玩过前几部「逆转」作品,那股新鲜感已经没了。我还顺便玩了之前剩下的《弹丸论破V3》,只能说作者有创作故事的才华,却完全不会做游戏。

年底赶论文之余,我竟然玩完了老版「寒蝉」、老版《月姬》、《魔法使之夜》。「寒蝉」写了超长的日常,却不会让人感觉无趣(像 Muv Luv 本体那样)。整体故事恐怖悬疑氛围渲染到位,故事框架及伏笔回收还算合理。对我而言,故事中并没有太多感人的表达,但有不少引人思考的表达。我非常认可它的质量,能够理解为什么它作为画风简陋的同人作品能受到那么多人的喜爱。相比之下,《月姬》画风稍好,虽然故事偏短,但每条结局都做到了叙事完整。由于我是先玩过「FSN」的,玩《月姬》时能够在画风和叙事上体会到熟悉感,这种体验很有趣。正如很多其他评论一样,相比「FSN」,《月姬》有一种清冷感,那淡淡的氛围更人回味无穷。至此,时隔二十年,我总算欣赏完了当年的「同人三大奇迹」。好像这个时间有点晚。但可能时间的早晚并不是很重要,因为那份同(独)人(立)创(游)作(戏)的创作理念已经传达到了我这里。我会将它们传递下去。《魔法使之夜》就是成熟的商业作品了,一流的美术和演出,笔法成熟的作家,按理来说会给人舒适的体验。但在我看来,这部作品显然是未完成之作,很多东西没讲完故事就戛然而止了。我不认为未完成的作品是好作品。

我一般通过玩游戏来休闲。但仔细想来,还是看视觉小说时那种沉醉的心情更令我放松。我其实是喜欢文字的,但一直没有胆量去探索,只能局限于和游戏略有交集的 Galgame。我希望从明年起能够更深入地挖掘出自己的喜好,去欣赏更多优秀文学作品。


科研就没什么可以讲的了。科研是工作,并不让人讨厌,只能说是空气一般自然的存在。既然是空气,也没有太多可以讨论的必要了。倒是今年写论文时的感想我过段时间会正式发表出来。

关于科研,我最想说的是:哪怕科研是工作,是一份非常有趣的工作,我也不想让它不必要地占用我做其他事情的时间。无论会承担怎样的后果,我都要花时间去做其他想做的事情。


按照习惯,我还是收个尾吧。我不想花太多的理性去思考,为什么要写这篇文章,这篇文章是写给谁看,到底写完了有什么意义。只是昨天睡着之前想起这几天看了一些别人的年终总结,突发奇想要把自己今年的事情也整理一下而已。于其花几个小时去思考做这件事的意义,不如像现在这样就动笔写完了。不需要有什么意义,仅凭一时的冲动就够了。是的,不经深思熟虑的冲动会导致失败。但是,我心中总有一些坎是不靠冲动就跨不过去的。如果说深思熟虑后,仍然愿意面对困难的事物可以称之为勇敢的话,那么先不顾一切地做出行动,再为失败负责,同样也是勇敢的。可能明早开始我也会羞得不敢看这篇文章,那也没什么关系。我不会许诺说明年年底还会写这样的文章,我不想给自己添加任何负担。想到做就做,想做就做,不想做就不做,我要尽力地去自由地活下去。

由于我严谨的作风,我又把文章通读了一遍,忍不住站在读者视角重新感受了一下这篇文章。说实话,我文字功底太差了,没有足够的写作经验,不能把复杂深刻的情感充分表达。哪怕我写的时候自己的情感已经酝酿得很到位了,读起来还是太理性了。但没什么关系,就凭我的洞察力和自我进化能力,提升文字表达能力是分分钟的事情。是啊,文字的表达能力太有限了,不管怎么描写,都只能勾勒出复杂思绪的一角。在那表层的文字之下,究竟藏住了什么呢?不付出大量的心思,是猜不到的。也因此,无法期盼读者能够有耐心猜下去。那么,就不断地强化笔锋的锐度,不断地写下去吧。

今年年初,多尺度自回归模型 VAR 为图像生成开辟了新的发展方向:通过将图像生成建模成下一尺度预测,且每轮一次性生成同一尺度的所有像素,VAR 以极快的速度实现了高质量图像生成。随后,有许多工作都尝试对其改进。为弥补 VAR 中 VQ (Vector Quantization,向量量化) 操作引入的信息损失,HART (Hybrid Autoregressive Transformer,混合自回归 Transformer) 把 VQ 损失的信息用一张残差图表示,并用一个轻量的扩散模型来生成该残差图。做完改进后,作者用 HART 实现了 $1024 \times 1024$ 高分辨率文生图任务。在这篇博文中,我们将学习 HART 的核心方法并分析它在文生图任务上的实验结果。

论文链接:https://arxiv.org/abs/2410.10812

以往工作

本文涉及的所有自回归图像生成方法都起源于 VQVAE, VQGAN。在阅读本文前,建议读者先熟悉这两个经典工作。

HART 直接基于 VAR (Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale Prediction) 开发,且其部分思想和 MAR (Masked Autoregressive models,出自论文 Autoregressive Image Generation without Vector Quantization) 类似。欢迎大家阅读我之前的解读。

VAR 解读

MAR 解读

在 VQGAN 两阶段生成方法的基础上,VAR 让自编码器输出一系列不同尺度的图像词元 (token),而不仅仅是最大尺度的词元。生成时,VAR 自回归地生成不同尺度的词元图,同一尺度的词元图会在一轮 Transformer 推理中一次性生成。

VQ 操作会丢失编码器输出中的信息,这导致所有使用 VQ 自编码器的图像生成模型生成质量略低。VAR, VQGAN 等方法之所以不得不使用 VQ,是因为这些方法都用类别分布(categorical distribution)来建模词元的分布。为了彻底去除 VQ 操作,MAR 使用扩散模型来代替类别分布,使得我们能够用精度更高的 VAE 来压缩图像。

弥补 VQ 的信息损失

为了缓解 VAR 中 VQ 造成的质量下降,HART 使用了一项思路直接的设计:既然 VQ 无论如何都会造成信息损失,不妨把损失的信息看成一张残差图像。用普通的 VAR 生成完图片后,再用扩散模型生成该残差图像。把残差图像加到原输出图像后,新输出图像会质量更高。

让我们通过论文里的图片来直观感受这一点。第一行是 VAR 自编码器和 HART 的混合自编码器的重建结果。可以看出,由于 VQ 操作,模型难以重建输入图像。第二行原 VAR 的输出和残差图像输出。我们发现,加上残差图像后,图像的细节更加丰富,不会像之前一样模糊。

在下两个小节里,我们来学习 HART 是怎么分别改进 VAR 的词元生成模型和自编码器的。

用扩散模型生成残差图像

为了理解整套方法,我们需要理解 HART 的「残差图像」是从哪来的。因此,我们先看词元生成模型上的修改,再看自编码器的对应修改。

我们先仔细回顾一下 VAR 中 VQ 误差是怎么引入的。VAR 借用了传统拉普拉斯金字塔的思想来建模不同尺度的词元图。

也就是说,VAR 并没有将完整图像拆解成内容相同、不同分辨率的词元图,而是拆解成了最低分辨率的图以及各个尺度上的信息损失。这里的信息损失不仅包括了下采样导致的,还包括了 VQ 导致的。

即使在多尺度拆解时考虑了 VQ 的信息损失,最终的重建特征(即解码器输入,词元查表输出的累加)依然不能和编码器输出特征完全一致。HART 想用扩散模型生成的「残差图像」,就是上图中重建特征和编码器输出特征的差。

和离散的词元图不同,残差图像是连续的。为了生成该连续图像,HART 参考 MAR,使用了一个图像约束的扩散模型。该任务可以解释为:已知离散词元图的输出,该如何用扩散模型生成细节,以提升输出图像质量。

HART 的生成模型示意图如下所示。前面的生成过程和 VAR 一模一样。在最后一步,Transformer 的中间隐状态会输入给用 MLP 表示的扩散模型,扩散模型会为每个词元独立地预测残差量。也就是说,这不是一个图像扩散模型,而是只生成一个词元值的像素扩散模型。词元之间的采样互相独立。得益于这种独立性假设,HART 可以用一个非常轻量的扩散模型来生成残差图,几乎没有增加整体的生成时间。

HART 还将 VAR 的类别约束换成了文本约束。我们稍后在实验部分讨论。

AE + VQVAE 混合自编码器

知道了 HART 要生成的残差图像从何而来,我们可以回头学习自编码器上的对应修改。现在,自编码器的解码器有两种输入:一种是 VAR 离散词元累加而成的近似重建特征,一种是加上了 HART 的残差图的精确重建特征,这个重建特征就等于编码器输出特征。为了同时处理这两类输入,在训练 HART 的混合自编码器时,解码器的输入一半的时候是编码器输出,另一半的时候是离散词元的重建特征。当然,在生成时,由于加上了残差图像,可以认为解码器的输入就等于编码器的输出。

下图中采用的术语 token 与 VAR 不同。VAR 把编码器输出和解码器输入都叫做特征图 (feature map),把过了 VQ 操作的索引图叫做词元图 (token map)。而 HART 将 VAR 里的特征图称为 token,continuous token 表示编码器输出特征,discrete token 表示词元的重建特征。这篇博文采用了 VAR 的称呼方法。同理,HART 里的 residual token 在本文被称为「残差图像」。

这样看来,HART 的混合编码器既像没有 KL Loss 的 VAE,即普通自编码器 (AE),也像 VQVAE。

高分辨率文生图实现细节

我们来简单看一下 HART 是如何把 ImageNet $256 \times 256$ 按类别生成的 VAR 拓展成 $1024 \times 1024$ 的文生图模型的。

  • 文本约束:HART 没有通过交叉注意力输入文本信息,而是和 VAR 对类别嵌入的做法一样,将文本嵌入作为第一尺度的输入及 AdaLN 层的输入。
  • 位置编码:不管是对于尺度编号还是图像位置编号,VAR 用的是可学习的绝对位置编码。HART 对尺度采取了正弦编码,对图像词元采取了 2D RoPE(旋转位置编码)。
  • 更大尺度:原 VAR 词元图的最大边长是 16,HART 往后面添加了 21,27,36,48,64 这几个边长。
  • 轻量级扩散模型:由于扩散模型仅需建模单个词元的分布,它仅有 37M 参数,只需 8 步就能完成高质量采样。

定量实验结果

先看一下最热门的「刷点」指标——ImageNet $256 \times 256$ 按类别生成。作者没放最好的 MAR 模型,我补上去了。

在这个任务上,HART 和 VAR 的主要区别在于是否使用扩散模型输出残差图像。从结果可以看出,残差扩散模型几乎没有提升推理时间,却对 FID 指标有不小的提升(考虑到数值越低,提升难度越大)。并且,通过比较不同模型的速度,我们发现类 VAR 模型最大的优势在于推理速度快。

再看一下这篇论文重点关注的文生图指标。除了常用的主要衡量文图匹配度的 GenEval 外,论文还展示了两个今年刚出的指标: MJHQ-30K 数据集上的指标和 DPG-Bench。

这些指标不见得很有说服力。在由用户投票的排名中 (https://imgsys.org/rankings),Playground v2.5 最好,SD3 和 PixelArt-Σ 差不多。但是,MJHQ FID 和 DPG-banech 指标都不能反映出这些模型的排名。特别地,FID 用到的 Inception V3 网络是在 $299 \times 299$ 的 ImageNet 上训练的,所以 FID 既不能很好地反映高分辨率图像的相似度,也不能反映更复杂的图像的相似度。

综上,HART 在高分辨率文生图任务上的表现暂时不能通过实验结果反映。根据部分社区用户的反馈(https://www.reddit.com/r/StableDiffusion/comments/1glig4u/mits_hart_fast_texttoimage_model_you_need_to_see/ ),HART 在高频细节的生成上存在缺陷。通过回顾 HART 的方法,我们可以猜测这是残差扩散模型的设计不够好导致的。

总结

为了缓解 VQ 自编码器中 VQ 操作带来的信息损失,HART 把信息损失当成一张残差图,并额外用一个轻量级像素扩散模型来独立地生成残差图的每个像素。HART 把这一改进直接应用到了 VAR 上,并提升了 VAR 的 ImageNet FID 指标。HART 在高分辨率文生图任务上依然无法媲美扩散模型,并且由于扩散模型存在诸多加速手段,它在生成速度上也没有优势。

VQ 操作将复杂的图像转换成了易于学习的图像词元,但牺牲了自编码器的重建质量。为了改进这一点,有许多工作都试图改进原 VQVAE 的最近邻 VQ 操作。但无论如何,VQ 导致的误差是不可避免的。HART 从另一个角度缓解 VQ 重建误差:用另一个模型来生成残差图像。这种设计思想很有前途,有希望彻底去除 VQ 的误差。然而,天下没有免费的午餐,提升了生成效果,就不得不增加训练和生成时间。HART 用轻量级像素扩散模型生成残差图的做法虽然不会拖慢模型速度,但效果还不够好。或许可以将其换成一个感受野稍大一点的扩散模型,在不显著增加生成时间的前提下提升残差图生成效果。

今年四月,北大和字节跳动在 Arxiv 上发表了论文 Visual Autoregressive Modeling: Scalable Image Generation via Next-Scale Prediction,介绍了一种叫做 Visual Autoregressive Modeling (视觉自回归建模,VAR)的全新图像生成范式。这种自回归生成方法将高清图像用多尺度词元图像表示,并用下一尺度预测代替了此前常用的下一词元预测。在 ImageNet $256 \times 256$ 图像生成任务上,VAR 的表现超越了 DiT。我们组的同学第一时间看了这篇论文,大家都觉得这篇论文有不小的创新,但其方法能否完全代替扩散模型还有待验证。通常来说,这篇论文的关注度会逐渐降下去,但近期发生的两件大事将 VAR 论文的热度推向了空前的高度:论文一作的严重违纪行为招致字节跳动对其索赔 800 万元、论文被评选为 Neurips 2024 会议的最佳论文。借此机会,我决定认真研究一下这篇论文并把我的学习结果分享给大家。

在这篇博文中,我会先回顾与 VAR 密切相关的早期工作 VQVAE 和 VQGAN,再介绍论文的方法细节与实验结果,最后分享我对该工作的测试结果与原理探究。在读 VAR 论文时,我发现有个地方的设计存在缺陷。相关实验结果表明, VAR 论文并没有完整地分析出这套方法有效的原因。欢迎大家仔细阅读这一部分并提出自己的思考与见解。

论文链接:https://arxiv.org/abs/2404.02905

VQGAN 原理回顾

VAR 算是 VQGAN 工作的改进版,而 VQGAN 又是 VQVAE 工作的改进版。要了解 VAR 的背景知识,最直接的方法就是回顾 VQVAE 与 VQGAN 这两个经典工作。我们先从自回归这种生成范式开始聊起,再将目光移向图像自回归生成,最后复习 VQVAE, VQGAN, Transformer 的实现细节。

推荐大家阅读我之前写的相关博文:

轻松理解 VQ-VAE:首个提出 codebook 机制的生成模型

VQGAN 论文与源码解读:前Diffusion时代的高清图像生成模型

Attention Is All You Need (Transformer) 论文精读

图像自回归生成

自回归(Autoregressive)是一种直观易懂的序列生成范式:给定序列前 $n$ 个元素,模型输出第 $n+1$ 个元素;把新元素添加进输入序列,再次输出第 $n+2$ 个元素……。以下是文本自回归生成的一个示例:

1
2
3
4
(空)  -> 今
今 -> 天
今天 -> 早
今天早 -> 上

具体来说,模型的输出并不是下一个元素应该是什么,而是下一个元素可能是什么。也就是说,模型的输出是下一个元素的概率分布。通过不断对下一个元素采样,我们就能随机生成出丰富多样的句子。

自回归生成仅适用于有顺序的序列数据。为了用自回归生成图像,我们需要做两件事:1)把图像拆分成一个个元素;2)给各个元素标上先后顺序。为此,最简单的做法是将图像拆成像素,并从左到右,从上到下地给图像生成像素。比如下图是经典自回归图像生成模型 PixelCNN 的示意图。假设图像有 $3 \times 3$ 个像素,并按顺序从左上到右下标号。在生成第 $5$ 个像素时,模型只能利用已经生成好的前 $4$ 个像素的信息。模型的输出是一个概率分布,表示灰度值大小分别取 0, 1, ..., 255 的概率。

顺带一提,建模概率分布的方法有很多种,这里我们使用的分布被称为类别分布(categorical distribution)。这种方法的好处是形式简洁,可以用简单的算法采样,缺点是元素的取值必须是离散的。比如虽然图像的灰度值理论上可以取 0~1 中间的任何实数(假设灰度值被归一化了),但我们用上图所示的 PixelCNN 时,只能表示 0, 1/255, 2/255, ..., 1 这 256 种灰度值,而不能表示更加精确的值。

VQVAE

PixelCNN 虽然能做图像生成,但它的效率太慢了:由于像素是逐个生成的,要生成几个像素,就要运行几次神经网络。能不能加速生成过程呢?如果要生成的图像更小一点就好了。

为了加速 PixelCNN,借助图像压缩网络,VQVAE 工作提出了一种两阶段的图像生成方法:先生成压缩图像,再用图像压缩网络将其复原成真实图像。由于压缩图像的像素数较少,而复原压缩图像的速度又很快,整套生成方法的速度快了很多。

以下是一个 VQVAE 的生成示例。根据 PixelCNN 输出的类别分布,我们可以采样出一些由离散值构成的压缩图像。这些离散值就和 NLP 里的文字一样,每一种值都有一种特殊的含义。我们可以认为离散值表示原始图像中一大块像素的颜色。借助图像压缩网络的解码器,我们可以把压缩图像复原成清晰的原始图像。

VQVAE 的训练顺序和生成顺序相反。我们先训练一个图像压缩网络。这种由编码器和解码器组成的图像压缩网络被称为自编码器,压缩出来的图像被称为隐图像(latent image)。训练好了自编码器后,我们再把训练集的所有图像都转成隐图像,让 PixelCNN 学习生成隐图像。比较有趣的是,训练 PixelCNN 时,只会用到编码器;而生成时,只会用到解码器。

在上述讨论中,我们略过了一个实现细节:该怎么让网络以离散值为输入或输出呢?输入离散值倒还好办,在 NLP 中,我们用嵌入层把离散的词语变成连续向量,这里的做法同理。可怎么让网络输出离散值呢?这里就要用到向量离散化(vector quantization, VQ)操作了。

离散化操作我们都很熟悉,将小数四舍五入至整数就是一种最常见的离散化。四舍五入,本质上是让一个小数变成最近的整数。同理,对于向量而言,假设我们已经准备好了一些向量(对应前面的「整数」),那么向量离散化就表示把输入的任意向量变成最近的已知向量。这里的「最近」指的是欧几里得距离。

具体示例如下所示。编码器可以输出一个由任意向量构成的二维特征。通过查找嵌入层里的最近邻,这些任意的向量会被转换成整数,表示最近邻的索引。索引可以被认为是 NLP 里的词元 (token),这样编码器输出特征就被转换成了词元构成的隐图像。而在将隐图像输入进解码器时,我们把嵌入层当成一张表格,利用隐图像里的索引,以查表的形式将隐图像转换成由嵌入构成的特征。准确来说,这个把图像压缩成离散隐图像的自编码器才被叫做 “VQVAE”,但有时我们也会用 VQVAE 代表整套两阶段生成方法。

上图中的「编码器输出特征」、「词元」、「嵌入」在不同论文里有不同的叫法,且一般作者都只会用数学符号来称呼它们。这里我们用了 VAR 论文的叫法。

嵌入层的具体学习过程我们不在此展开,对这块知识不熟悉的读者可以去仔细学习 VQVAE 论文。

VQGAN

VQVAE 的效果并不理想,这是因为它的压缩网络和生成网络都不够强大。为此,VQGAN 工作同时改进了 VQVAE 的两个网络。

  • VQGAN 工作将离散自编码器 VQVAE 换成了 VQGAN。在 VQVAE 的基础上,VQGAN 在训练时添加了感知误差和 GAN 误差,极大提升了自编码器的重建效果。
  • VQGAN 工作还把生成模型从 PixelCNN 换成了 Transformer。

Transformer

Transformer 是目前最主流的主干网络。相比其他网络架构,Transformer 的最大特点是序列里的元素仅通过注意力操作进行信息交互。因此,为了兼容文本自回归生成任务,最早的 Transformer 使用了两个特殊设计:

  • 由于注意力操作不能反映输入元素的顺序,词元嵌入在输入进网络之前,会和蕴含了位置信息的位置编码相加。
  • 自回归生成要求之前的词元不能看到之后的词元的信息。为了控制词元间的信息传播,Transformer 给自注意力操作加上了掩码。

VQGAN 用了完全相同的设计,把图像词元当成文本词元用 Transformer 来生成。

从词元预测到尺度预测

上述的传统图像自回归生成都是采用下一个词元预测策略:

  • 将图像用自编码器拆成离散词元。
  • 从左到右、从上到下按顺序逐个生成词元。

尽管通过自编码器的压缩,要生成的词元数已经大大减少,但一个个去生成词元还是太慢了。为了改进这一点,VAR 提出了一种更快且更符合直觉的自回归生成策略:

  • 将图像用自编码器拆成多尺度的离散词元。比如,原来一张隐图像的大小是 $16 \times 16$,现在我们用一系列尺度为 $1 \times 1, 2 \times 2, …, 16 \times 16$ 的由词元构成的图像来表示一张隐图像。
  • 从最小的词元图像开始,从小到大按尺度生成词元图像。

在这种策略下,我们要同时修改自编码器和生成模型。我们来看一下 VAR 是怎么做的。

多尺度残差离散自编码器

先来看自编码的修改。现在词元图像不是一张图像,而是多张不同尺度的图像。由于词元图像的定义发生了改变,编码器特征和嵌入的定义也要发生改变,如下图所示。

向量离散化部分我们可以沿用 VQVAE 的做法。现在新的问题来了:编码器的输出和解码器的输入都只是一张图像。该怎么把多尺度的图像组合成一张图像呢?

最简单的做法是完全不修改编码器和解码器,还是让它们输入输出最大尺度的图片。只有在中间的向量离散化/查表部分,我们才把这些图片下采样。

VAR 用了一种更加高级的做法:用残差金字塔来表示这些隐空间特征。我们先来回顾一下拉普拉斯金字塔这一经典图像处理算法。我们知道,图像每次下采样的时候,都会损失一些信息。既然如此,我们可以将一张高分辨率的图像表示为一张低分辨率的图像及其在各个分辨率下采样后的信息损失。如下图所示,最右侧的一列表示拉普拉斯金字塔的输出。

在计算拉普拉斯金字塔时,我们不断下采样图像,并计算当前尺度的图像和下一尺度的复原图像(通过上采样复原)的残差。这样,通过不断上采样最低尺度的图像并加上每一层的残差,我们最终就能精准复原出高分辨率的原图像。

现在,我们想把类似的金字塔算法应用到编码器特征上。该怎么把最大尺度的编码器特征拆解成不同尺度的图像的累加呢?

在计算拉普拉斯金字塔时,本质上我们用到了两类操作:退化和复原。对于图像而言,退化就是下采样,复原就是上采样。那么,对于编码器输出的隐空间特征,我们也需要定义类似的退化和复原操作。比较巧妙的是,VAR 并没有简单地把退化和复原定义为下采样和上采样,而是参考 Autoregressive Image Generation using Residual Quantization 这篇论文,将向量离散化引入的误差也算入金字塔算法的退化内。也就是说,我们现在的目标不是让编码器特征金字塔的累加和编码器特征相等,而是想办法让嵌入金字塔的累加和编码器特征尽可能相似,如下图所示。

基于这一目标,我们可以把退化定义为下采样加上离散化、查表,复原定义成上采样加一个可学习的卷积。我们来看看在这种新定义下,原来 VQVAE 的向量离散化操作和查表操作应该怎么做。

先看新的多尺度向量离散化操作。这个操作的输入是编码器特征,输出是一系列多尺度词元图像。算法从最低尺度开始执行,每个循环输出当前尺度的词元图像,并将残差特征作为下一个循环的输入特征。

对于多尺度查表操作,输入是多尺度词元图像,输出是一张最大尺度的隐空间特征,它将成为自编码器的解码器的输入。在这步操作中,我们只需要分别对各个尺度的词元图像做查表和复原(上采样+卷积),再把各尺度的输出加起来,就能得到一个和编码器特征差不多的特征。注意,为了方便理解,这几张示意图都省略了部分实现细节,且一些数值不是十分严谨。比如在查表时,我们可以让不同尺度的词元共享一个嵌入层,也可以分别指定嵌入层。

总结一下这一小节。为了实现尺度自回归生成,我们需要把图像编码成多尺度的词元图像。VAR 采用了一种多尺度残差离散化操作:将编码器特征拆解成最小尺度的特征以及不同尺度的残差特征,并对不同尺度的特征分别做向量离散化。这种做法不仅能高效地将特征拆解成多个尺度,还有一个额外的好处:原来 VQVAE 仅对最大尺度的特征做向量离散化,离散化后的误差会很大;而 VAR 把向量离散化引入的误差分散到多尺度离散化中,巧妙地降低了离散化的误差,提升了 VQVAE 的重建精度。

下一尺度自回归生成

把图像压缩成多尺度词元图像后,剩下的事就很简单了。我们只需要把所有词元拆开,拼成一维词元序列,之后用 Transformer 在这样的序列上训练即可。由于现在模型的任务是下一尺度预测,模型会一次性输出同尺度各词元的概率分布,而不是仅仅输出下一个词元的。这样,尽管序列总长度变长了,模型的整体生成速度还是比以前快。同时,随着预测目标的变更,自注意力的掩码也变了。现在同尺度的词元之间可以互相交换信息,只是前一尺度的词元看不到后面的词元。以下是一个 $3 \times 3$ 词元图像在下一词元和下一尺度预测任务下的注意力掩码示意图及生成过程示意图。

除此之外,VAR 的 Transformer 还做了一些其他修改:1)除了给每个词元加上一维位置编码外,同一尺度的词元还会加上同一个表示尺度序号的位置编码。所有位置编码都是可学习的,而不是预定义的正弦位置编码。2)Transformer 与解码器的共用嵌入层。另外,在生成新一层时,为了复用已经生成好的图像的信息,新一层的初始嵌入是通过对上一层的生成结果 bicubic 上采样得到的。

该 Transformer 的其他设计都与 VQGAN 相同。比如,Transformer 采用了 decoder-only 的结构。为了添加 ImageNet 类别约束,第一层的输入是一个表示类别的特殊词元。训练时用的误差函数是交叉熵函数。

ImageNet 图像生成定量实验

VAR 的方法部分我们看得差不多了,现在来简单看一下实验部分。论文宣称 VAR 在图像生成实验和参数扩增实验上都取得了不错的成果。特别地,VAR 的拟合能力胜过了 DiT,生成速度是 DiT 的 45 倍以上。我们就主要看一下 VAR 在 ImageNet $256 \times 256$ 图像生成上的实验结果。以下是论文中的表格。我同时还附上了何恺明团队的 MAR 工作(Autoregressive Image Generation without Vector Quantization)的实验结果。

先比一下 DiT 和 VAR。先看速度,不管是多大的模型,DiT 的速度都远远慢于 VAR。再看以 FID 为代表的图像拟合指标。VAR 在参数量为 600M 左右时并没有 DiT 效果好。但继续增加参数量后,DiT 的 FID 没有变好的趋势,而 VAR 的 FID 一直在降。最终 VAR 的 FID 甚至超过了 ImageNet 的验证集,可以认为 FID 再低的也意义不大了。

再比一下 MAR 和 VAR。MAR 的刷指标能力更加恐怖,943M 的模型就能有 1.55 的 FID。但根据 MAR 论文,其速度是 DiT-XL 的 5 倍左右,也就是说 VAR 还是比 MAR 快,是 MAR 速度的 9 倍左右。

ImageNet 图像生成已经被各个模型刷到头了。FID 结果能说明 VAR 的拟合能力很强,最起码不逊于 DiT。但在更有挑战性的文生图任务上,VAR 的效果还有待验证。另外,虽然刷指标的时候 DiT 用了 250 步采样,但实际用起来的时候一般就是采样 20 步。如果算上蒸馏的话,采样步数能缩小到 4 步。加上这些加速技巧的话,VAR 不见得会比 DiT 快。

VAR 各尺度生成结果

看完了论文的主要内容,我来分享一下我对 VAR 的一些理论分析与实验结果。

先看一下随机采样结果。我用的是最大的 d=30 的 VAR 模型。在官方采样脚本的默认配置下,两个随机种子 (0, 15) 的输出如下所示。用到的图像类别为火山、灯塔、老鹰、喷泉,每个类别的图各生成了两张。图像的生成速度很快,一秒就生成了全部 8 张图片。

我们还可以观察每个尺度的生成结束后解码出的临时图片。和我们预估得一样,图像是按从粗到精的顺序逐渐生成的。

为了进一步探究每一个尺度负责生成哪些图像成分,我们可以做如下的实验:从某个尺度开始,随机更换新的随机数生成器。这样,每张动图里不变的部分就是前几个尺度生成好的内容;不断在变的部分就是后几个尺度负责的内容。可以看出,从第三个尺度开始,图像的内容就基本固定下来了,也就是说结构信息是在前两个尺度里生成的。越往后,图像的细节越固定。

这个结果还挺令人惊讶的:难道 $2 \times 2$ 这么小的特征图就已经决定了图像的整体内容?让我们来仔细探究这一点。

有缺陷的单尺度生成

不知道大家在学习 VAR 的采样算法时候有没有感到不对劲:在生成同一个尺度的词元图像时,每个词元是独立地在一个概率分布里采样。

而根据作者在论文里的说法,VAR 的尺度自回归是一种新的自回归概率模型:

其中,$r_k$ 表示从小到大第 $k$ 个尺度的词元图像,共 $K$ 个尺度。同一个尺度的词元图像 $r_k$ 的每个词元的分布是并行生成的。这也就是说,VAR 的这种训练(用交叉熵误差)和采样方式是认为每张词元图像的概率等于所有词元的概率的乘积,词元的分布之间是独立的:

其中,$r_k^i$ 表示第 $k$ 个尺度的第 $i$ 个词元,$I_k$ 为第 $k$ 个尺度的词元总数。我觉得上面这个等式是不成立的,哪怕有之前尺度的信息作为约束,同一尺度的每个词元的概率分布之间不会是互不相关的。且随着 $I_k$ 的增大,上面这个式子的误差会越来越大。

词元之间的采样互相独立,理论上会导致图像出现不连贯的地方。比如,假设一个图像词元表示 $16 \times 16$ 个像素,那么每隔 16 个像素图像就会出现「断层」。但是,为什么 VAR 的输出结果那么正常呢?仔细分析 VAR 的生成算法,我们可以发现有两项设计提升了图像的连续性:

  • VAR 的自编码器使用了向量离散化操作。这个操作会让解码器的输入总是合理的,解码器也总是会输出连贯的图像。
  • 在生成一个新尺度的图像时,模型输入会被初始化成之前尺度的图像的 bicubic 上采样。bicubic 采样保证了词元嵌入之间的连续性。

此外,为了进一步缓解独立采样带来的负面影响,VAR 在生成完第二或第三个尺度后就已经把图像的整体内容确定下来了,后面的生成只是略微影响图像细节而已(因为随着词元数量变多,独立采样的误差越大)。这个结论已经在前文的可视化结果中验证了。为了证明只有前几个尺度是重要的,我做了一个大胆的实验:用 Transformer 生成完前两个尺度的词元后,后续所有词元都随机生成。如下图所示,我展示了固定前两个尺度的输出后,多个随机种子下的生成结果。结果显示,如果前两个尺度的词元生成得比较好,后面词元无论采样得多乱,都不怎么会影响最终的图像质量。

根据这些实验结果,我认为 VAR 真正有效的原因并不能用「下一尺度预测这种全新生成范式更好」这样粗浅的话来概括。VAR 中最核心的组件可能是其多尺度残差离散自编码器。这个编码器至少做到了以下几件事:

  • 使用向量离散化确保解码器的输入总是合理的。
  • 使用多尺度残差设计,且下一尺度的残差图像不仅记录了因下采样而导致的信息损失,还记录了因向量离散化带来的精度损失。相比简单的、人类能够理解的拉普拉斯金字塔,这种可学习的多尺度拆分方法或许更加合理。
  • 使用 bicubic 对低尺度词元图上采样。这步固定的操作让生成的图像总是连续的。

当然,这几件事是互相耦合的。不进行更深入的实验的话,我们难以解耦出 VAR 中最有效的设计。

多尺度生成其实并不是什么新奇的思想。之前 StyleGAN 和 Cascaded Diffusion 都用了类似的策略。然而,VAR 做了一个大胆的设计:同一尺度的不同词元在采样时是相互独立的。令人惊讶的是,这种在数学上不太合理的设计没怎么降低图像的质量。并且,得益于这一设计,VAR 能够并行地对同一尺度的词元采样,极大地提升了生成速度。

总结与评论

此前,以经典工作 VQGAN 为代表的图像自回归生成模型无论在速度上还是图像质量上都不尽如人意。究其原因,下一个图像词元预测的建模方式既不够合理,也拖慢了生成速度。为此,VAR 提出一种新式自回归策略:将词元图像拆分成多个尺度,通过下一尺度预测实现图像生成。为了兼容这一设计,VAR 对 VQGAN 的自编码器和 Transformer 都进行了修改:自编码器能够将图像编码成多尺度的残差词元图像,而 Transformer 同时输出同一尺度每个词元的独立分布。实验表明,VAR 在 ImageNet 图像生成指标上超越了以 DiT 为代表的扩散模型,且生成速度至少比 DiT 快 45 倍。另外,还有实验表明 VAR 符合扩增定律:增加参数量即可提升模型性能。

我个人认为,和其他前沿生成模型一样,VAR 在 ImageNet 上的表现已经满分了。它能否完成更困难的图像生成认为还有待验证。最近字节跳动发布了 VAR 的文生图版本:Infinity,但这个模型还没有开源。我们可以持续关注 VAR 的各个后续工作。VAR 的生成速度也没有比 DiT 快上那么多,通过减小采样步数,再加上模型蒸馏,DiT 不会比 VAR 慢。当然,VAR 或许也存在进一步加速的可能,只是相关研究暂时没有扩散模型那么多。

VAR 的数学模型是存在缺陷的:词元图的分布不应该等于词元间的独立分布的乘积。最起码论文里没有任何相关分析(用了类似做法的 MAR 论文也没有分析)。通过一些简单的生成实验,我们发现由于 VAR 在其他设计上提升了输出图像的连续性,哪怕同一尺度的词元间是独立采样,甚至是随机均匀采样,模型的输出质量也不会太差。我们需要通过更深入的实验来挖掘 VAR 的生效原理。

我觉得如果一个科研工作能够解释清楚 VAR 中哪些模块起到了最主要的作用,并取其精华,去其糟粕,提出一个更好的生成模型,那这会是一个很不错的工作。我觉得能够探索的方向有:

  • VAR 的前几个尺度的词元图是最重要的。能不能用更好的方式,比如用扩散模型,来生成前几个尺度的图像,而更大尺度的词元图用一个比 Transformer 更高效的模型来生成。这样模型的质量和效率能进一步提升。
  • VAR 还是用了 VQ 自编码器。无论怎么样,VQ 操作都会降低模型的重建质量。但另一方面,VQ 也能起到规范解码器输入的作用。究竟我们能不能把 VQ 自编码器换成精度更高的 VAE 呢?换了之后怎么设计多尺度编码呢?

以前我一直将 “quantization” 翻译成「离散化」,但经仔细学习后发现它与真正的离散化 “discretization” 存在区别。因此,以后我会采用「量化」这个更常见的翻译,尽管我认为这个翻译容易和「量化投资」里的「量化」混淆。