为了学习这门课程,我们需要先复习下面的知识
- 线性代数:向量、矩阵及其运算、梯度、散度
- 概率论:贝叶斯法则、条件概率和边缘概率、期望、协方差矩阵、高斯分布
- 微分方程:常微分方程、随机微分方程
- 深度学习:损失函数、训练、推理、神经网络架构
我挑一些我认为重要的知识来讲讲,后面的部分我们会用到
条件概率都知道吧?怎么从 P(A∣B) 得到 P(B∣A)? 下面的公式就可以得到:
P(A∣B)=P(B)P(B∣A)P(A)
记住这个公式,后面会用到
高斯分布在后面会反复出现,先记住它最常见的写法:
X∼N(μ,σ2)
其中 μ 是均值,σ2 是方差
不过后面你可能会见到这种形式:
N(x;μ,σ2)
注意这两个写法表达的东西有一点区别:前面的 X∼N(μ,σ2) 是说「随机变量 X 服从这个分布」;后面的 N(x;μ,σ2) 是这个分布在 x 处的概率密度,不是说连续型随机变量刚好取到 x 的概率。
记住它们两个
不过,深度学习是张量的艺术,我们还需要定义一种针对张量的高斯分布:

其中:
x(i)∼N(μ(i),Σ(i,i)) 和 Σ(i,j)=Cov(x(i),x(j))
此外,这里的 Cov() 是协方差。
讲人话就是:普通高斯只有一个均值和方差,多维高斯则有一串均值(均值向量)和一张记录各维度如何共同变化的表(协方差矩阵 Σ)。它的密度公式也会用到矩阵运算,但不是简单把乘法都换成矩阵乘法就完事了。
不过,Σ 有可能很复杂,但幸运的是,在我们这里,为了简化运算,它很大情况下都是各向同性的协方差矩阵,即:
Σ=σ2I=σ20⋮00σ2⋮0⋯⋯⋱⋯00⋮σ2
期望是什么这里不赘述了,我只把积分式公式放在这里:
E(X)=∫−∞+∞xf(x)dx
这个式子也请牢牢记住它
如果一个函数它是一个 凹函数 (形如 log(x)、x 的函数),那么它满足下面的性质:
f(E[X])≥E[f(X)]
其中 E(X) 是期望
注意点
这里所指的凹函数,非国内教材的凹函数的定义,我的高数老师以前说过国内外的定义是恰好相反的,所以要注意这点
记住这里的 log(x) 函数和这个不等式,后面有用
这个东西用来衡量两个概率分布 P 和 Q 之间的区别有多大,用下面的公式算:
DKL(P∥Q)=∫p(x)log(q(x)p(x))dx=Ex∼P[log(q(x)p(x))]
其中 p(x) 和 q(x) 是两个分布的密度。第一次看不直观没关系,后面主要用到它的作用:让两个分布尽量接近时,就想办法把 KL 散度变小。
我觉得铺垫的差不多了,我们可以进入正题了
大家都知道现在的生图模型都比较厉害了,但是我们还是要先从 基!本!功!练起,第一讲先学习无条件生成
什么是无条件生成?现在的生图模型基本上都是先让你输入一些图片、文字甚至视频来让他画出你想要的图片。无条件生成就是什么都不说,只让模型生成一张图片,比如你训练了一个专门生成狗的生图模型,你点击一下它,它就吐出一张狗的图片,狗是啥样子、在哪里全看模型心情。这是最简单的生图模型了
然后我们这讲学习的就是扩散模型(Diffusion Model)的生成范式,也就是讲讲扩散模型的生图原理
所谓扩散模型,就是一开始给你一张完全是噪声的图片,模型一点一点地把噪声去掉,然后从噪声里面剥出一张好看的图片。就像雕刻家雕一块石头一样,从一块不规则形状的石头里雕刻出一块精美的雕塑(不过我看人脑里多少也有点扩散模型的意思,每次看到毫无关联的“噪声”图片时脑子里瞬间就绘制出梗图了)
Fig.1 Diffusion 模型生图过程不过,这块完全是噪声的"石头"也不是河边随便找一个石头就可以雕刻出好康的东西的,不然我为什么不直接用全是 RGB(255,255,255) 的图片原地生图。我先说说这块石头的要求:
首先,它要有充足的随机性,也就是说,每次生成的图片总不能是一样的,这样搞人工智能就没有意义了,必须生成有新鲜感的东西,不然我为什么不用机械,因此生图的起点必须是一个随机的噪声图
其次,它必须是从一个容易采样的分布中生成的。什么意思?那我们就需要说说采样是什么意思
例子
这里有个概率分布,掷色子,表达式很简单 p(x) = 1/6,但你实际丢出这个色子的时,你这个动作,就叫完成了一次采样,也就是在符合这个概率分布的规则的同时,我在该概率分布里随机取了一个值
想象一下,如果你整了一个极其复杂的概率分布,计算机模拟一次取值要消耗大量的算力,比如要反复生成一万亿次才能得到噪声图,那就有点得不偿失了,所以一定要简单、容易取样
那我们就可以使用我们之前说到的高斯分布了,首先,它足够随机。其次,它容易生成也容易采样,计算机已经有非常成熟的算法来生成它,而且其概率函数的数学性质也很不错,这个在后面的数学推导我们会说
如 Fig.1 所示,扩散模型的生图原理,便是从噪声中一点点剥离噪声,最后生成目标图片,这就是它的推理过程。那么在训练时,我们就需要事先写一个程序,给清晰图片加上噪声,再让模型猜我们刚刚加的噪声是什么。它猜得准不准,就是我们给模型打分的依据。
训练时真的要把图片一步步去噪吗?
这里先讲最常用的简化训练方法:我们亲手加噪,所以知道标准答案 ϵ;把模型猜的 ϵθ 和它比较,就能计算损失。训练时不需要先完整生成一张图片再打分,真正从纯噪声一路去噪到成品图是生成时的流程。
Fig.2 给图片加上噪声要把图片拿给模型处理,自然要先把他变为一个数学对象来进行处理。当然,我们很自然就能想到用张量来表示它:
Fig.3 图片是张量所以,我们下面说的 x ,都不是一个单纯的数字变量,而是一个张量变量,一定要切记
这里的 xn 都是一个一个的像素点的表示,这是我们将 Height x Width x RGB 展开成一个超长的一维向量了
不过,这涉及一个问题,就是我们如何衡量模型做的好坏?也就是我们的损失函数要怎么设计?学过深度学习的都知道,我们必须把任务执行的好坏程度量化为函数,用来帮助模型找到自己存在的问题并使其进步
现在看着 Fig.2,我们着重看加噪声的这个环节,我们把 x0 记为我们原来的照片,每加一层噪声下标加一,那么针对从 xt−1 到 xt 的过程,那么我们定义发生这件事情的概率为
q(xt∣xt−1)
即我们拿到 xt−1 后,产生照片 xt 的条件概率。我们自己规定这一小步按高斯分布加噪,暂时用 W 和 V 表示旧图片和新噪声的系数:
q(xt∣xt−1)=N(xt;Wxt−1,V2I)
为什么要服从高斯分布而不是其他的什么分布,这是“上天的指示”吗?当然可以服从其他的分布,但是,高斯分布的数学性质很好,能帮我们减小工作量,这个我们后面会说。
什么?什么叫也可以服从其他分布?我们看到下面的图:
Fig.4 概率分布 q 是我们自己选的如图所示,总之给图片加噪声就是这个公式: 噪声图像 = 啥啥原图 + 啥啥噪声,也就是 xt=W×xt−1+V×ϵ (其中 ϵ∼N(0,I) 因为它是高斯噪声)。但别忘了,这个公式是我们自己定义的,反正有无数种方法能把 xt 搞出来,这只是其中一种,也是最聪明的一种。
这里的 W 和 V 随时间步变化,控制旧图片和新噪声各占多少。通常我们先规定每一步的 βt 怎么变化,这一串 βt 才叫 噪声调度(Noise Schedule);后面会令 W=1−βt、V=βt。
那为什么 xt=W×xt−1+V×ϵ 是高斯分布?我们知道 ϵ∼N(0,I),其均值为 0 ,协方差为 I。
注意
在这里,xt−1 是一个常量,不是变量!因为 xt−1 这张照片已经给定你了
那么在已知 xt−1 的条件下取期望,噪声的期望是 0,所以:
E[xt∣xt−1]=Wxt−1+V=0E[ϵ]=Wxt−1
现在再看协方差(这里的 xt 是一个图片向量,所以结果是矩阵):
Cov(xt∣xt−1)=Cov(Wxt−1+Vϵ)=Cov(Vϵ)=V2⋅=ICov(ϵ)=V2I
所以在给定 xt−1 时,xt 仍然服从高斯分布,均值是 Wxt−1,协方差是 V2I。到这一步我们还没给 W 和 V 选具体数值。
要让每一步加多少噪声都能由我们控制,就规定 0<βt<1,并取 W=1−βt、V=βt。代回去就是:
q(xt∣xt−1)=N(xt;1−βtxt−1,βtI)
为什么定义 W 和 V 为这两个数?
很容易看出 W2+V2=1,像给旧信号和新噪声的权重栓了根绳子:βt 越大,这一步保留的旧信号越少,加入的噪声越多。这个选择也让我们后面能写出好算的 q(xt∣x0)。它不能保证每个像素始终在某个固定范围内,也不能仅凭这个等式断言不会发生梯度爆炸。
上面那个式子只告诉我们:已知上一张图 xt−1,怎么得到下一张图 xt。但是训练的时候,要是每次想拿到第 t 步的图片,都得从原图开始一张一张地加噪声,加几百上千次,显然很麻烦。
能不能直接从 x0 跳到 xt?当然能,我们先把刚才的式子写成采样时的样子。为了少写几个根号,令 αt=1−βt,而且注意每一步都重新采样一个独立的高斯噪声 ϵt∼N(0,I):
xt=αtxt−1+1−αtϵt
先看看两步是什么样的。把 x1 代入 x2:
x1x2=α1x0+1−α1ϵ1=α2x1+1−α2ϵ2=α1α2x0+α2(1−α1)ϵ1+1−α2ϵ2
后面那两坨噪声看着很吓人,但它们都是相互独立的高斯噪声。两个独立的高斯随机变量加起来还是高斯的;它们的均值都是 0,协方差直接相加就好。因此 x2 在给定 x0 时,均值是 α1α2x0,协方差则是:
[α2(1−α1)+(1−α2)]I=(1−α1α2)I
发现规律了吗?前面原图的系数是各步 α 连乘再开根号,后面噪声的协方差则是 1 减去这个连乘。为了不把公式写成一条长龙,我们给这个连乘起个名字:
αˉt=∏i=1tαi=∏i=1t(1−βi)
那第 t 步是不是也这样?假设 xt−1 在给定 x0 时,均值为 αˉt−1x0、协方差为 (1−αˉt−1)I。再加一步噪声,均值乘上 αt,协方差变成:
αt(1−αˉt−1)I+(1−αt)I=(1−αˉt)I
这样就推出来了:
q(xt∣x0)=N(xt;αˉtx0,(1−αˉt)I)
讲人话就是:给定原图以后,任意第 t 步的图片,都能直接从这个高斯分布里采样出来。不用真的从 x0 一步一步加到 xt。实际写代码时,就是随机取一个 ϵ∼N(0,I),然后算:
xt=αˉtx0+1−αˉtϵ
注意这里的 ϵ 是把前面好多步独立噪声合起来之后得到的一个新的标准高斯噪声,不是说每一步都拿同一份噪声反复加。这个公式后面训练模型的时候非常好用。这就是为什么我说高斯分布的数学性质很好
至此,你成功整出来一个优化很好且能跳步加噪声的程序(比如你要加 80 次噪声,不用真加 80 次,只需要加一次就行了)
前面折腾半天,我们已经知道怎么从照片 x0 得到一张噪声图 xt 了。但生图的时候我们的模型要做的事情恰好相反:给你一张噪声图 xt,让你把它变回噪声少一点的 xt−1。这样一层一层剥下去,最后才能得到图片。
Fig.5 图片去噪过程这里我们先把两个字母搞清楚,不然后面看公式真的很容易晕:
- q:前向加噪,是我们自己规定好的过程。βt 怎么取、每一步加多少噪声,都是我们事先选的,不用模型学。
- pθ:反向去噪,是模型要学的过程。下标 θ 就是神经网络里的参数,训练的时候它会变。
于是我们把模型从 xt 生成 xt−1 的条件概率写成:
pθ(xt−1∣xt)
这个式子是什么意思?假设你手里只有一张已经加过噪声的图片 xt,模型会告诉你:下一张稍微干净一点的图片 xt−1 应该长什么样。注意,它不是前面那个 q(xt∣xt−1) 把竖线两边交换一下。加噪我们知道具体怎么加,可是从噪声图倒推回去,可能有不止一种合理的结果,这一步得让模型来学。
和前向过程类似,我们也让每一步的反向分布采用高斯形式:
pθ(xt−1∣xt)=N(xt−1;μθ(xt,t),σt2I)
这里的 μθ(xt,t) 是模型根据当前图片和时间步 t 给出的均值,决定这一步往哪儿去;σt2I 是这一步采样用的协方差。我们先把方差当成预先选好的量,主要让模型学习均值。后面还会看到,实际训练时可以不直接让网络预测这个均值,而是让它预测图片里混进了多少噪声。
那么生图的时候具体怎么走?先从简单好采样的标准高斯分布里抽一张纯噪声图 xT:
xT∼N(0,I)
然后用模型一步步采样 xT−1,xT−2,…,x0。讲人话就是:先抓一把随机噪声,再让模型反复修图,直到它看起来像训练集里的图片。
但是这里还有个问题:模型到底怎样才算学会了修图?一个很自然的想法是,既然我们想让它生成训练集里的图片,那就让模型给真实图片 x0 的概率尽可能大,也就是最大化对数似然:
maxθEx0∼q(x0)[logpθ(x0)]
这里 q(x0) 表示真实图片的数据分布,不是某一步加噪的条件概率;pθ(x0) 则是模型最终生成这张图片的概率。我们取个 log,主要是因为后面连乘的概率会变成连加,推导和计算都方便。
不过话说回来,模型走了 T 步才生成 x0,中间的 x1,…,xT 都是随机变量。要算出一张图的 pθ(x0),就得把这些中间步骤的所有可能性都考虑进去:
pθ(x0)=∫p(xT)∏t=1Tpθ(xt−1∣xt)dx1:T
这就麻烦了,谁愿意直接算这么大一坨积分?所以接下来我们不硬算 logpθ(x0),而是找一个能算的下界来优化,它叫 ELBO。前面复(预)习的琴生不等式,马上就要派上用场了。
先说清楚刚才的积分在干什么:如果我们已经指定了一张真实图片 x0,那么从噪声走到它,可以经过各种各样的 xT,xT−1,…,x1。pθ(x0) 要把所有可能的中间路线都加起来,这就是积分的来源。
这里谁是常量?
看下面的推导时,先拿训练集里一张给定的 x0 来算。此时 x0 是已知的;积分号里的 x1,…,xT 才是要遍历的中间变量。等到最后对整个训练集取平均,我们才让 x0 也跟着变化。
我们能不能利用已经写好的加噪过程 q,来帮忙处理这堆中间变量?可以。把从 x0 加噪得到整条路线的条件分布记成:
q(x1:T∣x0)=∏t=1Tq(xt∣xt−1)
x1:T 是 x1,…,xT 的缩写;右边能连乘,是因为下一步加噪只看上一步的图片。这个 q 是我们自己定的,这里并没有新训练一个模型。现在在原来的积分里乘上 q 再除以 q,相当于乘以 1:
pθ(x0)=∫pθ(x0:T)dx1:T=∫q(x1:T∣x0)q(x1:T∣x0)pθ(x0:T)dx1:T=Ex1:T∼q(⋅∣x0)[q(x1:T∣x0)pθ(x0:T)]
第一行的 pθ(x0:T) 是整条反向路线的联合概率密度,也就是上一节积分号里那一整串乘法。最后一行没有凭空冒出新东西:按照期望的定义,∫q(z)f(z)dz 就是“从 q 里抽 z,计算 f(z),再取平均”。这里只是把 z 换成了整条路线。
乘一个 q 再除一个 q,图什么?
单从代数看,确实啥也没变。但这样一来,积分就被改写成了对一个已知分布取期望。前向加噪的 q 是我们自己规定的,可以拿真实图片采样出中间路线;反向模型的 pθ 则是我们要训练的对象。这一步相当于把“枚举所有路线”改成了“沿着已知的加噪路线算平均”。
接下来,两边取 log,并用前面复习的琴生不等式。因为 log 是凹函数,先取平均再取 log,不小于先取 log 再取平均:
logpθ(x0)=logEq(x1:T∣x0)[q(x1:T∣x0)pθ(x0:T)]≥Eq(x1:T∣x0)[logpθ(x0:T)−logq(x1:T∣x0)]
右边就是我们要找的证据下界,英文叫 Evidence Lower Bound,简称 ELBO。叫“下界”是因为它不超过左边的 logpθ(x0);叫“证据”可以先理解成“我们确实看到了这张真实图片 x0”。我们想让模型给真实图片更高的概率,于是转而最大化这个下界。
最大化下界,等于最大化原式吗?
不一定!下界越高,说明我们保证的最低值越高;但它和真实的 logpθ(x0) 之间可能仍有差距。这里不是说两者相等,而是原式难算,我们先优化一个更好下手的目标。
光写成期望还不够,模型怎么从中知道哪一步去噪出了问题?我们希望把它拆成“一步一步的考核”。先把前向路线和反向路线分别展开:
q(x1:T∣x0)pθ(x0:T)=q(x1∣x0)⋯q(xT∣xT−1)=p(xT)pθ(xT−1∣xT)⋯pθ(x0∣x1)
这里 p(xT)=N(0,I) 是最开始抽的纯噪声,它是预先规定好的,不是神经网络预测出来的。为了方便对照每一步,我们还可以把刚才的前向路线换一种乘法顺序来写:
q(x1:T∣x0)=q(xT∣x0)∏t=2Tq(xt−1∣xt,x0)
这怎么突然「倒着」写了?
左边仍然是同一个 q 的联合分布,没有把前向过程换成反向模型。前一种写法是沿着 x0→xT 加噪;后一种只是用条件概率,把同一条路线的概率从 xT 往回拆。请特别注意 q(xt−1∣xt,x0) 还知道原图 x0,而要学的 pθ(xt−1∣xt) 不知道原图,这两个不是同一个东西。
把这些连乘放回 ELBO,再利用 log(ab)=loga+logb,最后得到三类东西:
ELBO(x0)=Eq(x1∣x0)[logpθ(x0∣x1)]−DKL(q(xT∣x0)∥p(xT))−t=2∑TEq(xt∣x0)[DKL(q(xt−1∣xt,x0)∥pθ(xt−1∣xt))]
吓哭了,但一步步看就行:
- 第一行管最后一步:给模型一张只差一步就干净的 x1,它能不能把 x0 还原出来?
- 第二行管起点:加到最后的 xT,跟我们准备拿来生图的标准高斯噪声像不像?这个 q 和 p(xT) 都是事先规定的,所以这一项不靠训练 θ 来改变。
- 第三行管中间每一步:模型学的 pθ(xt−1∣xt),要尽量接近知道正确答案 x0 时算出来的 q(xt−1∣xt,x0)。前面说过,KL 散度越小,两个分布就越接近;这里它前面有个减号,所以最大化 ELBO 就会推动这些 KL 项变小。
为什么训练时能看原图,生图时却不能?
训练时我们手里本来就有真实图片 x0,可以自己给它加噪,拿它当“标准答案”来检查模型的去噪步骤;生图时手里只有随机噪声 xT,没有标准答案,所以真正用来生成图片的 pθ 只能依赖当前的 xt。这就是第三行两个条件概率一个带 x0、另一个不带的原因。
而且,能看原图我还要生图模型干啥。(我去不早说!)
好,现在问题缩小了:只要能算出那个“知道原图的答案” q(xt−1∣xt,x0),中间每一步就有了训练目标。接下来轮到前面复习的贝叶斯法则出场。
先提醒一下,这里算的是前向加噪过程 q 自己的条件概率。假设训练时我们拿着原图 x0,还知道加噪到第 t 步得到的 xt,那么第 t−1 步的图片可能是什么样?这就是 q(xt−1∣xt,x0) 要回答的问题。
根据贝叶斯法则,再利用“xt−1 已经给定时,下一步 xt 不需要再看 x0”这个性质,可以写成:
q(xt−1∣xt,x0)=q(xt∣x0)q(xt∣xt−1)q(xt−1∣x0)
这里为什么能直接套贝叶斯?
把 x0 当成已经知道的条件,再把贝叶斯法则里的 A 换成 xt−1、B 换成 xt 就好。分子本来会出现 q(xt∣xt−1,x0),但我们定义的加噪只依赖上一张图,所以它等于 q(xt∣xt−1)。别把这个式子看成“只知道 xt 就能完美倒推”——这里还额外知道真实的 x0。
更妙的是,这三个分布我们之前都认识:
q(xt∣xt−1)q(xt−1∣x0)q(xt∣x0)=N(αtxt−1,βtI)=N(αˉt−1x0,(1−αˉt−1)I)=N(αˉtx0,(1−αˉt)I)
所以这玩意不是一个完全摸不着头脑的未知分布,它仍然是高斯分布。怎么算它的均值和方差?这里稍微有点绕,我们先把 xt−1 暂时记作 z。此时 x0 和 xt 都已经给定,只有 z 是待求的变量。高斯概率密度里面最重要的是指数上的“平方除以方差”;把贝叶斯式的分子代进去,只挑跟 z 有关的部分,就得到:
q(z∣xt,x0)∝exp[−2βt∥xt−αtz∥2−2(1−αˉt−1)∥z−αˉt−1x0∥2]
∝ 是什么意思?分母去哪了?
∝ 读作“正比于”。贝叶斯式分母 q(xt∣x0) 和那些不含 z 的系数,对分布随 z 怎么变化没有影响,所以先不写;最后它们会负责把整张概率密度曲线调整到积分为 1。不是说分母真的消失了。
怎么从这个指数读出高斯的均值和方差?把里面的平方展开,只盯着含 z 的项:
−21[(βtαt+1−αˉt−11)∥z∥2−2(βtαtxt+1−αˉt−1αˉt−1x0)Tz+C]
这里 C 是不含 z 的项。看着像天书?其实就是配平方:高斯指数里的 −∥z−μ∥2/(2σ2) 展开后,方括号里 ∥z∥2 的系数是 1/σ2,z 前面的向量系数是 μ/σ2。所以先把上面 ∥z∥2 的系数取倒数得到新方差,再用新方差乘 z 前面的向量得到新均值。代入 αˉt=αtαˉt−1 约分,结果是:
q(xt−1∣xt,x0)β~tμ~t(xt,x0)=N(xt−1;μ~t(xt,x0),β~tI)=1−αˉt1−αˉt−1βt=1−αˉtαˉt−1βtx0+1−αˉtαt(1−αˉt−1)xt
β~t 和 βt 是同一个东西吗?
不是。βt 是我们预先规定的正向加噪方差;带波浪号的 β~t 则是在**同时知道 x0 和 xt**之后,倒推 xt−1 算出来的方差。它们来自不同的条件分布,不要看名字像就把它们当成一样。
看着有点密,但意思很简单:训练时有原图 x0,我们就能算出“给定 xt,前一步应该怎样分布”这个标准答案。接下来拿它和模型的 pθ(xt−1∣xt) 比较就行。
回忆一下,ELBO 中间那项是两个分布的 KL 散度。我们先选择模型反向分布的方差也用 β~tI,让两个分布的协方差相同,这样 KL 散度只剩下均值之间的距离(这里讨论 t≥2):
DKL(q(xt−1∣xt,x0)∥pθ(xt−1∣xt))=2β~t1∥μ~t(xt,x0)−μθ(xt,t)∥2
为什么 KL 散度能变成均方误差?
前提是这两个都是高斯分布,而且协方差取成一样的。此时它们形状一样,区别主要在“中心点”在哪儿;KL 计算出来就是两个均值的平方距离乘上一个系数。如果方差也让网络自己预测,就不能直接用这里这么简单的式子。
这时你可能会问:既然比均值,直接让网络预测 μθ 不就完事了吗?可以,但我们已经有了一个非常方便的加噪公式:
xt=αˉtx0+1−αˉtϵ,ϵ∼N(0,I)
只要知道 xt 里混进的是哪份噪声 ϵ,我们就能把原图写出来:
x0=αˉtxt−1−αˉtϵ
这不是说生成时真的知道 x0
这是把训练时用来加噪的那份 ϵ 代回公式,方便改写标准答案。训练时 x0 和 ϵ 我们自己都有;生成时没有原图,也不知道真正的噪声,所以才需要模型根据 xt 和 t 去预测噪声。
把这个 x0 代进刚才的 μ~t,整理一下,可以得到一个看着顺眼得多的式子:
μ~t(xt,x0)=αt1(xt−1−αˉtβtϵ)
注意,这里的 ϵ 仍然是真实加进去的噪声。模型拿不到它,于是让神经网络 ϵθ(xt,t) 去预测,再用同一套算式给出模型的均值:
μθ(xt,t)=αt1(xt−1−αˉtβtϵθ(xt,t))
这下看出妙处了:标准答案的均值和模型的均值,其他部分一模一样,区别只有 ϵ 与 ϵθ。代回刚才的 KL,得到:
DKL=2β~tαt(1−αˉt)βt2∥ϵ−ϵθ(xt,t)∥2
前面的分数只取决于我们事先定好的加噪时间表,不是模型参数。于是核心训练任务变成了:给模型一张加过噪的图片和时间步,让它猜我们当时加进去的噪声,猜得越准越好。
实际训练常用一个更简单的版本:随机取一张真实图片 x0、一个时间步 t、一份标准高斯噪声 ϵ,直接合成 xt,然后计算预测噪声的均方误差:
Lsimple(θ)=Ex0∼q(x0),t∼U{1,…,T}ϵ∼N(0,I)[ϵ−ϵθ(αˉtx0+1−αˉtϵ,t)2]
它和刚才的 ELBO 完全一样吗?
不完全一样。上面的 KL 推导针对的是中间步骤 t≥2,而且前面还有一个随 t 变化的系数;实际常用的 Lsimple 把这个权重去掉,并把 t=1 也放进统一的噪声预测训练里。ELBO 的最后一步 x1→x0 本来还单独有一项。所以不能说“ELBO 严格等于这一个 MSE 式子”,它是从推导中得到启发、实际使用的简化训练目标。
到这里我们终于把怎么衡量模型修图修得好不好讲通了,而上面的理论,由 DDPM 这篇文章提出,原文链接在文章结尾。如今训练出题和打分的问题解决了,接下来看看模型真正生图时要走多少步。
训练时,我们是随便抽一个时间步 t,造出对应的 xt,让模型猜噪声。但生成时手里没有原图,只能从 xT 出发,一步一步往回走。这两个过程可别搞混了。
先看按前面的 DDPM 反向分布,生成一张图要干什么。我们已经有模型预测的均值 μθ(xt,t),每一步再从高斯分布里抽一份噪声 z:
xt−1=μθ(xt,t)+σtz,z∼N(0,I)
从 xT 走到 xT−1,再走到 xT−2……直到 x0。假如有一千步,就要请神经网络预测一千次噪声。训练完了还得等它一步步修图,生一张图片可太慢了。(按 DDIM 论文里的说法,一张 RTX 2080 Ti 上这么老老实实的生成,5万张 256x256 的图片直接用了 1000 小时)
生成时的 z 是什么?
ϵθ(xt,t) 是模型预测要从当前图片里去掉的噪声;上面新采样的 z 是这一步更新时额外加入的随机性。这两个别看都叫噪声,就把它们当成一个东西。通常最后一步不再加这份新的随机噪声。
那我直接把中间几步删了行不行?比如原本要走 x1000→x999→⋯→x500,我直接拿 x1000 算一次更新,假装它就是 x500?这倒是有点阿 Q 的精神胜利法的样子,听起来省了好多时间,但刚才的反向公式是按相邻两步推出来的。大步一跨,原来的系数和额外采样的随机噪声都不再适合这个跨度,图片质量可能明显下降。另一种想法是把连续几次更新代入、合成一个大公式,可公式里还是要在各个中间时间步调用网络,算力根本没省下来。
跳步到底要省什么?
主要省的是神经网络的调用次数,不是让纸面上的式子看起来短一点。要是写一个跨越五步的公式,结果还得分别计算那五步的 ϵθ,那速度上仍然没有赚到。
于是,DDIM 解决了这个问题
前面推训练损失时,有一个非常关键的便利:只要给定 x0,我们就能直接按下面的分布造出任意时刻的 xt:
q(xt∣x0)=N(αˉtx0,(1−αˉt)I)
简化版噪声预测训练就是靠它随机选 t 来造题的,并没有要求训练时必须真的把 x1,x2,…,xt 每一步都造出来。于是 DDIM(Denoising Diffusion Implicit Models)的主意来了:保留各个时刻 q(xt∣x0) 不变,但重新安排不同时间步之间怎么走,让生成时的更新可以不额外抽新噪声。这样,前面训练好的噪声预测网络还可以用。
边缘分布一样,不代表整条路线一样
「第 t 步的 xt 各自长什么样」和「xt 与 xt−1 之间怎么关联」是两件事。就像两部电影都拍到了同样的起点和终点,中间剪辑可以不同。DDIM 保留前者,但改变了后者
具体怎么更新?先请网络看着当前的 xt 猜噪声,再利用前面那个加噪公式,反推出它心目中的原图:
x^0(xt,t)=αˉtxt−1−αˉtϵθ(xt,t)
这个 x^0 就是“模型猜原图应该长这样”。假如我们打算从时间 t 直接跳到更早的时间 s,其中 0≤s<t,就按时间 s 应有的信号和噪声比例,把它们重新组合:
xs=αˉsx^0(xt,t)+1−αˉsϵθ(xt,t)
看这个式子,其实就是「s 时刻的图片 = 一部分模型猜的原图 + 一部分模型猜的噪声」。这一步没有再抽一份新的随机噪声,所以给定当前的 xt 和已经训练好的模型,结果 xs 就确定了。这是 DDIM 的确定性采样形式。
不过刚才说的“确定”别理解成“无论点多少次生成按钮,出来的都是同一张图”。起点 xT 仍然是随机抽的;同一个起点、同一个模型,走这套确定性更新才会得到同一个结果。
现在我们终于能真的跳步了:自己挑一串要走的时间点,例如 τ0=0<τ1<⋯<τS=T,从 xτS 开始,依次算 xτS−1,xτS−2,…,xτ0。每跨一次只调用一次预测噪声的网络,总共调用 S 次,而不一定非得调用 T 次。时间点不要求均匀分布,可以按生成效果调整。
既然能跳,我一步跳到底不就好了?
不行,模型在大跨度下的估计未必足够准。跳得越狠,网络调用越少、速度越快,但生成质量通常也会受影响。所以时间点怎么选、总共走几步,是速度和质量之间的取舍。课程用 CIFAR-10 上的实验给了一个很直观的表:
| 生成速度提升 | 1 倍(基准) | 10 倍 | 20 倍 | 50 倍 | 100 倍 |
|---|
| FID 相对基准的变化 | 基准 | +3% | +16% | +70% | +330% |
其中,FID 越低越好,它是用来衡量生成图片与真实图片分布差异的指标。
所以 DDIM 并不是让模型一眼把纯噪声看成成品图,而是换了一条能跨更大步子的去噪路线:训练时仍然学怎么猜噪声,生成时少走一些时间点。这就是“生成时跳步”的核心。
至此,我们有了出题的方法和判断模型做的好不好的损失函数。接下来还得考虑用什么网络来做噪声预测:DDPM、Stable Diffusion 1.5 等模型用过 U-Net,DiT 则采用 Transformer。虽然实现和训练细节可以不同,本文讨论的这类扩散模型共享“加噪、学会预测噪声、再逐步生成”这条主线;别把这里的一套具体公式当成所有生成模型都必须照搬的规定。
极致中配】2026年春季 斯坦福大学 CME296: 扩散与大视觉模型 Diffusion & Large Vision Models
Denoising Diffusion Implicit Models
Denoising Diffusion Probabilistic Models