深度学习笔记-8:GAN、标准化流、自编码器与扩散模型 - MuxiaoWF跳到主要内容

深度学习笔记-8:GAN、标准化流、自编码器与扩散模型

深度学习笔记-8,涵盖四大生成模型:GAN、标准化流、自编码器与变分自编码器(VAE)、扩散模型。对应《深度学习:基础与概念》第17-20章。

周一 9月 01 2025
18900 字 · 70 分钟

系列第 8/8 篇(完结) ← 上一篇 | 术语表

建议先看完第1-7篇,尤其是第7篇的采样方法和潜变量模型。本篇讲四种生成模型:GAN、标准化流、自编码器和扩散模型。

Chapter 17 生成对抗网络 (GAN)

可以去kaggle-我自己也是个画家看看(

对抗训练

用人话说:GAN的核心思想可以用”造假者vs鉴定师”来理解。生成器(Generator)就像一个造假画的人,它的目标是画出足以以假乱真的画;判别器(Discriminator)就像一个鉴定师,它的目标是分辨出哪些是真画、哪些是假画。两者不断博弈,造假者的水平越来越高,鉴定师的眼光也越来越准——最终造假者能生成以假乱真的作品。

生成模型的目标是学习一个从训练数据集中抽取样本所遵循的概率分布(即数据的”生成规律”) pdata(x)p_{\text{data}}(\mathbf{x}) 。一旦模型学会了这个分布,它就可以生成新的、与训练数据相似的样本。

  • 参数化模型(Parametric Model):我们引入一个带可学习参数的生成模型 p(xw)p(\mathbf{x} | \mathbf{w}),其中 x\mathbf{x} 是数据空间中的向量(如图像的像素值),w\mathbf{w} 是模型的可学习参数。
  • 条件生成模型(Conditional Generative Model):有时我们希望生成特定类型的样本,例如生成一只猫的图片。这可以通过引入条件变量 c\mathbf{c} 来实现,模型变为 p(xc,w)p(\mathbf{x} | \mathbf{c}, \mathbf{w})c\mathbf{c} 可以是类别标签(如”猫”或”狗”)或更复杂的描述。

本章讨论的第一类生成模型是非线性潜在变量模型(Nonlinear Latent Variable Model)。其核心思想是通过一个非线性变换,将一个简单的低维潜在分布(潜变量 z\mathbf{z} 所服从的分布)映射到复杂的高维数据分布。

还记得第7篇的潜变量模型吗? GAN也使用了同样的框架:一个简单的潜变量 z\mathbf{z} 通过神经网络变换为复杂的数据样本 x\mathbf{x}

  • 潜在空间(Latent Space):引入一个低维的潜在变量 z\mathbf{z},它遵循一个简单的先验分布 p(z)p(\mathbf{z}) ,通常选择标准正态分布: p(z)=N(z0,I)p(\mathbf{z}) = \mathcal{N}(\mathbf{z} | \mathbf{0}, \mathbf{I})
  • 生成器网络:定义一个由深度神经网络实现的非线性函数 x=g(z,w)\mathbf{x} = g(\mathbf{z}, \mathbf{w}) ,其中 w\mathbf{w} 是网络的权重参数。这个网络被称为生成器(Generator)。
  • 隐式分布(Implicit Distribution):生成器网络 g(z,w)g(\mathbf{z}, \mathbf{w}) 和先验分布 p(z)p(\mathbf{z}) 一起,隐式地 定义了数据空间上的一个分布 pG(x)p_G(\mathbf{x})。我们无法直接写出 pG(x)p_G(\mathbf{x}) 的解析形式,但可以通过从 p(z)p(\mathbf{z}) 采样 z\mathbf{z} 并计算 g(z,w)g(\mathbf{z}, \mathbf{w}) 来生成服从 pG(x)p_G(\mathbf{x}) 的样本。

对抗网络

对抗网络:生成器从潜变量 z 生成假图像,判别器判断输入是真是假

上图展示了 GAN 的整体架构:

  • 左侧:一个”Latent Variable” z\mathbf{z} 输入到”Generator”网络 g(z,w)g(\mathbf{z}, \mathbf{w}),输出”Synthetic Images”(合成图像)xsynth\mathbf{x}_{\text{synth}}
  • 中间:一个”Discriminator”网络 d(x,ϕ)d(\mathbf{x}, \mathbf{\phi})。 判别器接收两类输入:来自训练集的”Real Images”(真实图像)xreal\mathbf{x}_{\text{real}} 和来自生成器的合成图像。
  • 判别器输出一个标量 t[0,1]t \in [0, 1],表示输入图像是真实图像的概率。

对抗训练

对抗训练是 GAN 的核心机制。它引入了第二个网络——判别器(Discriminator),与生成器进行一场博弈。

  • 判别器网络:这是一个分类神经网络 d(x,ϕ)d(\mathbf{x}, \mathbf{\phi}) ,其参数为 ϕ\mathbf{\phi}。它的任务是区分输入图像是来自真实数据集 {xn}\{ \mathbf{x}_n \} 还是由生成器产生的合成图像。判别器的输出是一个介于 0 和 1 之间的标量,表示输入图像是真实图像的概率。
  • 博弈过程(想象一下造假者和鉴定师的对决):
    • 生成器的目标:最大化判别器的错误率。它希望生成的图像 xsynth=g(z,w)\mathbf{x}_{\text{synth}} = g(\mathbf{z}, \mathbf{w}) 能够”欺骗”判别器,让判别器认为它是真实图像,即 d(g(z,w),ϕ)1d(g(\mathbf{z}, \mathbf{w}), \mathbf{\phi}) \approx 1
    • 判别器的目标:最小化自己的错误率。它希望准确地区分真实图像和合成图像,即对于真实图像 xreal\mathbf{x}_{\text{real}} ,输出 d(xreal,ϕ)1d(\mathbf{x}_{\text{real}}, \mathbf{\phi}) \approx 1;对于合成图像 xsynth\mathbf{x}_{\text{synth}} ,输出 d(xsynth,ϕ)0d(\mathbf{x}_{\text{synth}}, \mathbf{\phi}) \approx 0
对抗损失函数的数学形式(极小极大博弈)

这种博弈可以用一个极小极大(minimax)博弈来形式化:

minwmaxϕV(w,ϕ)=Expdata(x)[logd(x,ϕ)]+Ezp(z)[log(1d(g(z,w),ϕ))]\min_{\mathbf{w}} \max_{\mathbf{\phi}} V(\mathbf{w}, \mathbf{\phi}) = \mathbb{E}_{\mathbf{x} \sim p_{\text{data}}(\mathbf{x})}[\log d(\mathbf{x}, \mathbf{\phi})] + \mathbb{E}_{\mathbf{z} \sim p(\mathbf{z})}[\log(1 - d(g(\mathbf{z}, \mathbf{w}), \mathbf{\phi}))]

其中:

  • 第一项 Expdata[logd(x,ϕ)]\mathbb{E}_{\mathbf{x} \sim p_{\text{data}}}[\log d(\mathbf{x}, \mathbf{\phi})] 是判别器在真实数据上的对数似然(判别器希望最大化这一项)。
  • 第二项 Ezp(z)[log(1d(g(z,w),ϕ))]\mathbb{E}_{\mathbf{z} \sim p(\mathbf{z})}[\log(1 - d(g(\mathbf{z}, \mathbf{w}), \mathbf{\phi}))] 是判别器在合成数据上的对数似然。判别器希望最大化这一项,而生成器希望最小化它。

简单来说就是:判别器想让这个值越大越好,生成器想让这个值越小越好。

训练过程

你可能会问:造假者和鉴定师怎么”一起训练”?答案是交替训练——先固定一个,训练另一个,然后轮换。

  1. 训练判别器(固定生成器不动):
  • 从真实数据集中采样一批真实样本 {xn}\{ \mathbf{x}_n \}
  • 从潜在分布 p(z)p(\mathbf{z}) 中采样一批 z\mathbf{z} ,通过生成器得到一批合成样本 {g(zn,w)}\{ g(\mathbf{z}_n, \mathbf{w}) \}
  • 计算判别器的损失 LDL_D,让判别器学会区分真假: LD=[1Nrealnreallogd(xn,ϕ)+1Nsynthnsynthlog(1d(g(zn,w),ϕ))]L_D = -\left[ \frac{1}{N_{\text{real}}} \sum_{n \in \text{real}} \log d(\mathbf{x}_n, \mathbf{\phi}) + \frac{1}{N_{\text{synth}}} \sum_{n \in \text{synth}} \log(1 - d(g(\mathbf{z}_n, \mathbf{w}), \mathbf{\phi})) \right]
  • 使用梯度下降法更新判别器参数 ϕ\mathbf{\phi} 以最小化 LDL_D
  1. 训练生成器(固定判别器不动):
  • 从潜在分布 p(z)p(\mathbf{z}) 中采样一批 z\mathbf{z}
  • 通过生成器得到合成样本 {g(zn,w)}\{ g(\mathbf{z}_n, \mathbf{w}) \}
  • 计算生成器的损失 LGL_G
为什么生成器的损失函数要换一种写法?

原始的生成器损失 log(1d())\log(1 - d(\cdot)) 在训练初期存在问题:当生成器很弱、判别器轻松分辨真假时,d()0d(\cdot) \approx 0,此时 log(1d())log(1)=0\log(1 - d(\cdot)) \approx \log(1) = 0,梯度几乎为零——生成器”学不动”了。

因此实践中使用一个替代目标: LG=1Nsynthnsynthlogd(g(zn,w),ϕ)L_G = -\frac{1}{N_{\text{synth}}} \sum_{n \in \text{synth}} \log d(g(\mathbf{z}_n, \mathbf{w}), \mathbf{\phi}) 这个目标是最大化判别器认为合成图像是真实的概率 d(g(z,w),ϕ)d(g(\mathbf{z}, \mathbf{w}), \mathbf{\phi}) 。在训练初期,即使判别器很有把握(d0d \approx 0),log(d)-\log(d) 也能提供强梯度。

  • 使用梯度下降法更新生成器参数 w\mathbf{w} 以最小化 LGL_G

函数图像

两种损失函数的梯度对比:为什么用 -log(d) 替代 log(1-d)

简单来说就是:横轴 dd 是判别器的输出(0=假,1=真)。当生成器很差(d0d \approx 0)时,log(1d)\log(1-d) 的梯度几乎为零(“学不动”),而 log(d)-\log(d) 的梯度很大(“学得快”)。

模式崩溃(Mode Collapse)

想象一下:你让一个人画各种动物,结果他发现画猫特别容易骗过鉴定师,于是不管你怎么催他,他永远只画猫。这就是模式崩溃——生成器”偷懒”只生成少数几种输出。

模式崩溃是 GAN 训练中一个常见且严重的问题。

  • 定义:在训练过程中,生成器的权重可能会适应到一种状态,使得所有潜在变量样本 z\mathbf{z} 都被映射到数据分布中一个很小的、有效的输出子集上。在极端情况下,生成器可能只会生成一个或少数几个固定的输出 x\mathbf{x}
  • 例子:一个训练手写数字的 GAN 可能学会只生成数字”3”,而完全忽略其他数字。
  • 后果:虽然判别器无法区分这些”3”与真实的”3”,但它无法识别生成器没有生成完整的数字范围。此时,判别器对这些”3”样本的输出会稳定在 0.5 左右(表示它完全无法区分),导致训练停止,生成器无法进一步改进。
  • 原因:这通常发生在判别器变得过于强大,或者生成器找到了一个可以稳定”欺骗”判别器的捷径时。

零梯度问题

用人话说:刚开始训练时,造假者的水平太差,鉴定师一眼就能看出真假。这时造假者得到的反馈是”你做的太假了”,但没有任何具体的改进方向——就像一个学生考试得了零分,但老师只说”错了”而不告诉他哪里错。这就是梯度消失问题。

训练 GAN 的一个根本困难在于,当生成分布 pG(x)p_G(\mathbf{x}) 和真实数据分布 pdata(x)p_{\text{data}}(\mathbf{x}) 差异很大时,判别器很容易学习,并且其梯度信号会变得非常弱。

函数图像

两个分布相距很远时,判别器在生成样本区域几乎为零,导致梯度消失

上图展示了问题所在:

  • pdata(x)p_{\text{data}}(x) 是真实数据的分布(例如一个高斯分布)。
  • pG(x)p_G(x) 是生成器的初始分布(例如另一个远离的高斯分布)。
  • 判别器函数 d(x)d(x) 在真实数据附近输出接近 1,在生成样本附近输出接近 0。
梯度消失的数学分析

由于两个分布相距很远,最优的 d(x)d(x) 在生成样本区域内会非常接近 0。考虑生成器的原始损失函数中的第二项:Ez[log(1d(g(z,w),ϕ))]\mathbb{E}_{\mathbf{z}}[\log(1 - d(g(\mathbf{z}, \mathbf{w}), \mathbf{\phi}))]

  • d(g(z,w),ϕ)0d(g(\mathbf{z}, \mathbf{w}), \mathbf{\phi}) \approx 0 时,log(1d())log(1)=0\log(1 - d(\cdot)) \approx \log(1) = 0
  • 更重要的是,d()d(\cdot) 在这个区域的梯度非常小(几乎是平的),导致生成器参数 w\mathbf{w} 的梯度 w\nabla_{\mathbf{w}} 也非常小。
  • 结果是,生成器的学习过程非常缓慢,甚至停滞。

改进

为了解决训练困难,研究者提出了多种改进方法。

最小二乘 GAN (LSGAN)

简单来说就是:把判别器的判断标准从”是/否概率”改成”打分”,用分数差距来给生成器提供梯度。

  • 使用一个更平滑的判别器函数 d~(x)\tilde{d}(x),使其在生成样本区域有更强的梯度,从而为生成器提供更有效的学习信号。
  • 最小二乘 GAN(Least-Squares GAN, LSGAN):
    • 修改判别器,使其输出一个实数值 d(x,ϕ)Rd(\mathbf{x}, \mathbf{\phi}) \in \mathbb{R},而不是概率 [0,1][0, 1]
    • 将交叉熵损失替换为最小二乘损失: minwmaxϕVLSGAN=Expdata[(d(x,ϕ)b)2]+Ezp(z)[(d(g(z,w),ϕ)a)2]\min_{\mathbf{w}} \max_{\mathbf{\phi}} V_{\text{LSGAN}} = \mathbb{E}_{\mathbf{x} \sim p_{\text{data}}}[(d(\mathbf{x}, \mathbf{\phi}) - b)^2] + \mathbb{E}_{\mathbf{z} \sim p(\mathbf{z})}[(d(g(\mathbf{z}, \mathbf{w}), \mathbf{\phi}) - a)^2] 其中 aabb 是目标值(例如 a=0,b=1a=0, b=1)。这种损失函数在远离目标值时会产生更大的梯度,有助于缓解梯度消失问题。

输入噪声

  • 向真实数据和合成样本都添加高斯噪声。
  • 效果:这使得数据点不再集中在离散的位置,而是散布在一个小区域内。这迫使判别器学习一个更平滑的决策边界,从而避免了在生成样本区域出现陡峭的、梯度为零的悬崖。

Wasserstein GAN (WGAN)

想象一下:假设 pGp_G 是一堆土,pdatap_{\text{data}} 是目标地形。Wasserstein 距离就是把这堆土搬到目标位置需要的最小”工作量”(土量 x 距离)。这个距离即使在两堆土完全不重叠时也能告诉你”差多远”,而原始GAN的损失在这种情况下已经”罢工”了(梯度为零)。

  • 直接衡量生成分布 pG(x)p_G(\mathbf{x}) 和真实分布 pdata(x)p_{\text{data}}(\mathbf{x}) 之间的距离(Wasserstein距离,又称推土机距离 Earth Mover’s Distance),并让生成器最小化这个距离。
  • 实现(WGAN):
    • 使用一个输出实数值的判别器(现在称为批评家 Critic)。
    • 通过梯度惩罚(Gradient Penalty)来限制判别器函数的梯度 xd(x,ϕ)\nabla_{\mathbf{x}} d(\mathbf{x}, \mathbf{\phi}) 的范数(使其接近 1),这保证了判别器是 1-Lipschitz 连续的(即函数变化率有上界),从而可以近似 Wasserstein 距离。
WGAN-GP 的损失函数

梯度惩罚 Wasserstein GAN(WGAN-GP)的损失函数为: EWGAN-GP(w,ϕ)=Expdata[d(x,ϕ)]+Ezp(z)[d(g(z,w),ϕ)]+ηEx^px^[(x^d(x^,ϕ)21)2]E_{\text{WGAN-GP}}(\mathbf{w}, \mathbf{\phi}) = -\mathbb{E}_{\mathbf{x} \sim p_{\text{data}}} [d(\mathbf{x}, \mathbf{\phi})] + \mathbb{E}_{\mathbf{z} \sim p(\mathbf{z})} [d(g(\mathbf{z}, \mathbf{w}), \mathbf{\phi})] + \eta \mathbb{E}_{\hat{\mathbf{x}} \sim p_{\hat{\mathbf{x}}}} [(\|\nabla_{\hat{\mathbf{x}}} d(\hat{\mathbf{x}}, \mathbf{\phi})\|_2 - 1)^2] 其中 x^\hat{\mathbf{x}} 是在真实数据和生成数据之间随机采样的点,η\eta 是惩罚项的权重。前两项是 Wasserstein 距离的估计,第三项确保判别器满足 Lipschitz 约束。

图像的生成对抗网络

深度卷积 GAN (DCGAN)

还记得第5篇的CNN吗? DCGAN就是把CNN的卷积结构用到了GAN里面。

DCGAN 是 GAN 发展史上的一个重要里程碑,它证明了 GAN 可以生成高质量的图像。

  • 架构:使用标准的卷积神经网络(CNN)作为生成器和判别器。
    • 生成器:从一个低维的潜在向量 z\mathbf{z} 开始,通过一系列的转置卷积(Transposed Convolution,一种”反向卷积”,用于将小图像放大)层逐步生成高分辨率的图像。
    • 判别器:一个标准的 CNN 分类器,输入图像并输出一个标量概率。
  • 训练稳定性:通过使用批量归一化(Batch Normalization)、合适的非线性激活函数(如 ReLU 和 Leaky ReLU)等技巧,DCGAN 的训练比早期的 GAN 更加稳定。

CycleGAN

想象一下:你有很多马的照片和斑马的照片,但没有”同一匹马变成斑马”的配对照片。CycleGAN 依然能学会马变斑马!它的秘诀是”循环一致性”——把马变成斑马再变回马,应该得到原来的马。

CycleGAN 是一种用于无配对图像到图像翻译(Unpaired Image-to-Image Translation)的模型。

  • 问题:我们有两个图像域 XX(如马的照片)和 YY(如斑马的照片),但没有成对的样本(即没有”同一匹马变成斑马”的配对图像)。
  • 目标:学习一个映射 GXYG_{X \to Y},能将域 XX 的图像转换为域 YY 的图像,反之亦然 GYXG_{Y \to X}
  • 对抗损失
    • 引入两个判别器 DXD_XDYD_Y
    • DYD_Y 试图区分真实的 YY 域图像和 GXY(X)G_{X \to Y}(X) 生成的图像。
    • DXD_X 试图区分真实的 XX 域图像和 GYX(Y)G_{Y \to X}(Y) 生成的图像。
  • 循环一致性损失(Cycle Consistency Loss):
    • 为了确保翻译是合理的,引入循环一致性约束。将一张 XX 域的图像 x\mathbf{x} 转换到 YY 域,再转换回 XX 域,应该得到一个与原始图像 x\mathbf{x} 非常相似的图像(”去了一趟再回来,还是一样的”)。
循环一致性损失和总损失的数学形式

循环一致性损失: Ecyc(wX,wY)=ExpX[GYX(GXY(x))x1]+EypY[GXY(GYX(y))y1]E_{\text{cyc}}(\mathbf{w}_X, \mathbf{w}_Y) = \mathbb{E}_{\mathbf{x} \sim p_X} [\| G_{Y \to X}(G_{X \to Y}(\mathbf{x})) - \mathbf{x} \|_1] + \mathbb{E}_{\mathbf{y} \sim p_Y} [\| G_{X \to Y}(G_{Y \to X}(\mathbf{y})) - \mathbf{y} \|_1] 其中 1\| \cdot \|_1 是 L1 范数(绝对值之和),比 L2 范数更能保留图像的细节。

总损失:

Etotal=EGAN(GXY,DY)+EGAN(GYX,DX)+ηEcyc(wX,wY)E_{\text{total}} = E_{\text{GAN}}(G_{X \to Y}, D_Y) + E_{\text{GAN}}(G_{Y \to X}, D_X) + \eta E_{\text{cyc}}(\mathbf{w}_X, \mathbf{w}_Y)

其中 η\eta 是循环损失的权重。

CycleGAN信息流

通过CycleGAN的信息流。数据点xn和yn的总误差是其4个组成部分误差的总和

潜在空间的语义结构

一个令人惊讶的发现是,训练好的 GAN 的潜在空间 z\mathbf{z} 会自发地组织成具有语义意义的结构。

  • 平滑插值:如果在潜在空间中沿着一条平滑的路径从 z1\mathbf{z}_1 走到 z2\mathbf{z}_2 ,生成的图像会平滑地从一个场景过渡到另一个场景,中间的图像看起来都很合理。 通过在潜空间内部随机生成的位置之间进行平滑移动得到

通过在潜空间内部随机生成的位置之间进行平滑移动得到

  • 解耦表示(Disentangled Representation):可以找到潜在空间中的特定方向,这些方向对应于语义上有意义的变换——比如改变微笑程度、改变发色、改变年龄等。
    • 例子(人脸): 人脸例子
习题1

题目背景:GAN 的训练目标是一个极小极大博弈:minGmaxDV(D,G)\min_G \max_D V(D, G)

GAN 为什么那么难训?“模式崩溃”又是啥?

GAN 的训练就像两个人在”军备竞赛”:判别器变强了,生成器的梯度信号就变差了;生成器变强了,判别器又得升级。两边得同步进步,但实际中很容易一方碾压另一方,导致训练崩掉。

模式崩溃:生成器学会”偷懒”了——只生成少数几种能骗过判别器的样本,比如生成数字时只出”1”和”7”,其他数字全不管。它找到了捷径,但没真正学会数据分布。

WGAN 用 Wasserstein 距离代替 JS 散度,解决了什么问题?

JS 散度有个致命 bug:两个分布只要不重叠(高维空间里几乎总是这样),JS 散度就是个常数 log2\log 2,梯度为零,生成器完全学不动。

Wasserstein 距离(推土距离)不同——即使两个分布不重叠,它也能告诉你”要把土推多远”,梯度始终有意义。训练更稳定,损失值也能真实反映生成质量。


第17章小结

一句话版本:造假者(生成器)和鉴定师(判别器)不断博弈,最终造假者能生成以假乱真的作品。

知识地图

  • 核心思想:生成器 vs 判别器的极小极大博弈
  • 关键问题:模式崩溃、梯度消失、训练不稳定
  • 改进路线:LSGAN(平滑损失)-> WGAN(Wasserstein距离)-> CycleGAN(无配对翻译)
  • 有趣性质:潜在空间有语义结构,可以”算术运算”(如 微笑的男人 - 男人 + 女人 = 微笑的女人)

Chapter 18 标准化流 (Normalizing Flows)

想象一下:你有一块橡皮泥,形状很简单(比如一个球)。标准化流就是一系列可逆的”捏”和”拉”操作,把这块简单的橡皮泥变成任何你想要的复杂形状(比如一匹马)。关键在于每一步都是可逆的——你也能把马捏回球。这就是标准化流的核心思想:通过一系列可逆变换,把简单的分布”变形”成复杂的分布。

还记得第7篇的变量替换公式吗? 标准化流的数学基础正是概率论中的变量替换:当你对一个随机变量做可逆变换时,新变量的概率密度可以通过雅可比行列式(Jacobian determinant,衡量变换对体积的缩放因子)来计算。

本章的目标是设计一类可逆(Invertible)的函数,这些函数可以作为生成模型中的变换层。这类模型被称为标准化流(Normalizing Flow)。关键要求是:

  • 可逆性:给定输出 x\mathbf{x},必须能唯一地计算出输入 z\mathbf{z}
  • 易计算的雅可比行列式(Jacobian Determinant):为了计算概率密度变换,需要知道变换的雅可比矩阵 J\mathbf{J} 的行列式 detJ|\det \mathbf{J}| 。这个计算必须是高效的。

考虑一个简单的线性变换:

x=az+b\mathbf{x} = a\mathbf{z} + b

其逆变换为:

z=1a(xb)\mathbf{z} = \frac{1}{a}(x - b)

虽然可逆且雅可比行列式容易计算(detJ=a|\det \mathbf{J}| = |a|),但它有一个根本性问题:线性变换在组合下是封闭的 。这意味着无论堆叠多少层线性变换,其整体效果仍然是一个线性变换。就像你无论怎么叠加拉伸和旋转,橡皮泥的形状本质上还是简单的。因此,即使使用多层,也只能生成高斯分布,无法捕捉复杂、非高斯的数据分布。

耦合流 (Coupling Flow)

想象一下:你把橡皮泥分成左右两半。左边那一半先不动,右边那一半根据左边的形状来”捏”——左边如果是圆的,右边就拉长;左边如果是扁的,右边就压扁。然后交换角色,右边不动,左边根据右边来”捏”。交替几次之后,橡皮泥就变成了复杂的形状!

为了解决线性变换表达能力不足的问题,我们引入耦合流(Coupling Flow),以 Real NVP(Real-valued Non-Volume Preserving)为例。

  • 核心思想:将潜在变量向量 z\mathbf{z} 分成两部分 z=(zA,zB)\mathbf{z} = (\mathbf{z}_A, \mathbf{z}_B),维度分别为 ddDdD-d。对这两部分应用不同的变换。
  • 变换规则
    1. 第一部分 zA\mathbf{z}_A 直接复制到输出(“不动的那半”): xA=zA\mathbf{x}_A = \mathbf{z}_A
    2. 第二部分 zB\mathbf{z}_B 进行一个仿射变换(Affine Transformation,即缩放+平移),但变换的参数(平移 bb 和缩放 ss)是 zA\mathbf{z}_A非线性函数xB=exp(s(zA,w))zB+b(zA,w)\mathbf{x}_B = \exp(s(\mathbf{z}_A, \mathbf{w})) \odot \mathbf{z}_B + b(\mathbf{z}_A, \mathbf{w}) 其中 \odot 表示哈达玛积(Hadamard Product,即逐元素相乘)。s(zA,w)s(\mathbf{z}_A, \mathbf{w})b(zA,w)b(\mathbf{z}_A, \mathbf{w}) 是由神经网络计算的缩放和平移向量。指数函数 exp()\exp(\cdot) 确保缩放因子为正,保证变换可逆。
可逆性和雅可比行列式的数学推导

可逆性证明:给定输出 x=(xA,xB)\mathbf{x} = (\mathbf{x}_A, \mathbf{x}_B),可以唯一地恢复输入: 1. zA=xA\mathbf{z}_A = \mathbf{x}_A (直接复制)。 2. 计算 s(zA,w)s(\mathbf{z}_A, \mathbf{w})b(zA,w)b(\mathbf{z}_A, \mathbf{w})。 3. zB=exp(s(zA,w))(xBb(zA,w))\mathbf{z}_B = \exp(-s(\mathbf{z}_A, \mathbf{w})) \odot (\mathbf{x}_B - b(\mathbf{z}_A, \mathbf{w}))

雅可比矩阵和行列式: 雅可比矩阵 J=x/z\mathbf{J} = \partial \mathbf{x} / \partial \mathbf{z} 可以分块表示为一个下三角矩阵

J=[Id0xBzAdiag(exp(s(zA,w)))]\mathbf{J} = \begin{bmatrix} \mathbf{I}_d & \mathbf{0} \\ \frac{\partial \mathbf{x}_B}{\partial \mathbf{z}_A} & \text{diag}(\exp(s(\mathbf{z}_A, \mathbf{w}))) \end{bmatrix}

由于 J\mathbf{J} 是下三角矩阵,其行列式等于主对角线上元素的乘积: detJ=exp(j=1Ddsj(zA,w))|\det \mathbf{J}| = \exp\left(\sum_{j=1}^{D-d} s_j(\mathbf{z}_A, \mathbf{w})\right) 关键点是,行列式不依赖于复杂的 xBzA\frac{\partial \mathbf{x}_B}{\partial \mathbf{z}_A} 项,只依赖于缩放因子 exp(s)\exp(s)。这使得计算非常高效。

实值NVP标准化流模型的单层结构

实值NVP标准化流模型的单层结构

多层堆叠

单层 Real NVP 有一个明显限制:zA\mathbf{z}_A 在变换中保持不变(“一半橡皮泥没被捏”)。这限制了模型的表达能力。

  • 解决方案:堆叠多个耦合层,并在每一层交换 zA\mathbf{z}_AzB\mathbf{z}_B 的角色。
    • 第一层:zA\mathbf{z}_A 不变,zB\mathbf{z}_B 变换。
    • 第二层:zB\mathbf{z}_B 不变,zA\mathbf{z}_A 变换。
  • 效果:通过这种交替,每一部分变量在不同的层中都会被变换。堆叠足够多的层后,模型可以学习非常复杂的、非线性的可逆变换。

一个更加灵活但仍然可逆的非线性层

多层堆叠的耦合流:通过交替交换角色,所有变量都会被变换

自回归流 (Autoregressive Flow)

想象一下:画画的时候,你先画天空(x1x_1),然后根据天空的颜色决定画什么颜色的草地(x2x_2),再根据天空和草地决定画什么颜色的房子(x3x_3)…每一个像素的值都取决于它前面已经画好的像素。这就是”自回归”的思想。

自回归流的灵感来自于概率论中的一个基本事实:任何多维联合分布都可以分解为一系列条件分布的乘积。

  • 联合分布分解:对于一个 DD 维的向量 x=(x1,x2,...,xD)\mathbf{x} = (x_1, x_2, ..., x_D),其联合概率可以写为: p(x)=p(x1,x2,...,xD)=i=1Dp(xix1,x2,...,xi1)=i=1Dp(xix1:i1)p(\mathbf{x}) = p(x_1, x_2, ..., x_D) = \prod_{i=1}^D p(x_i | x_1, x_2, ..., x_{i-1}) = \prod_{i=1}^D p(x_i | \mathbf{x}_{1:i-1}) 其中 x1:i1\mathbf{x}_{1:i-1} 表示 x1x_1xi1x_{i-1} 的子向量。这要求我们对变量进行一个固定的排序。

掩码自回归流 (MAF)

掩码自回归流(Masked Autoregressive Flow, MAF)直接利用上述分解,构建一个可逆的生成模型。

  • 变换规则:MAF 定义了一个从潜在变量 z\mathbf{z} 到数据 x\mathbf{x} 的变换: xi=h(zi,gi(x1:i1,wi))x_i = h(z_i, g_i(\mathbf{x}_{1:i-1}, \mathbf{w}_i))
    • ziz_i 是潜在变量 z\mathbf{z} 的第 ii 个分量。
    • gi(x1:i1,wi)g_i(\mathbf{x}_{1:i-1}, \mathbf{w}_i) 是一个条件器(Conditioner),通常是一个神经网络,它根据前面的 x1,...,xi1x_1, ..., x_{i-1} 来预测变换的参数。
    • h(,)h(\cdot, \cdot) 是一个耦合函数,它将 ziz_i 和条件器的输出结合起来生成 xix_i。这个函数必须关于 ziz_i可逆的
    • 关键点xix_i 只依赖于 ziz_i 和它前面的 x1,...,xi1x_1, ..., x_{i-1},不依赖于后面的 xi+1,...,xDx_{i+1}, ..., x_D
  • 掩码(Masking):为了在神经网络中实现这种”只依赖于前面变量”的约束,可以使用掩码 。通过在神经网络的权重矩阵中设置特定的零值,强制网络在计算 xix_i 时忽略 xj(ji)x_j (j \geq i) 的信息。

MAF vs IAF:效率的权衡

用人话说:MAF 和 IAF 就像同一枚硬币的两面。MAF “问概率快、生成慢”,IAF “生成快、问概率慢”。你选哪个取决于你的任务。

掩码自回归流(MAF)——高效似然计算,低效采样:

  • 给定一个数据点 x\mathbf{x},我们可以高效地计算其对数似然 logp(x)\log p(\mathbf{x})——因为所有 ziz_i 可以并行计算x\mathbf{x} 已知)。
  • 但从 MAF 采样则非常慢,因为生成过程必须严格按照顺序 x1x2...xDx_1 \to x_2 \to ... \to x_D 进行,每一步都必须等待前一步完成,时间复杂度为 O(D)O(D)

