第 14 讲 · 交叉注意力、扩散 Transformer 与 Prompt-to-Prompt · Cross-Attention, Diffusion Transformer & Prompt-to-Prompt

Generative AI · Lecture 14。个人学习讲义与配套实验,按主题整理并持续修订。

课程源码 ZIP ↓

个人整理的学习笔记,非官方讲义;课程来源与整理说明见课程介绍。配套示例未逐一运行验证。

本篇目录

对应 Maps to:CMU 10-423 / 10-623 / 10-723 Generative AI(Spring 2026;Matt Gormley、Aran Nayebi),Lecture 14 · Mon 9-Mar · Cross-Attention / Diffusion Transformer / Prompt-to-Prompt(slides:lecture14-ldm-dit-p2p)。 阅读材料:Rombach et al. (2022), High-Resolution Image Synthesis with Latent Diffusion Models(LDM);Ho & Salimans (2022), Classifier-Free Diffusion Guidance;Peebles & Xie (2023), Scalable Diffusion Models with Transformers(DiT);Hertz et al. (2022), Prompt-to-Prompt Image Editing with Cross Attention Control。 依据说明:本讲按原课第 14 讲公开的 slides 展开:条件图像生成的几类任务与图像编辑;LDM 回顾(自编码器、提示模型、潜空间里的 DDPM、“怎样让均值以提示为条件”);缩放点积注意力与交叉注意力(翻译的例子、LDM 里的交叉注意力、放在 U-Net 里的 Transformer 层);无分类器引导(动机、公式、算法 1、引导强度的例子);扩散 Transformer(时间线、ViT 回顾、DiT 结构、四种注入条件的方式与 adaLN-Zero、GFLOPs 与 FID、补丁大小、三条规模结论);Prompt-to-Prompt(固定种子与掩码编辑两种基线、关键想法、注意力替换的时机、形状不一致时的对齐、算法 1、几类编辑)。所有实验是本讲义自己设计的,不代表课堂上讲了什么。 配套代码 Code:code/lecture14/(5 个脚本 + 1 个模块;第一次运行要训练 9 个模型,01 约 9 分钟、03 约 17 分钟、04 约 15 分钟、05 约 16 分钟;之后都在 2–8 分钟) 预计阅读时间:3 小时(含运行代码)


0. 本讲导航 · How to read this lecture

0.1 学习目标 Learning goals

学完这一讲,你应该能够:

  1. 写出交叉注意力的公式,说清楚查询、键、值各来自哪里、注意力矩阵是什么形状、每一行是什么分布;说明它在 LDM 的去噪网络里放在哪里。
  2. 从贝叶斯公式推出无分类器引导 ϵ^=ϵ∅+w(ϵc−ϵ∅)\hat\epsilon = \epsilon_\varnothing + w(\epsilon_c - \epsilon_\varnothing),解释 w 为什么同时提高”听话程度”、降低多样性;说出训练时要做什么、采样时多花多少计算。
  3. 描述 DiT 的结构(patchify、adaLN-Zero、unpatchify),会算一个 DiT 的 GFLOPs,回答”补丁从 4 降到 2,计算量增加多少”。
  4. 说出 DiT 的三条规模结论,并能讲清楚我们的小实验复现了哪些、没复现哪些。
  5. 描述 Prompt-to-Prompt 的算法:为什么原提示和新提示要从同一个噪声出发、为什么只在前一段步数里替换注意力图、提示长度不同时怎样对齐;知道它成立的前提是什么。

0.2 先修与本讲范围 Prerequisites & scope

默认你已经会 Assumed本讲只给直觉,后面再展开 Previewed only
第 2 讲:缩放点积注意力、多头注意力视频扩散(第 25 讲)
第 5 讲:ViT;第 7、8 讲:DDPM、DDIM、预测噪声 ε真实图像的编辑(要先把真图”反演”成噪声:DDIM inversion、null-text inversion)
第 12 讲:带描述的形状世界、KL 自编码器、潜空间扩散Q-Former、规模定律(第 15 讲)

0.3 本讲地图 Map

§1  条件图像生成与"用文字编辑图像"
§2  LDM 回顾:怎样让去噪网络以提示为条件?
§3  交叉注意力                                                  ← 代码 01
§4  无分类器引导                                                ← 代码 02
§5  扩散 Transformer(DiT)                                     ← 代码 03、04
§6  Prompt-to-Prompt                                            ← 代码 05
§7–11  小结、误区、练习、延伸阅读、下一讲

本讲所有实验都在第 12 讲的带描述的形状世界里:每张 28×28 的图有形状、大小、上下、左右 4 个属性,描述有 4 种说法;图像先用第 12 讲的 KL 自编码器压成 4×7×7 的潜变量,扩散模型在潜空间里训练。训练时去掉 4 种属性组合,用来测”没见过的组合”。评估用两把尺子:用形状拟合读出 4 个属性、和描述比(听不听话),以及和真图比的 FD(像不像、多不多样)。


1. 条件图像生成 · Conditional image generation

slides 列了几类”有条件”的图像生成:按类别生成(“海葵""金翅雀”)、超分辨率、图像编辑、风格迁移、文生图。图像编辑本身又有好几种(Saharia et al., 2022):补全(inpainting:把指定的缺失像素填上)、上色(把灰度图还原成彩色)、扩图(uncropping:把图的一边”想象”出来)。

这一讲最终想做到的是 slides 第一页的那张图:只改提示,就能编辑一张生成的图——把一个词换成另一个(“猫”→“狗”),减弱某个描述词(“毛茸茸的”少一点),插入一个短语改风格(”……,炭笔画”)或改内容(”……,戴着帽子”)。要做到这些,先得搞清楚提示的每个词是怎样影响图像的每个部分的——这就是交叉注意力。


2. LDM 回顾:怎样让去噪网络以提示为条件 · Recall: LDM

第 12 讲的 LDM(Rombach et al., 2022)有三部分,分别活在三个”空间”里(slides 的图):

部分空间做什么训练方式
自编码器 E\mathcal E、D\mathcal D像素空间 ↔ 潜空间把 1024×1024 的图压成小得多的潜变量,再还原只用图像(不用提示)事先训练好、冻结;之后所有 LDM 都能复用
提示模型 τθ(y)\tau_\theta(y)提示空间“就是一个 Transformer”,把提示变成一串向量和扩散模型一起训练
去噪网络(U-Net)潜空间在 zT→z0z_T \to z_0 的反向过程里一步步去噪预测噪声 ε

前向过程和第 7 讲完全一样,只是 z0=E(x)z_0 = \mathcal E(x);反向过程多了一个条件:

pθ(z0:T)=p(zT)∏t=1Tpθ(zt−1∣zt,τθ(y)),pθ(zt−1∣zt,τθ(y))=N(μθ(zt,t,τθ(y)), Σθ(zt,t)).p_\theta(z_{0:T}) = p(z_T)\prod_{t=1}^{T}p_\theta(z_{t-1}\mid z_t, \tau_\theta(y)),\qquad p_\theta(z_{t-1}\mid z_t,\tau_\theta(y)) = \mathcal N\big(\mu_\theta(z_t, t, \tau_\theta(y)),\ \Sigma_\theta(z_t, t)\big).

