Skip to content

VAE

Variational Autoencoder

VAE 是一种带潜变量的生成模型。它一边学习近似后验分布 qϕ(zx),把样本映射到潜变量分布;一边学习生成模型 pθ(xz),从潜空间生成数据。

它和普通 Autoencoder 很像:

  • 都有一个“编码”过程;
  • 都有一个“解码”过程;
  • 都希望输入能被还原出来。

但 VAE 和普通 Autoencoder 的根本区别在于:

普通 Autoencoder 通常把一个样本映射到一个确定的向量;VAE 则把一个样本映射到一个概率分布。

所以 VAE 不只是“压缩再还原”,它真正想做的是:

学到一个结构良好的潜空间,使得我们既能重建已有样本,也能从潜变量里直接采样生成新样本。

为什么要引入潜变量

VAE 背后的思路是:很多复杂数据其实可以由一些更简单的隐藏因素生成。

例如一张人脸图片,表面上是大量像素,但更深层次上,它可能由下面这些因素共同决定:

  • 姿态;
  • 光照;
  • 表情;
  • 发型;
  • 身份特征。

这些隐藏因素可以记成潜变量 z

于是 VAE 先假设数据是这样生成的:

  1. 先从一个简单先验分布里采样潜变量 z
  2. 再根据 z 生成观测数据 x

这就是所谓的 latent variable model

VAE 的生成模型

VAE 最基本的生成过程写成:

zp(z)xpθ(xz)

这里:

  • p(z) 是潜变量的先验分布;
  • pθ(xz) 是解码器,也叫生成模型;
  • θ 是生成模型参数。

通常最常见的先验选择是标准高斯:

p(z)=N(0,I)

于是联合分布可以写成:

pθ(x,z)=p(z)pθ(xz)

而数据边缘分布就是:

pθ(x)=pθ(x,z)dz=p(z)pθ(xz)dz

这条式子说明:

如果我们能把所有潜变量都积分掉,就得到了样本 x 的概率。

真正的困难在哪里

如果我们想知道:

给定一个样本 x,它最可能对应什么潜变量 z

那就要看后验分布:

pθ(zx)=pθ(x,z)pθ(x)

把分母展开就是:

pθ(zx)=p(z)pθ(xz)p(z)pθ(xz)dz

问题就出在这里:

分母通常很难精确计算。

因为它要求对所有可能的潜变量 z 做积分,而在高维、复杂神经网络参数化的情况下,这个积分一般没有闭式解。

所以 VAE 面对的核心问题不是“没有生成模型”,而是:

有了生成模型以后,后验推断 pθ(zx) 很难直接算。

变分推断的想法

既然后验 pθ(zx) 难算,一个自然办法就是:

不要直接算它,改用一个容易计算的分布去近似它。

这个近似分布通常记成:

qϕ(zx)

这里:

  • qϕ(zx) 叫近似后验;
  • ϕ 是它的参数;
  • 在 VAE 里,它通常由一个神经网络输出,所以也常被叫做编码器。

于是 VAE 的结构就变成:

  • 编码器:qϕ(zx)
  • 解码器:pθ(xz)

这也是为什么它叫 Variational Autoencoder

  • Autoencoder 是因为它有 encoder / decoder 结构;
  • Variational 是因为它不是做确定性编码,而是在做变分推断。

TIP

q(z|x) 给定图片 x,推断它背后的隐变量 z 的分布

ELBO 是怎么来的

VAE 最核心的公式就是 ELBO。

先从一个恒等式开始。考虑后验近似分布和真实后验之间的 KL 散度:

DKL(qϕ(zx)pθ(zx))=Eqϕ(zx)[logqϕ(zx)pθ(zx)]

把 Bayes 公式

pθ(zx)=pθ(x,z)pθ(x)

代进去:

DKL(qϕ(zx)pθ(zx))=Eqϕ(zx)[logqϕ(zx)logpθ(x,z)+logpθ(x)]

因为 logpθ(x)z 无关,所以可以拿到期望外面:

DKL(qϕ(zx)pθ(zx))=logpθ(x)+Eqϕ(zx)[logqϕ(zx)logpθ(x,z)]

移项以后得到:

logpθ(x)=Eqϕ(zx)[logpθ(x,z)logqϕ(zx)]+DKL(qϕ(zx)pθ(zx))

定义

LELBO(x)=Eqϕ(zx)[logpθ(x,z)logqϕ(zx)]

于是就得到:

logpθ(x)=LELBO(x)+DKL(qϕ(zx)pθ(zx))

因为 KL 散度永远非负,所以:

LELBO(x)logpθ(x)

这就是为什么它叫 Evidence Lower Bound

它是对对数证据 logpθ(x) 的一个下界。

ELBO 的常见分解形式

把联合分布

pθ(x,z)=p(z)pθ(xz)

代回 ELBO:

LELBO(x)=Eqϕ(zx)[logpθ(xz)]DKL(qϕ(zx)p(z))