逆自回归流(IAF, Inverse Autoregressive Flow)——高效采样,低效似然计算:

  • 变换规则变为 xi=h(zi,gi(z1:i1,wi))x_i = h(z_i, g_i(\mathbf{z}_{1:i-1}, \mathbf{w}_i))——条件器依赖于潜在变量 z1:i1\mathbf{z}_{1:i-1} 而不是数据变量 x1:i1\mathbf{x}_{1:i-1}
  • 由于 z\mathbf{z} 可以一次性采样,所有 xix_i 可以并行计算,采样非常快。
  • 但计算似然(逆变换)需要串行求解,因为计算 ziz_i 必须先知道 z1:i1\mathbf{z}_{1:i-1}

两种自回归标准化流结构

两种自回归标准化流结构,(a)掩码自回归流允许对似然函数进行有效评估,(b)逆自回归流允许进行高效采样

选择依据

  • 如果你需要快速评估数据点的概率(例如密度估计、异常检测),选择 MAF
  • 如果你需要快速生成大量样本(例如图像生成),选择 IAF

与耦合流的关系:自回归流和耦合流是密切相关的。耦合流可以看作是自回归流的一种特例——它把变量分成两组(AABB )而不是 DD 组。这牺牲了一些表达能力,但极大地提高了计算效率(因为每组内的变换可以并行)。