slides 在这里停下来问:均值 μθ(zt,t,τθ(y))\mu_\theta(z_t, t, \tau_\theta(y)) 怎样”以提示为条件”? 按第 7 讲的选项 C,μθ\mu_\theta 由预测噪声的网络 ϵθ(zt,t,τθ(y))\epsilon_\theta(z_t, t, \tau_\theta(y)) 决定,所以问题变成:去噪网络怎样读提示?

第 12 讲用了最偷懒的办法:直接告诉网络 4 个属性的编号,各查一个嵌入、加起来,加到时间嵌入上(一个”词袋”)。它有两个问题:(1) 真实的提示是一句话,没人替你把它解析成”形状 = 圆、位置 = 左上”;(2) 一个整句的向量加到每个像素上,每个像素拿到的条件信息都一样——网络没法表达”这个词管图里这一块”。LDM 的答案是交叉注意力。


3. 交叉注意力 · Cross-attention

3.1 从自注意力到交叉注意力

回顾第 2 讲的缩放点积注意力:一个序列 x1,…,xnx_1,\ldots,x_n 自己和自己做注意力,qj=Wqxjq_j = W_q x_j、kj=Wkxjk_j = W_k x_j、vj=Wvxjv_j = W_v x_j,第 t 个位置的输出是 xt′=∑jat,jvjx'_t = \sum_j a_{t,j} v_j,at=softmax(st)a_t = \mathrm{softmax}(s_t),st,j=kj⊤qt/dks_{t,j} = k_j^\top q_t / \sqrt{d_k}。

交叉注意力只改一处:查询来自一个序列,键和值来自另一个序列(slides)。设 y1,…,yny_1,\ldots,y_n 是”提问”的一方,x1,…,xmx_1,\ldots,x_m 是”被看”的一方:

qt=Wqyt (t=1..n),kj=Wkxj,vj=Wvxj (j=1..m),yt′=∑j=1mat,jvj,at=softmax(kj⊤qt/d)j=1..m.q_t = W_q y_t\ (t = 1..n),\qquad k_j = W_k x_j,\quad v_j = W_v x_j\ (j = 1..m),\qquad y'_t = \sum_{j=1}^{m} a_{t,j} v_j,\quad a_t = \mathrm{softmax}\big(k_j^\top q_t/\sqrt d\big)_{j=1..m}.

写成矩阵:Q=YWq∈Rn×dQ = YW_q \in \mathbb R^{n\times d},K=XWk∈Rm×dK = XW_k \in \mathbb R^{m\times d},V=XWv∈Rm×dV = XW_v \in \mathbb R^{m\times d},

Y′=AV=softmax ⁣(QK⊤/d)V,A∈Rn×m.Y' = AV = \mathrm{softmax}\!\big(QK^\top/\sqrt d\big)V,\qquad A \in \mathbb R^{n\times m}.

n 和 m 可以不一样:AA 的每一行是”第 t 个查询在 m 个键上的概率分布”。slides 的翻译例子:把西班牙语 “estoy llegando tarde”(m = 3 个源语言词)翻成英语 “I am running late”(n = 4 个目标语言词)时,每个英语词的注意力是一个在 3 个西班牙语词上的分布——“late” 主要看 “tarde”。

3.2 LDM 里的交叉注意力

slides:在 LDM 里,

  • 查询矩阵来自 U-Net 的某一层(图像):nn 是潜空间的像素数(有压缩时)——如果没有压缩,就是图像的像素数;
  • 键 / 值矩阵来自提示编码器的输出(文字):mm 是提示的 token 数;
  • 一个(潜空间)像素的注意力权重,是它在提示的 token 上的一个概率分布;
  • 实际用的是多头的注意力和交叉注意力。

它被放在一个更大的 Transformer 层里,这个层插在 U-Net 的各个分辨率上(slides 引用的 LDM 论文图):自注意力(像素之间互相看)→ 交叉注意力(像素看提示)→ 前馈层,每个子层都有残差连接和层归一化。

直觉:交叉注意力让”条件”变成了逐像素的。图里画猫的那一块的像素,会更多地去看 “cat” 这个词、把 “cat” 的值向量加到自己身上;背景的像素可以看别的词。这也是第 6 节 Prompt-to-Prompt 的基础:注意力矩阵 AA 的第 j 列(reshape 成图的形状)就是”第 j 个词被画在了哪里”的一张热力图。

3.3 我们的缩小版(代码 01)

t2i_lab.CrossLDM:潜空间只有 7×7,不需要 U-Net 的上下采样,所以去噪网络是 4 个”卷积残差块 + 交叉注意力块”(49 个潜空间像素当查询);提示编码器是 2 层的小 Transformer(非因果),和去噪网络一起训练(和 LDM 论文一致;Stable Diffusion 用的是冻结的 CLIP 文字编码器)。每句提示前面加一个 <s>,补到 10 个位置。训练 8000 步(和第 12 讲的词袋模型一样),10% 的训练描述换成空提示(§4 要用)。共 338,628 个参数,其中提示编码器 102,016 个;一次前向 21.3 MFLOPs / 张。

手算一遍(第 1 部分):第 1 个交叉注意力层,一句提示 “a big square at the top right”:

量形状说明
Q=YWqQ = YW_q(Y:49 个潜空间像素)(1, 4, 49, 16)(批, 头, n = 49, dkd_k)
K=XWkK = XW_k(X:提示的 10 个位置)(1, 4, 10, 16)其中 2 个是 <pad>
A=softmax(QK⊤/dk)A = \mathrm{softmax}(QK^\top/\sqrt{d_k})(1, 4, 49, 10)每个头一张 n × m 的图
输出 AVWoAVW_o(1, 49, 64)回到图像一侧

手算和模块的输出最大相差 3.6e-07,AA 的每一行和都是 1.000000,<pad> 列的注意力是 0(被屏蔽)。中心像素 (3, 3) 在 8 个词上的注意力是 <s> 0.30、a 0.05、big 0.13、square 0.18、at 0.08、the 0.05、top 0.06、right 0.15;左上角的像素则是 0.12 / 0.17 / 0.16 / 0.09 / 0.14 / 0.11 / 0.07 / 0.14——两个像素看提示的方式不一样,这正是”逐像素的条件”。

一句话 + 交叉注意力 vs 词袋(第 2 部分,400 张测试图,不加引导):

条件形状大小上下左右4 个全对FD↓
第 12 讲:4 个属性编号的嵌入之和(词袋)0.7150.8500.8750.8970.48837.68
交叉注意力,说法 0 “a big square at the top right”0.7280.8370.8200.8170.44238.87
交叉注意力,说法 1 “a square , big , top right”0.7150.8370.8250.8150.43538.02
交叉注意力,说法 2 “the square is big and at the top right”0.7230.8320.8270.8200.44238.75
交叉注意力,说法 3 “top right : a big square”0.7100.8220.8220.8220.43337.73
交叉注意力,说法 0,无分类器引导 w = 3(§4)0.9130.9800.9981.0000.90219.70
  • 不加引导时,交叉注意力(0.442)略输给词袋(0.488)。这不奇怪:词袋直接拿到了 4 个属性的编号,相当于有人替它把句子解析好了;交叉注意力要自己从一句话里找出哪个词是形状、哪个是位置。
  • 4 种说法的结果几乎一样(0.433–0.442):提示编码器把词序完全不同的句子读成了同样的意思——这是词袋做不到的(它根本不读句子)。
  • 加上 §4 的无分类器引导,4 个全对从 0.442 跳到 0.902。
  • 没见过的 4 种组合(每种 50 张):交叉注意力平均 0.40、加引导 0.84、词袋 0.47。最难的是 “a small cross at the top right”:0.16 → 0.88。

