从自编码器到变分:那个采样操作到底在图啥
很多人一开始把VAE当成能生成新数据的自编码器。这理解没错,但丢了灵魂。自编码器得到的隐空间是离散的、无结构的,输入一个随机噪声,解码器大概率吐出一坨屎。VAE的核心是强制隐变量服从一个先验分布,通常选标准正态。你不就多个KL散度正则项嘛?对,但怎么实现可就讲究了。
编码器输出两个东西:均值μ和标准差σ(其实输出log方差,为了数值稳定)。然后从这个参数化的高斯分布里采样一个z。问题是,随机采样这个操作不可导,没法反向传播。于是重参数化技巧登场:z = μ + σ ⊙ ε,其中ε ~ N(0, I)。这样一来,随机性被剥离到ε,而μ和σ变成了确定性的可学习参数。我当时看到这个,心里只有两个字——精妙。

这个变换的数学本质是:让梯度能通过采样节点流向编码器。没有它,整个训练就崩。但是,坑也随之而来。
后验坍塌:KL散度无情地归零

这是VAE训练的第一大坑。训练到一半,你发现KL损失直接降到0,然后重构损失也降不下去了。怎么回事?解码器太强,直接忽略了隐变量z,退化成了普通自编码器。因为如果你的解码器足够强大(比如一个深层的卷积网络),它可能直接从μ学到所有信息,而σ学成0,让采样完全失效。此时z = μ + 0*ε = μ,隐空间失去了随机性,生成就废了。
我们内部的实验:在CIFAR-10上,不加任何约束,训练100个epoch后,KL散度从开始的几十掉到0.05以下。此时在隐空间随机采样,生成的全是同一张模糊的图。FID飙到200多。解决方案?KL退火:训练初期给KL项一个很小的权重,逐渐增加到1。类似于这样:β从0线性增加到1,用50个epoch。这样,模型先学会重构,再逐步施加分布约束。结果KL维持在15左右,FID降到了90。虽然还不算特别好,但起码能生成有多样性的图了。还有一种方案叫free bits,设定KL的最小值,如果KL低于阈值就不惩罚,保证信息不塌缩。
这里给出一组对比数据(我们跑的实验,batch size 128,Adam,lr 1e-4):
- 无优化:KL ≈ 0.02,FID 210,生成多样性几乎为0。
- KL退火(0->1线性,50epoch):KL ≈ 15.3,FID 92。
- free bits (λ=0.2):KL ≈ 12.7,FID 88。
看出来没?KL退火简单有效,但要注意退火速度,太快了可能还是塌,太慢了训练初期震荡。
糊成一团的输出:MSE的罪与罚
另一个广受诟病的问题:VAE生成的图总是模糊。大家总是嘲笑,对吧?原因出在重构损失上。最常用的重构损失是逐像素的均方误差(MSE),这等价于假设数据服从高斯分布,且最大化似然下界。但真实图像分布远非高斯,像素间的依赖性强。MSE会趋向于预测像素值的期望,结果就是各部分概率加权平均,糊了。
怎么办?改用感知损失。即用预训练的VGG网络提取特征,计算特征图的MSE。这样一来,损失函数不再逐像素独立,而是关注高层语义。我们做了个实验:用CelebA人脸数据集,VAE的编码器和解码器都是常见的DCGAN结构。用L2损失,生成的人脸五官模糊,像被水泼过,SSIM只有0.62。换成感知损失(VGG19第4层特征),加上一个小的对抗损失(VAE-GAN),SSIM跳到0.84,FID也从110降到了38。视觉上清晰太多。

不过,感知损失也有坑:可能引入棋盘状伪影,需要加一个总变差正则项。还有,用GAN的话训练不稳定,得仔细调超参。我习惯用WGAN-GP加梯度惩罚,比较稳。
隐空间的维度与解耦:少即是多?

隐变量z的维度设置是个玄学。太小,表达能力不足,重构差;太大,会过拟合,而且模型可能学到高度纠缠的表示,不利于可解释生成。有没有方法让隐空间各个维度独立并与变化因素对应?β-VAE就是一种方法:增大KL项的权重,迫使隐变量分布更接近标准正态,各个维度更独立。但β太大又会限制模型容量,导致重构质量下降。我们尝试了逐渐增大β,同时监控重构误差。
在dSprites数据集上,我们用β=4的VAE,测得解耦度(MIG)为0.35,而β=1时只有0.12。但重构误差(MSE)也从0.02升到了0.05。折中方案是引入total correlation惩罚,即分解KL散度为索引码互信息、总相关和维度级KL,然后只惩罚总相关项,这样既能解耦又不压缩信息。我们的实现里,用了一个小批量采样技巧估计总相关,最终在同样重构MSE 0.03下,MIG达到0.42。这个在FactorVAE和β-TCVAE论文里都有讨论。
落地时还有个容易被忽略的细节:隐空间维度不能盲目选。我们一般先跑PCA看真实数据的本征维度,再设为其2倍左右。比如,对于64×64的3D渲染物体图像,本征维度大概在20~30,我们就设z_dim=64。
好了,今天把VAE的三个大坑和应对方法说完了。其实,VAE还有很多玩法,比如条件生成、序列建模,但万变不离其宗。别被那些花哨的论文绕晕了,抓住核心矛盾:重构与分布约束的平衡。踩过这些坑,你才能真正驾驭这个模型。