连续流 (Continuous Flows)

神经 ODE (Neural ODE)

想象一下:普通的神经网络就像走楼梯——一步一个台阶,离散地跳跃。而神经 ODE 就像坐电梯——平滑地、连续地上升。

传统的神经网络和标准化流模型都是由离散的层组成的。神经常微分方程(Neural ODE)提供了一种全新的视角:将网络视为一个连续的动态系统

  • 核心思想:不是定义一系列离散的变换 z0z1zL\mathbf{z}_0 \to \mathbf{z}_1 \to \dots \to \mathbf{z}_L,而是定义一个连续时间 ** tt 上的向量场**(Vector Field,描述每个点的运动方向和速度)f(z(t),w)\mathbf{f}(\mathbf{z}(t), \mathbf{w}),其中 z(t)\mathbf{z}(t) 是在时间 tt 的状态向量。
  • 微分方程:状态 z(t)\mathbf{z}(t) 的演化由一个常微分方程(ODE)描述: dz(t)dt=f(z(t),w)\frac{d\mathbf{z}(t)}{dt} = \mathbf{f}(\mathbf{z}(t), \mathbf{w}) 其中 f()\mathbf{f}(\cdot) 是一个由深度神经网络实现的函数,w\mathbf{w} 是其参数。
  • 初始和最终状态:给定初始状态 z(0)\mathbf{z}(0),我们可以积分(integrate)这个 ODE,从 t=0t=0t=Tt=T ,得到最终状态 z(T)\mathbf{z}(T)z(T)=z(0)+0Tf(z(t),w)dt\mathbf{z}(T) = \mathbf{z}(0) + \int_0^T \mathbf{f}(\mathbf{z}(t), \mathbf{w}) dt
  • 与传统网络的类比:这类似于残差网络(ResNet): zl+1=zl+f(zl,wl)Δt\mathbf{z}_{l+1} = \mathbf{z}_l + \mathbf{f}(\mathbf{z}_l, \mathbf{w}_l) \Delta t 当步长 Δt0\Delta t \to 0 时,离散的残差连接就收敛到连续的 ODE。