3.4 交叉注意力图:每个词”被哪些像素看”

第 3 部分把 200 张图(说法 0,引导 w = 3)采样时的交叉注意力记下来,对所有层、所有头、所有步取平均,得到每张图一个 49 × 10 的矩阵。再用形状拟合找出每张图里”物体占了哪些潜空间像素”(平均占 18.2%,约 8.9 个像素)。如果一个词的注意力均匀地来自所有像素,那么它的注意力里”来自物体像素的份额”就等于物体的面积,比值 = 1;比值越大,这个词越是”被物体上的像素看”。

词的位置平均注意力(一行里分到的份额)来自物体像素的份额比值
<s>0.1290.1851.00
a0.2070.1580.85
(大小)0.1480.1931.07
(形状)0.0800.2601.44
at0.1320.1780.99
the0.1130.1650.91
(上下)0.0830.1841.00
(左右)0.1070.1750.96
  • 形状词的注意力集中在物体上(比值 1.44):像素在物体上时,更多地去看”自己该画成什么形状”。代码打印的例子里(“a big square at the top right”),形状词的 7×7 注意力图最亮的地方正是右上角的方块。
  • 位置词的比值接近 1:每个像素都要知道物体在哪——背景像素也要知道”这里不该画”——所以大家都看它们。
  • 形状词的比值在去噪过程中从 1.05(前 1/3 步,噪声最大)→ 1.40 → 1.69(最后 1/3 步):一开始图里还没有物体,注意力无处可”聚”;物体成形以后,注意力才落到物体上。

小结:交叉注意力图确实带着”哪个词管哪一块”的信息,但在我们的小模型里只是”轻微地集中”(1.44 倍)。§6 会看到,这一点决定了 Prompt-to-Prompt 在我们这里能做什么、不能做什么。


4. 无分类器引导 · Classifier-free guidance

4.1 动机

slides:扩散模型(不像 GAN)很擅长生成多样的样本;但当它以某个输入(文字、类别……)为条件时,这种多样性可能让它偏离提示。§3.3 的表格就是例子:不加引导时,只有 44% 的图 4 个属性全对。无分类器引导(classifier-free guidance,CFG;Ho & Salimans, 2022)让扩散模型更贴近提示,图的质量也更高。

4.2 推导

想要的是”更像 c 的那些图”:除了 p(z)p(z) 本身,再按”一个分类器有多确定这张图是 c”加权。贝叶斯公式:

log⁡p(c∣z)=log⁡p(z∣c)−log⁡p(z)+log⁡p(c)⟹∇zlog⁡p(c∣z)=∇zlog⁡p(z∣c)−∇zlog⁡p(z).\log p(c\mid z) = \log p(z\mid c) - \log p(z) + \log p(c) \quad\Longrightarrow\quad \nabla_z \log p(c\mid z) = \nabla_z\log p(z\mid c) - \nabla_z \log p(z).

把目标分布取成 p~(z∣c)∝p(z) p(c∣z)w\tilde p(z\mid c) \propto p(z)\,p(c\mid z)^w(w 越大,越偏向分类器有把握的图),它的得分函数(score,对数密度的梯度)是

∇zlog⁡p~(z∣c)=∇zlog⁡p(z)+w(∇zlog⁡p(z∣c)−∇zlog⁡p(z)).\nabla_z\log\tilde p(z\mid c) = \nabla_z\log p(z) + w\big(\nabla_z\log p(z\mid c) - \nabla_z\log p(z)\big).

第 8 讲讲过,预测噪声的网络和得分函数只差一个系数:ϵθ(zt,t,c)≈−1−αˉt ∇ztlog⁡pt(zt∣c)\epsilon_\theta(z_t, t, c) \approx -\sqrt{1-\bar\alpha_t}\,\nabla_{z_t}\log p_t(z_t\mid c)。两边乘上 −1−αˉt-\sqrt{1-\bar\alpha_t},就得到 slides 的公式:

 ϵ^=ϵθ(zt,t,∅)+w⋅(ϵθ(zt,t,c)−ϵθ(zt,t,∅)) \boxed{\ \hat\epsilon = \epsilon_\theta(z_t, t, \varnothing) + w\cdot\big(\epsilon_\theta(z_t, t, c) - \epsilon_\theta(z_t, t, \varnothing)\big)\ }
  • ϵθ(zt,t,∅)\epsilon_\theta(z_t, t, \varnothing) 是”没有条件”时的预测,代表 log⁡p(z)\log p(z);它和有条件的预测用同一个网络、同一组参数,只是把提示换成一个”空”的嵌入 ∅。训练时以一定概率(我们用 10%)把提示换成空提示,网络就同时学会了两种预测。
  • “无分类器”:两者之差 ϵc−ϵ∅\epsilon_c - \epsilon_\varnothing 就是一个”隐式分类器”的梯度。之前的 classifier guidance(Dhariwal & Nichol, 2021)要另外训练一个能认带噪声图的分类器 pϕ(c∣zt)p_\phi(c\mid z_t),再用它的梯度;CFG 不需要它。
  • w = 1 是普通的条件采样;w > 1 沿”有条件减去无条件”的方向外推,p(c∣z)p(c\mid z) 更高、多样性更低;w = 0 只用无条件的预测。
  • 两种写法:slides 的算法 1 写的是 ϵ^=(1+w′)ϵc−w′ϵ∅\hat\epsilon = (1+w')\epsilon_c - w'\epsilon_\varnothing,示例里 w′=7.5w' = 7.5。展开一下就是 ϵ∅+(1+w′)(ϵc−ϵ∅)\epsilon_\varnothing + (1+w')(\epsilon_c - \epsilon_\varnothing),所以 w=1+w′w = 1 + w':w′=0w' = 0 是普通采样,w′=7.5w' = 7.5 对应这里的 w=8.5w = 8.5。而 Stable Diffusion(diffusers 库)的 guidance_scale = 7.5 用的是上面方框里的写法,就是这里的 w=7.5w = 7.5。两种写法差 1,读论文和代码时要看清是哪一种。代码 02 第 1 部分数值核对:两种写法最大相差 1.7e-06(float32 的舍入)。
  • 代价:每一步要算两次去噪网络(有提示、空提示,拼成一个两倍大的批)。我们实测带引导采一张图约 42 ms、不带约 21 ms(⏱)。

slides 引用的 CFG 论文图:引导强度从 w = 0 增加到 w = 3,同一个类别的样本越来越”典型”、越来越像。

4.3 我们的实验(代码 02)

主模型(§3.3),400 张测试图,说法 0;多样性用 20 句提示 × 每句 20 张,量同一句提示的图里形状拟合出的中心坐标和半径的标准差(像素)。

