论文阅读:Scalable Diffusion Models with Transformers
引:这篇由 William Peebles 和 Saining Xie 提出的工作,将 latent diffusion 中常用的 U-Net 去噪主干替换成了 Transformer,形成 Diffusion Transformer,也就是 DiT。文章最值得关注的部分,是它如何把带噪 latent、扩散时间步和生成条件接入一个接近标准 ViT 的结构,并通过系统实验说明:增加模型规模,以及增加参与计算的 token 数,都能改善生成质量。
为了阅读任何与diffusion有关的文章,先学习一些前置知识或者了解一下有关diffusion models的发展脉络是很有助益的。在此推荐大神Lilian Weng的这篇博客。
背景
在本文提出时,图像扩散模型通常使用 U-Net 作为去噪网络。它把带噪图像或 latent 输入网络,通过逐层下采样、上采样和跨层连接来预测去噪所需的信息。这样的网络并不只有卷积,很多扩散 U-Net 也会在部分分辨率下插入 attention,但整体上仍然沿用多尺度的编码、解码结构。
另一方面,Transformer 已经在语言和视觉任务上展示了较好的扩展能力。那么,对于扩散模型而言,U-Net 的这套结构究竟是不是必需的?能不能像 ViT 一样,把输入切成一组 patch,再交给一个结构相对统一的 Transformer 处理?
这个替换还有一个需要解决的问题:普通 ViT 主要根据图像内容提取特征,而扩散模型还必须知道当前处于哪个噪声时间步,以及希望生成什么内容。这些条件怎样进入 Transformer,会直接影响它的去噪效果。
所以,本文主要围绕两个问题展开:
- 如何设计一个适合条件扩散的 Transformer,尤其是如何注入时间步和类别条件;
- 当模型变深、变宽,或者输入的 token 变多时,生成效果怎样变化。
方法
从图像到 latent diffusion
DiT 沿用 Latent Diffusion Models 的框架。我们先看它处理的对象是什么。
设真实图像为 ,作者使用一个预训练的 VAE 将它编码成 latent :
其中, 和 分别是 VAE 的编码器和解码器。对一张 的 RGB 图像,本文使用的 VAE 会将其压缩成 的特征,也就是空间分辨率缩小到原来的八分之一。
之后,扩散过程就在这个较小的 latent 上进行。训练 DiT 时,VAE 保持冻结,模型学习的是这些 latent 的分布。生成时先得到一份新的 latent,再用 VAE Decoder 将它还原成图像。
这里的 latent 仍然有二维空间布局,每个位置包含若干通道的连续特征。它既不是单个全局向量,也不是离散的图像 token 编号。后面切 patch 时,切的就是这张二维特征图。
DiT的训练预测目标
作者沿用 DDPM 的加噪与去噪设定。给干净的 latent 加入高斯噪声,可以得到时间步 对应的输入:
这里 由预先设定的噪声时间表决定。简单地说,这个式子在控制干净信号和噪声的比例,模型根据 知道当前输入被破坏到了什么程度。
对类别条件生成,我们还会给模型一个标签 。DiT 的任务就是接收 、 和 ,预测其中的噪声,以及反向扩散分布所需的方差参数。反向过程可以写成:
其中,均值 可以由模型预测的噪声和已知噪声时间表计算出来; 则控制这一步反向采样的不确定性。也就是说,DiT 提供每一步去噪需要的信息,再由扩散采样器更新 latent。