这是 VAE 最常见、也最值得记住的形式。

它可以分成两项来看。

第一项:重建项

Eqϕ(zx)[logpθ(xz)]

它表示:

从编码器得到潜变量以后,解码器能不能把原始样本重新生成出来。

所以这一项通常被叫做 reconstruction term

它越大,说明模型越会还原输入。

第二项:KL 正则项

DKL(qϕ(zx)p(z))

这一项表示:

编码器给出的潜变量分布,不要离先验分布太远。

所以它起到的是正则化作用。

如果没有这项,编码器可能会把每个样本都塞到一个很奇怪、互不连贯的潜空间位置;这样虽然重建可能很好,但采样生成就会很差。KL 项的作用就是把潜空间压得更规则、更平滑。

所以 ELBO 可以直接翻译成:

一边让模型会重建,一边让 latent space 保持规整。

TIP

ELBO = 重建项 - KL项

更常见写法是:

logp(x)>=Eq(z|x)[logp(x|z)]KL(q(z|x)||p(z))

其中,重建项 Eq(z|x)[logp(x|z)] 意思是 从 q(z|x) 里采样 z,然后看 Decoder 用 z 生成原图 x 的概率有多大,即 Decoder 能不能根据 zx 还原出来。

重建项的具体形式取决于对 pθ(xz) 的分布假设。

  • 如果是灰度像素当成 Bernoulli 分布,经常用 BCE
  • 如果是连续像素当成 Gaussian 分布,经常用 MSE

KL 项 KL(q(z|x)||p(z)) 代表 q(z|x)p(z) 有多不一样,这里 q(z|x) 为 Encoder 给出的隐变量分布,p(z) 为标准正态分布 N(0,I),所以 KL 项是在逼 Encoder 输出的分布不要太乱,尽量靠近标准正态分布。

为什么要这样?

因为生成时我们不会先有图片 x,所以不能用 q(z|x)。生成时只能:

z ~ N(0, I)

x ~ Decoder(z)

如果训练时 Encoder 输出的 z 分布乱七八糟,而生成时又从标准正态里采样,Decoder 就会懵。

为什么最大化 ELBO 有意义

logpθ(x)=LELBO(x)+DKL(qϕ(zx)pθ(zx))

可以看出,最大化 ELBO 至少有两层意义。

第一,它是在提高 logpθ(x) 的下界,也就是让模型更会解释训练数据。

第二,如果 ELBO 逼近得越来越紧,那就意味着:

DKL(qϕ(zx)pθ(zx))

会越来越小,也就是说近似后验 qϕ(zx) 会越来越接近真实后验。

所以训练 VAE,不只是“学会重建”,而是在同时学习:

  • 一个好的生成模型 pθ(xz)
  • 一个好的近似推断模型 qϕ(zx)

最常见的高斯 VAE

实践里最常见的是让编码器输出一个对角高斯分布:

qϕ(zx)=N(zμϕ(x),diag(σϕ2(x)))

也就是说,给定输入 x,编码器不会输出一个固定 latent vector,而是输出:

  • 一个均值向量 μϕ(x)
  • 一个方差向量 σϕ2(x)

于是 latent variable 是从这个分布里采样出来的。

通常先验依然取:

p(z)=N(0,I)

这样 KL 项通常可以写成闭式公式:

DKL(qϕ(zx)N(0,I))=12j=1d(μj2+σj2logσj21)

这个公式很重要,因为它让 KL 正则项的计算非常方便。

为什么不能直接采样然后反传

VAE 训练里一个最核心的工程问题是:

编码器输出的是一个分布,我们需要从里面采样 z,但“采样”这个操作本身不可直接反传。

如果直接写:

zN(μϕ(x),σϕ2(x))

那么梯度很难顺畅传回到 μϕ(x)σϕ(x)

这就是为什么 VAE 需要 reparameterization trick

重参数化技巧

对高斯分布,可以把采样写成:

ϵN(0,I)z=μϕ(x)+σϕ(x)ϵ

这里 表示逐元素乘法。

这条式子的意义特别大:

  • 随机性被放进了一个与参数无关的噪声 ϵ
  • 真正依赖参数的部分变成了一个可微的确定性变换。

于是损失函数就可以通过 zμϕ(x)σϕ(x) 反向传播。

这也是 VAE 能够用标准 SGD / Adam 稳定训练的关键之一。

VAE 的训练目标到底长什么样

对单个样本 x,我们希望最大化 ELBO,也就是:

LELBO(x)=Eqϕ(zx)[logpθ(xz)]DKL(qϕ(zx)p(z))

如果写成最小化损失,通常就是取负号:

LVAE(x)=Eqϕ(zx)[logpθ(xz)]+DKL(qϕ(zx)p(z))

所以常见实现里,你会看到总 loss 等于:

  • reconstruction loss
  • 加上 KL loss

前者希望保真,后者希望潜空间规整。

完整的训练流程

