变分自编码器(三):这样做为什么能成?
By 苏剑林 | 2018-04-03 | 210979位读者 |话说我觉得我自己最近写文章都喜欢长篇大论了,而且扎堆地来~之前连续写了三篇关于Capsule的介绍,这次轮到VAE了,本文是VAE的第三篇探索,说不准还会有第四篇~不管怎么样,数量不重要,重要的是能把问题都想清楚。尤其是对于VAE这种新奇的建模思维来说,更加值得细细地抠。
这次我们要关心的一个问题是:VAE为什么能成?
估计看VAE的读者都会经历这么几个阶段。第一个阶段是刚读了VAE的介绍,然后云里雾里的,感觉像自编码器又不像自编码器的,反复啃了几遍文字并看了源码之后才知道大概是怎么回事;第二个阶段就是在第一个阶段的基础上,再去细读VAE的原理,诸如隐变量模型、KL散度、变分推断等等,细细看下去,发现虽然折腾来折腾去,最终居然都能看明白了。
这时候读者可能就进入第三个阶段了。在这个阶段中,我们会有诸多疑问,尤其是可行性的疑问:“为什么它这样反复折腾,最终出来模型是可行的?我也有很多想法呀,为什么我的想法就不行?”
前文之要 #
让我们再不厌其烦地回顾一下前面关于VAE的一些原理。
VAE希望通过隐变量分解来描述数据X的分布
p(x)=∫p(x|z)p(z)dz,p(x,z)=p(x|z)p(z)
然后对p(x|z)用模型q(x|z)拟合,p(z)用模型q(z)拟合,为了使得模型具有生成能力,q(z)定义为标准正态分布。
理论上,我们可以使用边缘概率的最大似然来求解模型:
q(x|z)=argmaxq(x|z)∫˜p(x)ln(∫q(x|z)q(z)dz)dx=argmaxq(x|z)Ex∼˜p(x)[ln(∫q(x|z)q(z)dz)]
但是由于圆括号内的积分没法显式求出来,所以我们只好引入KL散度来观察联合分布的差距,最终目标函数变成了
L=Ex∼˜p(x)[−∫p(z|x)lnq(x|z)dz+∫p(z|x)lnp(z|x)q(z)dz]=Ex∼˜p(x)[Ez∼p(z|x)[−lnq(x|z)]+Ez∼p(z|x)[lnp(z|x)q(z)]]
通过最小化L来分别找出p(z|x)和q(x|z)。前一文《变分自编码器(二):从贝叶斯观点出发》也表明L有下界−Ex∼˜p(x)[ln˜p(x)],所以比较L与−Ex∼˜p(x)[ln˜p(x)]的接近程度就可以比较生成器的相对质量。
采样之惑 #
在这部分内容中,我们试图对VAE的原理做细致的追问,以求能回答VAE为什么这样做,最关键的问题是,为什么这样做就可行。
采样一个点就够 #
对于(3)式,我们后面是这样处理的:
1、留意到Ez∼p(z|x)[lnp(z|x)q(z)]正好是p(z|x)和q(z)的散度KL(p(z|x)‖q(z)),而它们俩都被我们都假设为正态分布,所以这一项可以算出来;
2、Ez∼p(z|x)[−lnq(x|z)]这一项我们认为只采样一个就够代表性了,所以这一项变成了−lnq(x|z),z∼p(z|x)。
经过这样的处理,整个loss就可以明确写出来了:
L=Ex∼˜p(x)[−lnq(x|z)+KL(p(z|x)‖q(z))],z∼p(z|x)
等等,可能有读者看不过眼了:KL(p(z|x)‖q(z))事先算出来,相当于是采样了无穷多个点来估算这一项;而Ez∼p(z|x)[−lnq(x|z)]却又只采样一个点,大家都是loss的一部分,这样不公平待遇真的好么?
事实上,Ez∼p(z|x)[lnp(z|x)q(z)]也可以只采样一个点来算,也就是说,可以通过全体都只采样一个点,将(3)式变为
L=Ex∼˜p(x)[−lnq(x|z)+lnp(z|x)q(z)]=Ex∼˜p(x)[−lnq(x|z)+lnp(z|x)−lnq(z)],z∼p(z|x)
这个loss虽然跟标准的VAE有所不同,但事实上也能收敛到相似的结果。
为什么一个点就够? #
那么,为什么采样一个点就够了呢?什么情况下才是采样一个点就够?
首先,我举一个“采样一个点不够”的例子,让我们回头看(2)式,它其实可以改写成:
q(x|z)=argmaxq(x|z)Ex∼˜p(x)[ln(Ez∼q(z)[q(x|z)])]
如果采样一个点就够了,不,这里还是谨慎一点,采样k个点吧,那么我们可以写出
q(x|z)=argmaxq(x|z)Ex∼˜p(x)[ln(1kk∑i=1q(x|zi))],z1,…,zk∼q(z)
然后就可以梯度下降训练了。
然而,这样的策略是不成功的。实际中我们能采样的数目k,一般要比每个batch的大小要小,这时候最大化ln(1kk∑i=1q(x|zi))就会陷入一个“资源争夺战”的境地:每次迭代时,一个batch中的各个xi都在争夺z1,z2,…,zk,谁争夺成功了,q(x|z)就大(说白了,哪个xi能找到专属于它的zj,这意味着zj只能生成xi,不能生成其它的,那么z(xi|zj)就大),但是每个样本都是平等的,采样又是随机的,我们无法预估每次“资源争夺战”的战况。这完全就是一片混战!如果数据集仅仅是mnist,那还好一点,因为mnist的样本具有比较明显的聚类倾向,所以采样数母k超过10,那么就够各个xi分了;但如果像人脸、imagenet这些没有明显聚类倾向、类内方差比较大的数据集,各个z完全是不够分的,一会xi抢到了zj,一会xi+1抢到了zj,训练就直接失败了。
因此,正是这种“僧多粥少”的情况导致上述模型(7)训练不成功。可是,为什么VAE那里采样一个点就成功了呢?
一个点确实够了 #
这就得再分析一下我们对q(x|z)的想法了,我们称q(x|z)为生成模型部分,一般情况下我们假设它为伯努利分布或高斯分布,考虑到伯努利分布应用场景有限,这里只假设它是正态分布,那么
q(x|z)=1D∏k=1√2πσ2(k)(z)exp(−12‖x−μ(z)σ(z)‖2)
其中μ(z)是用来计算均值的网络,σ2(z)是用来计算方差的网络,很多时候我们会固定方差,那就只剩一个计算均值的网络了。
注意,q(x|z)只是一个概率分布,我们从q(z)中采样出z后,代入q(x|z)后得到q(x|z)的具体形式,理论上我们还要从q(x|z)中再采样一次才得到x。但是,我们并没有这样做,我们直接把均值网络μ(z)的结果就当成x。而能这样做,表明q(x|z)是一个方差很小的正态分布(如果是固定方差的话,则训练前需要调低方差,如果不是正态分布而是伯努利分布的话,则不需要考虑这个问题,它只有一组参数),每次采样的结果几乎都是相同的(都是均值μ(z)),此时x和z之间“几乎”具有一一对应关系,接近确定的函数x=μ(z)。
而对于后验分布p(z|x)中,我们假设了它也是一个正态分布。既然前面说z与x几乎是一一对应的,那么这个性质同样也适用验分布p(z|x),这就表明后验分布也会是一个方差很小的正态分布(读者也可以自行从mnist的encoder结果来验证这一点),这也就意味着每次从p(z|x)中采样的结果几乎都是相同的。既然如此,采样一次跟采样多次也就没有什么差别了,因为每次采样的结果都基本一样呀。所以我们就解释了为什么可以从(3)式出发,只采样一个点计算而变成(4)式或(5)式了。
后验之妙 #
前面我们初步解释了为什么直接在先验分布q(z)中采样训练不好,而在后验分布中p(z|x)中采样的话一个点就够了。事实上,利用KL散度在隐变量模型中引入后验分布是一个非常神奇的招数。在这部分内容中,我们再整理一下相关内容,并且给出一个运用这个思想的新例子。
后验的先验 #
可能读者会有点逻辑混乱:你说q(x|z)和p(z|x)最终都是方差很小的正态分布,可那是最终的训练结果而已,在建模的时候,理论上我们不能事先知道q(x|z)和p(z|x)的方差有多大,那怎么就先去采样一个点了?
我觉得这也是我们对问题的先验认识。当我们决定用某个数据集X做VAE时,这个数据集本身就带了很强的约束。比如mnist数据集具有784个像素,事实上它的独立维度远少于784,最明显的,有些边缘像素一直都是0,mnist相对于所有28*28的图像来说,是一个非常小的子集;再比如前几天写的作诗机器人,“唐诗”这个语料集相对于一般的语句来说是一个非常小的子集;甚至我们拿上千个分类的imagenet数据集来看,它也是无穷尽的图像中的一个小子集而已。
这样一来,我们就想着这个数据集X是可以投影到一个低维空间(隐变量空间)中,然后让低维空间中的隐变量跟原来的X集一一对应。读者或许看出来了:这不就是普通的自编码器嘛?是的,其实意思就是说,在普通的自编码器情况下,我们可以做到隐变量跟原数据集的一一对应(完全一一对应意味着p(z|x)和q(x|z)的方差为0),那么再引入高斯形式的先验分布q(z)后,粗略地看,这只是对隐变量空间做了平移和缩放,所以方差也可以不大。
所以,我们应该是事先猜测出q(x|z)和p(z|x)的方差很小,并且让模型实现这个估计。说白了,“采样一个”这个操作,是我们对数据和模型的先验认识,是对后验分布的先验,并且我们通过这个先验认识来希望模型能靠近这个先验认识去。
整个思路应该是:
1、有了原始语料集;
2、观察原始语料集,推测可以一一对应某个隐变量空间;
3、通过“采样一个”的方式,让模型去学会这个对应。
这部分内容说得有点凌乱~其实也有种多此一举的感觉,希望读者不要被我搞糊涂了。如果觉得混乱的话,忽视这部分吧~
耿直的IWAE #
接下来的例子称为“重要性加权自编码器(Importance Weighted Autoencoders)”,简写为“IWAE”,它更加干脆、直接地体现出后验分布的妙用,它在某种程度上它还可以看成是VAE的升级版。
IWAE的出发点是(2)式,它引入了后验分布对(2)式进行了改写
∫q(x|z)q(z)dz=∫p(z|x)q(x|z)q(z)p(z|x)dz=Ez∼p(z|x)[q(x|z)q(z)p(z|x)]
这样一来,(2)式由从q(z)采样变成了从p(z|x)中采样。我们前面已经论述了p(z|x)方差较小,因此采样几个点就够了:
∫q(x|z)q(z)dz=1kk∑i=1q(x|zi)q(zi)p(zi|x),z1,…,zk∼p(z|x)
代入(2)式得到
q(x|z)=argmaxq(x|z)Ex∼˜p(x)[ln(1kk∑i=1q(x|zi)q(zi)p(zi|x))],z1,…,zk∼p(z|x)
这就是IWAE。为了对齐(4),(5)式,可以将它等价地写成
q(x|z)=argminq(x|z),p(z|x)Lk,Lk=Ex∼˜p(x)[−ln(1kk∑i=1q(x|zi)q(zi)p(zi|x))],z1,…,zk∼p(z|x)
当k=1时,上式正好跟(5)式一样,所以从这个角度来看,IWAE是VAE的升级版。
从构造过程来看,在(8)式中将p(z|x)替换为z的任意分布都是可以的,选择p(z|x)只是因为它有聚焦性,便于采样。而当k足够大时,事实上p(z|x)的具体形式已经不重要了。这也就表明,在IWAE中削弱了encoder模型p(z|x)的作用,换来了生成模型q(x|z)的提升。因为在VAE中,我们假设p(z|x)是正态分布,这只是一种容易算的近似,这个近似的合理性,同时也会影响生成模型q(x|z)的质量。可以证明,Lk能比L更接近下界−Ex∼˜p(x)[ln˜p(x)],所以生成模型的质量会更优。
直觉来讲,就是在IWAE中,p(z|x)的近似程度已经不是那么重要了,所以能得到更好的生成模型。不过代价是编码模型的质量就降低了,这也是因为p(z|x)的重要性降低了,模型就不会太集中精力训练p(z|x)了。所以如果我们是希望获得好的encoder的话,IWAE是不可取的。
还有一个工作《Tighter Variational Bounds are Not Necessarily Better》据说同时了提高了encoder和decoder的质量,不过我还没看懂~
重参之神 #
如果说后验分布的引入成功勾画了VAE的整个蓝图,那么重参数技巧就是那“画龙点睛”的“神来之笔”。
前面我们说,VAE引入后验分布使得采样从宽松的标准正态分布q(z)转移到了紧凑的正态分布p(z|x)。然而,尽管它们都是正态分布,但是含义却大不一样。我们先写出
p(z|x)=1d∏k=1√2πσ2(k)(x)exp(−12‖z−μ(x)σ(x)‖2)
也就是说,p(z|x)的均值和方差都是要训练的模型。
让我们想象一下,当模型跑到这一步,然后算出了μ(x)和σ(x),接着呢,就可以构建正态分布然后采样了。可采样出来的是什么东西?是一个向量,并且这个向量我们看不出它跟μ(x)和σ(x)的关系,所以相当于一个常向量,这个向量一求导就没了,从而在梯度下降中,我们无法得到任何反馈来更新μ(x)和σ(x)。
这时候重参数技巧就闪亮登场了,它直截了当地告诉我们:
z=μ(x)+ε×σ(x),ε∼N(0,I).
没有比这更简洁了,看起来只是一个微小的变换,但它明确地告诉了我们z跟μ(x),σ(x)的关系!于是z求导就不再是0,μ(x),σ(x)终于可以获得属于它们的反馈了。至此,模型一切就绪,接下来就是写代码的时间了~
可见,“重参数”堪称绝杀呀~
本文之水 #
哆里哆嗦,又水了一文~
本文大概是希望把VAE后续的一些小细节说清楚,特别是VAE如何通过巧妙地引入后验分布来解决采样难题(从而解决了训练难题),并且顺道介绍了一下IWAE。
要求直观理解就难免会失去一点严谨性,这是二者不可兼得的事情。所以,对于文章中的毛病,望高手读者多多海涵,也欢迎批评建议~
转载到请包括本文地址:https://kexue.fm/archives/5383
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Apr. 03, 2018). 《变分自编码器(三):这样做为什么能成? 》[Blog post]. Retrieved from https://kexue.fm/archives/5383
@online{kexuefm-5383,
title={变分自编码器(三):这样做为什么能成?},
author={苏剑林},
year={2018},
month={Apr},
url={\url{https://kexue.fm/archives/5383}},
}
June 25th, 2022
苏老师,
您这篇文章中提到
“VAE希望通过隐变量分解来描述数据X的分布
p(x)=∫p(x|z)p(z)dz,p(x,z)=p(x|z)p(z)(1)
然后对p(x,z)用模型q(x|z)拟合”
上篇文章《变分自编码器(二):从贝叶斯观点出发》(https://kexue.fm/archives/5343/comment-page-5)中又说
“
但事实上,直接来对p(x,z)进行近似是最为干脆的。具体来说,定义p(x,z)=p̃(x)p(z|x),我们设想用一个联合概率分布q(x,z)来逼近p(x,z)
”
我实在是没有读明白,究竟是用q(x,z)逼近p(x,z),还是用q(x|z)逼近p(x,z)呢?
还望指教,非常感谢
打错了,是“p(x|z)用模型q(x|z)拟合”才对,谢谢指出。
July 24th, 2022
苏老师您好,公式(5)中,lnp(z|x)怎么算出来呢?具体操作难道是Decoder之后再放一个encoder,然后生成一个对应的z,最小化当前z和之后z的均值?
在讲到这一步的时候,没有说lnp(z|x)也是一个高斯分布。如果假设所有的分布都是高斯分布,是不是对于高斯分布有点太通用了?
lnp(z|x)是给出p(z|x)的概率密度后,直接取对数得到的。
July 24th, 2022
此外,我个人认为公式中p和q有些混用?例如公式(4)中p(z|x)其实是未知的 我们真正计算只能使用q(z|x),所以我们最小化的其实是KL(q(z|x),q(z))?总感觉有哪里不太对,希望您不吝赐教。
没有混用,包括你前一个问题,答案也是一样的。
首先,确定出发点,在笔者关于VAE的推导体系中,没有“近似后验分布”这回事,请先忘记传统的贝叶斯推断体系。我们并不是给定q(x|z)和q(z),然后想办法估计q(z|x),这样的思想在本博客没有出现过。
划重点,我们是先构造了p(x,z)=p(z|x)˜p(x),然后再去构造q(x,z)=q(x|z)q(z),这两个构造是毫无关系的,毫无关系的,毫无关系的!没有谁是谁的近似。然后,我们去最小化KL(p(x,z)‖q(x,z)),目的是希望能实现p(x,z)=q(x,z)。
所以,整个过程是“先构造两个互不相关的分布”、“然后让它们主动地去相互接近”。所以不要问“q(x|z)和q(z)给定后对应q(z|x)是不是高斯分布”这种问题,我们从来没有说过它是,我们是希望两者能够主动地相互逼近。不是p(x,z)去逼近q(x,z),也不是q(x,z)去逼近p(x,z),是两者主动相互靠近。
September 8th, 2022
请问苏神,本文中的数据集 X 投影到一个低维隐变量空间。
如果隐变量空间维度和数据集 X 的样本数一致,对应 [变分自编码器(一)](https://kexue.fm/archives/5253) 图 vae是为每个样本构造专属的正态分布,然后采样来重构,那么 amortized inference 对应的是 变分自编码器(一)中图vae的传统理解吗?
在实现代码https://github.com/bojone/vae/blob/master/vae_keras.py中看到的是 z_mean, z_logvar 分别由两个 Dense 层从 intermediate_dim 投影到 latent_dim。感觉更类似 变分自编码器(一)中图vae的传统理解。不知道苏神对VAE vs Amortized VAE有什么看法?
https://erdogdu.github.io/csc412/slides/w11/sld11-1.pdf p12 页
不是很确定代码实现的 z_mean 和 z_logvar 对应 p12 的 N(μϕ(xi),Σϕ(xi)) 吗?
似乎所有的 VAE 代码都没有用让每个样本 x 对应一个专属的正态分布,而是 embedding 到 latent_dim,无法避免 amortization gap [Inference Suboptimality in Variational Autoencoders](https://arxiv.org/pdf/1801.03558.pdf)
谢谢苏神!
我看了你给的pdf链接,感觉有点莫名其妙。
应该说,pdf里边所谓的“Standard VAE”,才是我说的“传统理解”,而它笔下的“Amortized VAE”,才是VAE的正确理解。但是吧,其实它的“Amortized VAE”,才是一般文献里边的“Standard VAE”,反而它自己描述的所谓“Standard VAE”,我才是第一次见...
z_mean, z_logvar 分别由两个 Dense 层从 intermediate_dim 投影到 latent_dim,Dense层的输入是显然依赖于x的,所以很明显对应的是Amortized VAE。
October 12th, 2022
请问苏老师,我对于公式2还是有一些不理解。在我的概念里,最大似然求得是使事件发生概率最大的模型参数,比如a是高斯模型是均值,那求的是使p(x|a)最大的a,这样理解有问题吗?如果没有问题的话,为什么公式2求的是使q(x)的期望最大的q(x|z)呢(这里的x是被认为服从p(x)分布对吗?)?这里面好像没有模型的参数,而且条件概率怎么可以认为是哪个参数呢?我想来想去感觉似懂非懂的,还请有时间的时候帮忙解答,谢谢!
q(x|z)就是待求模型,如果将它参数化,就是求q(x|z)中的模型参数。
May 25th, 2023
请问苏神,你在(6)(7)式中是说明直接采样q(x|z)是不可行的,但是我有点不理解,gan是否是采用这种方式训练的
不是
March 11th, 2024
感谢苏老师精彩的文章!我对这句“理论上我们还要从q(x|z)中再采样一次才得到x。但是,我们并没有这样做,我们直接把均值网络μ(z)的结果就当成x。”仍有疑惑,我的想法中最终计算的||x-u(z)||2里的x是原始图像,但把u(z)当做x就成为了||u(z)-u(z)||缺少了与原始图像的计算。才疏学浅,望苏老师解惑!
这句话指的是推理过程,是先有了μ(z),再有‖x−μ(z)‖2或者q(x|z),然后从q(x|z)采样,最后认为从q(x|z)中采样的结果就是μ(z)(当方差足够小时,近似成立)
March 11th, 2024
我还有一个疑问是,阅读您《从贝叶斯观点出发》的文章后,我知道了对于p(x|z)的生成模型近似,使用了高斯分布。然而在我的理解中,一般的极大似然会从总体里取多个样本估计固定但未知的参数,也就是x通常是多个采样,但文章中对z是否要多次采样的说明是我有些疑惑,如果
z多次采样,其参数不就不再固定了,那好像就无法估计了。才疏学浅,打扰苏老师了。
首先要转换一下逻辑:
1、在本系列推导中,不存在“最大似然”这个东西,而是取而代之最小化两个分布的KL散度;
2、最大似然等价于最小化边缘分布的KL散度,但不好算;
3、而我发现,VAE就是在最小化联合分布的KL散度,这应该是VAE最简单的推导方法;
4、联合分布的KL散度,公式为∬,其中最外边的积分也就是期望,可以改为采样,但注意这是一个联合分布,(x,z)本质上是平权的、成对出现的,所以x,z出现次数相等是很合理的。
当然,也有一些工作是加大z的采样次数的,比如 https://kexue.fm/archives/8791 介绍的重要性加权自编码器,它会加强decoder,但弱化encoder。
原来如此,谢谢苏老师!我都明白了。
May 29th, 2024
苏老师您好!想就本文请教一个小问题,后面提到的 IWAE ,相较于原始 VAE 训练过程中对 z\sim p(z|x) 多次采样,除了理论出发点不同,从而前者可以解除对 p(z|x) 的先验设定以外,是不是没有实质性的区别?如果是这样,您在系列之二中提到 “实验过采样多个的情形,感觉生成的样本并没有明显变化”,那 IWAE 这套框架在什么情况下会明显提升样本生成的效果呢?
IWAE可以进一步参考:https://kexue.fm/archives/8791 ,它可能在采样数目非常多的时候才会有提升吧?我也没有深入实验过,判断生成样本没有明显变化也是凭肉眼的,没有定量计算过指标。
July 23rd, 2024
苏老师您好!想请教如下两个问题:
1.公式(5)中 lnq(z)这一项是不是不含参数,实际实现中可以忽略。
2.您文中提到,假设q(x|z)和p(z|x)都是方差很小的高斯分布(后验的先验)。q(x|z)我比较好理解,直接对均值计算MSE损失,可以认为是没有随机性。但是我们在推导VAE损失的之后,是希望p(z|x)与标准高斯分布的KL散度接近于0,这样p(z|x)的方差会接近于1,这和我们的先验是否矛盾呢?可以把VAE理解为推导的时候是分布于分布之间的对应,但是实现的时候是点对点的对应么?
1、q(z)的q是没有参数,但是z经过重参数后,z是有参数的,所以不可忽略;
2、我们是希望通过最小化“p(z|x)与标准高斯分布的KL散度”作为额外的正则项,来实现p(z|x)的边缘分布(也就是全体z的分布p(z))接近标准高斯分布,并不是希望p(z|x)本身接近标准高斯分布。