扩散模型推理(采样)完整过程讲解

扩散模型推理(采样)完整过程讲解

配套文档:DDPM基本原理讲解.md(讲训练与公式推导)。本文只讲推理——模型训好之后,一张图是怎么被”生”出来的。
写法约定:每个公式后面都跟一段”说人话”,只想搞懂思路的话,只读”说人话”也能通。

本文由AI生成。

0. 一个比喻:大理石里本来就有一尊雕像

米开朗基罗说过一句话:雕像本来就在那块大理石里,我只是把不属于它的部分去掉。

扩散模型的推理过程就是这个动作的精确版本:

比喻 推理时对应
一整块粗糙的大理石 一团纯随机噪声 $x_T$(雪花屏)
雕像 最终要生成的图 $x_0$
凿子每敲一下 一次”去噪步”
敲多少下 采样步数(1000 步 / 20 步 / 4 步)
雕刻师心里的样子 文本提示词(”一只戴帽子的猫”)

关键区别在于:雕刻师不知道石子里藏的是什么。他每敲一下之前,都必须先判断”哪些部分是多余的石头”。扩散模型里的这个”判断”,就是网络预测噪声的那一步。


1. 一句话版本

推理就三件事,循环做:

  1. 看一眼当前的噪声图 $x_t$,网络猜出”这里头掺了多少噪声” $\epsilon_\theta$;
  2. 减掉一点:用猜出来的噪声往前回退一步,得到 $x_{t-1}$;
  3. 重复$T$ 次,直到 $t = 0$,得到成品图。

$$\underbrace{x_T}{\text{纯噪声}} ;\to; x{T-1} ;\to; \cdots ;\to; x_t ;\to; x_{t-1} ;\to; \cdots ;\to; \underbrace{x_0}_{\text{成图}}$$

说人话:从一团雪花屏开始,反复问网络”噪声在哪”,然后擦掉一点点,擦几百次,图就浮出来了。


2. 推理 vs 训练:谁干什么

很多人把这两件事搞混。它们的分工非常干净:

训练(已讲过) 推理(本文)
起点 真实图 $x_0$ 纯噪声 $x_T \sim \mathcal N(0, I)$
方向 往图里加噪声 从图里减噪声
谁在主控 前向规则 $q$(固定,不用学) 网络 $\epsilon_\theta$(训练好的,冻结不动)
网络在做什么 学参数(被更新) 只做前向推理(参数不动)
需要 $x_0$ 吗 需要(监督标签就是它) 不需要(它正是要生成的东西)
一步的代价 一次前向 + 一次反向传播 只有一次前向
干多少次 几百万个样本 × 随机 $t$ 每个图走 $T$ 步

说人话:训练是”看着答案学解题”,推理是”上考场,没有答案,只能一步步自己推”。

一个必须记住的事实:推理时网络从来没有见过清晰图。它从头到尾只见过带噪的 $x_t$,它唯一会做的事就是”猜噪声”。最终那张清晰的图,是几百次”猜噪声 → 减一点”累积出来的结果,不是网络直接画出来的。


3. 出发前要备好的四样东西

推理不像训练那样需要数据和优化器,只需要这四样:

编号 东西 说明
① 训练好的噪声预测网络 $\epsilon_\theta(x_t, t, c)$ U-Net(或 DiT)。参数全部冻结
② 噪声调度 $\beta_t$、$\alpha_t$、$\bar\alpha_t$ 训练时用的那组,一个数字都不能改
③ 采样器(scheduler)的规则 决定”这一步怎么回退”,DDPM / DDIM / DPM-Solver…
④ 条件 $c$(可选) 文本提示词编码后的向量

说人话:网络是”工人”,$\bar\alpha_t$ 是”施工进度表”,采样器是”施工规范”,提示词是”甲方要求”。

其中最容易踩的坑:② 必须和训练时完全一致。换成另一条调度曲线,等于让工人按错误的进度表施工,出来的图会崩。


4. 第 0 步:起点是一团纯噪声

$$x_T \sim \mathcal N(0, I)$$

看清楚:这一步没有任何输入,没有任何参数。就是随机采一张每个像素都独立、服从标准高斯的雪花屏。

说人话:这就是为什么同一个提示词每次生成的图都不一样——起点是随机的。想要复现结果,就得固定这个随机数(就是大家常说的 seed)。

为什么起点必须是标准高斯? 因为训练时前向过程走到 $T$ 步,$\bar\alpha_T \approx 0$,图已经彻底变成 $\mathcal N(0, I)$ 了。推理是从终点往回走,自然就得从同一个分布出发——否则网络会收到一个它在训练中从没见过的输入,直接懵掉。

训练时的终点 推理时的起点
是什么 $x_T = \sqrt{\bar\alpha_T}x_0 + \sqrt{1-\bar\alpha_T}\epsilon \approx \epsilon$ $x_T \sim \mathcal N(0, I)$
分布 $\mathcal N(0, I)$ $\mathcal N(0, I)$
关系 训练把图推到这里 推理从这里往回走

5. 单步去噪到底在做什么

这一步是全文的核心。看起来是一行公式,其实内部分成四个小动作:

$$\underbrace{x_t}{\text{当前}} \xrightarrow{\ \text{① 预测噪声}\ } \epsilon_\theta \xrightarrow{\ \text{② 反推}\ } \hat x_0 \xrightarrow{\ \text{③ 求均值}\ } \mu_\theta(x_t, t) \xrightarrow{\ \text{④ 加抖动}\ } \underbrace{x{t-1}}_{\text{上一步}}$$

5.1 动作①:网络预测噪声

$$\epsilon_\theta = \epsilon_\theta(x_t,\ t,\ c)$$

输入三样:当前的带噪图 $x_t$、当前的时间步 $t$、条件 $c$(比如提示词)。输出一张和 $x_t$ 一样大的图,每个位置是一个数——“我觉得这个像素上的噪声分量是多少”。

说人话:网络不是画家,它是”噪声探测器”。你把一张糊图给它,它还你一张噪声图。

为什么必须把 $t$ 也喂进去? 因为不同噪声水平下”噪声长什么样”完全不同。$t$ 很大时整张图几乎全是噪声,$t$ 很小时只有细微的颗粒。不给 $t$,网络就不知道该用哪套判断标准。时间步通常编码成一个向量,加到网络的每一层里。

5.2 动作②:反推”原图大概长什么样”

训练时我们是从 $x_0$ 造出 $x_t$ 的:

$$x_t = \sqrt{\bar\alpha_t},x_0 + \sqrt{1-\bar\alpha_t},\epsilon$$

现在把它反着解出 $x_0$:

$$\hat x_0 = \frac{1}{\sqrt{\bar\alpha_t}}\Big(x_t - \sqrt{1-\bar\alpha_t};\epsilon_\theta\Big)$$