w形状大小上下左右4 个全对FD↓x 散布y 散布半径散布
0(只用无条件)0.2620.5600.4800.5100.04360.473.843.721.10
1(普通采样)0.7280.8370.8200.8170.44238.872.892.850.74
1.50.8580.9400.9300.9250.71217.302.372.300.59
20.9020.9830.9780.9850.86311.571.931.940.46
30.9130.9800.9981.0000.90219.701.511.660.40
50.9300.9671.0001.0000.92543.621.241.340.41
80.9280.9600.9950.9980.91072.971.351.520.49
120.9080.9550.9880.9900.868118.911.621.840.53
(真实数据)——————2.052.010.58
  • w = 0:4 个全对 0.043,和随便画差不多(瞎猜是 1/32 ≈ 0.031)——同一个网络也学会了无条件生成,FD 60.47。
  • 听话程度先升后平:w = 2 时已经 0.863,w = 5 时最高(0.925),再大反而略降。
  • FD 是 U 形:w = 2 最好(11.57),w = 12 时 118.91。适度的引导让图更像真图(不听话的图本身就是”不像真图”的一种);太强时 ϵ^\hat\epsilon 被外推到训练时从没见过的地方,图开始变形。
  • 多样性:不加引导时同一句提示的散布(2.89 / 2.85 / 0.74)比真实数据还大(2.05 / 2.01 / 0.58)——有些图根本没按提示画,散得比真图还开。w = 2 时最接近真实数据,w = 5 时最小(1.24 / 1.34 / 0.41):同一句提示画出来的图越来越像同一张,正是 slides 说的”w 越大,p(c∣z)p(c\mid z) 越高、多样性越低”。w 再往上散布又变大,这时图本身开始变形(FD 也很差),拟合出的位置和半径跟着乱。
  • 没见过的组合(每种 50 张):w = 1 / 3 / 8 时平均 0.40 / 0.84 / 0.87。引导对没见过的组合同样有效——它放大的是每个属性词各自的作用,不需要见过这个组合。

怎样选 w:FD 最好的 w(2)和”最听话”的 w(5)不是同一个。实践里也一样:Stable Diffusion 默认 guidance_scale = 7.5(我们的 w = 7.5),偏向听话;想要多样一点就调小。


5. 扩散 Transformer · Diffusion Transformer (DiT)

5.1 时间线

slides 的时间线:U-Net 2015 年为医学图像分割提出;2016–2018 年各种 U-Net 变体在像素级的自回归模型、条件 GAN 里很好用(PixelCNN++ 定下了标准的变体);2020 年 Ho et al. 用它做 DDPM;2021 年 Dhariwal & Nichol 加上 Transformer 块的注意力;2022–2023 年大家都继续用 U-Net,“因为它好用”;2023 年 5 月,扩散 Transformer 表明我们其实不需要 U-Net。

5.2 结构

回顾 ViT(第 5 讲):和 BERT 几乎一样,只是输入换成不重叠的 P×P 图像块(P ∈ {14, 16, 32}),每块线性嵌入成一个向量,加一维的位置嵌入。

DiT(slides)的主干基本就是一个 ViT,加了一点改动:

  • 输入:带噪声的潜变量(切成块)、时间步 t、标签(或其他条件信息);
  • 输出:噪声的预测(DiT 原文还预测协方差,大小都固定);
  • 最后一层 LayerNorm 之后,一个线性层把 T 个 token 的嵌入变回固定形状的输出(unpatchify)。
z_t (4×32×32) ──patchify(P)──▶ T = (32/P)² 个 token ──线性嵌入 + 二维正弦位置编码──▶ N 个 DiT 块 ──▶ LayerNorm ──▶ 线性 ──unpatchify──▶ ε̂
                                                                        ▲
                                              条件 c = 时间嵌入 + 标签(文字)嵌入(注入每个块)

我们的实现 t2i_lab.DiT:潜空间 4×7×7、块大小 1(49 个 token),d = 64、4 层;条件 c = 时间嵌入(经过一个 MLP)+ 整句提示的向量(提示编码器输出的平均)。

5.3 怎样把条件注入每个块:adaLN-Zero

slides:“DiT 块里有意思的地方是怎样以标签为条件”。原论文试了四种:

  1. 上下文拼接(in-context):把条件当作额外的 token 拼在序列后面,用普通的 Transformer 块(就像 ViT 的 [CLS]);
  2. 交叉注意力块:普通块里多一层交叉注意力,键和值是条件 token(§3);
  3. 自适应 LayerNorm(adaLN):LayerNorm 不带自己的缩放 γ、平移 β,改由一个 MLP 从 c 回归出来:adaLN(h)=LN(h)⋅(1+γ(c))+β(c)\mathrm{adaLN}(h) = \mathrm{LN}(h)\cdot(1+\gamma(c)) + \beta(c);
  4. adaLN-Zero:adaLN 再加上残差连接前的两个”门”:h←h+α1(c)⋅Attn(adaLN1(h))h \leftarrow h + \alpha_1(c)\cdot\mathrm{Attn}(\mathrm{adaLN}_1(h)),h←h+α2(c)⋅FFN(adaLN2(h))h \leftarrow h + \alpha_2(c)\cdot\mathrm{FFN}(\mathrm{adaLN}_2(h));回归 γ、β、α 的线性层初始化为全 0。

slides:“adaLN-Zero 在实验里最好;关键是学一个 MLP,输出 LayerNorm 和残差连接的缩放、平移参数”。

为什么零初始化有用:一开始 α = 0,每个块都是恒等映射(h+0h + 0),整个网络从”什么都不做”开始学——深的残差网络在训练初期不会被随机初始化的块”搅乱”。这和第 10 讲 LoRA 的 B = 0、adapter 的 Wup=0W_{\text{up}} = 0 是同一个道理。DiT 还把最后一层的调制和输出层也初始化为 0,所以一开始预测的 ε 就是 0。

代码 03 第 1 部分核对了这一点:刚初始化时,adaLN-Zero 的第 1 个块对输入的改变是 0.00,整个网络输出的 ϵ^\hat\epsilon 也是 0.00;其余三种方式第 1 个块就把输入改了 0.86–1.00、输出 ϵ^\hat\epsilon 的最大绝对值 1.73–1.88。

四种方式各训练 4000 步(第 2 部分,d = 64,4 层;400 张测试图):

注入条件的方式参数MFLOPs / 张最后 200 步的损失4 个全对(w = 1)4 个全对(w = 3)FD(w = 3)
上下文拼接319,30029.50.07900.3550.56249.71
交叉注意力386,37228.40.07680.4070.60024.73
adaLN393,02824.00.07730.3520.58045.21
adaLN-Zero426,30824.00.07520.3750.54527.32
  • 损失上 adaLN-Zero 最低,和论文一致;但听话程度上交叉注意力最好,adaLN-Zero 反而最低——四种方式之间最多只差 0.055,在我们这个小模型、4000 步的训练里,差别不大,排序也不稳定。论文的结论来自大得多的模型和 40 万步的训练。
  • 计算量:adaLN 两种方式每张图 24.0 MFLOPs;上下文拼接 29.5(序列从 49 个 token 变长了);交叉注意力 28.4(每层多一个注意力)。adaLN 只多了几个从条件回归 γ、β、α 的线性层,几乎不增加计算——论文选它的另一个原因。
  • 交叉注意力对文字条件很自然(一个词一个键);adaLN 只能吃一个整句的向量。实际的文生图 DiT(如 PixArt-α)用 adaLN 注入时间、用交叉注意力注入文字。

