More about Auto-encoder
本章内容是先回顾自编码器的基本原理,将encoder的output一个向量,我们叫做embedding等,与embedding是关于输入图像的表示。然后是更深入的学习auto-encoder,主要围绕三方面:
Auto-encoder可以看作是如下的结构,它主要包含一个编码器(Encoder)和一个解码器(Decoder),通常它们使用的都是神经网络。Encoder接收一张图像(或是其他类型的数据,这里以图像为例)输出一个vector,它之前称为code,现也可称为(Embedding、Latent Representation或Latent code),但不管它叫什么,我们只需要知道它是关于输入图像的表示;然后将vector输入到Decoder中就可以得到重建后的图像,希望它和输入图像越接近越好,即最小化重建误差(reconstruction error),误差项通常使用的平方误差。
本章内容是更深入的学习auto-encoder,主要围绕两方面:
做embedding的根本原因:An embedding should represent the object(一个embedding要能代表这个输入对象)。
一个好的embedding应该包含了关于输入的关键信息,从中我们就可以大致知道输入是什么样的。即希望得到一个关于input有代表性,解释性强的embedding,例如machine知道看到蓝色的耳机,它就会想到三九而不是其他人。
然而我们如何知道embedding能否很好的包含输入的特性呢?我们可以训练一个Discriminator(判别器,类似于二分类),输入是一个image和embedding,输出结果是看image和embedding是否是一对。它可以判断图片与code是否匹配,给出一个结果对匹配进行打分。
用 ϕ \phi ϕ来表述Discriminator的参数,希望通过训练最小化D的损失函数,loss of the classification task is 输出与标签的交叉熵 L D L_D LD,那么训练模型参数来最小化 L D L_D LD得到最小的损失值 L D ∗ L_D^* LD∗:
即 L D ∗ L_D^* LD∗= min ϕ L D \min\limits_{ϕ}L_D ϕminLD。(其中 L D ∗ L_D^* LD∗来评估向量表示的好或不好)
通过上述结论我们发现 L D ∗ L_D^* LD∗的值越小,则encoder的表现越好。
现假设encoder的参数为θ,那么可以通过minimize L D ∗ L_D^* LD∗得到表现好的encoder。 如下图:
我们需要调整encoder的参数 θ \theta θ ,然后用评估方法(根据 L D ∗ L_D^* LD∗来评估)来让生成向量最优化。
θ ∗ \theta^* θ∗= a r g min θ L D ∗ arg\min\limits_{\theta}L_D^* argθminLD∗;
将 L D ∗ L_D^* LD∗带入:即可得—— θ ∗ \theta^* θ∗= a r g min θ min ϕ L D arg\min\limits_{\theta}\min\limits_{ϕ}L_D argθminϕminLD。
即同时训练encoder的参数 θ \theta θ和discriminator的参数 ϕ \phi ϕ,使得 L D L_D LD最小化。
其实原来的auto-encoder 可以看作是上述框架的一个特例,与同时训练encoder和binary classifer 是一样的,只是它的特殊情况。
我们把Discriminator的内部架构设计一下:Discriminator接收一个图片和一个vector,vector通过Decoder解码生成一个图片,然后和输入图片进行相减,看它们的接近程度计算分数。
image和vector输入到判别器中,得到的结果score,就是auto-encoder的reconstruction error,即Discriminator得到的结果还是可以认为是最小化重建误差。
除了图像数据外,我们也可以在序列数据上使用Encoder-Decoder的结构模型。下面采用Skip thought 模型方法,这个模型训练过程和训练word embedding很像。
Skip thought 是一种利用句子之间顺序的半监督模型,利用一个encoder和两个decoder,同时预测句子的上一句和下一句,训练目标是使预测的上一句和下一句和label数据的error最小。
Quick thought是对于Skip thought的改进版本,它不使用Decoder,而是使用一个辅助的分类器。它将当前的句子,下一个句子和一些随机采样的句子作为输入,分别送到Encoder中得到对应的Embedding,然后将它们丢给分类器,classifier可以输出正确的下一句。
因为当前的句子的Embedding和它下一句的Embedding应该是越接近越好,而它和随机采样句子的Embedding应该差别越大越好,因此分类器应该可以根据Embedding判断出哪一个代表的是当前句子的下一句。
其中classifier和encoder是一起训练的。
CPC模型和Quick thought的思想是一样的,不过是用在声音信号上的。CPC技术同样接收一段序列数据,然后输出它的接下来数据的预测结果。
如何得到解释性更好的Embedding——特征解耦,因为对于Encoder的输入数据来说,经过Encoder得到的Embedding其实包含了关于它的很多类型的信息。
比如输入是声音信号时,Embedding可能包含了内容信息、讲话者信息等,如果输入的是一段文字,Embedding就可能包含语法信息、语义信息等。
我们希望encoder可以自动告诉我们哪些维度代表哪些信息。
具体做法:
Feature Disentangle- Voice Conversion
上述做法在语音处理方面其实有很大的用处,可以将声音和语义内容切分开。如下图:
然后将不同的声音和语义组合,得到完全不同的语音输出,可以做成一个变声器:
引入对抗训练的概念,也就是在训练中加入了Discriminator。目的是训练让前面的维度是语义,后面的维度代表男声还是女声。
我们训练一个声音信息的分类器,将embedding的前100维吃进去,判断encoder的输入音频是男还是女,encoder需要训练来骗过classifier,让被吃进去的那部分embedding,尽可能不包含声音信息即是让这个classifier不能区分男声还是女声,正确率越低越好。这样就使得语者的信息从前部分的维度剔除了出来,前100维就只剩下内容信息,语者信息都在了后部分的维度中:
在实际过程中,通常是利用GAN来完成这个过程,也就是把encoder看做generator(生成器),把Classifier看做discriminator(鉴别器)。先训练speaker classifier,再训练encoder,反复训练这两项,直到表现足够好。
另一种方式是改变网络结构,用两个Encoder分别输出身份信息和内容信息,再处理内容信息的Encoder上加一个IN(IN具体操作暂不了解),该IN可以抹掉global information(每个小部分都有的信息),即可清除身份信息,最后得到的Embedding是只包含内容信息的。再组合放入Decoder中。但是该方法还存在问题,就是第2个的Encoder处理得到的Embedding还包含内容信息。
改进的方法就是在Decoder中加入AdaIN,将encoder2得到的embedding接到AdaIN上,过滤掉代表身份信息的Embedding中保留的内容信息。
我们之前讲的code都说是一个连续的vector,如果Encoder能够输出离散的向量,那么更有利于我们解读code的信息,比如可以用一些聚类的方法将向量分成一些簇。可以将code直接变成One-hot或者Binary的形式,取最大值或者设置阈值即可实现,这样看维度信息就可以直接完成分类了。
一般情况下,Encoder输出的Embedding都是连续值的向量,这样才可以使用反向传播算法更新参数。但如果可以将其转换为离散值的向量,例如one-hot向量或是binary向量,我们就可以更加方便的观察Embedding的哪一部分表示什么信息。当然此时不能直接使用反向传播来训练模型,一种方式就是用强化学习来进行训练。
binary向量更好,因为可表示的信息更大,而one-hot过于稀疏。
设置一个codebook,里面是一排向量,这个通过训练得到,是需要学习到的。图像通过Encoder输出原始向量vector,这是连续的。接下来用这个vector去计算和codebook里面的向量的相似度,相似度最高的vector3作为decoder的输入。这样可以固定向量的类别,相当于做了离散化。离散化之后信息 更易分类:
上面的模型中,如果输入的是语音信息,那么语者信息和噪音信息会被过滤掉,因为上面的Codebook中保存的是离散变量,而内容信息是一个个的字,是容易用离散向量来表示的,而其他信息不适合用离散变量表示,因此会被过滤掉。
既然可以用离散向量来表示输入信息,那么我们可以考虑让embedding不再是向量而是序列句子。
比如一个 seq2seq2seq auto-encoder 模型,使用这些sequence 作为code来还原文章。期待这些code可以就是原来那篇文章的摘要或者精简版本,但是实际上由于encoder和decoder的存在(都是机器),这些code会参杂一些“暗号”,虽然是文字的组合,但没有实际含义。
如果要让这些code有实际含义,将会用到GAN的概念,就是预先训练一个可以识别人类是否能读懂的句子的discriminator(鉴别器),然后去训练这些code,使得code具有可读性。
那今天的encoder就会学着去产出一个可以骗过discriminator(就是像是人写出来的句子)又可以给decoder还原为文章的句子。
注意:如果发现LossFunction是不可微分的话,那么就用强化学习去硬train。
本章是在Auto-encoder中如何去衡量encoder的好坏,怎样的embedding是个好的——能够代表这个输入对象。我们可以将Auto-encoder理解为是一种思想,它可以嵌入到其他一些model中使用,也可以做一些变形以方便处理问题。比如结合GAN的概念,引入Discriminator(鉴别器),可以很好的处理最小化重构误差问题,即得到的评分就是重构误差。其次是讲解如何去让embedding更具有解释性,主要有两大类方法:
通过Auto-encoder与GAN 的结合变通,与一些其他技术,可能会在多方面会有广泛的实际应用。