说人话:这就是个移项——把”噪声 × 系数”从当前图里减掉,剩下的部分再放大回原来的尺度,就得到一张”我认为的原图” $\hat x_0$。
注意它叫 $\hat x_0$(带个帽子),表示这是猜的,不是真的。$t$ 很大的时候这个猜测非常不准,越往后越准。

为什么要绕这一圈? 因为网络只会输出噪声,而我们真正想要的是”上一步的图”。$\hat x_0$ 是从”噪声语言”翻译回”图像语言”的桥梁。

5.3 动作③:求上一步的均值 $\mu_\theta$

这一步直接借用训练时推导出来的”标准答案”公式(见原理文档 5.3 节),把里面的真实 $x_0$ **换成我们猜的 $\hat x_0$**:

$$\mu_\theta(x_t, t) = \frac{\sqrt{\bar\alpha_{t-1}},\beta_t}{1 - \bar\alpha_t},\hat x_0 ;+; \frac{\sqrt{\alpha_t},(1 - \bar\alpha_{t-1})}{1 - \bar\alpha_t},x_t$$

说人话:上一步的图应该落在”我猜的原图 $\hat x_0$“和”当前这张 $x_t$“之间。这两个系数就是配方,告诉我们往哪边偏多少。
而这两个系数是训练时就算好的常数,跟网络无关,推理时直接查表。

通常第二个系数($x_t$ 那一项)占大头——上一步跟当前步本来就很像,$\hat x_0$ 只起到”往真实图上拉一把”的修正作用。

5.4 动作④:加一点随机抖动

$$x_{t-1} = \mu_\theta(x_t, t) + \sigma_t,z, \qquad z \sim \mathcal N(0, I)$$

其中 $\sigma_t$ 有两种常见取法:

$$\text{DDPM 原版:}\ \sigma_t = \sqrt{\beta_t} \qquad\text{或}\qquad \sigma_t = \sqrt{\tilde\beta_t},\ \ \tilde\beta_t = \frac{1-\bar\alpha_{t-1}}{1-\bar\alpha_t}\beta_t$$

说人话:不要直接跳到均值,要在均值附近随机挑一个点。这是”抽样”(sampling),不是”求平均”。

这里有个特别反直觉的问题:我们明明在去噪,为什么还要主动加噪声?

三个理由:

  1. 我们在采样,不是在做点估计。 目标是从一个概率分布里抽一个样本,而不是取它的均值。直接取均值会导致生成的图过度平滑、缺乏细节(类似”把所有可能性平均一下”)。
  2. 单步的模型不完美。 网络猜的 $\hat x_0$ 有误差,$\mu_\theta$ 就不准。随机抖动给了模型”纠错”的机会——这一步走偏了,下一步还能走回来。
  3. 它对应理论上的逆过程。 数学上真正的反向过程是随机的(除非 $\beta_t \to 0$),去掉随机项反而是对理论的偏离。

但注意:这也正是 DDIM 能做确定性采样的切入点——如果愿意接受一点点理论偏差,就可以把 $\sigma_t$ 直接设成 0,换来大幅加速。见第 9 节。

5.5 完整公式与一个数值例子

把上面四步合并,就是 DDPM 论文里那条采样公式:

$$\boxed{x_{t-1} = \frac{1}{\sqrt{\alpha_t}}\left(x_t - \frac{1 - \alpha_t}{\sqrt{1 - \bar\alpha_t}},\epsilon_\theta(x_t, t)\right) + \sigma_t z}$$

说人话:括号里是”去掉噪声并放大回原尺度”,外面的 $1/\sqrt{\alpha_t}$ 是补偿收缩,最后那个 $\sigma_t z$ 是随机抖动。一行公式,四个动作全在里面。

一维数值例子(真实图像是几千维,这里用一个数字示意):

设当前处在 $t$ 时刻,$\bar\alpha_{t-1} = 0.95$,$\bar\alpha_t = 0.94$,于是 $\alpha_t = 0.94/0.95 = 0.9895$,$\beta_t = 0.0105$。

步骤 计算 结果
当前状态 $x_t$ $0.438$
① 网络预测 $\epsilon_\theta(x_t, t)$ $0.55$
② 反推原图 $\hat x_0 = \dfrac{0.438 - \sqrt{0.06}\times 0.55}{\sqrt{0.94}}$ $0.313$
③ 求均值 $\mu_\theta = 0.171,\hat x_0 + 0.829,x_t$ $0.416$
④ 加抖动 $x_{t-1} = 0.416 + 0.094\times(-0.5)$ $0.369$

而这张图的真值是 $x_0 = 0.3$。看整个过程:$0.438 \to 0.416 \to 0.369$,一步就往真值靠近了。网络猜的原图 $0.313$ 也很接近真值 $0.3$。

说人话:单步只挪动了一点点(0.438 → 0.369)。别嫌慢——每一步的小挪动才是”稳”的来源。一次想挪到位,反而会崩。


6. 整个循环:从 $T$ 到 $0$

把单步串起来,完整流程是:

1
2
3
4
5
6
7
① 采起点           x_T ~ N(0, I)
② for t = T, T-1, ..., 1:
预测噪声 ε_θ = ε_θ(x_t, t, c)
反推原图 x̂_0 = (x_t - √(1-ᾱ_t)·ε_θ) / √ᾱ_t
求均值 μ_θ = 系数₁·x̂_0 + 系数₂·x_t
加抖动 x_{t-1} = μ_θ + σ_t·z
③ 输出 x_0

这个过程中几个值得盯着的量:

时刻 $\bar\alpha_t$(原图还剩多少) 图长什么样 网络在干什么
$t = T$ $\approx 0$ 纯雪花屏 猜大轮廓、构图、色块分布
$t$ 中等 $\approx 0.5$ 模糊的影子 定主体形状、大致结构
$t$ 较小 $\approx 0.9$ 看得清了,有噪点 补纹理、边缘、细节
$t \to 0$ $\to 1$ 成品 最后抛光

说人话:这是一个从粗到细的过程——先定骨架,再填血肉,最后磨皮。所以你中途去看中间结果,会先看到一团模糊的色块,慢慢才变清晰。
这也解释了一个现象:前几步基本决定整张图的构图和内容,后面几十步主要是在补细节。

每步都要跑一次完整的网络。 这是扩散模型慢的根本原因——生成一张图 = 网络跑 $T$ 次。$T = 1000$ 时,一次生成要跑一千次 U-Net。


6.5 番外:视频扩散模型 vs 图片扩散模型,原理差在哪

一句话:骨架一条都没变(加噪 → 预测噪声 → 回退),图片扩散就是视频扩散在 $F = 1$ 时的特例。所有差别都来自同一件事:多了一个轴之后,哪些环节必须跟着改。

6.5.1 最本质的区别:噪声加在「整段视频」上,不是逐帧加

图片扩散 视频扩散
数据 一张图 $x_0 \in \mathbb{R}^{C \times H \times W}$ 一个片段 $x_0 \in \mathbb{R}^{F \times C \times H \times W}$
时间步 整张图一个 $t$ 整段共用一个 $t$
噪声 $\epsilon \in \mathbb{R}^{C \times H \times W}$ $\epsilon \in \mathbb{R}^{F \times C \times H \times W}$,一个时空噪声场

