变分自编码器 VAE

本文结合豆包生成

先从自编码器(AE) 说起,再讲VAE是怎么把它升级成能生成新内容的「变分自编码器」。

先搞懂基础——自编码器(AE)是什么?

大白话:AE就是一个「压缩-还原」的AI机器,分两个核心部分:

  • 编码器:把输入的样本(比如一张人脸照片x),压缩成一个很短的特征码z(也叫隐变量,相当于这张脸的“精华摘要”)

  • 解码器:拿着这个z,把原来的照片还原出来,得到

它的训练目标只有一个:还原出来的和原图x越像越好,对应的损失就是「重构损失」(比如像素差的平方和MSE)。

极简公式版:

\[\begin{align*} z &= \text{Encoder}(x) \\ \hat{x} &= \text{Decoder}(z) \\ \text{Loss} &= \text{MSE}(x, \hat{x}) \quad \text{(最小化这个损失)} \end{align*} \]

AE的致命痛点:只能压缩还原,没法生成新东西

训练好AE之后,只有编码器输出的那些z,解码器才能还原出合理的图片。如果随便编一个z,解码器输出的基本都是乱码、噪声。

原因很简单:AE的隐空间(所有z的集合)是离散、有空洞、无规律的——训练数据对应的z都是一个个孤立的点,点和点之间的空白区域全是无效的,解码器根本不知道这些z该对应什么内容。

而VAE,就是专门解决这个问题的:它要把隐空间变成连续、规整、处处都能用的,这样随便采样一个z,都能生成合理的新内容。


VAE的核心思路——给隐变量z加上概率分布

VAE的核心改动,完全针对编码器:

AE的编码器:输入x,输出一个固定的z

VAE的编码器:输入x,输出z的概率分布(默认用最易计算的正态分布)

大白话解释:

比如一张人脸x,AE说“这张脸的精华就是z=[1,2,3]”,一锤子买卖;

而VAE说“这张脸的精华,大概率在以μ=[1,2,3]为中心、σ=[0.1,0.2,0.1]为宽度的正态分布里,你从这个范围里随便采样一个z,都能还原出这张脸”。

为什么要这么做?

  1. 给每个xz留了容错空间,不会让z缩成孤立的点;

  2. 我们可以约束所有样本对应的分布,都往标准正态分布N(0, I) 靠(均值为0,方差为1),这样所有分布都集中在同一个规整的空间里,点和点之间没有空洞,隐空间就连续了!

先把符号说清楚

符号 含义
\(x\) 输入的训练样本(比如人脸、手写数字)
\(z\) 隐变量(压缩后的精华特征)
\(q_\phi(z|x)\) 编码器(推断网络),\(\phi\)是编码器参数;输入x,输出z的正态分布
\(p_\theta(x|z)\) 解码器(生成网络),\(\theta\)是解码器参数;输入z,输出还原的x
\(p(z)\) z的先验分布,我们规定它是标准正态分布N(0, I) 。输入一个具体的隐变量取值z,输出这个z在标准正态分布下对应的概率密度值

VAE的核心技巧——重参数化(Reparameterization Trick)

这里有个致命的工程问题:我们要从编码器输出的正态分布\(N(\mu, \sigma^2)\)里采样z,但“采样”这个动作是随机的、不可导的——反向传播更新参数时,梯度根本传不回去,模型没法训练。

重参数化就是专门解决这个问题的,核心思路:把随机性和可导的参数完全拆分开

公式&大白话解释

原来的采样:\(z \sim N(\mu, \sigma^2)\) → 随机性来自\(\mu\)\(\sigma\),梯度直接断了
重参数化之后:

\[z = \mu + \sigma \cdot \varepsilon \]

其中 \(\varepsilon \sim N(0, 1)\),也就是从标准正态分布里采样一个和模型参数完全无关的随机噪声\(\varepsilon\)

大白话翻译:

  • 把所有随机性都甩给\(\varepsilon\)\(\varepsilon\) 是在每一次前向传播的重参数化步骤里,临时、实时采样生成的随机数)。\(\mu\)\(\sigma\)都是编码器输出的、可导的参数;
  • 梯度可以正常通过\(\mu\)\(\sigma\)回传给编码器,解决了不可导的问题。

实用细节:编码器一般不直接输出\(\sigma^2\),而是输出\(log\sigma^2\)。因为\(\sigma^2\)必须是正数,而神经网络的输出可以是任意实数,输出\(log\sigma^2\)后,用\(\sigma = \exp(log\sigma^2 / 2)\)就能得到一定为正的\(\sigma\),避免数值错误。


VAE的核心公式——损失函数(ELBO证据下界)

我们训练VAE的终极目标,是让模型能生成和训练数据一致的样本,也就是最大化训练样本x的出现概率\(\log p(x)\)(对数似然)