一张图片 x 进来:

  1. Encoder 输出:μϕ(x)logσϕ2(x)
  2. 采样标准噪声:ϵN(0,I)
  3. 得到隐变量:z=μϕ(x)+exp(12logσϕ2(x))ϵ
  4. Decoder 重建:x^=Decoder(z)
  5. 计算 loss:L=Lrecon+LKL

训练时最小化这个 loss。

为什么用 logvar 而不是 sigma?

logvarϕ(x)=logσϕ2(x)

网络实际输出的是 μϕ(x)logvarϕ(x)。采样时再把 logvar 还原成标准差:

σϕ(x)=exp(12logvarϕ(x))

这样写主要有三个好处:

  • 方差和标准差必须为正,直接预测 σϕ(x) 可能会得到负数;
  • logvarϕ(x) 可以是任意实数,网络输出不需要额外加正数约束;
  • KL 项里本来就会出现 logσϕ2(x),用 logvar 计算更方便、更稳定。

直觉上,网络不是直接说“标准差是多少”,而是先说“方差取对数后是多少”,再通过指数变换保证最后得到的标准差一定为正。

VAE 怎么生成新样本

训练完成后,VAE 的生成过程非常自然:

  1. 从先验分布采样潜变量
zp(z)=N(0,I)
  1. 再通过解码器生成样本
xpθ(xz)

这就是为什么 VAE 是一个真正的生成模型:

它不是只能重建已有输入,还可以从先验里直接采样,生成全新的样本。

VAE 和普通 Autoencoder 的区别

这是最容易混淆的地方。

普通 Autoencoder 通常做的是:

z=fϕ(x),x^=gθ(z)

也就是说:

  • 编码器输出一个确定向量;
  • 解码器再从这个确定向量重建输入;
  • 目标通常只是重建误差最小。

而 VAE 做的是:

qϕ(zx),pθ(xz)

也就是说:

  • 编码器输出一个分布;
  • latent 通过采样得到;
  • 目标不是单纯重建,而是 ELBO;
  • 它还要求潜变量分布不要偏离先验太远。

所以最本质的差别不是“有没有 encoder / decoder”,而是:

VAE 的 latent space 是概率建模的结果,而不是单纯压缩的中间层。

TIP

普通 AutoEncoder 是:

图片 x -> Encoder -> 隐变量 z -> Decoder -> 重建图片 xhat

训练目标通常是:让 xhat 尽量像 x

但普通 AE 有个问题:它学到的 z 空间不一定规整。你随机采样一个 z,Decoder 可能根本不知道怎么生成合理图片。

VAE 希望做到:

随机采样一个 z -> Decoder -> 生成一张合理图片

为了让随机采样有效,VAE 会要求隐变量空间长得比较规整,通常希望:

z ~ N(0, I)

VAE 的优点

VAE 之所以重要,主要有几方面原因。

第一,它给了深度生成模型一个非常干净的概率建模框架。它不是纯经验技巧,而是从 latent-variable model 和 variational inference 推出来的。

第二,它的 latent space 通常比较平滑、连续、可插值。因为 KL 项会把潜变量分布往标准高斯上拉,所以在 latent space 里做插值,往往对应样本语义上的平滑变化。

第三,它训练通常比早期一些显式概率模型更稳定,也比 GAN 更容易解释训练目标。

VAE 的局限

VAE 也有明显局限。

最经典的一个问题是:生成结果有时会偏模糊。原因并不是一句“VAE 天生模糊”那么简单,而是它常见的解码分布假设和像素级似然形式,会鼓励模型在不确定区域取平均,结果看起来就容易发糊。

另一个常见问题是 posterior collapse,也就是解码器太强时,模型可能几乎不使用潜变量,导致 qϕ(zx) 退化得很严重。

所以很多后续工作会对 VAE 做改造,例如:

  • 改更强的后验族;
  • 调整 KL 权重;
  • 使用 hierarchical VAE;
  • 使用更强的 decoder;
  • 使用 flow-based posterior。

总结

VAE = 带概率潜变量的 Autoencoder,用 ELBO 同时学会重建和规整 latent space。

核心公式

生成模型:

pθ(x,z)=p(z)pθ(xz)

训练目标:

LELBO(x)=Eqϕ(zx)[logpθ(xz)]DKL(qϕ(zx)p(z))

VAE 是一种基于潜变量建模和变分推断的生成模型。它假设数据由潜变量 z 生成,但由于真实后验 pθ(zx) 很难直接计算,于是引入近似后验 qϕ(zx) 来做推断。通过对数似然的下界 ELBO,VAE 把训练目标分成了两部分:一部分要求模型能够从 latent variable 重建输入,另一部分要求编码器给出的潜变量分布不要偏离先验太远。再加上重参数化技巧,模型就可以用标准反向传播稳定训练。因此,VAE 不只是一个“会压缩的 Autoencoder”,而是一个真正可采样、可生成、可解释的深度生成模型。