加噪公式还是同一条:

$$x_t = \sqrt{\bar\alpha_t},x_0 + \sqrt{1 - \bar\alpha_t},\epsilon$$

说人话:变的只是 $\epsilon$ 的形状。加噪规则、损失函数、采样循环全部照搬,一句没改。

为什么非得整段共用一个 $t$? 看反例最清楚:如果每帧各自独立采 $t$、独立加噪,那训练时帧与帧之间没有任何关联,网络也不可能有理由去学跨帧关系——生成时每帧各画各的,结果就是疯狂闪烁。

共用一个 $t$ 之后,模型要一次性预测整个时空噪声场。为了把损失降下来,它必须利用”相邻帧应该长得差不多”这个规律。所以时间一致性不是被显式教出来的,是被损失函数逼出来的。

补充:近年确实出现了”每帧不同噪声水平”的做法(Diffusion Forcing、FIFO、CausVid 等),目的是做流式生成、无限长视频和自回归续写。但主流文生视频(Mochi、CogVideoX、HunyuanVideo 等)仍然整段共享 $t$。

6.5.2 逐项对照

环节 图片扩散 视频扩散
训练样本 单张图 一个 clip(常见 16–121 帧)
编码器 2D VAE,空间压缩 $8\times8$ 3D VAE,额外压缩时间(常见 $4\times8\times8$)
潜变量形状 $c \times h \times w$ $f \times c \times h \times w$
卷积 2D conv 3D conv(卷积核多一维时间)
DiT 切块 2D patch 3D tubelet(时空小块)
位置编码 2D RoPE 3D RoPE(多一维时间)
网络层 只有空间层 空间层 + 时间层(见 7.2.0)
损失函数 $\lVert \epsilon - \epsilon_\theta \rVert^2$ 完全一样,只是张量多一维
条件 文本 文本 +(可选)首帧/尾帧、运动强度、帧率、音频
算力 基准 大致 × $F$
评测 FID、CLIP score FVD、VBench(含 Dynamic Degree)

6.5.3 视频独有的三个麻烦

① 时间一致性(flicker)。不但每帧要好看,相邻帧的纹理、颜色、人物身份还不能跳。这是图片模型根本不存在的问题。

② 动态程度(dynamic degree)。一个模型可以靠”干脆不动“来骗过一致性指标——生成一段每帧都清晰、但完全静止的东西。所以视频评测必须同时看”稳不稳”和”动不动”两个维度。

这一条直接解释了为什么需要 STG:CFG 把画面推清晰的同时会把动态一起推掉(因为它推离的是”没动态的无条件模型”)。STG 的全部意义就是”提清晰度,但不牺牲动态程度“。

③ 长度。一次能生成的帧数受显存限制。长视频要靠滑窗或自回归续写(拿前一段的尾帧当条件),于是又冒出”长期一致性”问题——几十秒之后,人物可能已经悄悄变了。

6.5.4 对推理流程的实际影响

  • 起点 $x_T$ 不再是”一张噪声图”,而是 $f \times c \times h \times w$ 的一整块时空噪声。
  • 每一步网络输出的是整个时空噪声场 $\epsilon_\theta$,采样器对它整体做一次回退。
  • 视频上的 CFG 要比文生图保守(常取 3–7 而非 7.5),否则视频会变静止。
  • 多出一类视频专属旋钮:STG、时间层引导、运动强度(motion bucket)。
  • 端到端成本 ≈ 单帧 × 帧数 × 去噪步数,这是视频推理昂贵的根源。

7. 引导(Guidance):三种让生成更听话的技术

前面讲的采样循环有个前提:网络输出的 $\epsilon_\theta$ 是拿来直接用的。但实践中大家几乎不会直接用——而是先对它做一番”加工”,让生成结果更清晰、更贴合条件。这类加工统称 guidance(引导)。

说人话:网络给的是”原始意见”,引导就是对这份意见做加权、放大、外推,把生成轨迹往我们想要的方向推一把。

三种常见引导,解决的问题各不相同:

技术 要解决的问题 核心手法 代价
CFG 让图贴合提示词 跑”有条件 / 无条件”两遍,做外推 成本 ×2,多样性下降
STG 提升画面质量但不牺牲动态 跑”完整 / 跳层”两遍,做外推 成本 ×3(含 CFG)
Modality Guidance 控制多模态之间的一致性与耦合强度 给每个模态配权重,或用跨模态相似度做梯度 模态冲突、过耦合

7.1 Classifier-Free Guidance(CFG)

不带条件的扩散模型只能”随机画一张说得通的图”。要让它听提示词,就得把条件 $c$ 送进网络,并且用外推放大效果。

7.1.1 条件怎么进网络

文本提示词先被一个文本编码器(如 CLIP / T5)转成一串向量,然后通过 cross-attention 注入 U-Net 的中间层。

说人话:U-Net 每层在处理图像时,都可以”抬头看一眼”提示词,决定哪些词跟当前这块区域有关。

7.1.2 为什么要做两次预测

推理时,网络被要求跑两遍:

$$\epsilon_{\text{cond}} = \epsilon_\theta(x_t, t, c) \qquad \text{(带提示词)}$$

$$\epsilon_{\text{uncond}} = \epsilon_\theta(x_t, t, \varnothing) \qquad \text{(把提示词换成”空”)}$$

然后做外推:

$$\boxed{\epsilon = \epsilon_{\text{uncond}} + w,(\epsilon_{\text{cond}} - \epsilon_{\text{uncond}})}$$

$w$ 就是大家熟悉的 guidance scale(默认常取 7.5)。

说人话:$\epsilon_{\text{cond}} - \epsilon_{\text{uncond}}$ 是”这个提示词让噪声预测改变了多少“,也就是提示词起作用的方向。$w$ 是放大倍数——沿着这个方向多走几步,效果就更明显。

$w$ 效果
$w = 1$ 不做外推,就是普通的条件生成
$w = 7.5$ 常用默认值,明显贴合提示词
$w > 15$ 过度饱和、颜色炸裂、结构扭曲

说人话(代价):$w$ 越大越贴合提示词,但多样性越低、越容易过曝。这是一个”听话程度 ↔ 画面质量/多样性”的权衡。
另外注意:每步都要跑两次网络,所以带 CFG 的推理成本是普通推理的两倍。

7.1.3 常见误解:$w = 7.5$ 是”放大 7.5 倍”吗?要不要归一化?

不是 7.5 倍。 把公式展开就清楚了:

$$\epsilon = \epsilon_{\text{uncond}} + 7.5,(\epsilon_{\text{cond}} - \epsilon_{\text{uncond}}) = 7.5,\epsilon_{\text{cond}} - 6.5,\epsilon_{\text{uncond}}$$

被放大的是”差值”,基线仍然是 $\epsilon_{\text{uncond}}$。