但这个\(\log p(x)\)直接算不出来,因为它要对所有可能的z积分:\(p(x) = \int p(x|z)p(z) dz\),这个积分没有闭式解,根本算不动。

所以数学家们用「变分推断」,推导出了\(\log p(x)\)下界ELBO(Evidence Lower Bound),也就是:

\[\log p(x) \geq \text{ELBO} \]

我们只要最大化ELBO,就相当于把\(\log p(x)\)的下界往上抬,间接实现了终极目标。

ELBO的分解(核心公式)

ELBO可以拆成两个极易理解的部分,我们的损失函数就是负的ELBO(因为梯度下降是最小化损失):

\[\text{ELBO} = \underbrace{\mathbb{E}_{q_\phi(z|x)} \left[ \log p_\theta(x|z) \right]}_{\text{重构项:越大越好}} - \underbrace{D_{KL}\left( q_\phi(z|x) \parallel p(z) \right)}_{\text{KL散度项:越小越好}} \]

对应的损失函数:

\[\text{Loss} = -\text{重构项} + \text{KL散度项} \]

我们要做的就是最小化这个Loss

拆解每一项:

1. 重构项:和AE的重构损失完全等价

公式里的\(\mathbb{E}_{q_\phi(z|x)} \left[ \log p_\theta(x|z) \right]\),就是从编码器输出的分布里采样z,解码器用z还原出x的概率的期望

  • 大白话:还原得越像原图x,这个值就越大,对应的负重构项就越小,损失就越小。
  • 工程实现:这个项直接等价于AE里的MSE损失(连续数据,比如图片)或交叉熵损失(离散数据,比如文本),直接用就行。

2. KL散度项:约束隐空间的正则项

KL散度\(D_{KL}(P \parallel Q)\),就是衡量两个概率分布的“距离”:两个分布越像,KL散度越小,完全一致时等于0。

这里的KL散度,就是编码器输出的分布\(q_\phi(z|x)\),和我们规定的标准正态先验\(p(z)=N(0,I)\)的距离

  • 大白话:我们逼着编码器输出的分布尽量往标准正态分布靠,这样所有样本的z分布都集中在同一个规整的空间里,不会乱跑,隐空间就没有空洞了。

关键福利:KL散度的闭式解(不用采样,直接算)

因为我们假设\(q_\phi(z|x)\)是对角协方差的正态分布\(N(\mu, \sigma^2 I)\),先验是\(N(0,I)\),所以它们的KL散度有现成的闭式解,不用复杂的采样,直接用\(\mu\)\(\sigma\)就能算,是VAE能高效训练的核心:

单个维度的KL散度公式:

\[D_{KL}\left( N(\mu, \sigma^2) \parallel N(0,1) \right) = \frac{1}{2} \left( \sigma^2 + \mu^2 - 1 - \log \sigma^2 \right) \]

d维的多元正态分布(每个维度独立),直接把每个维度的KL散度加起来即可:

\[D_{KL}\left( q_\phi(z|x) \parallel p(z) \right) = \frac{1}{2} \sum_{i=1}^d \left( \sigma_i^2 + \mu_i^2 - 1 - \log \sigma_i^2 \right) \]


VAE完整的训练流程

  1. 取一个训练样本x,输入编码器;
  2. 编码器输出两个向量:均值\(\mu\),和对数方差\(log\sigma^2\)(维度和隐变量z一致);
  3. 用重参数化技巧采样z\(z = \mu + \exp(log\sigma^2 / 2) \cdot \varepsilon\),其中\(\varepsilon \sim N(0,I)\)
  4. z输入解码器,得到重构的\(\hat{x}\)
  5. 计算损失:Loss = 重构损失(MSE/交叉熵) + KL散度损失(闭式解计算)
  6. 反向传播,更新编码器\(q_\phi(z|x)\)和解码器\(p_\theta(x|z)\)的参数\(\phi\)\(\theta\)
  7. 重复以上步骤,直到模型收敛。

训练好的VAE怎么用?核心能力

  1. 生成新样本:直接从标准正态分布\(N(0,I)\)里随机采样一个z,丢给解码器,就能生成一个全新的、和训练数据同分布的样本(比如全新的人脸、手写数字);
  2. 隐空间插值:取两个样本的z1z2,做线性插值\(z = a \cdot z1 + (1-a) \cdot z2\)a从0到1),就能生成从样本1平滑过渡到样本2的内容;
  3. 特征解耦:隐变量z的不同维度,可能对应不同的语义特征(比如人脸的微笑程度、年龄),调整对应维度的值,就能精准修改生成内容的属性。
posted @ 2026-03-14 16:37  wljss  阅读(88)  评论(0)    收藏  举报