由于 f(z(t),w)\mathbf{f}(\mathbf{z}(t), \mathbf{w}) 是一个复杂的神经网络,通常无法解析求解 ODE。我们需要使用数值 ODE 求解器 (如 Runge-Kutta 方法)。

  • 过程
    1. 定义 ODE 函数 f(z(t),w)\mathbf{f}(\mathbf{z}(t), \mathbf{w})
    2. 提供初始条件 z(0)\mathbf{z}(0)
    3. 指定积分区间 [0,T][0, T]
    4. 调用黑盒 ODE 求解器(如 scipy.integrate.solve_ivp)来计算 z(T)\mathbf{z}(T)
  • 求解器的自适应性:高级求解器(如 dopri5)是自适应的。它们会根据函数 f\mathbf{f} 的复杂程度,自动选择积分步长和时间点 tt。这使得求解过程更高效、更精确。

反向传播(伴随方法)

训练神经 ODE 的主要挑战是计算损失函数 LL 关于参数 w\mathbf{w} 的梯度。Chen et al. (2018) 提出了一种高效的伴随方法(Adjoint Method),其内存成本与网络深度无关——这是一个巨大的优势。

伴随方法的数学细节
  • 定义伴随向量a(t)=Lz(t)\mathbf{a}(t) = \frac{\partial L}{\partial \mathbf{z}(t)} a(t)\mathbf{a}(t) 表示损失 LL 对时间 tt 的状态 z(t)\mathbf{z}(t) 的梯度。在 t=Tt=T 时,a(T)\mathbf{a}(T) 就是损失对最终输出 z(T)\mathbf{z}(T) 的梯度,通常可以直接计算。
  • 伴随方程a(t)\mathbf{a}(t) 本身也遵循一个 ODE: da(t)dt=a(t)Tzf(z(t),w)\frac{d\mathbf{a}(t)}{dt} = -\mathbf{a}(t)^T \nabla_{\mathbf{z}} \mathbf{f}(\mathbf{z}(t), \mathbf{w}) 这个方程可以从 t=Tt=Tt=0t=0 反向积分。
  • 参数梯度wL=0Ta(t)Twf(z(t),w)dt\nabla_{\mathbf{w}} L = -\int_0^T \mathbf{a}(t)^T \nabla_{\mathbf{w}} \mathbf{f}(\mathbf{z}(t), \mathbf{w}) dt

训练流程: 1. 前向传播:使用 ODE 求解器从 t=0t=0t=Tt=T 积分,得到 z(T)\mathbf{z}(T),并计算损失 LL不需要存储中间的 z(t)\mathbf{z}(t)。 2. 反向传播:使用反向的 ODE 求解器从 t=Tt=Tt=0t=0 积分伴随方程,同时计算参数梯度 wL\nabla_{\mathbf{w}} L

内存优势:由于不需要存储前向传播的中间状态,内存消耗是常数,而传统方法的内存消耗与网络深度成正比。

神经 ODE 流

神经 ODE 可以用于构建一种新型的标准化流模型,称为连续标准化流

  • 变换:从输入 z(0)\mathbf{z}(0) 到输出 z(T)\mathbf{z}(T) 的变换由 ODE 定义: dz(t)dt=f(z(t),w)\frac{d\mathbf{z}(t)}{dt} = \mathbf{f}(\mathbf{z}(t), \mathbf{w})
  • 密度变换:如果我们在输入空间定义一个简单的先验分布 p(z(0))p(\mathbf{z}(0))(如标准正态分布),那么通过 ODE 的演化,这个分布会传播到输出空间 p(z(T))p(\mathbf{z}(T))
  • 对数密度的演化:Chen et al. (2018) 证明,对数概率密度 logp(z(t))\log p(\mathbf{z}(t)) 的演化遵循另一个 ODE: dlogp(z(t))dt=Tr(fz(t))\frac{d \log p(\mathbf{z}(t))}{dt} = -\text{Tr}\left( \frac{\partial \mathbf{f}}{\partial \mathbf{z}(t)} \right) 其中 f/z\partial \mathbf{f} / \partial \mathbf{z}f\mathbf{f} 关于 z\mathbf{z} 的雅可比矩阵,Tr()\text{Tr}(\cdot) 表示矩阵的迹。
  • 训练:为了计算输出 z(T)\mathbf{z}(T) 的对数似然 logp(z(T))\log p(\mathbf{z}(T)),我们需要同时求解两个 ODE:
    1. dz/dt=f(z,w)d\mathbf{z}/dt = \mathbf{f}(\mathbf{z}, \mathbf{w}),从 z(0)\mathbf{z}(0)z(T)\mathbf{z}(T)
    2. dlogp/dt=Tr(f/z)d\log p/dt = -\text{Tr}(\partial \mathbf{f} / \partial \mathbf{z}),从 logp(z(0))\log p(\mathbf{z}(0))logp(z(T))\log p(\mathbf{z}(T))。 这可以通过将两个方程拼接成一个增广系统来实现,然后用一个 ODE 求解器同时求解。
  • 采样:从 p(z(T))p(\mathbf{z}(T)) 采样时,先从 p(z(0))p(\mathbf{z}(0)) 采样 z(0)\mathbf{z}(0),然后通过求解 ODE 得到 z(T)\mathbf{z}(T)

连续标准化流

一个简单高斯分布是如何通过连续转换变成t=T时刻的一个多峰分布的。当流线分开时,密度降低;当流线靠拢时,密度增加

习题2

标准化流和 GAN 各有什么优缺点?

标准化流:能精确算似然(适合异常检测这种需要知道概率的任务),训练稳定。但变换必须可逆,架构设计受限,表达能力也因此打了折扣。

GAN:生成质量通常更猛,架构随便设计。但没法算似然,训练是出了名的难搞。

简单说:标准化流是”规矩的好学生”,GAN 是”才华横溢但脾气暴躁的天才”。


第18章小结

一句话版本:通过一系列可逆变换,把简单的分布(如高斯分布)“变形”成复杂的数据分布,就像把橡皮泥捏成任意形状。

知识地图

  • 核心思想:可逆变换 + 变量替换公式(雅可比行列式)
  • 三大架构:耦合流(Real NVP,分两半交替变换)、自回归流(MAF/IAF,逐维度条件变换)、连续流(Neural ODE,连续变换)
  • 关键权衡:MAF “问概率快、生成慢”,IAF “生成快、问概率慢”
  • 与GAN对比:标准化流能精确计算似然(GAN不能),但表达能力受限于可逆约束

Chapter 19 自编码器 (Autoencoder)

想象一下:自编码器就像”有损压缩”。你把一张高清照片压缩成一个小文件(编码),然后从小文件还原出一张照片(解码)。压缩的过程就是”提取精华”,还原的过程就是”从精华重建”。如果压缩还原后的照片和原图很像,说明编码器学到了数据的核心特征。

确定性的自编码器 (Deterministic Autoencoder)

自编码器(Autoencoder)是一种旨在学习数据有效表示的神经网络模型。其核心思想是通过一个”编码-解码”过程来重构输入数据。

  • 网络结构:一个典型的自编码器包含两部分:
    1. 编码器(Encoder):将输入向量 x\mathbf{x} 映射到一个潜在表示(Latent Representation,也叫隐藏表示)z(x)\mathbf{z}(\mathbf{x})
    2. 解码器(Decoder):将潜在表示 z\mathbf{z} 映射回输出向量 y(z)\mathbf{y}(\mathbf{z})
  • 训练目标:网络的输出单元数与输入单元数相同。训练的目标是让网络的输出 y\mathbf{y} 尽可能接近原始输入 x\mathbf{x},从而学习一个恒等映射。
  • 潜在表示:训练完成后,网络内部的隐藏层(即 z\mathbf{z})提供了一种对输入数据的压缩或抽象表示,可用于后续任务(如分类、聚类)。

如果不对网络施加任何限制,最简单的解是让网络学习一个恒等函数(直接复制输入到输出),这就像”压缩”后文件大小不变——完全没用。为了迫使网络学习有意义的表示,必须引入某种形式的约束。

  • 引入约束:常见的约束方式有:
    1. 维度约束:限制潜在表示 z\mathbf{z} 的维度 MM 小于输入 x\mathbf{x} 的维度 DD(即 M<DM < D)。这迫使网络进行 降维(Dimensionality Reduction),学习数据中最主要的特征——就像把100维的数据压缩成10维。
    2. 稀疏性约束(Sparsity Constraint):即使 MDM \geq D,也可以通过正则化(如 L1 正则化)鼓励 z\mathbf{z} 中的大部分元素为零,从而学习一个稀疏表示
    3. 去噪约束:通过向输入添加噪声,训练网络从被破坏的输入中恢复原始输入。这迫使网络学习数据的内在结构和鲁棒性。

线性自编码器

考虑一个最简单的自编码器:输入层、一个隐藏层(M<DM < D)、输出层,且所有激活函数都是线性的。

  • 误差函数:通常使用平方误差来衡量重构误差: E(w)=12n=1Ny(xn,w)xn2E(\mathbf{w}) = \frac{1}{2} \sum_{n=1}^N \| \mathbf{y}(\mathbf{x}_n, \mathbf{w}) - \mathbf{x}_n \|^2
  • 与 PCA 的等价性:当隐藏层使用线性激活函数时,该自编码器的最优解等价于主成分分析
    • 在误差函数的全局最小值处,网络将输入数据投影到由数据前 MM 个主成分张成的子空间上。
    • 连接到隐藏单元的权重向量构成了主子空间的一组基(尽管它们不一定正交或归一化)。
  • 非线性激活函数的局限性:即使在隐藏层使用非线性激活函数(如 sigmoid),对于这种两层网络结构,最优解仍然等价于线性 PCA。这表明仅靠非线性激活函数无法突破线性降维的限制。

深度自编码器

为了实现真正的非线性降维,需要引入更深的网络结构。

  • 非线性映射:网络可以看作两个连续的映射 F1F_1F2F_2
    • F1F_1:将 DD 维输入空间映射到 MM 维潜在空间 SS。由于非线性层的存在,这个映射可以非常复杂,不再局限于线性变换。
    • F2F_2:将 MM 维潜在空间 SS 映射回 DD 维输出空间。
  • 几何解释:如下图所示,F2F_2 定义了潜在流形 SS 如何嵌入到高维数据空间中。由于 F2F_2 是非线性的,这个嵌入可以是非平面的,从而能够捕捉数据中复杂的非线性结构。
  • 训练挑战:与线性自编码器不同,深度自编码器的误差函数 E(w)E(\mathbf{w}) 不再是关于参数 w\mathbf{w} 的二次函数,因此优化过程是非线性的。这需要使用计算量大的非线性优化技术,并且存在陷入局部最优的风险。

几何解释

几何解释

稀疏自编码器

另一种约束方式是通过正则化来鼓励潜在表示 z\mathbf{z} 的稀疏性。

  • L1 正则化:在误差函数中加入一个 L1 范数项,惩罚潜在单元激活值的绝对值之和: E(w)=E(w)+λk=1KzkE(\mathbf{w}) = E(\mathbf{w}) + \lambda \sum_{k=1}^K |z_k| 其中 E(w)E(\mathbf{w}) 是原始的未正则化误差(如平方误差),KK 是隐藏层的单元数,λ\lambda 是正则化系数。
  • 效果:L1 正则化倾向于产生稀疏解,即大部分 zkz_k 的值为零或接近零。这迫使网络只使用少数几个隐藏单元来表示输入,从而学习到更具解释性的特征。
  • 梯度计算:尽管正则化项作用于单元激活值而非网络参数,但通过自动微分仍然可以高效地计算梯度用于训练。

去噪自编码器 (Denoising Autoencoder)