说人话:条件通常只让预测偏移一点点(比如 0.20 → 0.25,差 0.05)。$w$ 把这一小段偏移量拉长 7.5 倍,得到 $0.20 + 7.5 \times 0.05 = 0.575$。
如果真是”7.5 倍原值”,那应该是 $7.5 \times 0.25 = 1.875$——整张图每个像素都这么放大的话,画面立刻就炸了。

那为什么 $w$ 大了还是会过曝? 因为虽然不是 7.5 倍,尺度确实会飘。设两个预测高度相关(相关系数 $\rho = 0.95$,各自 $\text{std} = 1$):

$$\text{Var}(\epsilon_{\text{cfg}}) = \underbrace{1}{\text{Var}(\epsilon{\text{uncond}})} + w^2\underbrace{(2-2\rho)}{=,0.1} + 2w\underbrace{(\rho-1)}{=,-0.05} = 1 + 5.625 - 0.75 = 5.875 ;\Rightarrow; \text{std} \approx 2.42$$

标准差从 1.0 涨到约 2.42。采样器拿到的 $\epsilon$ 比训练时见过的”胖了一倍多”,去噪步子迈过头 → 过饱和。这就是”w 太大画面炸掉”的定量来源。

于是就有了归一化,这件事专门叫 rescaling(Lin et al., WACV 2024):

$$\epsilon_{\text{rescaled}} = \epsilon_{\text{cfg}} \times \frac{\text{std}(\epsilon_{\text{cond}})}{\text{std}(\epsilon_{\text{cfg}})}$$

$$\epsilon_{\text{final}} = r \cdot \epsilon_{\text{rescaled}} + (1-r) \cdot \epsilon_{\text{cfg}}$$

说人话:把外推结果的”胖瘦”按 $\epsilon_{\text{cond}}$ 的标准重新校准回去。$r$ 是混合系数,控制”校准得多彻底”。
注意 std 是对整张预测图的所有空间位置和通道统一算一个值,不是逐像素做——否则会破坏空间结构。

$r$ 效果
$r = 0$ 不归一化(多数框架的默认值)
$r = 0.7$ 常用取值,明显缓解高 $w$ 下的过饱和
$r = 1$ 完全校准,但画面容易发平、对比度下降

为什么默认不做归一化? 因为完全 rescale 会让画面对比度下降、显得平淡(论文原文的说法正是 avoid “plain looking” images)。而在常用 $w$ 区间(6–9),那一点点过饱和带来的观感反而”讨喜”,社区也就默认接受了。只有当 $w$ 明显偏大、画面开始炸时才值得打开它。

顺带一提:7.2 节 STG 里提到的 rescaling 是同一个手法。凡是靠”外推”做引导的地方(CFG、STG、Autoguidance),都会遇到尺度漂移,都可以用这一招拉回来。

CFG 最大的毛病:它把生成结果推离”无条件方向”,而”无条件”意味着低信息量、低动态、低多样性。在文生图上这还能接受(不过是画面变艳一点),但在视频生成里就致命了——$w$ 一拉高,画面清晰了,但视频不动了,看起来像一张静止的图。


7.2 Spatiotemporal Skip Guidance(STG)

论文:Hyung et al., Spatiotemporal Skip Guidance for Enhanced Video Diffusion Sampling, CVPR 2025(arXiv:2411.18664)

动机:有没有一种引导,能提升质量但不牺牲动态性?

先说它的思想来源 Autoguidance:不用”无条件模型”当参照,而是用一个更弱但同任务的模型当参照,然后把结果推离它:

$$\tilde\epsilon_w = \epsilon_{\text{强}} + w,(\epsilon_{\text{强}} - \epsilon_{\text{弱}})$$

问题是:训练一个额外的弱模型,对十亿参数的视频模型来说贵到做不了。

7.2.0 先搞清楚:什么是「空间层」和「时间层」

如果还没看 6.5 节,建议先读它:视频扩散和图片扩散的整体差异(尤其是”整段共用一个 $t$”这一点)是理解本节的前提。

先排一个雷:视频扩散模型里”时间”这个词出现了两次,指的是完全不同的东西。
扩散时间步 $t$(加噪到第几步)≠ 视频时间轴(第几帧)。空间层 / 时间层里的”时间”是后者。

视频的 latent 比图片多一个维度:图片是 $N$ 个 patch token,一段 $F$ 帧的视频就是 $F \times N$ 个 token。网络里每一层做的事都是”让 token 之间互相看、交换信息”,区别只在于允许谁看谁:

允许哪些 token 互相看 负责什么 这一层变弱之后
空间层 同一帧内部的 $N$ 个 画面结构:轮廓、纹理、构图、物体长相 画面糊、结构散、细节丢失
时间层 跨帧、同一位置的 $F$ 个 运动与一致性:往哪动、颜色/身份跨帧是否稳定 帧间闪烁、物体变形、运动不连贯

说人话:空间层管”每一帧画得像不像“,时间层管”帧和帧之间连不连得上“。

一个检验方法:把视频的帧顺序打乱再喂进去——还能正常干活的就是空间层(它根本不在乎顺序),一打乱就崩的就是时间层(它靠顺序建模运动)。

两种摆法(决定了后面用哪种跳法)

架构 怎么摆 代表模型 适合哪种跳法
3D 全注意力(joint) 一层 attention 直接把 $F\times N$ 个 token 一起算,时空交互一次完成 Mochi、HunyuanVideo 两个轴拆不开 → Residual Skip
时空分离(factorized) 先一层 Spatial Attention(帧内),再一层 Temporal Attention(跨帧),串起来 Open-Sora、CogVideoX、LTX-Video 层级清楚 → Attention Skip,且可分别引导

**还有三类层不属于”时空层”**:

层 干什么 STG 跳不跳
文本交叉注意力(cross-attention) 图像 token 去读提示词 不跳
时间步调制(AdaLN / 时间嵌入) 把扩散步数 $t$ 告诉网络 不跳
前馈层 FFN 对每个 token 独立做变换 通常不跳

回到 STG:正因为只跳时空层,跳层后的那个”弱模型”仍然读得到提示词(cross-attention 还在)、仍然知道现在加噪到第几步(时间嵌入还在),只是”把画面组织起来”的能力被削掉了。所以它恰好是一个”懂我意思、也知道该怎么动,就是画得糙“的自己——这正是 STG 需要的参照物。

如果模型是时空分离架构,两项还能分开调(对应 7.2.2 里的 $w_1, w_2$):跳空间层 → 主要提升画面清晰度;跳时间层 → 主要提升时间一致性。

7.2.0.1 具体到代码:怎么判断一个层是”空间层”还是”时间层”

判据只有一个:看 attention 之前那一行 reshape,把哪个维度折叠进了 batch。以 Stable Video Diffusion 为例(src/diffusers/models/attention.py L1214–1257,TemporalBasicTransformerBlock.forward):