5.4 GFLOPs、FID 与补丁大小

GFLOPs(slides):一种与硬件无关的计算代价的度量。一次 FLOP 是一次浮点运算(一次加法、一次乘法);1 GFLOP = 10910^9 FLOPs;GFLOPs 衡量模型做一次前向传播(或生成一张图)要多少计算。FID(第 6 讲):真图和生成图都过一个预训练的 Inception-v3,取中间层特征,各拟合一个多元高斯,算两个高斯的 Fréchet 距离——越小越好。我们用的 FD 是同一个公式,只是特征来自第 6 讲的”形状裁判”网络。

补丁大小:减小 DiT 的补丁大小 P 会增加 GFLOPs,但不增加参数量(只有输入嵌入层和输出层随 P2P^2 变)。所以 DiT 研究的是 FID 和 GFLOPs 的关系,而不是 FID 和参数量的关系。

slides 的问题:补丁从 p = 4 降到 p = 2,总计算量增加多少? 自己算一遍:一个 Transformer 块,T 个 token、宽度 d(前馈层 4d):

FLOPs/块≈2T⋅(4d2+8d2)⏟Q、K、V、O 四个投影 + 前馈层的两个矩阵+2⋅2T2d⏟QK⊤ 和 AV=24Td2+4T2d.\text{FLOPs/块} \approx \underbrace{2T\cdot(4d^2 + 8d^2)}_{\text{Q、K、V、O 四个投影 + 前馈层的两个矩阵}} + \underbrace{2\cdot 2T^2 d}_{QK^\top \text{ 和 } AV} = 24Td^2 + 4T^2d .

p 减半 → T 变成 4 倍:线性部分 × 4,注意力部分 × 16,合起来比 4 倍多一点。代码 04 第 1 部分在 28×28 的像素空间里实测(d = 64,4 层):

补丁token 数参数MFLOPs / 张每个训练步(批 64,⏱)
p = 716432,1139.021 ms
p = 449427,85624.239 ms
p = 2196426,308118.9169 ms

p = 4 → 2 计算量是 4.9 倍(公式:24⋅196⋅642+4⋅1962⋅6424\cdot196\cdot64^2 + 4\cdot196^2\cdot64 每块 ≈ 29.1 M,4 块 116 M,加上嵌入和 adaLN ≈ 119 M ✓),参数量几乎没变。slides 的数字:DiT-XL/2 是 118.6 GFLOPs。

为什么我们只量计算、不比较补丁大小的生成质量:DiT 原文在 32×32×4 的潜空间上用 p = 2 / 4 / 8;我们的潜空间只有 7×7(7 是质数,只能 p = 1)。像素空间可以切 p = 7 / 4 / 2,但我们试过:像素空间的 DiT 训练 3000 步,连”位置”都学不会(准确率约 0.5,等于瞎猜),比较就没有意义了——这本身也是”潜空间扩散省事”的又一个例子(README)。质量随计算量的变化,我们改用模型宽度来做。

5.5 DiT 的规模结论

slides 的三条结论:

  1. GFLOPs 和 FID 强相关:增加 GFLOPs,FID 就更好;
  2. 大模型在训练时更”省计算”:同样的训练计算量,大 DiT 在测试时比小 DiT 好;
  3. DiT 在差不多的计算量下打败了 U-Net 主干的 LDM:LDM-4(103.6 GFLOPs)vs DiT-XL/2(118.6 GFLOPs)。

代码 04 第 2 部分:潜空间里把 DiT 的宽度从 32 加到 128(深度 4、adaLN-Zero),各训练 4000 步,每 1000 步存一份 EMA 快照,引导 w = 3 评估。训练计算量 ≈ 3 × 每张图的前向 FLOPs × 批大小 64 × 步数(反向传播约是前向的 2 倍)。

模型参数MFLOPs / 张1000 步2000 步3000 步4000 步4000 步的 FD
d = 32186,3408.20.0700.1230.1550.410154.95
d = 64426,30824.00.0930.3500.5430.54527.32
d = 96821,92449.70.1800.5720.6230.67026.14
d = 1281,373,18885.00.4520.5620.6270.79814.31

(中间几列是 4 个属性全对的比例。)

  • 结论 1 复现了:训练 4000 步后,GFLOPs 和”4 个全对”的斯皮尔曼秩相关是 +1.00,和”FD 越小越好”也是 +1.00——宽度每加一档,生成就更好。
  • 结论 2 没有复现:把计算量相差不到 35% 的快照配成对(共 9 对),大模型只赢了 1 对。例如 d = 128 训练 3000 步(0.049 PFLOPs)是 0.627,d = 96 训练 4000 步(0.038 PFLOPs)是 0.670;d = 128 训练 1000 步(0.016 PFLOPs)是 0.452,d = 64 训练 3000 步(0.014 PFLOPs)是 0.543。我们的模型和训练都太短:早期的快照还在快速下降的阶段(EMA 也有滞后),大模型还没进入”省计算”的区间。
  • 结论 3(代码 03 第 3 部分):DiT adaLN-Zero 训练 4000 步(0.018 PFLOPs)4 个全对 0.545、FD 27.32;卷积 + 交叉注意力的主模型在同样 4000 步的快照(0.016 PFLOPs)是 0.398、FD 55.48——同样的计算量下 DiT 更好,和 slides 一致。主模型训练满 8000 步(0.033 PFLOPs)是 0.902、FD 19.70。

6. Prompt-to-Prompt

6.1 两种基线

slides 先给两种已有的”用文字编辑图像”的做法:

  • 固定随机种子:改一部分提示、保持随机种子(扩散的起点噪声)不变,再跑一遍采样器。问题:整张图的结构可能大变——背景、整个蛋糕还是一块、画面里有多少蛋糕都不一样了。这不像”编辑”,更像”生成一张无关的图”。
  • 带掩码的编辑(例如 Blended Diffusion):用户画一个掩码,指定哪部分不变,再用文字提示告诉扩散模型怎样改没被遮住的部分。构图保持住了,但要用户画掩码。

6.2 关键想法

Prompt-to-Prompt(Hertz et al., 2022):只用文字、不要掩码。

  • 拿一个预训练好的 LDM;
  • 用原提示 y 跑一遍扩散,记下交叉注意力权重(从像素到文字);
  • 用新提示 y* 再跑一遍,但(小心地)把原来那一轮的交叉注意力权重抄进来;
  • 怎样抄,取决于编辑的类型;
  • 只有推理,没有训练:只改了从预训练模型采样的方式。

slides 的步骤:

  1. 编码原提示 y;
  2. 在 y 上跑扩散,得到每一步的注意力权重 AT−1,…,A1A_{T-1},\ldots,A_1;
  3. 编码新提示 y*;
  4. 再跑一遍扩散:(a) 复用原来那一轮的噪声 zTz_T;(b) 在时间步 τ 之前,用原来那一轮的注意力权重 AT−1,…,AτA_{T-1},\ldots,A_\tau;(c) 之后换成这一轮自己的 Aτ−1∗,…,A1∗A^*_{\tau-1},\ldots,A^*_1;(d) 不论用哪一份注意力权重,乘的都是 y 的值*(attend to y*);
  5. 在潜空间里的话,用解码器还原成像素。

