0%

无监督学习:AE、VAE

Why we need encoder

我们知道,对于计算机来说,图像、视频、文字等信号都是用离散的数字去表示的。以图片为例,对于神经网络而言,当然可以直接把像素直接作为输入,并基于这些像素去做各种的下游任务,例如图像分类、文生图片等。那么,encoder的意义到底是什么?

以我个人的观点来看,encoder的作用实际上是去除数据中的噪声,压缩数据的大小,提取数据之间的共性,其最终目的是获得一个更高效的、更适合下游任务的表示来替代原始的数据。例如,假设我们现在正在想知道一个图片所表示的文本(CLIP),数据集中有一张猫站在草地上的图片和一张猫站在地板上的图片,而对应的文本描述都是 a photo of a cat,我们显然希望能够将这两张图片用类似的特征去表示[1],这时我们就会使用encoder将原始的差异很大图片编码成两个类似的特征,并且,用来表示这张图所需的数字要小得多。例如一张512*512*3的图片,可能最终只需要2048维,也就是2048个数字去完全表示。

Auto Encoder

Auto Encoder,即自编码器,其是用在没有标签的数据集上的,也就是说是一种无监督的算法。相对于上文中提到的CLIP编码器,这种编码器没有任何的监督,其目的在于去除噪声、压缩数据,即用更少的数据去保留原数据更多的信息。它的作用可以类比于一个压缩软件,可以把数据压缩成另一种格式(类比.zip文件),并且还能再还原出原数据。

但是与压缩软件固定的算法不同,神经网络通常无法用明确的算法去定义原数据是怎么被转换为压缩后的数据的,那么我们如何知道压缩后的数据能不能表示原数据?直观的想法是,如果我们能从压缩后的数据还原出原始数据(类似解压缩操作),那么这个被压缩了的数据就一定蕴含了原数据的所有信息。

因此Auto Encoder通常包括一个encoder(负责压缩数据)和一个decoder(负责解压数据),其算法也可以描述为:

1
2
3
#x: 原始数据
h = encoder(x)
y = decoder(h)

在训练的过程中,需要最小化原始数据x和解压缩后的数据y的区别,通常可以采用均方误差损失去进行优化。当训练完成后,decoder应当能够从encoder压缩后的数据还原出原始的数据,这时便可以使用encoder对原始数据进行编码,于是完成了数据的降维工作。

Denoising Auto Encoder

Auto Encoder看起来已经效果很棒了,我们似乎可以用这种方式去压缩并解压绝大部分的数据。然而,在自编码器的上空,“却依然笼罩着两朵乌云”。其一,如果给单独decoder一个数据,通常无法生成很好的结果。其二,有可能会出现Auto Encoder直接把输入复制到输出的情况,这种模型虽然损失函数是最小的,但却毫无意义。

首先,当我们有了decoder之后,我们会自然的想这样一件事情:能否把decoder单独使用,用来生成新的数据?然而,我们会发现即使给解码器一个满足压缩数据分布的数据,decoder依然无法生成合理的数据,而通常会生成噪声。

这是由于在auto encoder中,自编码器的输入输出是一种确定的关系,假设我们最后编码的特征只有1维,也就是一个数字来表示原数据。如果encoder把图片A编码为10,把图片B编码为12,那么10和12都建立了与原始数据的映射,而数字11却并没有建立任何映射。假如把decoder视为一个函数,那么11并不在函数的定义域内,因此decoder(11)的值也是未定义的,因此通常也是随机的噪声。

那么既然其原因在于decoder的定义域比较狭窄,那么问题就变成了如何拓展decoder的定义域。而decoder的定义域则是由encoder在训练的过程中确定的,decoder只会建立encoder的输出到原始数据的映射,也就是说,decoder的定义域便是encoder的值域。那么问题则转变为了如何拓宽encoder的值域,也就是encoder的编码范围。

依然考虑这个例子,为什么encoder的定义域是离散的,为什么10和12之间的数字均不是有效的特征?这是因为原始数据就是离散的表示,而encoder中每一步的操作又都是确定的,因此encoder的输出也自然而然的是离散的。这就导致了在这些离散点之间的区域是无效的。因此,为了扩展encoder的编码范围,而不是让encoder仅仅是将输入数据固定的映射到某些确定的特征上,我们可以把原数据变成连续的数据,而对于计算机来说,就是在原始数据上以某种概率分布添加噪声,这样每次输入的数据都是不同的,而强迫网络学到更深层次的信息。

以我个人的观点来看,加噪声的方式可以看做假定原数据遵循着某种概率分布(所谓的共性),加噪声类似于在这个概率分布上每次进行采样不同的值,从而迫使网络能够真正学习到数据背后的分布规律,从而所有满足这种分布的数据,都可以用encoder来编码表示,以此来增强网络的泛化性。

Variational Autoencoder

Variational Autoencoder, 即变分自编码器,更为彻底的解决了上文所提到的Auto Encoder的两个问题[4]。相比于上文中所提到的加噪声的思想,VAE的想法则更为激进。既然问题出现在压缩之后的数据不够连续,那么干脆直接由encoder确定一个概率分布来表示压缩后的数据,而decoder则需要从这个概率分布当中进行采样作为输入,进而解码出数据。同时,这个分布应该是与encoder无关的,一个先验的分布。如此一来,在训练完成之后,就不再需要encoder,只要从这个概率分布中随机的进行采样,那么decoder都能给出一个合理的,数据中没有的结果,因此与其他Auto Encoder不同,VAE可以被称为是一个真正的生成模型。