1
2
3
4
5
6
# 进来时形状是 (B·F, N, C),N = h × w 个空间位置
hidden_states = hidden_states[None, :].reshape(batch_size, num_frames, seq_length, channels) # (B, F, N, C)
hidden_states = hidden_states.permute(0, 2, 1, 3) # (B, N, F, C)
hidden_states = hidden_states.reshape(batch_size * seq_length, num_frames, channels) # (B·N, F, C)
attn_output = self.attn1(hidden_states) # ← attention 现在只在 F 这一维内做
# 做完再原路 reshape 变回去

对比一下两个模块收到的形状:

模块 attention 看到的形状 被折叠进 batch 的是 所以它是
BasicTransformerBlock.attn1 $(B\cdot F,\ N,\ C)$ 帧 $F$ 空间层(attention 只在空间维 $N$ 内做)
TemporalBasicTransformerBlock.attn1 $(B\cdot N,\ F,\ C)$ 空间位置 $N$ 时间层(attention 只在帧维 $F$ 内做)

说人话:同一个 attention 算子,喂进去的形状不同,它就变成不同的层。折叠谁,谁之间就不通信。

在 SVD 里,这两个模块是一一配对出现的(src/diffusers/models/transformers/transformer_temporal.py L205 的 TransformerSpatioTemporalModel):

1
2
3
4
5
6
7
self.transformer_blocks          = nn.ModuleList([BasicTransformerBlock(...)])         # 空间 + 文本交叉注意力
self.temporal_transformer_blocks = nn.ModuleList([TemporalBasicTransformerBlock(...)]) # 时间

for block, temporal_block in zip(self.transformer_blocks, self.temporal_transformer_blocks):
hidden_states = block(hidden_states, encoder_hidden_states=...) # 先做空间
hidden_states_mix = temporal_block(hidden_states_mix + emb, num_frames=...) # 再做时间(+ 帧序号嵌入)
hidden_states = self.time_mixer(x_spatial=..., x_temporal=...) # AlphaBlender 按 alpha 混合

7.2.0.2 一个反直觉的事实:很多模型根本没有独立的”时间层”

上面那种”空间层 + 时间层配对”的写法叫 factorized。但现在主流的视频大模型不这么干——它们把 $F\times N$ 个 token 直接展平成一个长序列,用一个 attention 一次性把时空全做完,靠 3D RoPE 让模型自己分辨谁跟谁隔得近。

这类架构叫 full 3D attention,里面既没有”纯空间层”也没有”纯时间层”,只有合体的时空层。在你本地这份 diffusers 里可以直接验证:

模型 是否有独立时间层 具体模块 文件
Stable Video Diffusion 有 TransformerSpatioTemporalModel(空间 Block + 时间 Block 配对) models/transformers/transformer_temporal.py L205
AnimateDiff 有 MotionAdapter 插入 U-Net 的 motion module(时间自注意力) models/unets/unet_motion_model.py
Mochi 没有 展平后一个 3D 全注意力 models/transformers/transformer_mochi.py
HunyuanVideo 没有 同上 models/transformers/transformer_hunyuan_video.py
LTX-Video 没有 同上(整个文件搜不到任何 temporal 模块) models/transformers/transformer_ltx.py
EasyAnimate / Allegro 没有 同上,用 3D RoPE 区分时空 transformer_easyanimate.py / transformer_allegro.py

说人话:如果你去找”时间层”这个模块,在 Mochi、HunyuanVideo、LTX 里是找不到的——它根本不是一个独立模块,而是融在同一个 attention 里了。

这正好解释了 STG 为什么叫 “Spatiotemporal**”:因为在这些模型里空间和时间拆不开**,只能整个残差块一起跳(Residual Skip)。只有 SVD、AnimateDiff 这类分离架构,才有真正意义上的”独立时间层”,可以用 Attention Skip 分别引导(也就是 7.2.2 里 $w_1, w_2$ 那两条只对分离架构成立)。

7.2.1 STG 的核心招数:自己给自己当弱模型

STG 的洞察非常巧:不需要真的去训练一个弱模型,把原模型的某些层”跳过”就得到了一个弱模型。

两种跳法:

跳法 做法 公式
Residual Skip 整个残差块直接置为恒等(这一层什么都不做) $\text{Res}’(z_l) = z_{l+1} = z_l$
Attention Skip 把注意力矩阵换成单位阵(每个位置只看自己) $\text{SA}’(Q,K,V) = I \cdot V = V$

关键是**只跳”时空层”**(spatiotemporal layers)——也就是负责建模空间结构和时间演化的那些层,而不是文本交叉注意力层。

7.2.2 公式

基本形式(和 Autoguidance 同构):

$$\boxed{\tilde\epsilon_w = \epsilon_\theta + w,(\epsilon_\theta - \epsilon_\theta^b)}$$

其中 $\epsilon_\theta^b$ 是”跳层版”的预测。

如果模型的空间层和时间层是分开的(factorized),可以分别引导:

$$\tilde\epsilon_\theta = \underbrace{\epsilon_\theta(x_t)}_{\text{完整}} + w_1\big(\epsilon_\theta(x_t) - \epsilon_\theta^{s}(x_t)\big) + w_2\big(\epsilon_\theta(x_t) - \epsilon_\theta^{t}(x_t)\big)$$

说人话:$w_1$ 管”画面清晰度”,$w_2$ 管”时间一致性”。两项可以正交化后再相加,避免互相干扰。

实际使用时 STG 通常和 CFG 一起用,于是每步要跑三遍网络:

$$\epsilon_{\text{final}} = \underbrace{\epsilon_{\text{uncond}}}{\text{空提示}} + \underbrace{w{\text{cfg}}(\epsilon_{\text{cond}} - \epsilon_{\text{uncond}})}{\text{CFG 项}} + \underbrace{w{\text{stg}}(\epsilon_{\text{cond}} - \epsilon_{\text{perturbed}})}_{\text{STG 项}}$$

说人话:把三路预测(空提示 / 正常 / 跳层)拼成一个 batch 一起送进网络,最后按两个系数合成。

7.2.3 为什么 STG 比 CFG 好

差别在于参照物是谁:

CFG 推离的是 STG 推离的是
参照模型 无条件模型 跳层的自己
参照物特性 质量低、且不懂提示词、且没动态 质量低,但懂同一个提示词、有同样的动态
外推副作用 多样性↓、动态性↓、过饱和 主要只推”质量”这一个方向

说人话:CFG 是”离那个啥都不懂的版本远一点”,结果连多样性和运动一起被推掉了。STG 是”离那个懂我意思但画得糙的版本远一点”——它俩在”画什么、怎么动”上是一致的,差值里只剩”画得好不好”,所以只推质量,不伤动态。

论文实测(VBench / FVD):

模型 指标 CFG STG
Mochi Imaging Quality 0.524 0.628
Mochi Dynamic Degree 0.87 0.86(几乎不掉)
SVD FVD ↓ 151.3 128.7
SVD Dynamic Degree 0.562 0.694(反而涨了)