论文的算法 1:zT∼N(0,I)z_T \sim \mathcal N(0, I),zT∗←zTz^*_T \leftarrow z_T;每一步 zt−1,At←DM(zt,y,t)z_{t-1}, A_t \leftarrow DM(z_t, y, t),At∗←DM(zt∗,y∗,t)A^*_t \leftarrow DM(z^*_t, y^*, t),A^t←Edit(At,At∗,t)\hat A_t \leftarrow \mathrm{Edit}(A_t, A^*_t, t),zt−1∗←DM(zt∗,y∗,t){A←A^t}z^*_{t-1} \leftarrow DM(z^*_t, y^*, t)\{A \leftarrow \hat A_t\};其中

Edit(At,At∗,t)={At∗t<τAt其他\mathrm{Edit}(A_t, A^*_t, t) = \begin{cases} A^*_t & t < \tau \\ A_t & \text{其他} \end{cases}

(t 从 T 往下数,所以”其他”是前面噪声大的那些步。)两次去噪在同一个批里同步进行,所以不需要先存下所有的 AtA_t。

6.3 为什么先用一阵原来的注意力图?

slides 的问题。答案:去噪的前几步(噪声大)决定图的构图——东西画在哪、多大;后几步只是补细节。前几步用原来的注意力图,等于强制新图”在原来的地方画东西”,构图就和原图一样;后几步换成新的注意力图,新词的细节(新形状的轮廓、新纹理)才长得出来。τ 越晚,越像原图;τ 太晚,新词就画不出来。slides 引用的论文图正是”改变替换的时刻”:越晚替换,越像原图。

6.4 形状不一致时:对齐

slides:如果 AtA_t 和 At∗A^*_t 形状不一样怎么办?只替换对应的部分:

  • 潜空间那一维永远不变(例如 1024 个像素);
  • 如果用固定长度的文字编码器(CLIP 补到 77 个 token),提示那一维也不变;
  • 但词可能对不齐:把 “orange” 换成 “big tabby” 时,后面的 “cat sitting” 都往后挪了一位。做法:把原来 “orange” 那一列的注意力抄给 “big” 和 “tabby” 两列,其余的词按对应关系抄。

我们的 t2i_lab.align_tokens 用 difflib 求两句话的对齐(代码 05 第 1 部分):

原提示新提示新提示每个词的注意力从哪里来
orange cat sittingbig tabby cat sitting<s>←<s>、big←orange、tabby←orange、cat←cat、sitting←sitting
a big circle at the top lefta big square at the top leftsquare←circle,其余一一对应
a circlea big circlebig←新(插入的词用它自己的注意力),其余一一对应

6.5 其他编辑

slides:P2P 不只换词,不同的编辑靠不同的方式操纵交叉注意力:换一个词(如上);减弱 / 加强一个描述词(把这个词那一列的注意力乘以一个系数 c);插入一个短语改风格或内容(新词用自己的注意力,原有的词抄原来的注意力)。

6.6 我们的实验(代码 05)

所有编辑都带引导(w = 3)。量三件事:新形状画对了吗;大小、象限保住了吗;中心和半径移动了多少像素(形状拟合)。另外放一个只用推理的对照:“共享前几步的轨迹”——前 k% 的步数两边都用原提示去噪(轨迹完全相同),之后第二行才换成新提示。它直接检验”构图是不是在前几步定下来的”。

完整的描述,换形状词(主模型,200 句提示):

做法新形状画对大小没变象限没变中心移动(像素)半径变化
固定种子、只换提示(基线)0.9050.9650.9901.280.64
P2P:前 40% 的步数用原注意力图0.9000.9650.9951.230.59
P2P:前 60%0.9100.9550.9951.100.56
P2P:前 80%0.8600.9600.9950.970.55
P2P:前 100%0.4550.9050.9950.860.73
对照:前 60% 的步数两边都用原提示0.8800.9750.9950.840.42
  • 描述已经把大小和位置写死了,所以固定种子的基线就几乎保住了构图(象限 0.990、大小 0.965、中心只移动 1.28 像素)——slides 说的那个问题,在”提示把一切都说清楚”的情况下本来就不大。
  • P2P 注入得越久,中心移动得越少(1.28 → 0.86 像素);但注入全部步数时新形状只画对了 0.455(基线 0.905):原图的注意力图带着原来形状的轮廓——哪些像素在”看形状词”,本身就勾勒出了一个圆或一个方块——抄得太久,新形状就长不出来。这正是 P2P 只在前 τ 步注入的原因(§6.3)。
  • 共享前 60% 的轨迹:移动更少(0.84 像素),新形状照样画对 0.880。

只说形状的提示(“a circle” → “a square”):构图完全由噪声决定,这才是 slides 说的情形。主模型从没见过这么短的提示,所以用一个一半训练描述不完整的对照模型(partial_caption:形状一定说,大小、上下、左右各以 1/2 的概率说;其余配置和主模型相同)。它在完整描述上同样听话(4 个全对 0.830,主模型 0.880)。

做法新形状画对大小没变象限没变中心移动(像素)
固定种子、只换提示(基线)0.9200.5200.6953.13
P2P:前 20%0.9150.5400.7002.97
P2P:前 60%0.8950.5850.7052.87
P2P:前 100%0.4800.5700.7202.47
对照:前 20% 的步数两边都用原提示0.9150.5700.7502.71
对照:前 40%0.8600.7100.7902.14
对照:前 60%0.7550.8300.8701.06
  • 基线的问题现在很明显:只换一个词,30% 的图换了象限、大小保住的只有 0.520(≈ 随机),中心平均移动 3.13 像素——“整张图的结构可能大变”。
  • P2P 几乎没有帮助:象限保住的比例最多从 0.695 升到 0.720,而那时新形状只画对了 0.480。
  • 共享轨迹有帮助:前 60% 的步数共享,象限保住 0.870、大小 0.830(代价是新形状画对的比例降到 0.755)。

为什么在我们这里 P2P 不灵? P2P 成立的前提是:“哪个词画在哪里”由交叉注意力图决定,所以抄注意力图就等于抄构图。§3.4 量过:我们的形状词的注意力只是轻微地集中在物体上(1.44 倍),位置词的注意力均匀地分给所有像素;去噪网络的卷积主干从同一个噪声里就能决定”把东西画在哪”,构图活在潜变量的去噪轨迹里,而不在注意力图里。P2P 论文用的 Imagen、Stable Diffusion 不一样:它们在 64×64、32×32、16×16 等多个分辨率上都有交叉注意力,名词的注意力图非常集中(P2P 论文画出了 “a furry bear watching a bird” 里每个词的平均注意力图,“bear""bird” 的图几乎就是物体的掩码)。一个方法在大模型上有效,不等于它的前提在小模型上也成立——这是本讲最值得记住的”负结果”。

还有一个细节(slides 的”为什么先用原注意力图一阵”):线性噪声调度下,DDIM 50 步的前 40% 步里 αˉt<0.03\bar\alpha_t < 0.03,图几乎还是纯噪声;构图要到中段才定下来,所以”共享前 20%“几乎没用,要共享到 60% 才明显。

注意力重新加权(第 4 部分,每行 100 张图):

提示里的词 × c× 0× 0.5× 1× 2× 4
“big”:平均半径(像素)7.017.207.427.858.58
“small”:平均半径6.385.645.064.224.00
“small”:形状画对0.880.880.880.750.24
形状词:形状画对0.260.670.910.960.85
  • c 像一个旋钮:把 “big” 的注意力乘 0 → 4,平均半径 7.01 → 8.58;把 “small” 乘 0 → 4,半径 6.38 → 4.00。c = 0 等于把这个词删掉(半径回到”没说大小”的平均),c > 1 比原词更”大”或更”小”。c 太大时形状会被破坏(“small” × 4 时形状只画对 0.24)。
  • 把形状词的注意力乘 0,形状就退回瞎猜(0.26 ≈ 1/4):形状的信息确实是**经由”看这个词”**进来的。
  • 这一类编辑在我们的模型里很好用,因为它改的是”这个词的内容有多少流进图里”,不依赖”注意力图决定构图”这个前提。

7. 小结 · Summary

  1. 交叉注意力:查询来自图像(U-Net 的当前层,n 个潜空间像素),键和值来自提示(m 个 token);A∈Rn×mA \in \mathbb R^{n\times m} 的每一行是一个像素在提示的词上的分布。它让条件变成逐像素的。
  2. 无分类器引导:ϵ^=ϵ∅+w(ϵc−ϵ∅)\hat\epsilon = \epsilon_\varnothing + w(\epsilon_c - \epsilon_\varnothing),来自 p(z)p(c∣z)wp(z)p(c\mid z)^w 的得分函数;训练时以 10% 左右的概率丢掉提示,采样时多算一倍。w 增大 → 更听话、更不多样;FD 是 U 形的。
  3. DiT:ViT 式的主干 + adaLN-Zero 注入条件(零初始化让每个块从恒等映射开始);补丁越小 GFLOPs 越大、参数不变;GFLOPs 和生成质量强相关。
  4. Prompt-to-Prompt:同一个噪声、同一个批里,原提示和新提示一起去噪,前 τ 步把新提示的交叉注意力图换成原来的;提示长度不同时按词对齐。它依赖”注意力图决定构图”这个前提。
  5. 我们的小实验:交叉注意力 + 引导让 4 个属性全对从 0.442 到 0.902;DiT 在同样计算量下比卷积主干好、宽度越大越好,但”大模型更省计算”没有复现;P2P 的换词编辑在我们的模型里保不住构图,重新加权却很好用。

8. 常见误区 · Common pitfalls

  • “无分类器引导要训练一个分类器。” 不要。有条件和无条件的预测来自同一个网络(训练时随机丢掉提示),两者之差就是一个隐式分类器的梯度。
  • “w 越大越好。” 听话程度先升后平,FD 是 U 形,多样性一直在降;我们的 FD 在 w = 2 最好、听话程度在 w = 5 最好。
  • “slides 两页的 w 是同一个数。” ϵ∅+w(ϵc−ϵ∅)\epsilon_\varnothing + w(\epsilon_c - \epsilon_\varnothing) 里 w = 1 是普通采样(diffusers 的 guidance_scale 就是这个 w);(1+w′)ϵc−w′ϵ∅(1+w')\epsilon_c - w'\epsilon_\varnothing 里 w’ = 0 才是。w=1+w′w = 1 + w'。
  • “补丁大小只影响分辨率。” 它决定 token 数,计算量和 token 数成正比(注意力部分和平方成正比),参数量却几乎不变——DiT 用 GFLOPs 而不是参数量来做规模分析的原因。
  • “adaLN-Zero 的零初始化让模型学不动。” 梯度照样能流到那些全 0 的线性层(它们的输入不是 0),只是一开始每个块都是恒等映射。
  • “P2P 换词,抄的是注意力图,所以新词的内容也被抄走了。” 不会:抄的是权重 A,乘的仍是新提示的值 V*。正因为如此,抄得太久时新词的内容会被塞进原来那个词的”轮廓”里(我们的 0.455)。
  • “一个方法在 Stable Diffusion 上有效,在小模型上也有效。” P2P 依赖”交叉注意力图决定构图”,我们的小模型不满足这个前提。

9. 练习 · Exercises

练习 1(交叉注意力的形状)。 Stable Diffusion 1.x 的潜空间是 4×64×64,提示用 CLIP 编码成 77 个 768 维的向量。在 64×64 那一层(通道数 320,8 个头)的交叉注意力里,Q、K、V、A 各是什么形状?A 一共有多少个数?如果改成”自注意力 + 把提示拼在像素序列后面”(上下文拼接),这一层的注意力矩阵有多大?

参考答案

n = 64 × 64 = 4096 个像素,m = 77 个 token。Q:(8 头, 4096, 40)(320 / 8 = 40);K、V:(8, 77, 40)(由 768 维的文字向量投影到 320 维再分头);A:(8, 4096, 77),共 8 × 4096 × 77 ≈ 252 万个数。上下文拼接后序列长 4096 + 77 = 4173,自注意力矩阵是 (8, 4173, 4173) ≈ 1.39 亿个数——其中像素看像素的部分 (8, 4096, 4096) 本来自注意力就有,多出来的是像素看文字、文字看像素、文字看文字。交叉注意力只算”像素看文字”这一块,便宜得多。

练习 2(引导的推导)。 (a) 从 p~(z∣c)∝p(z) p(c∣z)w\tilde p(z\mid c) \propto p(z)\,p(c\mid z)^w 推出 ϵ^=ϵ∅+w(ϵc−ϵ∅)\hat\epsilon = \epsilon_\varnothing + w(\epsilon_c - \epsilon_\varnothing)。(b) 证明 w = 1 时 p~(z∣c)=p(z∣c)\tilde p(z\mid c) = p(z\mid c)。(c) 我们的 w = 0 为什么 4 个全对只有 0.043?

参考答案

(a) 见 §4.2:取对数、求梯度,∇log⁡p~=∇log⁡p(z)+w∇log⁡p(c∣z)\nabla\log\tilde p = \nabla\log p(z) + w\nabla\log p(c\mid z),再用贝叶斯公式 ∇log⁡p(c∣z)=∇log⁡p(z∣c)−∇log⁡p(z)\nabla\log p(c\mid z) = \nabla\log p(z\mid c) - \nabla\log p(z),最后乘上 −1−αˉt-\sqrt{1-\bar\alpha_t} 把得分换成噪声预测。(b) w = 1 时 p(z)p(c∣z)=p(z,c)=p(c)p(z∣c)∝p(z∣c)p(z)p(c\mid z) = p(z, c) = p(c)p(z\mid c) \propto p(z\mid c)。(c) w = 0 时 ϵ^=ϵ∅\hat\epsilon = \epsilon_\varnothing,完全不看提示,是在从 p(z)p(z) 采样:4 个属性随机,全对的概率约 1/32 ≈ 0.031;0.043 和它差不多。

练习 3(引导的代价)。 一个模型不带引导采一张图要 50 步。带引导时每步算两次网络。(a) 计算量变成几倍?(b) 有人提出”只在前 25 步加引导,后 25 步不加”,计算量是几倍?你预计效果会怎样?(提示:§6.6 讲过构图在哪几步定下来。)

参考答案

(a) 2 倍(实际实现里把两份拼成一个两倍大的批,时间上通常不到 2 倍,我们实测 42 ms vs 21 ms,正好 2 倍)。(b) (25 × 2 + 25) / 50 = 1.5 倍。引导主要作用在”画什么、画在哪”上,这在噪声大的那些步里决定;后面的步只补细节。所以只在前面(或中间)加引导通常能保住大部分听话程度、还减少过度饱和;这正是后来一些”引导区间”(guidance interval)论文的做法。但要注意线性调度下前 40% 的步几乎是纯噪声,真正决定构图的是中段,所以”前一半”未必是最好的区间——要实验。

练习 4(DiT 的 GFLOPs)。 用 §5.4 的公式 24Td2+4T2d24Td^2 + 4T^2d 估算 DiT-XL/2 的 GFLOPs:潜空间 32×32×4、p = 2、d = 1152、28 层。和 slides 的 118.6 GFLOPs 比。p = 4、p = 8 时呢?

参考答案

p = 2:T = (32 / 2)² = 256。每层 24⋅256⋅11522+4⋅2562⋅1152≈8.15×109+0.30×109=8.46×10924\cdot256\cdot1152^2 + 4\cdot256^2\cdot1152 \approx 8.15\times10^9 + 0.30\times10^9 = 8.46\times10^9,28 层 ≈ 2.37×10112.37\times10^{11} FLOPs。这里一次乘加算 2 次 FLOP;DiT 论文按”乘加次数”(MACs)报 GFLOPs,除以 2 ≈ 118 G,和 118.6 吻合(还有 adaLN 的调制层等少量计算)。p = 4:T = 64,每层 24⋅64⋅11522+4⋅642⋅1152≈2.04×109+0.02×10924\cdot64\cdot1152^2 + 4\cdot64^2\cdot1152 \approx 2.04\times10^9 + 0.02\times10^9,28 层 ≈ 57.7 G FLOPs ≈ 28.9 G MACs;p = 8:T = 16,≈ 7.2 G MACs。每减半一次补丁,计算量约 × 4。

练习 5(adaLN-Zero)。 (a) 证明:如果回归 γ、β、α 的线性层权重和偏置都是 0,那么 DiT 块的输出等于输入。(b) 既然一开始所有块都是恒等映射、输出层也是 0,网络的输出 ε̂ ≡ 0,梯度能传回去吗?哪些参数第一步就有非零的梯度?

参考答案

(a) γ = β = α = 0,块变成 h+0⋅Attn(LN(h))+0⋅FFN(⋯ )=hh + 0\cdot\mathrm{Attn}(\mathrm{LN}(h)) + 0\cdot\mathrm{FFN}(\cdots) = h。(b) 损失 ∥ϵ−0∥2\lVert\epsilon - 0\rVert^2 对输出层权重 WoutW_{\text{out}} 的梯度是 −2(ϵ−0)h⊤-2(\epsilon - 0)h^\top,h(最后一层 LayerNorm 的输出)不是 0,所以输出层第一步就有梯度;调制层(adaLN 的线性层)的梯度正比于它的输入 SiLU(c)(不是 0)和下游传回来的梯度——输出层一旦变成非 0,下一步各块的 α 也开始有梯度。所以网络从”恒等”开始,一层一层地”打开”。和 LoRA 的 B = 0 一样:A 第一步没有梯度(因为 B = 0),B 有。

练习 6(P2P 的前提)。 §6.6 里 P2P 在我们的模型上保不住构图,但”共享前 60% 的轨迹”可以。(a) 说出两者的区别:P2P 在注入期间,新图和原图的潜变量 ztz_t 一样吗?(b) 如果想让我们的模型”更适合 P2P”,你会怎样改它的结构或训练?

参考答案

(a) 共享轨迹时,前 k 步两行的输入(噪声、提示)完全相同,所以 ztz_t 完全相同——构图被原样复制。P2P 注入期间,两行的注意力权重相同,但值 V 不同(新提示的 V*),交叉注意力的输出就不同,zt∗z^*_t 从第一步起就和 ztz_t 分开了;只有当”画在哪”完全由 A 决定、V 只决定”画成什么”时,两者的构图才会一致。我们的模型里,卷积主干会根据 V 带来的内容去决定位置和大小,所以构图跟着变。(b) 让”位置”必须经过交叉注意力:比如更高分辨率的潜空间(更多像素、注意力图更细)、在每个分辨率都放交叉注意力、减小卷积的感受野、或者训练时对注意力图加一个”集中”的正则(后来的一些工作正是这样做的)。也可以同时注入自注意力图(像素之间的关系),这在后来的编辑方法里很常见。

练习 7(重新加权)。 P2P 的重新加权不重新归一化:把 “big” 那一列乘以 c 之后,这一行的和不再是 1。(a) 如果重新归一化(除以新的行和),c = 0 和 c = 4 的效果会怎样变?(b) 我们的 “small” × 4 时形状只画对 0.24,为什么?

参考答案

(a) 重新归一化后,其他词的注意力会被等比例放大(c = 0 时)或缩小(c = 4 时),于是”加强 big”同时”减弱了所有其他词”——形状、位置的信息也会变弱。不归一化时只改动了 big 这一列的贡献,其他词的贡献不变,编辑更”局部”。(b) 半径已经被压到形状拟合的下限(4 像素),继续加强 “small” 只会把物体压得更小、更模糊,形状拟合就认不出是什么形状了;同时 small 的值向量被放大了 4 倍,在交叉注意力的输出里压过了形状词的贡献。

10. 延伸阅读 · Further reading

  • LDM 与交叉注意力:Rombach et al. (2022), LDM;Saharia et al. (2022), Imagen;Podell et al. (2023), SDXL。
  • 引导:Dhariwal & Nichol (2021), Diffusion Models Beat GANs on Image Synthesis(classifier guidance);Ho & Salimans (2022), Classifier-Free Diffusion Guidance;Kynkäänniemi et al. (2024), Applying Guidance in a Limited Interval Improves Sample and Distribution Quality。
  • DiT:Peebles & Xie (2023), DiT;Chen et al. (2023), PixArt-α;Esser et al. (2024), Stable Diffusion 3(MM-DiT)。
  • 用文字编辑:Hertz et al. (2022), Prompt-to-Prompt;Mokady et al. (2023), Null-text Inversion;Tumanyan et al. (2023), Plug-and-Play Diffusion Features;Avrahami et al. (2022), Blended Diffusion。

11. 下一讲预告 · Next lecture

第 15 讲有两个主题。第一个接着第 13 讲:把图像交给一个冻结的大语言模型时,与其把几十上百个图像块都塞进去,不如用一组可学习的查询向量(Q-Former,BLIP-2)通过交叉注意力去”问”图像编码器,只交出几个 token——这正是本讲交叉注意力的又一个用法。第二个是规模定律:损失怎样随参数量 N、数据量 D、计算量 C 变化;为什么 Kaplan 和 Chinchilla 给出了不同的”最优配比”;数据质量又怎样改变这些曲线。我们会在一个能精确算出”不可约损失”的小世界里,亲手拟合这些幂律。

← 返回课程目录