右侧展示了另外两种条件注入方式。本文选择了
adaLN-Zero这种注入方式,后文会解释理由。
从 latent 到 token
现在我们有了一张带噪的 latent 特征图,要怎样把它交给 Transformer 呢?作者采用的方式和 ViT 很接近:切 patch,再做线性映射。
设 latent 的大小为 ,patch 大小为 ,那么它会被划分成:
个 patch。每个 patch 展平后有 个数,再通过线性层映射成一个 维 token。这里, 是 token 数量, 是 Transformer 的隐藏维度。
举个例子,对前面 的 latent,如果使用 ,我们就会得到 个 patch。每个 patch 包含 个数,这 16 个数经过同一个线性映射后,成为一个高维 token。在 DiT-XL 中,隐藏维度为 1152,所以输入形状的变化可以整理为:
这些 token 还会加上固定的二维正弦、余弦位置编码,告诉模型各个 patch 原本位于什么位置。之后,所有 token 进入一系列 DiT blocks,通过 self-attention 和前馈网络交换、更新信息。
这里的 self-attention 可以访问全部图像 token。在同一个扩散时间步中,模型会一起处理整张 latent,而不是按照从左到右的顺序逐个生成 patch。
对同一张 的 latent,不同 patch size 会产生不同长度的序列:
Latent patch size p Token 数量 N 8 16 4 64 2 256 可以看到,patch 边长减半,token 数量就会变成原来的四倍。模型因此会用更多 token 参与信息交互,但这并没有改变 latent 本身的分辨率。
从计算量来看,标准 Transformer block 中,线性投影和前馈网络大致包含 的开销,attention 中的位置对交互则包含 的开销。所以 token 变多时,计算量会明显增加;而主干的权重在不同 token 间共享,参数量不会随 token 数量同比增加。增加 token,是一种基本不增加主干参数、却能增加模型计算量的扩展方式。 后面的实验会专门比较这一点。
条件注入
我们已经知道 latent token 怎样产生,但只输入它们还不够。模型还要知道时间步 和类别标签 :前者告诉它当前的噪声状态,后者告诉它希望生成哪一类图像。
作者为时间步构造正弦、余弦 embedding,再通过 MLP 映射到隐藏维度;类别标签则通过一个可学习的 embedding 表得到向量。对于 adaLN 系列的 block,两者相加形成条件向量:
接下来,关键就是这个条件向量怎样影响图像 token。作者比较了四种设计:
| 条件注入方式 | 具体做法 |
|---|---|
| In-context conditioning | 将时间步和类别 embedding 作为两个额外 token,与图像 token 一起做 self-attention;最后移除这两个条件 token |
| Cross-attention | 将两个条件 embedding 组成独立序列,在 self-attention 之后增加一层 cross-attention,由图像 token 读取条件 |
| adaLN | 根据时间步与类别的组合条件,动态生成 LayerNorm 后的缩放、平移参数 |
| adaLN-Zero | 在 adaLN 基础上,再控制残差分支的输出幅度,并将 block 初始化为恒等映射 |
实验中效果最好的是 adaLN-Zero。下面重点介绍它怎样工作。
Adaptive LayerNorm(adaLN)
普通 LayerNorm 会对每个 token 的特征做归一化,再使用可学习的缩放和平移参数调节结果,这样的参数在训练完成后是固定的。而adaLN 的想法是在这些参数上做条件注入,我们可以将它表示为:
这里 是第 个 token 的特征, 和 是根据条件预测出来的两个 维向量, 表示逐元素相乘。对于同一个样本、同一个 block,这组条件参数会被广播到全部 token。
adaLN-Zero
Zero 指的是通过零初始化,使每个残差 block 从恒等映射开始训练,从而改善深层网络的优化。这是对于ResNet和扩散U-Net的做法的保留。
一个标准的残差更新可以写成 。如果训练开始时,残差分支 的贡献为零,那么这个 block 就先执行 ,随后再逐步学习怎样修改输入。作者将这种初始化方式用到了 DiT 中。
具体来说,每个 adaLN-Zero block 会根据条件向量 生成六个 维向量:attention 分支的缩放 、平移 和残差门控 ,以及前馈分支对应的 。一个 block 可以写成:
作者将生成这些调制参数的 MLP 的最后一个线性层初始化为零,因此两条残差分支暂时都不改变输入,整个 block 满足 。attention 和 FFN 的权重仍然采用正常初始化,并没有被全部置零。
从 token 恢复噪声预测
经过多个 DiT blocks 后,每个 token 仍然是一个 维特征。为了得到空间上的预测,作者在最后进行条件归一化,再用线性层将每个 token 映射成 个数。其中C个通道用于预测噪声,另外C个用于计算反向过程的方差。
至此,一次 DiT 前向计算就完成了:
其中 表示用于计算方差的输出参数。求出这两项之后就能得到最终的了,也就是完成一次去噪。
Note
读到这里,我们可能会产生疑问:难道模型不需要直接输出对于均值的预测?其实从DDPM的原理出发,已知噪声和方差,我们可以求出均值。公式如下:
这个式子的推导很关键,日后会做一篇文章出来单独记录和Diffusion Models有关的数学推导。
有了以上的这个公式,就可以推导出最后的的公式了:
训练
训练时,我们已经有真实图像,也知道它的类别,所以可以直接构造监督。具体过程为:
- 使用冻结的 VAE Encoder,将图像转换成 latent ;
- 随机采样时间步 和高斯噪声 ,按前面的加噪公式构造 ;
- 将 输入 DiT,得到噪声预测及方差参数;
- 根据预测和已知噪声计算损失,更新 DiT。
噪声预测使用均方误差:
这个监督很直接:噪声是我们自己加入的,所以它的真实值已知。对于协方差预测,作者沿用 Improved DDPM / ADM 的做法,使用变分目标中的对应项进行训练。官方实现计算这一项时,会对噪声预测部分停止梯度,方差预测则参与该项的优化。
实现细节:官方 PyTorch 训练代码从 VAE 的后验分布采样 latent,并乘以
0.18215进行缩放;最终送入 VAE Decoder 前再还原这个尺度。本文公式中的 可以理解为已经按该约定处理后的扩散输入。
此外,为了支持后面的 Classifier-Free Guidance(CFG),训练中会随机将一部分样本的类别标签替换为可学习的空条件 embedding。官方实现默认的类别丢弃概率为 10%。这样,同一个 DiT 既学会给定类别时怎样去噪,也学会没有类别条件时怎样去噪。
推理与 Classifier-Free Guidance
推理时没有真实图像,模型从高斯噪声 latent 开始生成。给定类别 ,在每个采样时间步,我们可以分别计算有类别条件和空条件下的噪声预测,再组合成:
其中 是 guidance scale。当 时,这个式子就是普通的有条件噪声预测;当 时,它沿着有条件与无条件预测的差异进一步外推,加强类别条件的作用。
整个生成过程可以整理为:
- 采样一张与目标 latent 同形状的高斯噪声 ;
- 在当前时间步输入 latent、时间步与类别条件,计算 DiT 的预测;
- 使用 CFG 组合噪声预测,并由噪声时间表和模型输出确定反向采样所需的均值、方差;
- 采样得到噪声更少的 latent,沿选定的时间步序列重复这一过程;
- 得到最终 latent 后,用 VAE Decoder 还原成图像。
本文训练采用 1000 个离散扩散时间步,主要的 FID 对比使用重采样时间表后的 250 步 DDPM 采样。模型每一步都处理全部 latent token,生成一张图仍然需要多次前向计算。
实验
数据与基本设定
作者在 ImageNet 上训练类别条件图像生成模型,分别生成 和 的图像。VAE 使用 Stable Diffusion 的预训练模型,DiT 本身从头训练。
为了分析扩展性,作者设置了四种模型规模。下面摘自原论文 Table 1;这一列 Gflops 的计算条件统一为 latent 大小 、patch size :
| 模型 | Block 数量 | 隐藏维度 | Attention heads | 单次前向 Gflops() |
|---|---|---|---|---|
| DiT-S | 12 | 384 | 6 | 1.4 |
| DiT-B | 12 | 768 | 12 | 5.6 |
| DiT-L | 24 | 1024 | 16 | 19.7 |
| DiT-XL | 28 | 1152 | 16 | 29.1 |
每种规模又分别使用 8、4、2 三种 patch size,共形成 12 个配置。例如,DiT-XL/2 就表示 XL 规模、latent patch size 为 2;在 图像生成中,它约有 6.75 亿参数,单次前向计算量为 118.6 Gflops。
所有配置使用相同的训练超参数:AdamW、固定学习率 、batch size 256、weight decay 为零,采用水平翻转作为数据增强,并使用衰减系数为 0.9999 的 EMA 参数进行评估。原论文的实验使用 JAX,在 TPU-v3 上训练;官方另外提供了 PyTorch 实现。
评价主要使用 FID-50K,也就是从模型中生成 50,000 张图像,在 Inception 特征空间比较生成数据与真实数据的分布差异,数值越低越好。论文还报告 IS、sFID 和 Precision / Recall 等指标。
条件注入:为什么选择 adaLN-Zero?
作者固定 XL/2 的主体规模,分别训练前面介绍的四种条件注入结构。原论文 Fig. 5 比较了它们训练到 400K,也就是 40 万步时的 FID 曲线。
结果中,adaLN-Zero 在各个评估阶段都优于 cross-attention 和 in-context conditioning,也明显优于普通 adaLN。在 40 万步时,它的 FID 约为 in-context 方案的一半。
计算量方面,adaLN 和 adaLN-Zero 都为 118.6 Gflops,in-context 为 119.4 Gflops,而 cross-attention 达到 137.6 Gflops。因此,adaLN-Zero 在这个比较里同时得到了更好的生成质量和较小的额外计算开销。
这组实验接回了前面的结构设计:条件怎样进入网络,以及残差分支从什么状态开始学习,都对最后的效果有明显影响。 后续的 scaling 实验因此统一采用 adaLN-Zero。
模型变大、token 变多,会发生什么?