可以看到:质量明显提升,而动态程度基本不掉甚至回升——这正是 CFG 做不到的。

7.2.4 实践要点

  • 跳哪一层是超参,得按模型调。官方实现的默认值:Mochi 第 34 层、CogVideoX 第 11 层、LTX-Video 第 19 层、HunyuanVideo 第 2 层。
  • 架构决定跳法:3D 全注意力的大模型(如 Mochi)适合 Residual Skip;空间/时间层分离的模型(如 Open-Sora)适合 Attention Skip。
  • $w_{\text{stg}}$ 太大也会过冲,可配合 rescaling(约束方差)或 restart sampling 把轨迹拉回数据流形。
  • 代价:每步三路前向,比纯 CFG 再贵 50%。

7.3 Modality Guidance(模态引导:跨模态对齐与耦合强度)

要解决的问题和前两个不一样:前面两个关心”画得好不好 / 贴不贴合文本”,而 Modality Guidance 关心的是——当有多个模态的条件同时存在时,它们之间该”绑”多紧?

典型场景:

场景 涉及的模态 要控制的”耦合强度”
图生视频(I2V) 首帧图 + 文本 新生成的帧要多大程度保持首帧的样子
多 ControlNet 深度图 + 边缘图 + 姿态 + 文本 各控制信号谁说了算
参考图生成 / ID 保持 参考图 + 文本 是”神似”还是”像素级复刻”
音频驱动视频 音频 + 文本 + 视频 口型/动作跟音频对齐到什么程度
图像编辑 原图 + 编辑指令 哪些区域必须保持、哪些可以放开了改

说人话:这是一个”松紧旋钮“。拧太松,两个模态各说各话(图不对文、视频不像参考图);拧太紧,输出被参考模态吸死,失去创造性和细节,还容易产生伪影。

7.3.1 形式一:在预测空间给每个模态配权重

最自然的形式是 CFG 的多模态推广——每个模态一支预测,各自一个外推系数:

$$\hat\epsilon_\theta = \epsilon_{\text{uncond}} + \sum_{k} \lambda_k \big(\epsilon_\theta(x_t, t, c_k) - \epsilon_{\text{uncond}}\big)$$

其中 $c_k$ 是第 $k$ 个模态的条件,$\lambda_k$ 是它的引导强度。

说人话:总预测 = 无条件基线 + 每个模态各自”贡献”的方向 × 权重。只有一个模态、$\lambda = w$ 时,它退化成普通 CFG。
$\lambda_k$ 之间的相对比例决定了”谁说了算”,它们的绝对值决定了”总体绑多紧”。

权重归一化规则很重要(多控制模型的通用做法):

  • 所有 $\lambda_k$ 之和 $\le 1$:原样使用,各模态按字面权重生效;
  • 之和 $> 1$:按比例缩放到和为 1。

说人话:比如 ${\text{seg}: 4.0,\ \text{edge}: 1.0}$ 之和是 5,会被归一化成 ${0.8,\ 0.2}$。所以重要的不是绝对数值,是比例——你把两个都乘 10 倍,结果一模一样。

7.3.2 形式二:用跨模态相似度做梯度引导

前一种是”跑多遍网络求差”,另一种思路是直接算一个跨模态对齐得分,然后沿它的梯度推:

$$\hat\epsilon_\theta(x_t, t, c) = \epsilon_\theta(x_t, t, c) ;+; \lambda_t ,\nabla_{x_t},\mathcal S\Big(f_{\text{img}}(\hat x_0),\ f_{\text{mod}}(c_m)\Big)$$

其中:

  • $\hat x_0$ 是当前步反推出来的”我猜的原图”;
  • $f_{\text{img}}$、$f_{\text{mod}}$ 是把图像和另一模态(文本/音频/参考图)映射到同一个语义空间的编码器(最典型就是 CLIP 的图像塔和文本塔);
  • $\mathcal S$ 是两者在这个空间里的相似度(通常就是余弦相似度);
  • $\lambda_t$ 是这一时刻的耦合强度。

说人话:每一步都问一句——“我猜的这张图,和那个参考模态像不像?”像的话就加分;不像的话,梯度会告诉我们”往哪个方向改能更像”,于是顺着推一把。
这就是经典的 CLIP guidance / 语义扩散引导(SDG) 那一类做法:文本权重、图像权重两个旋钮,分别控制”贴合文字”和”贴合参考图”。

一个非常实用的技巧:到点就放手(stop guidance)。

反向过程大致分三段:混沌期($t$ 大,只有模糊轮廓)→ 语义期(定结构、定内容)→ 细化期($t$ 小,补纹理)。

经验是:只在语义期施加跨模态引导,进入细化期就把 $\lambda_t$ 置 0。

$$\lambda_t = \begin{cases} \lambda, & t > t_{\text{stop}} \ 0, & t \le t_{\text{stop}} \end{cases}$$

说人话:早期用引导”把方向掰对”,后期松手让它自由发挥细节。全程死拽着不放,反而会损害画面真实度、引入伪影。

7.3.3 耦合强度的三种状态

$\lambda$ 现象 什么时候要
太小 模态”脱钩”——生成结果跟参考图/控制信号对不上 几乎不要
适中 语义一致、结构对齐,但细节自由 绝大多数情况
太大 模态坍缩:输出被参考模态吸死,过饱和、边缘伪影、失去多样性 只在需要严格复刻结构时

说人话:这是个典型的”过拟合旋钮”。$\lambda$ 太大不是”更听话”,而是把生成问题退化成了复制问题。

7.3.4 坑

  1. 模态冲突:两个模态本身互相矛盾(比如文本要”白天”,参考图是”夜景”),加大 $\lambda$ 只会让网络左右为难,结果是四不像。先解决条件冲突,再调权重。
  2. 编码器自身的偏差:用 CLIP 做对齐,就会继承 CLIP 的偏好(它对风格、构图敏感,对细节、数量、空间关系迟钝)。
  3. 梯度引导要反传:形式二需要对 $x_t$ 求梯度,比形式一更慢、更吃显存。
  4. 跨模态对齐 ≠ 像素级对齐:相似度是在语义空间算的,它能保证”像那个意思”,不保证逐像素一致。要像素级一致得走 ControlNet / 编码器特征注入那一类结构条件。

7.4 三种引导怎么选

CFG STG Modality Guidance
控制的是什么 贴合文本的程度 画面质量(不伤动态) 多模态之间的一致性与耦合
参照物 无条件预测 跳层后的自己 另一模态的表示 / 各模态分支
主要用在 文生图(几乎必开) 视频生成 图生视频、多控制、参考图、跨模态生成
每步前向次数 ×2 ×3(与 CFG 叠加) ×(1 + 模态数)或 +1 次梯度反传
调过头会怎样 过饱和、多样性崩 过冲出流形、画面失真 模态坍缩、伪影、被参考图吸死
能一起用吗 — 是,STG 通常叠加在 CFG 上 是,可叠加在 CFG/STG 之上

