VAE
Variational Autoencoder
VAE 是一种带潜变量的生成模型。它一边学习近似后验分布
它和普通 Autoencoder 很像:
- 都有一个“编码”过程;
- 都有一个“解码”过程;
- 都希望输入能被还原出来。
但 VAE 和普通 Autoencoder 的根本区别在于:
普通 Autoencoder 通常把一个样本映射到一个确定的向量;VAE 则把一个样本映射到一个概率分布。
所以 VAE 不只是“压缩再还原”,它真正想做的是:
学到一个结构良好的潜空间,使得我们既能重建已有样本,也能从潜变量里直接采样生成新样本。
为什么要引入潜变量
VAE 背后的思路是:很多复杂数据其实可以由一些更简单的隐藏因素生成。
例如一张人脸图片,表面上是大量像素,但更深层次上,它可能由下面这些因素共同决定:
- 姿态;
- 光照;
- 表情;
- 发型;
- 身份特征。
这些隐藏因素可以记成潜变量
于是 VAE 先假设数据是这样生成的:
- 先从一个简单先验分布里采样潜变量
; - 再根据
生成观测数据 。
这就是所谓的 latent variable model。
VAE 的生成模型
VAE 最基本的生成过程写成:
这里:
是潜变量的先验分布; 是解码器,也叫生成模型; 是生成模型参数。
通常最常见的先验选择是标准高斯:
于是联合分布可以写成:
而数据边缘分布就是:
这条式子说明:
如果我们能把所有潜变量都积分掉,就得到了样本
真正的困难在哪里
如果我们想知道:
给定一个样本
,它最可能对应什么潜变量 ?
那就要看后验分布:
把分母展开就是:
问题就出在这里:
分母通常很难精确计算。
因为它要求对所有可能的潜变量
所以 VAE 面对的核心问题不是“没有生成模型”,而是:
有了生成模型以后,后验推断
很难直接算。
变分推断的想法
既然后验
不要直接算它,改用一个容易计算的分布去近似它。
这个近似分布通常记成:
这里:
叫近似后验; 是它的参数; - 在 VAE 里,它通常由一个神经网络输出,所以也常被叫做编码器。
于是 VAE 的结构就变成:
- 编码器:
- 解码器:
这也是为什么它叫 Variational Autoencoder:
Autoencoder是因为它有 encoder / decoder 结构;Variational是因为它不是做确定性编码,而是在做变分推断。
TIP
q(z|x) 给定图片
ELBO 是怎么来的
VAE 最核心的公式就是 ELBO。
先从一个恒等式开始。考虑后验近似分布和真实后验之间的 KL 散度:
把 Bayes 公式
代进去:
因为
移项以后得到:
定义
于是就得到:
因为 KL 散度永远非负,所以:
这就是为什么它叫 Evidence Lower Bound:
它是对对数证据
ELBO 的常见分解形式
把联合分布
代回 ELBO:
这是 VAE 最常见、也最值得记住的形式。
它可以分成两项来看。
第一项:重建项
它表示:
从编码器得到潜变量以后,解码器能不能把原始样本重新生成出来。
所以这一项通常被叫做 reconstruction term。
它越大,说明模型越会还原输入。
第二项:KL 正则项
这一项表示:
编码器给出的潜变量分布,不要离先验分布太远。
所以它起到的是正则化作用。
如果没有这项,编码器可能会把每个样本都塞到一个很奇怪、互不连贯的潜空间位置;这样虽然重建可能很好,但采样生成就会很差。KL 项的作用就是把潜空间压得更规则、更平滑。
所以 ELBO 可以直接翻译成:
一边让模型会重建,一边让 latent space 保持规整。
TIP
ELBO = 重建项 - KL项
更常见写法是:
其中,重建项
重建项的具体形式取决于对
- 如果是灰度像素当成
Bernoulli 分布,经常用BCE。 - 如果是连续像素当成
Gaussian 分布,经常用MSE。
KL 项
为什么要这样?
因为生成时我们不会先有图片
z ~ N(0, I)
x ~ Decoder(z)
如果训练时 Encoder 输出的
为什么最大化 ELBO 有意义
从
可以看出,最大化 ELBO 至少有两层意义。
第一,它是在提高
第二,如果 ELBO 逼近得越来越紧,那就意味着:
会越来越小,也就是说近似后验
所以训练 VAE,不只是“学会重建”,而是在同时学习:
- 一个好的生成模型
; - 一个好的近似推断模型
。
最常见的高斯 VAE
实践里最常见的是让编码器输出一个对角高斯分布:
也就是说,给定输入
- 一个均值向量
; - 一个方差向量
。
于是 latent variable 是从这个分布里采样出来的。
通常先验依然取:
这样 KL 项通常可以写成闭式公式:
这个公式很重要,因为它让 KL 正则项的计算非常方便。
为什么不能直接采样然后反传
VAE 训练里一个最核心的工程问题是:
编码器输出的是一个分布,我们需要从里面采样
,但“采样”这个操作本身不可直接反传。
如果直接写:
那么梯度很难顺畅传回到
这就是为什么 VAE 需要 reparameterization trick。
重参数化技巧
对高斯分布,可以把采样写成:
这里
这条式子的意义特别大:
- 随机性被放进了一个与参数无关的噪声
; - 真正依赖参数的部分变成了一个可微的确定性变换。
于是损失函数就可以通过
这也是 VAE 能够用标准 SGD / Adam 稳定训练的关键之一。
VAE 的训练目标到底长什么样
对单个样本
如果写成最小化损失,通常就是取负号:
所以常见实现里,你会看到总 loss 等于:
- reconstruction loss
- 加上 KL loss
前者希望保真,后者希望潜空间规整。
完整的训练流程
一张图片
- Encoder 输出:
, - 采样标准噪声:
- 得到隐变量:
- Decoder 重建:
- 计算 loss:
训练时最小化这个 loss。
为什么用 logvar 而不是 sigma?
网络实际输出的是
这样写主要有三个好处:
- 方差和标准差必须为正,直接预测
可能会得到负数; 可以是任意实数,网络输出不需要额外加正数约束; - KL 项里本来就会出现
,用 logvar 计算更方便、更稳定。
直觉上,网络不是直接说“标准差是多少”,而是先说“方差取对数后是多少”,再通过指数变换保证最后得到的标准差一定为正。
VAE 怎么生成新样本
训练完成后,VAE 的生成过程非常自然:
- 从先验分布采样潜变量
- 再通过解码器生成样本
这就是为什么 VAE 是一个真正的生成模型:
它不是只能重建已有输入,还可以从先验里直接采样,生成全新的样本。
VAE 和普通 Autoencoder 的区别
这是最容易混淆的地方。
普通 Autoencoder 通常做的是:
也就是说:
- 编码器输出一个确定向量;
- 解码器再从这个确定向量重建输入;
- 目标通常只是重建误差最小。
而 VAE 做的是:
也就是说:
- 编码器输出一个分布;
- latent 通过采样得到;
- 目标不是单纯重建,而是 ELBO;
- 它还要求潜变量分布不要偏离先验太远。
所以最本质的差别不是“有没有 encoder / decoder”,而是:
VAE 的 latent space 是概率建模的结果,而不是单纯压缩的中间层。
TIP
普通 AutoEncoder 是:
图片
-> Encoder -> 隐变量 -> Decoder -> 重建图片
训练目标通常是:让
但普通 AE 有个问题:它学到的
VAE 希望做到:
随机采样一个
-> Decoder -> 生成一张合理图片
为了让随机采样有效,VAE 会要求隐变量空间长得比较规整,通常希望:
z ~ N(0, I)
VAE 的优点
VAE 之所以重要,主要有几方面原因。
第一,它给了深度生成模型一个非常干净的概率建模框架。它不是纯经验技巧,而是从 latent-variable model 和 variational inference 推出来的。
第二,它的 latent space 通常比较平滑、连续、可插值。因为 KL 项会把潜变量分布往标准高斯上拉,所以在 latent space 里做插值,往往对应样本语义上的平滑变化。
第三,它训练通常比早期一些显式概率模型更稳定,也比 GAN 更容易解释训练目标。
VAE 的局限
VAE 也有明显局限。
最经典的一个问题是:生成结果有时会偏模糊。原因并不是一句“VAE 天生模糊”那么简单,而是它常见的解码分布假设和像素级似然形式,会鼓励模型在不确定区域取平均,结果看起来就容易发糊。
另一个常见问题是 posterior collapse,也就是解码器太强时,模型可能几乎不使用潜变量,导致
所以很多后续工作会对 VAE 做改造,例如:
- 改更强的后验族;
- 调整 KL 权重;
- 使用 hierarchical VAE;
- 使用更强的 decoder;
- 使用 flow-based posterior。
总结
VAE = 带概率潜变量的 Autoencoder,用 ELBO 同时学会重建和规整 latent space。
核心公式
生成模型:
训练目标:
VAE 是一种基于潜变量建模和变分推断的生成模型。它假设数据由潜变量