变分自编码器(四):一步到位的聚类方案
By 苏剑林 | 2018-09-17 | 343025位读者 |由于VAE中既有编码器又有解码器(生成器),同时隐变量分布又被近似编码为标准正态分布,因此VAE既是一个生成模型,又是一个特征提取器。在图像领域中,由于VAE生成的图片偏模糊,因此大家通常更关心VAE作为图像特征提取器的作用。提取特征都是为了下一步的任务准备的,而下一步的任务可能有很多,比如分类、聚类等。本文来关心“聚类”这个任务。
一般来说,用AE或者VAE做聚类都是分步来进行的,即先训练一个普通的VAE,然后得到原始数据的隐变量,接着对隐变量做一个K-Means或GMM之类的。但是这样的思路的整体感显然不够,而且聚类方法的选择也让我们纠结。本文介绍基于VAE的一个“一步到位”的聚类思路,它同时允许我们完成无监督地完成聚类和条件生成。
理论 #
一般框架 #
回顾VAE的loss(如果没印象请参考《变分自编码器(二):从贝叶斯观点出发》):
$$KL\Big(p(x,z)\Big\Vert q(x,z)\Big) = \iint p(z|x)\tilde{p}(x)\ln \frac{p(z|x)\tilde{p}(x)}{q(x|z)q(z)} dzdx\tag{1}$$
通常来说,我们会假设$q(z)$是标准正态分布,$p(z|x),q(x|z)$是条件正态分布,然后代入计算,就得到了普通的VAE的loss。
然而,也没有谁规定隐变量一定是连续变量吧?这里我们就将隐变量定为$(z, y)$,其中$z$是一个连续变量,代表编码向量;$y$是离散的变量,代表类别。直接把$(1)$中的$z$替换为$(z,y)$,就得到
$$KL\Big(p(x,z,y)\Big\Vert q(x,z,y)\Big) = \sum_y \iint p(z,y|x)\tilde{p}(x)\ln \frac{p(z,y|x)\tilde{p}(x)}{q(x|z,y)q(z,y)} dzdx\tag{2}$$
这就是用来做聚类的VAE的loss了。
分步假设 #
啥?就完事了?呃,是的,如果只考虑一般化的框架,$(2)$确实就完事了。
不过落实到实践中,$(2)$可以有很多不同的实践方案,这里介绍比较简单的一种。首先我们要明确,在$(2)$中,我们只知道$\tilde{p}(x)$(通过一批数据给出的经验分布),其他都是没有明确下来的。于是为了求解$(2)$,我们需要设定一些形式。一种选取方案为
$$p(z,y|x)=p(y|z)p(z|x),\quad q(x|z,y)=q(x|z),\quad q(z,y)=q(z|y)q(y)\tag{3}$$
代入$(2)$得到
$$KL\Big(p(x,z,y)\Big\Vert q(x,z,y)\Big) = \sum_y \iint p(y|z)p(z|x)\tilde{p}(x)\ln \frac{p(y|z)p(z|x)\tilde{p}(x)}{q(x|z)q(z|y)q(y)} dzdx\tag{4}$$
其实$(4)$式还是相当直观的,它分布描述了编码和生成过程:
1、从原始数据中采样到$x$,然后通过$p(z|x)$可以得到编码特征$z$,然后通过分类器$p(y|z)$对编码特征进行分类,从而得到类别;
2、从分布$q(y)$中选取一个类别$y$,然后从分布$q(z|y)$中选取一个随机隐变量$z$,然后通过生成器$q(x|z)$解码为原始样本。
具体模型 #
$(4)$式其实已经很具体了,我们只需要沿用以往VAE的做法:$p(z|x)$一般假设为均值为$\mu(x)$方差为$\sigma^2(x)$的正态分布,$q(x|z)$一般假设为均值为$G(z)$方差为常数的正态分布(等价于用MSE作为loss),$q(z|y)$可以假设为均值为$\mu_y$方差为1的正态分布,至于剩下的$q(y),p(y|z)$,$q(y)$可以假设为均匀分布(它就是个常数),也就是希望每个类大致均衡,而$p(y|z)$是对隐变量的分类器,随便用个softmax的网络就可以拟合了。
最后,可以形象地将$(4)$改写为
$$\mathbb{E}_{x\sim\tilde{p}(x)}\Big[-\log q(x|z) + \sum_y p(y|z) \log \frac{p(z|x)}{q(z|y)} + KL\big(p(y|z)\big\Vert q(y)\big)\Big],\quad z\sim p(z|x) \tag{5}$$
其中$z\sim p(z|x)$是重参数操作,而方括号中的三项loss,各有各的含义:
1、$-\log q(x|z)$希望重构误差越小越好,也就是$z$尽量保留完整的信息;
2、$\sum_y p(y|z) \log \frac{p(z|x)}{q(z|y)}$希望$z$能尽量对齐某个类别的“专属”的正态分布,就是这一步起到聚类的作用;
3、$KL\big(p(y|z)\big\Vert q(y)\big)$希望每个类的分布尽量均衡,不会发生两个几乎重合的情况(坍缩为一个类)。当然,有时候可能不需要这个先验要求,那就可以去掉这一项。
实验 #
实验代码自然是Keras完成的了(^_^),在mnist和fashion-mnist上做了实验,表现都还可以。实验环境:Keras 2.2 + tensorflow 1.8 + Python 2.7。
代码实现 #
代码位于:https://github.com/bojone/vae/blob/master/vae_keras_cluster.py
其实注释应该比较清楚了,而且相比普通的VAE改动不大。可能稍微有难度的是$\sum_y p(y|z) \log \frac{p(z|x)}{q(z|y)}$这个怎么实现。首先我们代入
$$\begin{aligned}p(z|x)&=\frac{1}{\prod\limits_{i=1}^d\sqrt{2\pi\sigma_i^2(x)}}\exp\left\{-\frac{1}{2}\left\Vert\frac{z - \mu(x)}{\sigma(x)}\right\Vert^2\right\}\\
q(z|y)&=\frac{1}{(2\pi)^{d/2}}\exp\left\{-\frac{1}{2}\left\Vert z - \mu_y\right\Vert^2\right\}\end{aligned}\tag{6}$$
得到
$$\log \frac{p(z|x)}{q(z|y)}=-\frac{1}{2}\sum_{i=1}^d \log \sigma_i^2(x)-\frac{1}{2}\left\Vert\frac{z - \mu(x)}{\sigma(x)}\right\Vert^2 + \frac{1}{2}\left\Vert z - \mu_y\right\Vert^2 \tag{7}$$
注意其实第二项是多余的,因为重参数操作告诉我们$z = \varepsilon\otimes \sigma(x) + \mu(x),\,\varepsilon\sim \mathcal{N}(0,1)$,所以第二项实际上只是$-\Vert \varepsilon\Vert^2/2$,跟参数无关,所以$$\log \frac{p(z|x)}{q(z|y)}\sim -\frac{1}{2}\sum_{i=1}^d \log \sigma_i^2(x) + \frac{1}{2}\left\Vert z - \mu_y\right\Vert^2 \tag{8}$$
然后因为$y$是离散的,所以事实上$\sum_y p(y|z) \log \frac{p(z|x)}{q(z|y)}$就是一个矩阵乘法(相乘然后对某个公共变量求和,就是矩阵乘法的一般形式),用K.batch_dot实现。
其他的话,读者应该清楚普通的VAE的实现过程,然后才看本文的内容和代码,不然估计是一脸懵的。
mnist #
这里是mnist的实验结果图示,包括类内样本图示和按类采样图示。最后还简单估算了一下,以每一类对应的数目最多的那个真实标签为类标签的话,最终的test准确率大约有83%,对比这篇文章《Unsupervised Deep Embedding for Clustering Analysis》的结果(最高也是84%左右),感觉应该很不错了。
聚类图示 #
按类采样 #
fashion-mnist #
这里是fashion-mnist的实验结果图示,包括类内样本图示和按类采样图示,最终的test准确率大约有58.5%。
聚类图示 #
按类采样 #
总结 #
文章简单地实现了一下基于VAE的聚类算法,算法的特点就是一步到位,结合“编码”、“聚类”和“生成”三个任务同时完成,思想是对VAE的loss的一般化。
感觉还有一定的提升空间,比如式$(4)$只是式$(2)$的一个例子,还可以考虑更加一般的情况。代码中的encoder和decoder也都没有经过仔细调优,仅仅是验证想法所用。
转载到请包括本文地址:https://www.spaces.ac.cn/archives/5887
更详细的转载事宜请参考:《科学空间FAQ》
如果您还有什么疑惑或建议,欢迎在下方评论区继续讨论。
如果您觉得本文还不错,欢迎分享/打赏本文。打赏并非要从中获得收益,而是希望知道科学空间获得了多少读者的真心关注。当然,如果你无视它,也不会影响你的阅读。再次表示欢迎和感谢!
如果您需要引用本文,请参考:
苏剑林. (Sep. 17, 2018). 《变分自编码器(四):一步到位的聚类方案 》[Blog post]. Retrieved from https://www.spaces.ac.cn/archives/5887
@online{kexuefm-5887,
title={变分自编码器(四):一步到位的聚类方案},
author={苏剑林},
year={2018},
month={Sep},
url={\url{https://www.spaces.ac.cn/archives/5887}},
}
August 24th, 2023
苏老师,怎么理解q(y)是一个均匀分布呢?
均匀分布的概率就是常数。
August 26th, 2023
苏老师,glow是否也可以像您这篇文章说的做聚类,似乎可以,但不知从何入手?
很难。因为flow-based模型做的是精确的最大似然,而如果用来做聚类的话,相当于要最大化$\log \sum_y q(x|y)q(y)$,看上去是难以优化的。
August 29th, 2023
苏老师,我想做一个具有监督分类功能的glow,我能不能这么做:
用最终的z去输入进一个softmax分类器,得到模型的预测分类类别y,这个y一边我使用真实标签通过交叉熵损失做为有监督的分类指导,一方面我设置10个mu,sigma(minist数据集),并设置为可训练的参数,每个样本我都用y去选择这个样本对应的编码向量z的先验分布的均值和方差,也就是在刚才说的那10个(mu,sigma)之中选,这样的优化策略是为了是为了使我的glow具有条件生成功能的同时,还具有分类的功能。不知道这种方案行不行...(担心自己没有说清楚自己的困惑,但已经很努力的表达了...)
你设置10个均值方差的时候,就已经相当于在训练条件生成模型$p(x|y)$,有了$p(x|y)$,根据贝叶斯公式就可以求出$p(y|x)$,似乎不用另外训练分类器。当然你这样另外训练分类器大概率也是可行的。
谢谢苏老师,已经实现了
苏老师,您说的根据贝叶斯公式求出p(y|x),具体怎么做呢?能点拨一下吗?我发现另外训练分类器有点受局限。
$p(y|x)=\frac{p(x|y)p(y)}{p(x)}\propto p(x|y)p(y)$,通过统计求出$y$的分布$p(y)$,$p(x|y)$则可以通过条件生成模型算出,于是可以归一化求出$p(y|x)$。代价是计算量比较大,有多少个$y$就是要计算多少次$p(x|y)$。
March 22nd, 2024
苏老师您好!非常感谢您精彩的论文,我还是有些难以理解3式的获取方式,3式中最后一个可以理解为条件概率,但前两个式子似乎没有直接的对应关系,望苏老师解惑!
前两个式子不是恒等式啊,它是假设,是将左边的式子假设为右边的形式。
可能是我思维太局限了,总感觉不能直接推出来的就不会成立。
比如$p(z,y|x)=p(y|z,x)p(z|x)$是恒成立的,$p(z,y|x)=p(y|z)p(z|x)$意味着假设$p(y|z,x)=p(y|z)$,即给定$z$的情况下,$y$不依赖于$x$。
March 28th, 2024
如何理解:∑yp(y|z)logp(z|x)q(z|y) 表示 “希望z能尽量对齐某个类别的“专属”的正态分布”?
在重参数之前,这一项是:
$$\mathbb{E}_{x\sim \tilde{p}(x)}\left[\sum_y \int p(y|z)p(z|x)\ln \frac{p(z|x)}{q(z|y)} dz\right] = \mathbb{E}_{x\sim \tilde{p}(x)}\left[\sum_y p(y|z) KL\big(p(z|x)\big\Vert q(z|y)\big)\right]$$
让这一项足够小的方式是:1、$p(y|z)$足够接近one hot(即$y$接近确定性);2、$KL\big(p(z|x)\big\Vert q(z|y)$足够接近于0,这意味着$p(z|x)\approx q(z|y)$,即$z$几乎只跟某个$y$有关了(即接近$y$的聚类中心)。
苏神,对于您的解答,我有两个小问题
1. 公式中将 $p(y|z)$ 提取到对 $z$ 的积分外,是否合理?也就是说,为什么下面的公式成立?
$$
\begin{aligned}
\mathbb{E}_{x \sim \tilde{p}(x)}\left[\sum_y \int p(y | z) p(z |x) \ln \frac{p(z| x)}{q(z| y)} d z\right]&=\mathbb{E}_{x \sim \tilde{p}(x)}\left[\sum_y p(y |z) K L(p(z |x) \| q(z | y))\right]\\
&= \mathbb{E}_{x \sim \tilde{p}(x)}\left[\sum_y p(y | z) \int p(z|x) \ln \frac{p(z|x)}{q(z|y)} dz\right]
\end{aligned}
$$
2. 假定 KL 散度接近零,为什么 p(y|z) 足够接近 one hot 时,这一项才足够小?
当然,如果这样理解的话,好像又行得通了:在 $p(y|z)$ 足够接近 one hot 时,上式成立,此时如果 KL 散度接近零,这一项就足够小了。
但这样又引入了新的问题,即如果其它解也能使该项 loss 降得很低,模型为什么一定会优化到 $p(y|z) \in \{0, 1\}$ 和 $p(z|x) \approx q(z|y)$ 呢?
求苏神赐教~
这里你说的是对的,前面的解释是我疏忽了。
那我们可以直接看$(5)$和$(8)$,$(8)$中出现了$\Vert z - \mu_y\Vert^2$这一项,它倾向于让$z$对齐某个聚类中心,而$z$对齐聚类中心后,$p(y|z)$应该能尽量准确预测出对应的类别$y$,才能使得它求和的时候尽量命中了包含最小化$\Vert z - \mu_y\Vert^2$的那一项,从而达到最小化。
大致就是这样理解吧。从理论上来说,确实不能保证解唯一,但是SGD通常会“赢者通吃”,也就是说,如果开始阶段某个$y$对应的$\Vert z - \mu_y\Vert^2$这一项是所有$y$中最小的,那么后面通常会尽量最小化这一项(小的更小),所以迫使它倾向于聚类的解。
May 12th, 2024
苏神,(3)式中的假设
$$p(z,y|x)=p(y|z)p(z|x)$$
是否不太合适?因为它等价于$p(y|z)=p(y|z,x)$,进而等价于$p(y,x|z)=p(y|z)p(x|z)$,也就是在已知编码$z$时,$x$和它的类别$y$是独立的。这样的假设不会和最终目标:编码$x$为$z$, 然后对$z$做聚类得到类别$y$ 发生冲突吗?
假如$z$是一只猫的latent,$p(y|z)$预测$z$对应的类别是$y$,假设预测是准确的,那么$y$的有效值只有一个,那么就是“猫”;$p(x|z)$预测的是$z$对应的原始图片,猫的图片有无穷无尽。
相当于说,在给定$z$时,$y$就是“猫”这个类别,$x$则是无穷无尽的猫图,它们之间确实是独立的?
刚意识到我问了一个愚蠢的问题,从概率图的角度看,过程$x\xrightarrow{\text{编码}} z\xrightarrow{\text{预测}}y$本就暗含假设:$x$与$y$关于$z$条件独立,也就是说这个假设是必需的。感谢您的解释!
August 8th, 2024
不知道博主看过VaDE这篇文章没有https://www.ijcai.org/proceedings/2017/0273.pdf, 用GMM表示latent space, 思路跟本文大体一致,公式推导也基本没差。主要区别在三点:1,方差设置为可学习参数而不是全部设为1;2.用贝叶斯求解p(y|z)而不是训练分类器;3.p(y)同样设为可学习参数而不是均匀分布. 经过在mnist和fashionmnist上测试发现,这三点均会导致acc低于本文设置。第一个相对好理解,增加了方差可能导致提前拟合从而cluster比较接近;第二点我猜是贝叶斯比较依赖初始化参数,因此VaDE需要预训练并拟合GMM得到参数进行初始化;最让我难以理解的是第三点,作者的代码直接设置可学习参数并按照均匀分布初始化p(y),然而训练过程中p(y)会不断变大导致概率和大于1违背逻辑,但性能并不差。当我尝试给可学习参数加个softmax作为p(y)反而性能大幅下降,不清楚问题出在哪
抱歉之前没看过VaDE。我去搜索了一下VaDE的代码(居然是keras+theano!),确实像你说的没有归一化,我也感觉比较奇怪。不过你说加上Softmax会大幅下降就更奇怪了,“大幅”是有多大来着?按理说固定为均匀分布也不会差很多?能不能看看加上Softmax后训练完成的$p(y)$长什么样?
我观察了训练过程,加了Softmax后训练一开始各类weight就会开始波动,而变小的weight会一直变小到最后成0,所以最终输出的label直接少了两三个导致准确率大幅下降。除非用temperature softmax让概率变化很慢性能才能接近均匀分布结果,但用均匀我担心并不适合所有情况,毕竟mnist是刚好各类比较均衡,如果用到我们没有groud truth的生物数据可能合理性会被质疑
看来是Softmax的赢者通吃特性造成了负面效果。
均匀分布是一个先验(正则),或者说是一个期望,期望算法能找到尽可能显著的规律(而不是过拟合),它的结果不一定是均匀,我觉得问题不大。就算不加该正则项,通常也要加别的,防止方差过大导致的过拟合问题。