说人话(一句话选型):
想让图更贴提示词 → 调 CFG;
想让视频更清晰又不想变卡 → 加 STG;
想让两个模态对齐(像参考图 / 跟着控制信号走)→ 调 Modality Guidance。
三者可以同时开,它们作用的维度不同,互不冲突。


8. 潜空间:Stable Diffusion 的完整链路

在像素空间做扩散,一张 512×512×3 的图有 78 万个数,跑一千次网络太贵。Stable Diffusion 的做法是先把图压缩再扩散。

完整链路长这样:

1
2
3
4
5
提示词 ──→ 文本编码器 ──→ 条件向量 c
↓
随机噪声 z_T (64×64×4) ──→ [ 潜空间扩散:T 步去噪 ] ──→ z_0
↓
VAE 解码器 ──→ 512×512×3 图片
环节 尺寸 说明
像素空间图片 $512 \times 512 \times 3$ 78 万维
VAE 编码后(潜变量) $64 \times 64 \times 4$ 1.6 万维,缩小 48 倍
扩散过程 全在 $64\times64\times4$ 上做 计算量降一个量级
VAE 解码后 $512 \times 512 \times 3$ 只在最后做一次

说人话:扩散过程全程在”压缩包”里进行,只有开头不需要编码(因为起点直接采噪声),只有结尾解码一次。这就是 SD 能在消费级显卡上跑起来的原因。

为什么起点不用编码? 因为起点是纯噪声,直接在潜空间采一个 $64\times64\times4$ 的标准高斯就行——它解码出来在像素空间也是一团”结构化的噪声”,正好对应。


9. 为什么能加速:从 1000 步到 4 步

既然每步都要跑一次网络,减少步数就是最直接的加速手段。但随便跳步是不行的——每一步的公式都假设”这一步很小”。

9.1 DDIM:去掉随机项,变成确定性 ODE

DDIM 的关键洞察:把 $\sigma_t$ 设成 0,采样就变成确定性的:

$$x_{t-1} = \sqrt{\bar\alpha_{t-1}},\hat x_0 + \sqrt{1 - \bar\alpha_{t-1}};\epsilon_\theta(x_t, t)$$

说人话:直接把”我猜的原图 $\hat x_0$”和”我猜的噪声 $\epsilon_\theta$”按比例调一杯鸡尾酒,就得到上一步。没有随机项,同样的起点永远得到同样的图。

好处是:确定性路径可以用更大的步子走,50 步甚至 20 步就能有相当好的效果。

9.2 更高阶的求解器

方法 步数 思路
DDPM 1000 原始随机采样,每步很小
DDIM 20–50 确定性 ODE,允许大步长
DPM-Solver 15–25 高阶数值求解器,一步顶多步
LCM / 一致性模型 1–4 直接学”从任意点跳到终点”的映射

说人话:前三种都是”把同一条路径走快一点”,最后一种是”直接训练一个会抄近路的模型“——它学的是一步到位,所以 4 步就能出图。

注意一个常见误解:加速采样器不需要重新训练扩散模型(LCM 除外)。它们只是用更聪明的数值方法走同一条路,所以同一个 checkpoint 换个 scheduler,出图速度和风格就会变。


10. 常见问题(FAQ)

Q1:为什么同一个提示词,每次生成的图都不一样?
因为起点 $x_T$ 是随机采的。固定随机种子(seed)就能复现。

Q2:能不能中途停下来看看?
能。取出任意一步的 $x_t$,用 $\hat x_0 = (x_t - \sqrt{1-\bar\alpha_t}\epsilon_\theta)/\sqrt{\bar\alpha_t}$ 就能”预测”出当前的成品大概长什么样(这叫 latent preview)。前几步的预测非常模糊,越往后越准。

Q3:网络一次都没见过清晰图,怎么知道”猫”长什么样?
训练时它见过海量真实图,并且在每一个噪声水平上都练过。它学到的不是”猫的图片”,而是**”在任意噪声水平下,哪些分量是噪声”**。把噪声一次次剥掉,剩下的自然就是符合数据分布的东西。

Q4:生成的图是不是把训练集的图背下来了?
不是逐像素复制。模型学到的是数据分布的统计规律。极端情况(训练样本极少、重复很多次、提示词很特殊)确实可能发生过拟合式的”复现”,但正常训练下它生成的是新的样本。

Q5:步数越多越好吗?
不一定。步数太少 → 还没走完路径,图不完整;步数太多 → 对好的求解器来说是浪费时间,且某些 scheduler 在极多步数下反而会过冲。一般 20–50 步就饱和了。

Q6:为什么最后几步看起来”没什么变化”?
因为 $\bar\alpha_t \to 1$,图已经基本干净了,最后几步只是在做细微的纹理修正。肉眼看不出,但对最终画质有贡献。

Q7:推理时能改 $\beta_t$ 调度吗?
不能随便改。调度是训练时就定死的,$\epsilon_\theta$ 是在那条调度下训练的。换调度等于让网络面对陌生的噪声水平。

Q8:为什么要有”负提示词”(negative prompt)?
它就是 CFG 公式里的 $\epsilon_{\text{uncond}}$ 那一路——只不过把”空”换成”我不想要的东西”。这样 $w$ 放大的方向就变成”远离负提示词描述的内容”。

Q9:一张图要跑多少次网络?
不带 CFG:$T$ 次。带 CFG:$2T$ 次(每步跑两遍)。SDXL 这类大模型,一次 1024×1024 出图(30 步 + CFG)就是 60 次大模型前向。

Q10:为什么不用一步生成?
一步 = 要求网络直接从纯噪声映射到清晰图,这个映射极其复杂、多值(一团噪声可以对应无数张合理的图),学不动。拆成一千个小步,每一步都是简单的”擦掉一点点”,才变得可学。

Q11:STG 只用在视频上吗?能用在图片上吗?
STG 是针对视频提出的,因为它专门挑”时空层”来跳——图没有时间维度,也就没有时间层可跳。但”跳层造弱模型”这个思路本身是通用的,任何基于 Transformer 的残差结构都能试。只是它的核心卖点(保住动态性)在图片上无从体现。

Q12:STG 和 CFG 一起开,参数怎么调?
一般先固定 CFG 在常用值(视频模型常取 3–7,比文生图的 7.5 保守),再加 STG。$w_{\text{stg}}$ 从 0.5–1.0 起试,逐步加;跳层位置优先用该模型的官方默认值,不要乱改。$w_{\text{stg}}$ 过大时先开 rescaling,看是否有改善。

Q13:为什么参考图/控制信号的权重一开大,画面就”死”了?
这就是 7.3.3 说的模态坍缩。耦合强度太大时,采样轨迹被牢牢锁在参考模态上,网络没有余地去做自由发挥,结果是过饱和、边缘硬、细节假,看起来像”贴”上去的。解决办法有两个:一是把权重降回适中区间;二是用 7.3.2 的 stop guidance——只在语义期($t$ 较大时)施加引导,进入细化期就松手。