还记得后面的扩散模型吗? 去噪自编码器和扩散模型的核心思想非常相似——都是”给数据加噪声,然后学习去掉噪声”。可以说,去噪自编码器是扩散模型的思想前身。

去噪自编码器通过学习从被破坏的输入中恢复原始输入来学习数据的鲁棒表示。

  • 训练过程
    1. 取一个原始输入向量 xn\mathbf{x}_n
    2. 对其施加噪声(如随机将部分输入置零,或添加高斯噪声),得到一个被破坏的版本 x~n\tilde{\mathbf{x}}_n
    3. x~n\tilde{\mathbf{x}}_n 作为输入送入自编码器,得到输出 y(x~n,w)\mathbf{y}(\tilde{\mathbf{x}}_n, \mathbf{w})
    4. 训练目标是最小化输出与原始、未破坏的输入 xn\mathbf{x}_n 之间的误差: E(w)=n=1Ny(x~n,w)xn2E(\mathbf{w}) = \sum_{n=1}^N \| \mathbf{y}(\tilde{\mathbf{x}}_n, \mathbf{w}) - \mathbf{x}_n \|^2
  • 学习机制:通过学习“去噪”,网络被迫发现数据中的统计规律和内在结构。例如,在图像数据中,学习到相邻像素高度相关,从而可以利用周围像素的信息来修复被破坏的像素。
  • 与得分匹配的关系:去噪自编码器的训练与得分匹配(Score Matching) 密切相关。得分函数 s(x)=xlnp(x)s(\mathbf{x}) = \nabla_{\mathbf{x}} \ln p(\mathbf{x}) 是指向数据密度高区域的”箭头”。去噪自编码器学习的重构方向 y(x~)x~\mathbf{y}(\tilde{\mathbf{x}}) - \tilde{\mathbf{x}} 也指向数据流形,类似于得分向量。这个联系将在扩散模型章节中再次出现。

去噪自编码器

在去噪自编码器中,数据点被假定存在于数据空间中的一个低维流形上,并且被加性噪声破坏了。自编码器会学习将损坏的数据点映射回它们原来的值,因此自编码器为数据空间中的每个点学习了一个指向流形的向量

掩码自编码器 (Masked Autoencoder, MAE)

还记得第6篇的Transformer吗? MAE 把 Transformer 用到了图像上——把图像切成小块(patch),就像把文本切成 token 一样,然后随机遮掉大部分块,让模型学会恢复它们。

掩码自编码器是去噪自编码器的一种特殊形式,特别适用于图像和基于 Transformer 的架构。

  • 掩码操作:输入图像被分割成多个“块”。训练时,随机选择并“掩码”或丢弃其中一部分块(如 75%)。与 BERT 不同,这里不是用一个固定的“mask token”替换,而是直接省略这些块。
  • 架构:通常与视觉 Transformer结合使用。
    • 编码器(Encoder):接收未被掩码的块作为输入,计算它们的表示。
    • 解码器(Decoder):需要重建整个图像(包括被掩码的块)。为了实现这一点,在编码器和解码器之间,需要将被掩码的块用一个* 固定的 mask token 向量*(并附加上位置编码)重新插入,以恢复原始序列长度。
  • 训练目标:损失函数只计算在被掩码的块上的重构误差(如均方误差)。解码器被训练来预测这些缺失块的原始像素值。
  • 优势
    1. 计算效率:由于编码器只处理未被掩码的块(如 25%),大大减少了计算量。
    2. 强大的表示学习:通过预测图像中缺失的大片区域,编码器被迫学习到图像的全局语义和结构信息。
  • 下游任务:训练完成后,解码器被丢弃。编码器(可能附加新的输出层)被用于图像分类、检测等下游任务。

掩蔽自编码器在训练阶段的架构

掩蔽自编码器在训练阶段的架构。训练结束后,解码器被抛弃,编码器用于将图像映射到内部表示,以便在后续任务中使用

函数图像

被掩蔽的图像在左侧(有80%的输入区块被掩蔽),重建的图像在中间,原始图像在右侧

变分自编码器 (VAE)

想象一下:普通自编码器是”有损压缩”——把图片压缩成一个固定的向量。VAE 更进一步:它不是压缩成一个固定的向量,而是压缩成一个概率分布(比如”均值是这里,方差是这么大”的高斯分布)。生成新图片时,你只需要从这个分布中随机采样一个点,然后解码就行了。

还记得第7篇的变分推断和ELBO吗? VAE 的数学基础正是变分推断——用一个简单的分布 q(z)q(\mathbf{z}) 去近似复杂的后验分布 p(zx)p(\mathbf{z}|\mathbf{x}),并最大化 ELBO。

变分自编码器(Variational Autoencoder, VAE)是一种概率生成模型,它通过变分推断来近似复杂的后验分布。

  • 生成模型:VAE 定义了一个潜在变量模型——生成数据的方式是:先从简单的分布采样 z\mathbf{z},再通过解码器生成 x\mathbf{x}p(xw)=p(xz,w)p(z)dzp(\mathbf{x}|\mathbf{w}) = \int p(\mathbf{x}|\mathbf{z}, \mathbf{w}) p(\mathbf{z}) d\mathbf{z} 其中 p(z)p(\mathbf{z}) 是先验分布(通常为标准正态分布 N(0,I)\mathcal{N}(\mathbf{0}, \mathbf{I})),p(xz,w)p(\mathbf{x}|\mathbf{z}, \mathbf{w}) 是由解码器神经网络定义的似然函数。
  • 后验推断的困难:直接计算后验分布 p(zx,w)p(\mathbf{z}|\mathbf{x}, \mathbf{w}) 是困难的,因为边缘似然 p(xw)p(\mathbf{x}|\mathbf{w}) 无法解析计算(需要对所有可能的 z\mathbf{z} 积分)。

为了解决后验推断的困难,VAE 使用证据下界(ELBO, Evidence Lower Bound)来近似最大化对数似然。

  • 优化目标:最大化 ELBO L(w)\mathcal{L}(\mathbf{w}),这等价于在近似后验 q(z)q(\mathbf{z}) 和真实后验 p(zx,w)p(\mathbf{z}|\mathbf{x}, \mathbf{w}) 之间最小化 KL 散度(衡量两个分布的差异)。

摊销推理

为了高效地学习,VAE 使用一个神经网络(编码器)来近似所有数据点的后验分布。

  • 编码器网络:引入一个参数化的编码器网络 q(zx,ϕ)q(\mathbf{z}|\mathbf{x}, \mathbf{\phi}),它将输入 x\mathbf{x} 映射到一个潜在变量 z\mathbf{z} 的分布(通常是高斯分布)。
  • 参数化:一个典型的编码器输出一个对角高斯分布的均值 μ(x,ϕ)\mathbf{\mu}(\mathbf{x}, \mathbf{\phi}) 和方差 σ2(x,ϕ)\mathbf{\sigma}^2(\mathbf{x}, \mathbf{\phi})q(zx,ϕ)=j=1MN(zjμj(x,ϕ),σj2(x,ϕ))q(\mathbf{z}|\mathbf{x}, \mathbf{\phi}) = \prod_{j=1}^M \mathcal{N}(z_j | \mu_j(\mathbf{x}, \mathbf{\phi}), \sigma_j^2(\mathbf{x}, \mathbf{\phi}))
  • 联合优化:现在,ELBO 同时依赖于解码器参数 w\mathbf{w} 和编码器参数 ϕ\mathbf{\phi} 。目标是联合优化 L(w,ϕ)\mathcal{L}(\mathbf{w}, \mathbf{\phi})

重参数化技巧 (Reparameterization Trick)

用人话说:问题是这样的——神经网络需要通过”反向传播”来学习,但”采样”这个操作就像一堵墙,梯度传不过去。重参数化技巧的妙招是:把”随机采样”从参数计算中分离出来。就像说”我不直接从分布里抽样,而是先抽一个固定的随机数,再用公式算出采样结果”——这样梯度就能顺着公式传回去了。

直接对 ELBO 进行梯度下降是困难的,因为采样操作阻断了反向传播。

  • 问题:ELBO 包含一个期望项,需要用蒙特卡洛方法(Monte Carlo,即随机采样近似)近似: 1Ll=1Llnp(xz(l),w),z(l)q(zx,ϕ)\frac{1}{L} \sum_{l=1}^L \ln p(\mathbf{x}|\mathbf{z}^{(l)}, \mathbf{w}), \quad \mathbf{z}^{(l)} \sim q(\mathbf{z}|\mathbf{x}, \mathbf{\phi})z(l)\mathbf{z}^{(l)} 是从 qq 中采样的,qq 依赖于 ϕ\mathbf{\phi},因此梯度无法通过采样操作传递到编码器。
  • 解决方案:重参数化技巧将随机性从参数依赖中分离出来。
    • 对于高斯分布,可以将采样表示为: z=μ+σϵ,ϵN(0,I)\mathbf{z} = \mathbf{\mu} + \mathbf{\sigma} \odot \mathbf{\epsilon}, \quad \mathbf{\epsilon} \sim \mathcal{N}(\mathbf{0}, \mathbf{I})
    • 现在,z\mathbf{z} 显式地依赖于 μ\mathbf{\mu}σ\mathbf{\sigma}(即 ϕ\mathbf{\phi} ),而 ϵ\mathbf{\epsilon} 是一个与参数无关的独立噪声源。
    • 这使得梯度可以通过 μ\mathbf{\mu}σ\mathbf{\sigma} 反向传播到编码器网络。

将潜变量z固定到特定采样值的过程阻止了误差信号向编码器网络的反向传播

将潜变量z固定到特定采样值的过程阻止了误差信号向编码器网络的反向传播

重参数化技巧

重参数化技巧通过对一个独立随机变量e的样本进行计算而不是直接采样z,从而允许误差信号反向传播到编码器网络

结合以上所有部分,VAE 的完整 ELBO 目标函数可以写为:

VAE 完整 ELBO 目标函数的数学形式L=n{12j=1M[1+lnσnj2μnj2σnj2]+1Ll=1Llnp(xnzn(l),w)}\mathcal{L} = \sum_n \left\{ \frac{1}{2} \sum_{j=1}^M \left[ 1 + \ln \sigma_{nj}^2 - \mu_{nj}^2 - \sigma_{nj}^2 \right] + \frac{1}{L} \sum_{l=1}^L \ln p(\mathbf{x}_n|\mathbf{z}_n^{(l)}, \mathbf{w}) \right\}

其中 zn(l)=μn+σnϵn(l)\mathbf{z}_n^{(l)} = \mathbf{\mu}_n + \mathbf{\sigma}_n \odot \mathbf{\epsilon}_n^{(l)}(重参数化),μn=μ(xn,ϕ)\mathbf{\mu}_n = \mathbf{\mu}(\mathbf{x}_n, \mathbf{\phi})σn=σ(xn,ϕ)\mathbf{\sigma}_n = \mathbf{\sigma}(\mathbf{x}_n, \mathbf{\phi}) 。通常 L=1L=1,即每个数据点只采样一次。

直觉理解:ELBO由两部分组成——KL散度项确保编码器输出的分布不要太偏离标准正态分布(正则化),重建项确保解码器能从潜变量中还原原始数据(保真度)。两者之间需要平衡。

习题3

VAE 的”重参数化技巧”是干嘛的?没有它会怎样?

VAE 的编码器输出的是一个分布(均值+方差),生成潜变量时要从这个分布里采样。问题是:采样这个操作没法求导——梯度传不回编码器。

重参数化技巧很巧妙:把 z=μ+σϵz = \mu + \sigma \odot \epsilon,其中 ϵ\epsilon 是从标准正态里采的噪声。这样随机性被转移到了 ϵ\epsilon 上,梯度可以通过 μ\muσ\sigma 正常反向传播了。

没有这个技巧的话,VAE 就没法用梯度下降训练编码器,只能用 REINFORCE 那种高方差的方法,训练会非常痛苦。

普通自编码器能生成新数据吗?VAE 为什么可以?

普通自编码器不行。它的潜空间没有约束,数据点的潜变量东一个西一个,从潜空间随便采一个点,解码出来大概率是乱七八糟的东西。