既然要确定一个概率分布,那么首先必须假定压缩后的特征满足某种概率分布,从而才能通过学习其参数,确定一个具体的概率分布。这是一种典型的贝叶斯学派的思想,因此论文名字也叫做Auto-Encoding Variational Bayes。

论文则选择了正态分布来表示数据,因此Encoder需要给出的就是正态分布的均值和标准差。而Decoder则需要从这个正态分布中进行采样,再生成出原数据,总的架构如下图。

vae

实际上,通常Encoder会为一个图像预测多个正态分布,显然一张图片不会遵循多种分布,但由于我们这里的概率分布并不是通过数学公式计算出来的,而是由Encoder推断出来的,那么很有可能是不准确的。因此我们允许Encoder给出多种可能的答案,对于这些正态分布,vae都会进行一次采样,再交给decoder进行输出。

vae的前向过程很好理解,encoder提取出正态分布,decoder从正态分布中采样进行生成。但是问题在于,我们如何构造损失函数?注意到decoder的输入是和原始图像满足同一个概率分布的随机值,其输出也并不一定应该是原始图像,那么直接采用和Auto Encoder一样的重建损失函数显然是不合理的。

vae的优化

这是一些数学部分

本质上,参数为 的encoder建立了一个以输入x为条件的条件概率分布,我们用z来表示encoder的输出(特征), 那么可以写为,同理,参数为 的decoder则可以表示为。与此同时,注意到我们最开始的假定:z应当是一个正态分布,所以z也应该满足我们的先验概率分布

我们的目标是:

  • 要让encoder的输出去满足我们的的先验概率分布。

  • 要让decoder能够从encoder生成的概率分布中生成出符合原数据分布的数据,也就是让decoder能够学习到分布

这样,训练之后我们任意给出一个满足先验概率分布​的数据,decoder都应该能生成合理的结果。

首先考虑第一个目标,根据贝叶斯公式,我们有

因此我们需要计算这个积分,也就是在整个特征空间去进行积分,具体到计算机上而言(如果采用蒙特卡洛积分)则是对于所有encoder输出的正态分布的概率空间去采样并生成数据,再依照概率去加权平均。换句话说,就是要让decoder生成无数次。然而我们上文说过,encoder将会同时给出很多正态分布的推测,如果对这些推测都去计算积分,那么时间上的开销太大了,无法进行训练。那么既然无法直接计算,需要一种近似的概率分布去估算它。

假设这个近似的概率分布为,我们希望尽可能的接近,因此需要最小化这两个分布之间的差异。我们通常用KL散度[5]来描述两个概率分布之间的差异,有

注意到,由于我们假定原始数据满足一个概率分布,因此应该是一个常数,所以可以把提出来,变成

再次注意到,由于概率分布的归一化条件,,因此有

由于是一个常数,所以在优化时,只需要优化前两项即可,即

到这里,已经可以优化我们的第一个目标,即让encoder的输出贴近一个正态分布,还剩下第二个目标:要让decoder学习从正态分布到原数据的分布。

我们可以用最大似然估计去估算decoder的参数,也就是说,一个合适的参数应该最大化 ,也就是最大化,由于对数函数是单调递增的,应当最小化

由此我们的损失函数可以写为

也就是论文[4]中要最大化的

这其中第一项是为了优化目标1,第二项则是为了优化目标2。

这里值得重新回头再看,既然我们最终的目标是让decoder能够生成符合原数据分布的数据,为什么不直接使用最大似然,也就是上述损失函数的第二项去完成优化,这样岂不是更简单?

需要注意的是,VAE的目标已经超越了拓展encoder的编码范围,而变成了得到一个生成模型。如果说之前的Auto Encoder的decoder只是为了encoder服务的话,那么在vae这里,便是encoder为了decoder而服务。从前由encoder决定特征分布的范围,decoder需要用encoder给出的特征重建。而现在则是decoder告诉encoder:我需要你将数据用正态分布表示,而我将从正态分布中采样,生成新的数据。

我们之前一直假定了encoder生成的特征是满足正态分布的,而损失函数的第一项的意义则是约束encoder的输出必须贴近正态分布(实际上给出的先验q(z)为一个标准正态分布),只有这样才真正做到了获得一个与encoder无关的特征分布,从而可以将decoder单独拿出来,作为生成器从正态分布中生成新的数据。原论文描述如下:

那么现在可以来真正的计算损失函数:

对于第一项KL散度,由于我们已经假设,是满足正态分布的,而我们人为规定为一个标准正态分布。两个正态分布的KL散度可以写为(省略积分推导过程)

我们有,代入之后即有

对于第二项的最大似然函数,如果假设输出是呈伯努利分布,就是优化BCE Loss,如果假设输出是呈高斯分布,那就是优化mse loss,具体选择每一种都可以。以我个人的实践经验来看,这种回归问题大多常用mse loss更好。

剩下唯一的问题便是采样该如何实现了,显然,对于一个正态分布而言,其可以写为,其中z是一个标准正态分布。这样所谓采样的过程就是可导的了,就可以用梯度下降的方式去优化,这个技巧叫做重参数技巧,实际上现在已经非常常用,diffusion model中的加噪声过程也是采用了同样的方式。

References

  1. Learning Transferable Visual Models From Natural Language Supervision

  2. Deconstructing Denoising Diffusion Models for Self-Supervised Learning

  3. 自编码器(AE、VAE)的原理与代码实现

  4. Auto-Encoding Variational Bayes

  5. KL散度

PS:

文中加粗表示的以我个人的观点来看意思是我本人是这样理解,且并没有特意去查专业的论文来佐证,有可能同样的观点已经被提出并证明,但我并没有看见,也有可能这种观点是错误的,那就是本人的水平问题了,欢迎指正。