Q14:多个控制信号打架怎么办?
调权重解决不了真正的语义冲突(比如一个要白天、一个要黑夜)。先改条件本身让它们不矛盾,再谈权重分配。权重只决定”平票时听谁的”,不能凭空造出一个同时满足矛盾条件的结果。

Q15:视频扩散模型和图片扩散模型是两套原理吗?
不是,是同一套。视频只是把数据从 $C\times H\times W$ 变成 $F\times C\times H\times W$,加噪公式、损失函数、采样循环一个字都没改;图片模型就是它在 $F=1$ 时的特例。真正的差别有两处:一是整段视频共用一个时间步 $t$(否则帧间无关联,生成会闪烁),二是网络里多了时间层来建模帧与帧的关系。详见 6.5 节。


11. 公式速查表

环节 公式 说明
起点 $x_T \sim \mathcal N(0, I)$ 无需输入,随机性来源
预测噪声 $\epsilon_\theta = \epsilon_\theta(x_t, t, c)$ 网络唯一会做的事
反推原图 $\hat x_0 = \dfrac{x_t - \sqrt{1-\bar\alpha_t},\epsilon_\theta}{\sqrt{\bar\alpha_t}}$ 从噪声语言翻译回图像语言
单步均值 $\mu_\theta = \dfrac{\sqrt{\bar\alpha_{t-1}}\beta_t}{1-\bar\alpha_t}\hat x_0 + \dfrac{\sqrt{\alpha_t}(1-\bar\alpha_{t-1})}{1-\bar\alpha_t}x_t$ 两个系数是训练时算好的常数
DDPM 采样 $x_{t-1} = \dfrac{1}{\sqrt{\alpha_t}}\Big(x_t - \dfrac{1-\alpha_t}{\sqrt{1-\bar\alpha_t}}\epsilon_\theta\Big) + \sigma_t z$ 四个动作合并成一行
DDIM 采样 $x_{t-1} = \sqrt{\bar\alpha_{t-1}},\hat x_0 + \sqrt{1-\bar\alpha_{t-1}},\epsilon_\theta$ 无随机项,确定性
CFG 外推 $\epsilon = \epsilon_{\text{uncond}} + w(\epsilon_{\text{cond}} - \epsilon_{\text{uncond}})$ $w$ 越大越贴合提示词;放大的是差值
CFG 重标定 $\epsilon_{\text{rescaled}} = \epsilon_{\text{cfg}}\cdot \text{std}(\epsilon_{\text{cond}})/\text{std}(\epsilon_{\text{cfg}})$ 修正外推带来的尺度漂移,按 $r$ 混合
STG 外推 $\tilde\epsilon_w = \epsilon_\theta + w(\epsilon_\theta - \epsilon_\theta^b)$ $\epsilon_\theta^b$ = 跳层后的”弱模型”预测
STG + CFG $\epsilon = \epsilon_{\text{uncond}} + w_{\text{cfg}}(\epsilon_{\text{cond}} - \epsilon_{\text{uncond}}) + w_{\text{stg}}(\epsilon_{\text{cond}} - \epsilon_{\text{ptb}})$ 三路前向,视频常用
多模态外推 $\hat\epsilon = \epsilon_{\text{uncond}} + \sum_k \lambda_k(\epsilon_{c_k} - \epsilon_{\text{uncond}})$ 每个模态一个权重,单模态时退化为 CFG
跨模态梯度 $\hat\epsilon = \epsilon_\theta + \lambda_t \nabla_{x_t}\mathcal S\big(f_{\text{img}}(\hat x_0), f_{\text{mod}}(c_m)\big)$ 用相似度梯度做对齐,$t \le t_{\text{stop}}$ 时置 0
潜空间解码 $\text{图} = \text{VAE}_{\text{decode}}(z_0)$ 只在最后做一次
视频加噪 $x_t = \sqrt{\bar\alpha_t}x_0 + \sqrt{1-\bar\alpha_t}\epsilon,\ \epsilon \in \mathbb{R}^{F\times C\times H\times W}$ 与图片同式,整段共用一个 $t$

12. 五句话记住推理

  1. 起点是随机的:从标准高斯噪声出发,这是”每次生成都不一样”的根源。
  2. 网络只会一件事:给它带噪图和时间步,它猜噪声;$\hat x_0$、$\mu_\theta$ 都是从噪声反推出来的,不是网络直接输出的。
  3. 慢 vs 快的取舍:步数越多越稳但越慢;DDIM / DPM-Solver 用更聪明的走法压缩到 20 步,LCM 直接学抄近路压到 4 步。
  4. 引导是三个不同的旋钮:CFG 管”贴不贴提示词”,STG 管”清不清晰”(不伤动态),Modality Guidance 管”多模态绑多紧”——它们可以同时开。
  5. 换成视频不是换一套原理:只是数据多一个轴 $F$,整段共用一个 $t$,网络多出时间层;图片模型就是 $F = 1$ 的特例。

参考

  • Ho, Jain, Abbeel. Denoising Diffusion Probabilistic Models, NeurIPS 2020(arXiv:2006.11239)——采样算法 Algorithm 2
  • Song, Meng, Ermon. Denoising Diffusion Implicit Models, ICLR 2021(arXiv:2010.02502)——DDIM 与确定性采样
  • Ho, Salimans. Classifier-Free Diffusion Guidance, NeurIPS 2021 Workshop(arXiv:2207.12598)——CFG
  • Rombach et al. High-Resolution Image Synthesis with Latent Diffusion Models, CVPR 2022(arXiv:2112.10752)——潜空间扩散 / Stable Diffusion
  • Lu et al. DPM-Solver, NeurIPS 2022(arXiv:2206.00927)——高阶求解器
  • Hyung et al. Spatiotemporal Skip Guidance for Enhanced Video Diffusion Sampling, CVPR 2025(arXiv:2411.18664)——STG,代码 github.com/junhahyung/STGuidance
  • Karras et al. Guiding a Diffusion Model with a Bad Version of Itself, NeurIPS 2024(arXiv:2406.02507)——Autoguidance,STG 的思想来源
  • Dhariwal, Nichol. Diffusion Models Beat GANs on Image Synthesis, NeurIPS 2021(arXiv:2105.05233)——classifier guidance
  • Nichol et al. GLIDE, ICML 2022(arXiv:2112.10741)——CLIP guidance / 跨模态对齐引导
  • NVIDIA Cosmos Transfer 2.5 文档——多控制模态(Edge / Depth / Seg / Vis)的权重与归一化规则
  • Lin et al. Common Diffusion Noise Schedules and Sample Steps are Flawed, WACV 2024(arXiv:2305.08891)——CFG 的 rescaling / guidance rescale

扩散模型推理(采样)完整过程讲解

https://xyz.desirer233.fun/2026/10/07/AI/扩散模型推理过程讲解/

作者

Desirer

发布于

2026-10-07

更新于

2026-10-07

许可协议