上排固定 patch size,比较模型规模;下排固定模型规模,比较 patch size。
先固定 patch size,只增加 Transformer 的深度和宽度。图中可以看到,更大的模型在训练过程中通常能得到更低的 FID。再固定主干规模,将 patch size 从 8 减到 4、再减到 2,同样能得到明显改善。
后者尤其值得关注,因为它基本没有增加 Transformer 主干的参数,却增加了 token 数量与计算量。对这组模型来说,仅用参数量描述模型规模,并不足以说明它实际处理了多少信息交互。
作者进一步在原论文 Fig. 8 中,将 12 个配置在 40 万步时的 FID 与单次前向 Gflops 对照,观察到较强的负相关关系:即使深度、宽度和 patch size 的组合不同,计算量接近的模型也可能取得接近的 FID。
另外,固定训练步数并不等于固定训练成本。作者在 Fig. 9 中又按总训练计算量比较,估计方式为:
其中 是 batch size, 是训练步数,系数 3 将一次前向和近似为两次前向开销的反向传播合在一起。在论文考察的预算范围内,一些较大模型即使训练步数更少,也比训练更久的小模型更有效地利用计算量。
所以,扩展模型时需要一起考虑深度、宽度和 token 数,再看给定训练预算下的生成效果。这也是标题中 Scalable 所对应的主要实验内容。
最终生成效果
在确定结构之后,作者继续训练 DiT-XL/2。 模型训练到 7M,也就是 700 万步; 则单独训练了一个模型,训练到 3M 步。下面的最终成绩与前面 40 万步的消融、scaling 比较属于不同训练阶段。
下表选自原论文 Table 2,展示 ImageNet 下的结果:
| 方法 | CFG scale | FID-50K ↓ | Precision ↑ | Recall ↑ |
|---|---|---|---|---|
| LDM-4 | 不使用 | 10.56 | 0.71 | 0.62 |
| LDM-4-G | 1.50 | 3.60 | 0.87 | 0.48 |
| DiT-XL/2 | 不使用 | 9.62 | 0.67 | 0.67 |
| DiT-XL/2-G | 1.25 | 3.22 | 0.76 | 0.62 |
| DiT-XL/2-G | 1.50 | 2.27 | 0.83 | 0.57 |
DiT-XL/2 在 CFG scale 为 1.50 时取得 2.27 的 FID。表中同时可以看到,guidance 的作用很大:同一个模型在无 guidance 时的 FID 为 9.62;随着 guidance 增强,生成结果更集中于条件要求,Precision 提高,Recall 则下降。这对应生成样本质量与分布覆盖之间的取舍。
在 下,原论文 Table 3 中 DiT-XL/2-G 在相同 CFG scale 下的 FID 为 3.04,优于表中此前的扩散模型。不过该表中的 StyleGAN-XL 为 2.41,仍然更低,所以这一分辨率下的结论应限定为当时比较的扩散模型。
分辨率变化也能直接接回前面的 token 分析: 图像对应 的 latent,使用 时共有 1024 个 token,是 情况的四倍。同一 XL/2 配置的单次前向计算量因此从 118.6 增加到 524.6 Gflops。
小模型能不能靠多采样几步补回来?
扩散模型有一个特殊之处:训练完成后,还可以通过增加采样步数,让每张图像使用更多计算。那么,一个小 DiT 多去噪几次,能不能达到大模型的效果呢?
作者在原论文 Sec. 5.2 / Fig. 10 中,对训练了 40 万步的 12 个模型分别使用 16、32、64、128、256 和 1000 个采样步,比较 FID-10K 与采样计算量。
其中一个例子是,DiT-L/2 使用 1000 步时,每张图约需 80.7 Tflops,FID-10K 为 25.9;DiT-XL/2 使用 128 步时,每张图约需 15.2 Tflops,FID-10K 为 23.7。后者计算量约为前者的五分之一,生成效果却更好。
这个实验说明,在本文考察的模型和采样设置中,增加小模型的采样次数,并不能直接替代提高单步模型的能力。一次前向计算能做多好的去噪,同样影响最终结果。
核心点和不足
值得关注
这篇文章将图像扩散的去噪问题,整理成了一组空间 token 在时间步与类别条件下更新的问题。patchify 负责把 latent 接入 Transformer,adaLN-Zero 负责注入条件、组织残差更新,线性输出头再把 token 还原成去噪所需的空间预测。整体结构比较统一,也便于分别调整深度、宽度和 token 数。
它提出的一个有用视角是,生成模型的规模应结合实际计算方式来理解。两个参数量接近的模型,可以因为 patch size 不同而有完全不同的 token 数量、计算量和生成效果。进一步看,模型变大与采样步数变多,也是两种不同的计算投入,需要分别比较。
这也能帮助我们理解 Nexus 中的 DiT 模块:先把当前要生成的对象转换为 token,让时间步和任务条件参与特征更新,再将输出映射回目标表示。具体 token 可以来自图像 latent、八叉树的 occupancy pattern 或逐顶点特征;使用什么训练目标、怎样解读输出,则由各自的生成任务决定。
仍然存在的问题
首先,更小的 patch 会带来更长的序列。前面 到 的例子已经说明,即使模型的深度和宽度保持一致,token 数也会让计算量明显上升。对于更高分辨率的输入,怎样更有效地组织这些 token 的交互,仍然是需要继续处理的问题。
其次,latent diffusion 的结果也受预训练 VAE 的影响。DiT 学习的是编码后的分布,最终图像要经过 Decoder 还原;压缩过程中没有保留下来的细节,会对最终结果形成限制。
另外,本文主要验证的是 ImageNet 类别条件生成,时间步与类别可以组合成一个条件向量。若要处理文本描述、空间布局等更复杂的条件,还需要考虑怎样保留条件内部的多个信息单元,以及它们与图像 token 怎样交互。原论文也将文本到图像作为后续可以探索的方向。
总结
DiT 的主要过程可以归纳为:
- 将带噪 latent 切成 patch,并映射为带位置编码的 token;
- 用 adaLN-Zero 将时间步和类别条件注入 Transformer,更新全部 token;
- 将输出重新拼成噪声和方差参数,经过多步采样得到 latent,再用 VAE 解码成图像。
其核心是用一个接近标准 ViT 的结构完成条件去噪,并把扩展模型的途径分解为增加主干规模和增加 token 数量。
从这篇文章出发,可以继续读 Latent Diffusion,了解预训练 VAE 怎样建立这个连续图像空间;也可以回看 Improved DDPM / ADM 中的方差学习和条件归一化设计。之后再读使用 DiT 的工作,就可以重点追踪:它把什么对象做成了 token,条件怎样进入网络,以及训练目标和输出表示发生了什么变化。
参考
- William Peebles、Saining Xie:Scalable Diffusion Models with Transformers,方法与实验依据 arXiv v2。论文发表于 ICCV 2023。
- 作者项目页:文中两张配图来自该页面。
- 官方 PyTorch 实现:主要核对了 models.py、train.py 和 扩散损失实现。实验成绩采用论文数值。
- AI 协助生成初稿。