VAE 通过 KL 散度把潜空间”整理”成了接近标准正态分布的样子——连续、平滑、有组织。从这个潜空间里随便采一个点,解码出来都是有意义的数据。这就是 VAE 能当生成模型的原因。


第19章小结

一句话版本:自编码器学习”压缩-解压”数据,VAE 把它升级为概率版本——压缩成分布而非点,从而能生成新数据。

知识地图

  • 确定性自编码器:编码器 + 解码器,通过约束学习有意义的表示
    • 线性自编码器 ≈ PCA
    • 深度自编码器:真正的非线性降维
    • 稀疏自编码器:L1正则化鼓励稀疏
    • 去噪自编码器:从噪声中恢复原始数据(与扩散模型思想相通)
    • 掩码自编码器:Transformer + 大面积遮挡
  • 变分自编码器(VAE):编码成分布,用ELBO训练,重参数化技巧让梯度能传播
  • 与GAN对比:VAE训练稳定但生成图像容易模糊,GAN训练困难但生成质量高

Chapter 20 扩散模型 (Diffusion Models)

想象一下:你给朋友打电话,信号一开始很清楚(原始图像)。然后有人在电话线上逐步加入越来越多的杂音(前向加噪),直到你完全听不清对方在说什么(变成纯噪声)。扩散模型做的事情就是:学会如何从一堆杂音中一步步还原出清晰的信号(反向去噪)。

你可能会问:”加噪声谁不会?去掉噪声才是难点吧?”没错!扩散模型的巧妙之处在于:虽然前向加噪是固定的、不需要学习的,但反向去噪的每一步都很小,小到神经网络能轻松学会。

扩散模型(Diffusion Model)是目前在图像生成等领域达到 SOTA(State-of-the-Art,最先进)效果的生成模型框架。其核心逻辑可概括为”前向加噪 -> 反向去噪”:

  1. 前向过程(Forward Process,编码器):将训练数据(如图像)通过多步加性高斯噪声(Gaussian Noise)逐步”污染”,最终使数据变成标准高斯分布的样本(完全不含原始数据信息);
  2. 反向过程(Reverse Process,解码器):训练一个深度神经网络,学习逆转上述加噪过程——从标准高斯样本出发,逐步去噪,最终生成与训练数据分布一致的新样本。

与GAN和VAE的对比:扩散模型可看作一种”层次化VAE”(Hierarchical VAE)——前向加噪的分布是固定的(无需学习),仅需学习反向去噪的生成分布。相比 GAN,它避免了对抗训练的不稳定性,且训练简单、易并行;但生成样本时需多次通过解码器(通常需要数百到数千步),计算成本较高。

前向加噪过程

前向加噪过程:从原始图像 x 开始,经 T 步加噪后得到接近高斯分布的 z_T,反向过程则是从 z_T 逐步去噪回 x

前向编码器(Forward Encoder)

用人话说:前向编码器就是”加噪声的规则”。每一步,你往图片上撒一点高斯噪声(就像往照片上撒沙子)。撒一次还不太模糊,但撒几百次之后,照片就变成一片随机的沙粒——完全看不出原来是什么了。

前向编码器定义了”如何逐步给数据加噪”,整个过程是一个马尔可夫链(Markov Chain,即每一步只依赖前一步的结果,不依赖更早的历史),具体如下:

对于训练集中的一张原始图像 xx,第一步加噪是将 xx 与独立高斯噪声混合,得到第一个含噪图像 z1z_1

z1=1β1x+β1ϵ1z_1 = \sqrt{1-\beta_1}x + \sqrt{\beta_1}\epsilon_1

其中:

  • ϵ1N(ϵ10,I)\epsilon_1 \sim \mathcal{N}(\epsilon_1 | 0, I):标准高斯噪声(均值0,单位协方差矩阵);
  • β1(0,1)\beta_1 \in (0,1)噪声方差参数(Noise Variance),控制第一步加噪的强度。β\beta 越小,加噪越弱,图像变化越小;
  • 系数 1β1\sqrt{1-\beta_1}β1\sqrt{\beta_1} 的作用:保证 z1z_1 的均值比 xx 更接近0,协方差比 xx 更接近单位矩阵 II (为后续多步加噪最终收敛到标准高斯做铺垫)。

从概率分布角度,z1z_1 给定 xx 的条件分布是高斯分布:

q(z1x)=N(z11β1x,β1I)q(z_1 | x) = \mathcal{N}(z_1 | \sqrt{1-\beta_1}x, \beta_1 I)

将单步加噪重复 TT 次,得到含噪序列 z1,z2,...,zTz_1, z_2, ..., z_T,每一步的加噪规则与第一步一致:

zt=1βtzt1+βtϵtz_t = \sqrt{1-\beta_t}z_{t-1} + \sqrt{\beta_t}\epsilon_t

其中 ϵtN(ϵt0,I)\epsilon_t \sim \mathcal{N}(\epsilon_t | 0, I),且每个 ϵt\epsilon_t 都是独立的新噪声。

对应的条件分布为:

q(ztzt1)=N(zt1βtzt1,βtI)q(z_t | z_{t-1}) = \mathcal{N}(z_t | \sqrt{1-\beta_t}z_{t-1}, \beta_t I)

参数设置βt\beta_t 需人工设定(称为 noise schedule),通常遵循 β1<β2<...<βT\beta_1 < \beta_2 < ... < \beta_T(前期加噪弱,后期加噪强),确保 TT 足够大时 zTz_T 接近标准高斯。


前向加噪过程可表示为概率图模型:

  • 阴影节点 xx:观测变量(原始图像,已知);
  • 空白节点 z1,...,zTz_1, ..., z_T:潜变量(含噪图像,未知);
  • 前向分布 q(ztzt1)q(z_t | z_{t-1}):定义加噪方向(编码器,已知的);
  • 目标学习的反向分布 p(zt1zt,w)p(z_{t-1} | z_t, w):定义去噪方向(解码器,ww 为网络参数,需要学习的);
  • 条件分布 q(zt1zt,x)q(z_{t-1} | z_t, x):已知原始图像 xx 时,从 ztz_t 反推 zt1z_{t-1} 的分布——这是训练目标推导的关键。

前向加噪过程概率图模型

扩散模型的概率图模型:x 是已知的原始图像,z_1 到 z_T 是逐步加噪的潜变量

扩散核(ztz_t 的边际分布)

用人话说:扩散核告诉你一个好消息——训练时你不需要真的一步一步加噪到第 tt 步,而是可以一步到位直接从原始图像 xx 生成第 tt 步的含噪图像 ztz_t。这大大加快了训练速度!

前向过程中,若想直接得到 ztz_t(无需计算中间的 z1,...,zt1z_1,...,z_{t-1}),可通过”边际分布”(Marginal Distribution)实现。ztz_t 给定 xx 的条件分布(称为扩散核 Diffusion Kernel)是高斯分布:

q(ztx)=N(ztαtx,(1αt)I)q(z_t | x) = \mathcal{N}(z_t | \sqrt{\alpha_t}x, (1-\alpha_t)I)

其中 αt\alpha_tβ\beta 的累积乘积(信号保留比例):

αt=τ=1t(1βτ)\alpha_t = \prod_{\tau=1}^t (1-\beta_\tau)
扩散核的推导思路
  1. 前向过程的联合分布为 q(z1,...,ztx)=q(z1x)τ=2tq(zτzτ1)q(z_1,...,z_t | x) = q(z_1 | x) \prod_{\tau=2}^t q(z_\tau | z_{\tau-1})(马尔可夫链性质);
  2. z1,...,zt1z_1,...,z_{t-1} 积分,利用”独立高斯变量之和仍为高斯”的性质,可推导出 q(ztx)q(z_t | x) 的均值为 αtx\sqrt{\alpha_t}x ,方差为 (1αt)I(1-\alpha_t)I

训练意义:扩散核让你在训练时可以直接跳到任意步 tt,无需运行完整的前向链,极大提升训练效率。

扩散核也可改写为加噪形式(这在后面推导损失函数时非常有用):

zt=αtx+1αtϵtz_t = \sqrt{\alpha_t}x + \sqrt{1-\alpha_t}\epsilon_t

注意:此处 ϵt\epsilon_t 是”累计噪声”(从 xxztz_t 的总噪声),而非单步加噪的 ϵτ\epsilon_\tau

极限情况:当加噪步数 TT \to \infty 时,αT0\alpha_T \to 0,扩散核变为 q(zTx)=N(zT0,I)q(z_T | x) = \mathcal{N}(z_T | 0, I)——zTz_T 完全是标准高斯噪声,与原始图像 xx 毫无关系。这就是我们想要的:前向过程最终”抹掉”了所有原始信息。

条件分布(反向过程的”标准答案”)

用人话说:我们要训练一个神经网络来”去噪”,但它需要”标准答案”来学习。条件分布 q(zt1zt,x)q(z_{t-1} | z_t, x) 就是这个标准答案——它告诉你”如果你知道原始图像 xx 是什么,那么从 ztz_t 应该怎样恢复到 zt1z_{t-1}”。

我们的目标是学习反向去噪(从 ztz_tzt1z_{t-1}),但直接反转 q(ztzt1)q(z_t | z_{t-1}) 会得到 q(zt1zt)q(z_{t-1} | z_t) ,该分布需要知道我们不知道的 p(x)p(x)(数据分布),所以无法计算。因此,我们考虑”已知 xx 时的反向条件分布” q(zt1zt,x)q(z_{t-1} | z_t, x)——好消息是,这个分布是简单的高斯分布!

条件分布的推导过程
  1. 应用贝叶斯定理(Bayes’ Theorem):

    q(zt1zt,x)=q(ztzt1,x)q(zt1x)q(ztx)q(z_{t-1} | z_t, x) = \frac{q(z_t | z_{t-1}, x) q(z_{t-1} | x)}{q(z_t | x)}
  2. 利用马尔可夫性简化:前向过程是马尔可夫链,因此 q(ztzt1,x)=q(ztzt1)q(z_t | z_{t-1}, x) = q(z_t | z_{t-1}),且 q(zt1x)q(z_{t-1} | x)q(ztx)q(z_t | x) 均为扩散核。

  3. 由于分子分母均为高斯分布,最终 q(zt1zt,x)q(z_{t-1} | z_t, x) 也是高斯分布:

    q(zt1zt,x)=N(zt1mt(x,zt),σt2I)q(z_{t-1} | z_t, x) = \mathcal{N}(z_{t-1} | m_t(x, z_t), \sigma_t^2 I)

    其中:

  • 均值 mt(x,zt)m_t(x, z_t)mt(x,zt)=(1αt1)1βtzt+αt1βtx1αtm_t(x, z_t) = \frac{(1-\alpha_{t-1})\sqrt{1-\beta_t}z_t + \sqrt{\alpha_{t-1}}\beta_t x}{1-\alpha_t}
  • 方差 σt2\sigma_t^2(仅依赖 β\betaα\alpha,与 x,ztx, z_t 无关): σt2=βt(1αt1)1αt\sigma_t^2 = \frac{\beta_t(1-\alpha_{t-1})}{1-\alpha_t}

该分布的意义:它为训练神经网络提供了”目标分布”——训练时让网络预测的反向分布 p(zt1zt,w)p(z_{t-1} | z_t, w) 尽可能接近这个”标准答案” q(zt1zt,x)q(z_{t-1} | z_t, x)

反向解码器(Reverse Decoder)

用人话说:反向解码器就是那个”去噪器”——一个神经网络,输入含噪图像 ztz_t 和当前步数 tt,输出去噪后的均值。它就是扩散模型需要训练的核心部分。

反向解码器的核心是”学习一个深度神经网络,近似 q(zt1zt,x)q(z_{t-1} | z_t, x) 对应的反向去噪过程”,最终通过该网络从 zTz_T (纯噪声)生成 xx(清晰的数据样本)。

直接计算 q(zt1zt)q(z_{t-1} | z_t) 不可行(需要对所有可能的 xx 积分),因此用神经网络建模反向分布 p(zt1zt,w)p(z_{t-1} | z_t, w),形式为高斯分布:

p(zt1zt,w)=N(zt1μ(zt,w,t),βtI)p(z_{t-1} | z_t, w) = \mathcal{N}(z_{t-1} | \mu(z_t, w, t), \beta_t I)

其中:

  • μ(zt,w,t)\mu(z_t, w, t):由深度神经网络输出的均值(ww 为网络参数,tt 作为输入以适应不同步的噪声强度);
  • 方差设为 βtI\beta_t I:参考前向加噪的方差,且当 βt\beta_t 较小时,反向分布近似高斯,方差接近 βtI\beta_t I

关于网络架构:神经网络的输出维度需与输入(ztz_t)一致(图像数据中即图像尺寸)。常用的架构是 U-Net——一种具有跳跃连接(Skip Connection)的编码器-解码器结构,适合捕捉图像的局部和全局特征。近年来也有工作使用 Transformer 架构。

βt\beta_t 的选择:为什么要”小步慢走”?

想象一下:如果你一次加很多噪声(βt\beta_t 大),就像把照片一下子弄模糊——去噪时你很难猜出原来是什么。但如果你每次只加一点点噪声(βt\beta_t 小),每一步的变化都很小,神经网络就很容易学会”把这一步的模糊去掉”。

建议设置 βt1\beta_t \ll 1(每步加噪弱),原因:

  1. 前向加噪中,βt\beta_t 小则 ztz_tzt1z_{t-1} 差异小,反向去噪时”修正幅度”小,网络更容易学习;
  2. 反向分布 q(zt1zt)q(z_{t-1} | z_t) 会近似高斯: 上 下
  • 上图:βt\beta_t 大时,q(zt1zt)q(z_{t-1} | z_t) 是多峰分布(复杂,网络难以建模);
  • 下图:βt\beta_t 小时,q(zt1zt)q(z_{t-1} | z_t) 接近高斯(简单,易建模)。

代价:需大量步数 TT(通常数百到数千步)才能让 zTz_T 接近标准高斯,导致生成样本时计算成本高。这就是扩散模型”训练快、生成慢”的根本原因。

反向过程的联合分布

整个反向去噪过程是一个马尔可夫链,联合分布为:

p(x,z1,...,zTw)=p(zT){t=2Tp(zt1zt,w)}p(xz1,w)p(x, z_1, ..., z_T | w) = p(z_T) \left\{ \prod_{t=2}^T p(z_{t-1} | z_t, w) \right\} p(x | z_1, w)

其中:

  • p(zT)=N(zT0,I)p(z_T) = \mathcal{N}(z_T | 0, I)(与前向过程的q(zT)q(z_T)一致);
  • p(xz1,w)p(x | z_1, w):最终从z1z_1(弱噪声)生成xx(无噪声)的分布,形式与p(zt1zt,w)p(z_{t-1} | z_t, w)类似(高斯分布)。

训练目标:证据下界(ELBO)

还记得VAE的ELBO吗? 扩散模型用的是完全相同的思路——直接最大化对数似然太难了(需要对所有可能的噪声路径积分),所以我们最大化它的一个下界ELBO。

生成模型的理想训练目标是最大化数据的对数似然 lnp(xw)\ln p(x | w),但该似然需积分所有潜变量 z1,...,zTz_1,...,z_T,涉及复杂的神经网络,无法直接计算。因此借鉴VAE的思路——最大化似然的下界(ELBO)。

对任意潜变量分布 q(z)q(z),有:

lnp(xw)=L(w)+KL(q(z)p(zx,w))\ln p(x | w) = \mathcal{L}(w) + KL(q(z) \| p(z | x, w))

其中 L(w)\mathcal{L}(w) 是 ELBO,KL()0KL(\cdot \| \cdot) \geq 0。因此 lnp(xw)L(w)\ln p(x | w) \geq \mathcal{L}(w),最大化 L(w)\mathcal{L}(w) 可间接最大化似然。

选择 q(z)=q(z1,...,zTx)q(z) = q(z_1,...,z_T | x)(前向过程的固定分布),代入ELBO并简化,最终分解为”重建项”和”一致性项”:

ELBO 的完整推导L(w)=q(z1x)lnp(xz1,w)dz1t=2TKL(q(zt1zt,x)p(zt1zt,w))q(ztx)dzt\mathcal{L}(w) = \int q(z_1 | x) \ln p(x | z_1, w) dz_1 - \sum_{t=2}^T \int KL(q(z_{t-1} | z_t, x) \| p(z_{t-1} | z_t, w)) q(z_t | x) dz_t
  1. 重建项:奖励网络对原始数据 xx 的重建能力(类似VAE的重建损失)。
  2. 一致性项:确保反向分布 p(zt1zt,w)p(z_{t-1} | z_t, w) 与目标分布 q(zt1zt,x)q(z_{t-1} | z_t, x) 尽可能一致(通过最小化KL散度)。

由于两个高斯分布之间的KL散度有解析解,一致性项可简化为平方损失: KL(q(zt1zt,x)p(zt1zt,w))=12βtmt(x,zt)μ(zt,w,t)2+constKL(q(z_{t-1} | z_t, x) \| p(z_{t-1} | z_t, w)) = \frac{1}{2\beta_t} \| m_t(x, z_t) - \mu(z_t, w, t) \|^2 + const 其中 mt(x,zt)m_t(x, z_t) 是”标准答案”的均值,μ(zt,w,t)\mu(z_t, w, t) 是网络输出的均值。

简单来说就是:ELBO 由两部分组成——重建项要求”从很少的噪声中恢复原图”,一致性项要求”每一步去噪都做得准确”。一致性项是扩散模型训练的核心。

关键改进:预测噪声而非去噪图像

你可能会问:为什么要让网络预测噪声,而不是直接预测去噪后的图像?用人话说:噪声比图像简单得多。想象你面前有一张被沙子覆盖的画——让你直接猜画的全貌很难,但让你猜”上面有多少沙子”相对容易。而且,知道了沙子的分布,去掉沙子就很简单了。

实践中,将网络的目标从”预测去噪图像 μ(zt,w,t)\mu(z_t, w, t)”改为”预测累计噪声 ϵt\epsilon_t”,可显著提升生成质量。

为什么预测噪声等价于预测去噪图像(数学推导)
  1. 由扩散核公式 zt=αtx+1αtϵtz_t = \sqrt{\alpha_t}x + \sqrt{1-\alpha_t}\epsilon_t,反解 xx

    x=1αtzt1αtαtϵtx = \frac{1}{\sqrt{\alpha_t}}z_t - \frac{\sqrt{1-\alpha_t}}{\sqrt{\alpha_t}}\epsilon_t
  2. qq 的均值 mtm_t 改写为 ϵt\epsilon_t 的函数:

    mt(x,zt)=11βt{ztβt1αtϵt}m_t(x, z_t) = \frac{1}{\sqrt{1-\beta_t}} \left\{ z_t - \frac{\beta_t}{\sqrt{1-\alpha_t}} \epsilon_t \right\}
  3. 如果定义网络 g(zt,w,t)g(z_t, w, t) 预测累计噪声 ϵt\epsilon_t,则网络输出 μ(zt,w,t)\mu(z_t, w, t)gg 的关系为:

    μ(zt,w,t)=11βt{ztβt1αtg(zt,w,t)}\mu(z_t, w, t) = \frac{1}{\sqrt{1-\beta_t}} \left\{ z_t - \frac{\beta_t}{\sqrt{1-\alpha_t}} g(z_t, w, t) \right\}

整合后,最终训练目标简化为(省略权重因子,经验表明可提升性能):

L(w)=t=1Tg(αtx+1αtϵt,w,t)ϵt2\mathcal{L}(w) = -\sum_{t=1}^T \| g(\sqrt{\alpha_t}x + \sqrt{1-\alpha_t}\epsilon_t, w, t) - \epsilon_t \|^2

损失函数的直觉理解:对每个训练样本 xx 和随机时间步 tt,采样噪声 ϵt\epsilon_t 生成 ztz_t,让网络 gg 预测”加了什么噪声”,损失就是”预测噪声”与”真实噪声”的平方差。训练目标非常简洁明了!

训练和生成算法

用人话说:训练就是反复做一件事——随机挑一张图,随机加一些噪声,让网络猜”加了什么噪声”,然后调整网络让它猜得更准。生成就是反过来——从纯噪声开始,让网络一步步猜”这一步加了什么噪声”,然后把噪声去掉。

训练过程

  1. 预处理:设定噪声 schedule {β1,...,βT}\{\beta_1, ..., \beta_T\},计算每个 ttαt=τ=1t(1βτ)\alpha_t = \prod_{\tau=1}^t (1-\beta_\tau)
  2. 迭代训练
  • 从训练集采样一个数据样本 xx
  • 随机采样一个时间步 tt(避免对所有 tt 计算,提升效率);
  • 采样标准高斯噪声 ϵN(0,I)\epsilon \sim \mathcal{N}(0, I)
  • 计算含噪样本 zt=αtx+1αtϵz_t = \sqrt{\alpha_t}x + \sqrt{1-\alpha_t}\epsilon
  • 计算损失 L(w)=g(zt,w,t)ϵ2\mathcal{L}(w) = \| g(z_t, w, t) - \epsilon \|^2,通过随机梯度下降更新网络参数 ww
  1. 终止:直到损失收敛。

生成过程(采样):

  1. p(zT)=N(0,I)p(z_T) = \mathcal{N}(0, I) 采样纯噪声 zTz_T
  2. t=Tt=Tt=2t=2,逐步去噪:
  • 网络 gg 输入 ztz_ttt,输出预测噪声 g(zt,w,t)g(z_t, w, t)
  • 计算去噪后的均值 μ(zt,w,t)\mu(z_t, w, t),然后加一点小噪声生成 zt1z_{t-1}
  1. 最终一步(t=1t=1):不加噪声,直接输出生成的样本 xx

生成速度的问题:扩散模型的主要缺点是生成时需要数百到数千步去噪,计算成本高。改进方向包括:

  • 隐扩散模型(Latent Diffusion Model, LDM):先用自编码器把高分辨率图像压缩到低维隐空间,在隐空间进行扩散(维度低,计算快),最后解码回高分辨率图像。Stable Diffusion 就是基于这个思路。
  • 更快的采样器:DDIM 等方法可以在更少的步数内生成质量相近的图像。

得分匹配 (Score Matching)

想象一下:你在一座山上(概率密度的”地形”),得分函数就是在你脚下画一个箭头,指向”上山”的方向(概率密度增加的方向)。如果你知道每个点的箭头方向,你就能沿着箭头走到山顶(概率最高的地方),那里就是数据最可能出现的位置。

得分匹配(Score Matching)是另一类生成模型框架,与扩散模型密切相关,核心是”学习数据分布的得分函数”(Score Function),进而通过朗之万动力学生成样本。

得分函数是对数概率密度对数据的梯度:

s(x)=xlnp(x)s(x) = \nabla_x \ln p(x)

其中:

  • x\nabla_x 表示对数据向量 xx 的梯度(不是对网络参数的梯度);
  • xx 是图像,s(x)s(x) 也是同尺寸的图像(每个像素对应梯度值)。

得分函数的意义:学习得分函数等价于学习数据分布(差一个归一化常数),而得分函数不需要知道归一化常数——这是一个巨大的优势,因为归一化常数通常是无法计算的。

得分损失函数

目标是学习一个神经网络模型 s(x,w)s(x, w),使其接近真实得分函数 xlnp(x)\nabla_x \ln p(x),损失函数为:

J(w)=12s(x,w)xlnp(x)2p(x)dxJ(w) = \frac{1}{2} \int \| s(x, w) - \nabla_x \ln p(x) \|^2 p(x) dx

问题:真实得分函数未知——训练数据仅为有限样本,无法直接计算 xlnp(x)\nabla_x \ln p(x)。解决方案是去噪得分匹配

去噪得分匹配 (Denoising Score Matching)

用人话说:去噪得分匹配的核心思想和扩散模型一样——给数据加噪声,然后学习”噪声的方向”(即得分函数)。加了噪声之后,得分函数变得容易计算了。

