6.1 自编码器与变分自编码器VAE
1.从自编码器说起:把输入压成一个低维的潜在表示
说起来,从这一章起我们正式进入生成模型这一大块。前面那些章节,模型大多在做判断,给一张图判断是猫是狗,给一段文本判断情感是正是负。这一章开始,模型要做的事情换了,它要自己造出新的东西来。我们第一站先聊自编码器(Autoencoder),它本身算不上多强的生成模型,却是后面VAE、Diffusion这些方法的思想源头,值得好好讲一讲。
自编码器的结构其实很简单,两段。前一段叫编码器(Encoder),负责把输入 压成一个低维的向量 ,这里 是输入(比如一张图压平后的像素向量), 叫潜在表示(latent representation),维度比 小得多。后一段叫解码器(Decoder),负责把这个 再还原成 , 就是模型重建出来的版本。整张网络训练时只有一个目标,就是让 尽量贴近 ,差距越小越好。这个差距靠重建误差来衡量,最常见的写法是均方误差:
这里 表示重建误差这一项, 是向量各分量差的平方和。整个训练过程不需要任何标签,输入本身就是答案,所以这是无监督学习。
最关键的地方在中间那个瓶颈。 的维度被人为压得很低,比方说一张 的彩图,输入维度有十五万那么多,却硬要压成一个几十维的向量。这么一压,模型就没办法把原图的每个细节都存下来,它只能去抓住最关键、最能复原图的那部分信息。这就像小张期末复习,只能带一张A4纸进考场,纸就那么大,他自然得挑最要紧的公式和要点记上去。瓶颈逼着模型学会取舍,而学到的 就是输入的精华。
自编码器能做的事其实不少。拿它来压缩数据,相当于学到了一个比原图小得多的表示,存起来省地方。拿它来去噪也很在行,做法是输入一张加了噪声的图,目标却是还原干净的原图,模型学一阵子就能把噪声滤掉。我之前翻过一本讲医学影像的书,里头就拿这种去噪自编码器来处理CT片子,把扫描过程里混进来的颗粒噪声抹得干干净净,效果相当不错。
2.潜在空间没规律:能压缩、能去噪,却生不出新东西
说到这里你大概会想,既然自编码器学会了把图压成 再还原,那我随便挑一个 喂给解码器,是不是就能生成一张新图?这个想法很自然,可实际一跑就发现问题大了。
问题出在自编码器学出来的潜在空间毫无规律。模型训练时只盯着重建误差这一件事, 这个空间里的点分布得完全随性,哪里有空白、哪里挤成一团,全凭训练数据怎么喂。我们随便抓一个 丢进解码器,那个位置多半从来没有见过任何训练样本,解码器要么输出一团乱码,要么输出一张毫无意义的图。
打个比方。小明有一本厚厚的画册,他给每幅画都编了一个简短的目录编号,也就是 。可这本目录的编号规则乱七八糟,第12号是山水,第13号突然跳到一只猫,第14号又变成抽象色块。要让他凭空说一个新编号、然后画一幅像样的画出来,他做不到,因为他脑子里根本没有一个连续顺滑的编号体系。自编码器也是这个道理,它能把见过的东西压缩和还原,却没有把潜在空间整理成一个能让人自由采样的样子,所以拿来生成新东西是不行的。
要让模型真正能生成,我们就得给潜在空间立规矩。这就是VAE要做的事。
3.VAE:让编码器输出一个分布,让潜在空间有结构
变分自编码器(Variational Autoencoder,简称VAE)的想法其实就一句话,让潜在空间有结构。它和普通自编码器最大的区别,在于编码器输出的目标变了,从原来一个确定的点 ,变成一个分布。
具体怎么做的呢,我们假设潜在向量 的每一维都独立地服从一个一元高斯分布(也就是一元正态分布),各维互不影响。这样假设的好处是协方差矩阵成了对角阵,整个分布只需要每一维各自的均值和方差就能定下来。编码器看完输入 之后,输出这个分布的两个参数,均值向量 和方差向量 ,其中 (读作mu)的第 维 是该维分布的中心位置,(读作sigma平方)的第 维 是该维分布的离散程度。有了 和 ,我们就定下了潜在空间里的这个分布,逐维写作 , 表示高斯分布。然后我们从这个分布里随机采样出一个 ,再交给解码器去还原。
这一步看起来变化不大,意义却深。普通自编码器里,每个输入对应 空间里孤零零一个点,点之间是什么情况没人管。VAE则让每个输入对应一小团概率云,云和云之间会相互重叠,潜在空间于是被填得满满当当、连续顺滑。这么一来,潜在空间里随便哪个位置都至少落在某一团云的影响范围里,解码器在那儿也就不会手足无措了。
我说句题外话。我之前看过一部讲传统纹样的纪录片,里头提到日本有种水墨染布的工艺,每一笔下去都化开成一团晕染的墨色,而不是一个死板的点,相邻的墨色互相渗透,整张布面就连成了一片没有空隙的画。VAE的潜在空间给我的感觉就很像这样,每个样本撑开一小片区域,区域之间彼此交融,没有空洞。
4.重参数化技巧:让梯度能穿过采样这一步
VAE这里头有个麻烦,采样这一步没法直接求导。你看, 是从逐维分布 里随机采出来的,随机性这个操作本身没有梯度可言,反向传播到了采样这一步就走不下去了。可训练又必须让梯度能从重建误差一路传回到编码器,去调 和 这两个参数,这件事该怎么办。
解决这个麻烦的小技巧叫重参数化(reparameterization)。做法是把随机性挪到外面去。我们先从标准正态分布 (均值是 、方差是 的正态分布)里采一个随机数 ,(读作epsilon)是这个辅助噪声。然后把采样改写成下面这个式子:
这里 表示逐元素相乘(向量对应位置相乘)。这么一写,随机性就全藏在 这个外部变量里了, 我们当作常数看,不参与求导。而 和 都成了 这个表达式里的普通参数,对它们求导毫无障碍。梯度于是能从重建误差顺利回传到编码器,训练也就转起来了。
实际工程里还有个小细节。神经网络直接输出的往往是方差的对数 ,而不是 本身,这是因为方差必须为正数,让网络自由地输出任意实数、再通过取指数还原成正数会比较稳当。你将来翻代码看到变量名logvar,大概就是它了。
5.损失函数:重建项加上KL散度,两手一起抓
VAE的损失由两部分组成,一部分管还原得准不准,一部分管潜在空间规不规矩。在拆这两项之前,得先说清这个损失是怎么来的——它不是拍脑袋拼出来的,而是从"最大化数据似然 "用变分推断推出来的,叫 ELBO(证据下界)。 这条推导是 VAE 的理论命脉,我们走一遍。
VAE 想最大化的是数据的对数似然 ,但 这个积分在神经网络里没法直接算( 的空间太大)。变分推断的招数是引入一个编码器 (近似后验)来绕开它。先写出一个恒等式——对任意 :
这个等式怎么来的?把 乘进去再除出去:(最后一步用了 1.4 节的 Jensen 不等式, 是凹函数)。这个下界就是 ELBO,展开:
(推导里把 拆开,前半是重建项,后半凑出 KL。)因为 而 KL 非负,所以 ELBO 是 的下界——最大化 ELBO 就是在逼近最大化似然。而我们要最小化的损失,就是负的 ELBO:
第一项就是重建项(负对数似然,均方误差或交叉熵都是它的具体形式),第二项就是 KL 项。这就解释了为什么 VAE 的损失恰好是这两项之和——它们加起来正好是负 ELBO,最小化它等价于最大化数据似然的下界。理解了这一层,下面拆开讲两项就有根了。我们一项一项说。
第一项是重建项,跟普通自编码器一样,要求解码出来的 尽量贴近输入 。具体形式可以是均方误差,也可以是更贴近图像分布的交叉熵,看任务而定。这一项鼓励模型把输入信息忠实地编进 里。
第二项是KL散度。我们在1.4 节聊信息论基础时已经见过它了,KL散度衡量两个分布的差异程度,差距越大这项越大。这里要约束的,是编码器对每个输入 在每一维上输出的分布 ,要让它尽量贴近一个标准正态分布 。KL散度记作 ,这一项逐维写作:
在每一维独立、单变量情形下,这一项有非常工整的闭式表达:
这里 是潜在向量的维度, 是维度编号, 和 分别是第 维的均值和方差, 是求和符号, 是前面的一个常数系数。这个式子看起来吓人,意思却很直白,它要求 接近 、 接近 。求和号里的 这部分鼓励均值贴近零, 这部分鼓励方差贴近一,你不妨把 代进去验证一下,这部分恰好等于零。
把两项合起来,VAE的损失大概是这个样子:
这里 是一个用来调节两项权重的系数(在一种叫 -VAE 的变体里, 就是核心调参对象),训练时我们就在重建得准和潜在空间规整这两件事之间找平衡。 想让信息编得尽量细, 想让潜在分布尽量贴近标准正态,两者互相拉扯,最后落在一个折中的位置上。
为什么要约束成标准正态呢,这是因为一旦每个输入对应的分布都被推向 ,整个潜在空间就被大致填满了,而且填得规规矩矩。我们想生成新样本的时候,直接从 里随便采一个 ,喂给训练好的解码器,输出的多半就是一张说得过去的新图。生成这件事,到这儿就彻底通了。
6.VAE的图偏模糊,以及它身后的那些事
VAE真能生成,这一点没问题,可它生成的图通常偏模糊,细节糊糊的,少了点锐利劲儿。原因主要落在那项KL散度上, 把每个输入的分布都用力拽向同一个标准正态,分布之间的差异被压扁了,很多精细的、个体化的信息也跟着被磨掉了。再加上重建项如果用均方误差,模型倾向于输出各处都偏平均、偏中庸的结果,画面就更糊了。
要更清楚更锐利的生成效果,业界后来走上了别的路。一种思路是引入对抗训练,让一个生成器和一个判别器互相博弈,这就是GAN(生成对抗网络)那一支,DCGAN、StyleGAN都属于这一家。另一种思路是逐步去噪,从纯噪声出发,一步一步把图雕出来,这就是DDPM开出来的扩散模型这条路,后来的Latent Diffusion、Stable Diffusion一路走下来,再往后还有把U-Net换成Transformer的DiT、转向Flow Matching的新写法,Sora的视频生成也建立在这一脉之上。
说起来,VAE并没有因此就被冷落。Diffusion那一支发展到Latent Diffusion之后,大家发现直接在像素空间里一步步去噪太贵了,于是把VAE请回来当压缩器,先用它把图压到潜在空间里再去做扩散,VAE就这样成了现代生成管线里相当重要的一环。这就好比一部老工具,原以为要被新工具取代,结果新工具做着做着又把它请回来搭档了。
VAE的思想还渗透在别处。3.4 节讲Transformer时我们见过编码器、解码器的两段式结构,VAE也是一种两段式,只不过它把中间的瓶颈换成了一个分布。4.10 节会聊到的CLIP,把图像和文本对齐到一个共享的潜在空间,那个空间讲究的也是连续、可比较,和VAE约束潜在空间的初衷是一脉相通的。
这一章我们从自编码器讲起,看清了它为什么压缩去噪在行、生成却不行,又顺着VAE看明白怎么给潜在空间立规矩、怎么用重参数化让梯度穿过采样、怎么用重建项加KL散度把模型训练起来。下一章我们继续生成模型这条路,去看GAN那一家是怎么把图生成得又清楚又锐利的。
练习
Q1. 普通自编码器学到的潜在空间为什么不能用来生成新样本?VAE是怎么解决这个问题的?
普通自编码器训练时只盯着重建误差, 空间里的点分布完全随性,哪里有空白、哪里挤成一团全凭数据怎么喂,随便抓一个 丢进解码器,那个位置多半没见过任何训练样本,输出一团乱码。VAE把编码器输出的目标从一个确定的点 改成一个分布(每维独立的高斯 ),每个输入对应一小团概率云,云和云互相重叠,潜在空间被填得满满当当、连续顺滑,随便哪个位置都落在某团云里,解码器在那儿不会手足无措,这才真能生成。
Q2. VAE的重参数化技巧 ()解决了什么问题?
解决了"采样这一步没法直接求导"的问题。 是从分布 里随机采出来的,随机性这个操作本身没有梯度,反向传播到采样这步就走不下去了,可训练又必须让梯度从重建误差传回编码器去调 、。重参数化把随机性挪到外部变量 (当常数不参与求导), 和 成了表达式里的普通参数,对它们求导毫无障碍,梯度就能顺利回传,训练转起来了。
Q3. 易错点:VAE的损失为什么是"重建项 + KL散度"两项之和,这两项是不是各管各的、互不相干?
不是互不相干,它们加起来正好是负的ELBO(证据下界),最小化它等价于最大化数据似然的下界。从变分推断推出来:,而KL非负,所以ELBO是 的下界,最大化ELBO就在逼近最大化似然。展开ELBO得到重建项(让 贴近 )减去KL项(让编码器输出的分布贴近标准正态 ),取负号就是损失。两项互相拉扯——重建项想编细信息,KL项想让分布规整,最后落在折中点。理解这一层就知道这两项不是拼凑,是有理论根的。
Q4.(面试题) 请解释 VAE 损失中 KL 散度项 为什么能把潜在空间推向标准正态,并说明这带来什么好处和代价。
这一项逐维写成求和,每一维的 鼓励均值贴近0, 鼓励方差贴近1(把 代进去这部分恰好等于0,是它的最小值)。所以整个KL项就是在把编码器对每个输入输出的分布 尽量推向标准正态 。好处是:一旦每个输入的分布都被推向 ,整个潜在空间就被大致填满而且规规矩矩,想生成新样本时直接从 随便采一个 喂给解码器,输出的多半就是一张说得过去的新图,生成这件事就通了。代价是:KL把分布都用力拽向同一个标准正态,分布之间的差异被压扁,很多精细、个体化的信息被磨掉,再加上重建项若用均方误差模型倾向输出偏平均中庸的结果,所以VAE生成的图通常偏模糊、细节糊糊的,少了锐利劲儿。这也是后来生成模型走向GAN(对抗求锐利)和扩散模型(逐步去噪)的重要原因。