去噪得分匹配的推导过程
  1. 用高斯核平滑数据,得到近似分布 qσ(z)q_\sigma(z)

    qσ(z)=q(zx,σ)p(x)dxq_\sigma(z) = \int q(z | x, \sigma) p(x) dx

    其中 q(zx,σ)=N(zx,σ2I)q(z | x, \sigma) = \mathcal{N}(z | x, \sigma^2 I)

  2. 损失函数改为”平滑分布的得分匹配”:

    J(w)=12s(z,w)zlnqσ(z)2qσ(z)dzJ(w) = \frac{1}{2} \int \| s(z, w) - \nabla_z \ln q_\sigma(z) \|^2 q_\sigma(z) dz
  3. 简化后,对高斯核 q(zx,σ)=N(zx,σ2I)q(z | x, \sigma) = \mathcal{N}(z | x, \sigma^2 I),其得分函数为:

    zlnq(zx,σ)=1σϵ(ϵ=zx)\nabla_z \ln q(z | x, \sigma) = -\frac{1}{\sigma} \epsilon \quad (\epsilon = z - x)

与扩散模型的联系:若结合扩散模型的噪声水平(σ=1αt\sigma = \sqrt{1-\alpha_t}),则得分函数为:

zlnq(zx,σ)=11αtϵ\nabla_z \ln q(z | x, \sigma) = -\frac{1}{\sqrt{1-\alpha_t}} \epsilon

此时得分损失与扩散模型的损失本质等价:得分函数 s(z,w)s(z, w) 对应扩散模型的噪声预测网络 g(z,w)g(z, w) (仅差一个常数缩放因子)。因此”去噪得分匹配”与”扩散模型”殊途同归!

朗之万动力学采样 (Langevin Dynamics Sampling)

想象一下:你在一个雾蒙蒙的山上,看不见路,但能感受到脚下的坡度(得分函数)。朗之万动力学就是——每一步你沿着”上坡”方向走一小步,再加一点点随机的”风”的扰动。走很多步之后,你就会到达山顶(概率密度最高的地方)。

训练好得分模型后,通过朗之万动力学(Langevin Dynamics)生成样本——利用得分函数引导采样方向(指向概率密度增加的方向),步骤如下:

  1. 初始化样本 x0N(0,I)x_0 \sim \mathcal{N}(0, I)(从标准高斯开始);
  2. 迭代更新(k=0k=0K1K-1): xk+1=xk+η2s(xk,w)+ηϵk(ϵkN(0,I))x_{k+1} = x_k + \frac{\eta}{2} s(x_k, w) + \sqrt{\eta} \epsilon_k \quad (\epsilon_k \sim \mathcal{N}(0, I)) 其中 η\eta 为步长(小值,保证稳定)。每一步包含两个部分:得分函数的”确定性引导”和噪声的”随机扰动”。
  3. 迭代终止后,xKx_K 即为生成的样本。

单一噪声水平的权衡σ\sigma 太小,得分函数在数据流形外无定义,采样不稳定;σ\sigma 太大,平滑过度,扭曲原始数据分布。

解决方案:退火朗之万动力学(Annealed Langevin Dynamics)——使用递减的噪声方差序列 {σ12<σ22<...<σL2}\{\sigma_1^2 < \sigma_2^2 < ... < \sigma_L^2\}

  • σL\sigma_L:初始采样从平滑分布出发,避免流形问题;
  • 逐步减小 σ\sigma:逐步逼近原始数据分布;
  • 这与扩散模型的逐步去噪逻辑完全一致!

随机微分方程 (SDE) 视角

用人话说:前面讲的离散步数(每步加一点点噪声)在数学上可以推广为连续过程——就像把”一步一步爬楼梯”变成”坐电梯”。SDE 就是描述这个连续过程的数学语言。好消息是,有了 SDE,我们可以用更高效的数值方法来加速生成。

当扩散模型的步数 TT \to \infty,每步噪声方差 βt0\beta_t \to 0 时,离散的前向/反向过程可表示为随机微分方程(SDE, Stochastic Differential Equation):

SDE 的核心公式
  1. 前向SDE(加噪过程):

    dz=f(z,t)dt漂移项(确定性)+g(t)dv扩散项(随机性)dz = \underbrace{f(z, t)dt}_\text{漂移项(确定性)} + \underbrace{g(t)dv}_\text{扩散项(随机性)}
  2. 反向SDE(去噪过程):

    dz={f(z,t)g2(t)zlnp(z)}dt+g(t)dvdz = \left\{ f(z, t) - g^2(t) \nabla_z \ln p(z) \right\} dt + g(t)dv

    其中 zlnp(z)\nabla_z \ln p(z) 是得分函数,引导去噪方向。

  3. 对应的ODE(确定性过程):

    dzdt=f(z,t)12g2(t)zlnp(z)\frac{dz}{dt} = f(z, t) - \frac{1}{2}g^2(t) \nabla_z \ln p(z)

    ODE 可使用高效的自适应步长求解器,大幅减少函数调用次数,提升生成效率。

关键意义:SDE 框架将扩散模型、得分匹配、朗之万动力学统一在一个数学体系下——它们都是同一枚硬币的不同面。

引导扩散 (Guided Diffusion)

用人话说:前面讲的扩散模型只能”随机生成”图片——生成什么完全看运气。但实际应用中,我们想”指定”生成什么,比如”生成一只猫”或”根据文字描述生成图片”。引导扩散就是给扩散模型加一个”导航”,让它朝我们想要的方向生成。

前述扩散模型均为无条件生成(Unconditional Generation),而实际应用中常需条件生成(Conditional Generation,如根据类别标签、文本描述生成图像)。引导扩散通过”引入引导信号”控制生成过程,主要有两种方式。

分类器引导 (Classifier Guidance)

利用预训练的分类器 p(cx)p(c | x)cc 为条件,如类别标签”猫”),通过贝叶斯定理将”无条件得分函数”修正为”条件得分函数”,引导去噪过程向目标条件靠拢。

简单来说就是:条件得分 = 无条件得分 + 分类器的梯度(乘以一个权重):

score(x,c,λ)=xlnp(x)+λxlnp(cx)score(x, c, \lambda) = \nabla_x \ln p(x) + \lambda \nabla_x \ln p(c | x)
  • λ=0\lambda=0:无引导,退化为无条件生成;
  • λ=1\lambda=1:严格遵循条件分布 p(xc)p(x | c)
  • λ>1\lambda>1:增强引导强度(生成样本更符合 cc,但多样性降低——“越听话但越单调”)。
分类器引导的数学推导

由贝叶斯定理:

lnp(xc)=lnp(cx)+lnp(x)lnp(c)\ln p(x | c) = \ln p(c | x) + \ln p(x) - \ln p(c)

xx 求梯度(xlnp(c)=0\nabla_x \ln p(c) = 0,因为 p(c)p(c)xx 无关):

xlnp(xc)=xlnp(x)+xlnp(cx)\nabla_x \ln p(x | c) = \nabla_x \ln p(x) + \nabla_x \ln p(c | x)

缺点:需要额外训练一个能处理含噪图像的分类器(标准分类器只在清洁数据上训练),且分类器可能只关注局部特征,影响整体生成质量。

无分类器引导 (Classifier-Free Guidance)

用人话说:无分类器引导的思路更巧妙——不需要额外的分类器,而是在训练时”偶尔故意忘掉条件”。这样模型同时学会了”有条件生成”和”无条件生成”,生成时通过调节两者的比例来控制”听话程度”。

无需预训练分类器,直接训练一个”条件-无条件统一模型”:训练时随机将部分样本的条件 cc 置空(如 c=0c=0,概率10%-20%),使模型同时学习 p(xc)p(x | c)(条件)和 p(xc=0)p(x | c=0)(无条件)。

生成时的得分函数为:

score(x,c,λ)=λxlnp(xc)+(1λ)xlnp(x)score(x, c, \lambda) = \lambda \nabla_x \ln p(x | c) + (1-\lambda) \nabla_x \ln p(x)
  • 0<λ<10<\lambda<1:条件与无条件得分的混合;
  • λ>1\lambda>1:削弱无条件得分的影响,强制生成样本更符合 cc

优势:

  • 无需额外训练分类器,简化流程;
  • 模型关注整体特征(而非分类器的局部特征),生成质量更高。

这种方法是目前最主流的条件生成方式,Stable Diffusion、DALL-E 等模型都使用了无分类器引导。

应用场景

  1. 文本引导图像生成(文生图): 将条件 cc 改为文本描述(prompt),结合大语言模型(如 Transformer):
  • 文本通过语言模型编码为向量,作为扩散模型的额外输入;
  • 扩散模型中加入交叉注意力层(Cross-Attention),让网络关注文本 token 与图像特征的对应关系。

    还记得第6篇的Transformer吗? 交叉注意力正是 Transformer 的核心机制——这里用它来让图像”理解”文本描述。 文生图

    文生图效果对比:左侧 $ \lambda=0 $ 无引导,右侧 $ \lambda=3 $ 强引导

  1. 图像超分辨率: 输入低分辨率图像,条件 cc 为低分辨率图像,扩散模型从高分辨率高斯噪声出发,逐步去噪生成与低分辨率匹配的高分辨率图像。
  2. 潜扩散模型(Latent Diffusion Model): 解决高分辨率图像生成的计算成本问题:
  • 第一步:训练自编码器(Autoencoder),将高分辨率图像压缩到低维隐空间;
  • 第二步:固定自编码器,在隐空间训练扩散模型(维度低,计算快);
  • 第三步:扩散模型生成的隐向量通过自编码器解码器,恢复为高分辨率图像。
  • Stable Diffusion 就是基于这个架构!
  1. 其他应用:
  • 图像修复(Inpainting):条件 cc 为”缺失部分的掩码 + 已知部分图像”,生成缺失区域; 图像修复

    左为原始图像,中为掩码图像,右为修复结果

  • 图像上色、去模糊、视频生成等:均通过将任务相关信息作为条件 cc,引导扩散模型生成目标结果。
习题4

扩散模型让网络预测噪声,而不是直接预测去噪后的图像。为啥这样更好?

想象一张被沙子盖住的画:直接猜画的全貌很难,但猜”上面有多少沙子”容易得多。噪声就是”沙子”——它比图像简单,网络学起来更轻松。而且知道了噪声,去噪就是减法:x=ztnoisex = z_t - \text{noise}

“前向过程”和”反向过程”分别在干嘛?为什么前向不需要学?

前向过程就是”搞破坏”——一步步往图像上加噪声,直到变成纯噪声。这个过程是固定的,每步加多少噪声提前定好,不需要学习。

反向过程是”搞修复”——从纯噪声一步步去掉噪声,恢复出图像。这个需要学习,因为网络得理解”什么是噪声”、“什么是图像结构”。

打个比方:把沙子撒到画上(前向)不需要技术,但把沙子精确地扫掉(反向)需要手艺。


第20章小结

一句话版本:先一步步加噪声把图片变成纯噪声,再训练一个神经网络学会一步步去掉噪声。就像被干扰的电话信号——你知道噪声是怎么加的,就能学会怎么去掉。

知识地图

  • 核心思想:前向加噪(固定的) + 反向去噪(需要学习的)
  • 训练目标:让神经网络预测每一步添加的噪声(而非直接预测去噪后的图像)
  • 数学框架:ELBO -> 得分匹配 -> SDE(三者本质等价)
  • 条件生成:分类器引导(需要额外分类器) -> 无分类器引导(主流方案)
  • 实际应用:Stable Diffusion = 潜扩散模型 + 无分类器引导 + Transformer 文本编码器
  • 优势:训练稳定、生成质量高
  • 劣势:生成速度慢(需要数百步去噪)

感谢您的阅读!如果可以,给俺点些关注吧~

深度学习笔记-8:GAN、标准化流、自编码器与扩散模型

周一 9月 01 2025
18900 · 70 分钟
封面
示例歌曲
示例艺术家
封面
示例歌曲
示例艺术家
0:00 / 0:00