北 京 大 数 据 研 究 院
BEIJING INSTITUTE OF BIG DATA RESEARCH

【科普系列】深度学习 Part 3

【导读】今天给大家带来深度学习第三期科普内容——自编码器

1. 什么是自编码器(Definition)


我们先不谈神经网络,简单介绍一般的自编码器,其原理很简单。自编码器可以理解为一个试图去还原其原始输入的系统。如下图所示。



图中所示的自编码器有两部分组成:编码器(encoder)和解码器(decoder),它们本质上都是对输入信号做某种变化。编码器将输入x变换为新的编码信号h, h=f(x);解码器将编码h变换为输出信号x̂ ,即x̂ =g(h)=g(f(x))。实际上自动编码器的目的就是尽可能使输出信号x̂复现输入信号x,即使重构误差L(x,x̂ )=L(x,g(f(x)))尽可能小。


本期文章介绍的自编码器其实就是一种特殊的神经网络。我们知道简单的神经网络结构包括:输入层(x),隐藏层(h),输出层(y)。而自编码器是一种输出层与输入层相同的,使用反向传播算法对输入进行重构的无监督学习模型(因为模型中并不需要数据的标签y)。简单来说,就是将神经网络输出层中的y换成x,其结构如下图所示。


对于图中所示的网络结构,当我们采用Sigmoid函数作为激活函数时,该网络(自编码器)涉及下列变换:

其中,

该神经网络需要最小化的目标函数就是重构误差L(x,x̂ ),这里的误差可以是平方误差(squared error loss)或交叉熵误差(cross entropy error)。

2. 为什么要用自编码器 (Motivation)


也许你要问这样做有什么意义?学习函数去近似恒等函数,看似很简单,也感觉没什么意义,但对于自编码器,我们往往不关注输入层和输出层,而更关心中间的隐含层能给我们带来什么。中间隐含层能给我们提供一种新的特征表达(feature representation),而好的特征是一个成功的学习模型的重要因素。 在搭建自编码器时,我们对中间层做一些特殊的约束(例如对其节点个数的限制),往往能够发现数据所隐含的有趣结构。另外,如果隐含层节点个数少于输入层节点个数,也体现了自编码器的另一个重要目的:对数据进行降维。


接下来我们举一个简单的图像识别的例子,每一张图片大小均为10×1010×10,因此我们的自编码器的输入层有100个节点,假设隐含层也有100个节点,再加上输出层,这样我们就得到了一个自编码器。对自编码器训练完之后,每一个隐藏节点对应100个参数(舍去bias),我们用这100个参数便可以对隐含层的每一个节点可视化,如下图所示,下图中每一个小方块对应一个隐藏节点:

从上图我们可以看到,不同的隐藏单元学会了在图像的不同位置和方向进行边缘检测,即这个自编码器帮助我们提取出了图形的边缘特征。

3. 堆叠自编码器(Stacking Autoencoders)


对于深层神经网络,其优势在于能够逐层的学习原始数据的特征表达,每一层以前一层的表达为基础,随着层数的增加也变得更抽象,更复杂。堆叠自编码器实际上就在做这样的事情:逐层构建自编码器,将每个自编码器得到的表达作为一层隐含层,然后加入数据的标签,再次利用反向传播算法对网络中的参数进行微调(监督学习),便得到了最终的深层神经网络。堆叠自编码器能够得到原始数据的高度非线性表达(highly nonlinear representations)。 下图展示了堆叠自编码器的基本步骤


注:

  • 每一个WiWi表示相邻层之间的系数矩阵

  • 可以重复图示中的第二部多次,以得到深层神经网络

  • 最后一步之前,整个网络的训练不是一蹴而就的,而是逐层进行(layer-wise unsuperwised pre-training)


对于常见的分类任务,堆叠自编码器一般分为以下两个阶段:

1 ) 逐层预训练(layer-wise unsuperwised pre-training):每一层的训练都是一个无监督学习任务

2 ) 微调(fine-tuning): 图中第三步我们加入数据标注yy后,再利用反向传播算法对已得到的系数进行微调,这时则是一个监督学习任务


也许会有人问,为什么不直接训练多层的神经网络,而要逐层训练?理论上,反向传播算法可以用来训练任意的深层神经网络。然而在实际应用中的效果并不是很好,主要原因是该优化问题有很多局部最优解以及梯度扩散导致训练缓慢。另一方面,逐层训练是一种比较好的参数初始化策略,一系列的无监督学习任务能较好的去拟合数据的结构,使得在进行最终的监督学习时整个网络已经处于一个较优的初始状态,进而提升算法的迭代效率和迭代的稳定性。


4. 自编码器的变体 (Autoencoder Variants)


1 )稀疏自编码器(Sparse Autoencoder)

我们在前面提到,自编码器可以用来对数据进行降维,但其实我们也可以对数据“升维”,即自编码器的隐含层的节点数量比输入层节点多。升维的同时对隐含层的节点加一个稀疏约束,自编码器仍可以得到好的特征表达。这就是所谓的稀疏自编码,其基本思想就是高维而稀疏的特征表达是比较好的。


我们先简单介绍一个应用稀疏自编码器的例子,感兴趣的同学可以学习参考文献[5]。这篇文章提出了稀疏卷积自编码器(sparse convolutional autoencoder),该编码器可用于细胞核的检测以及病理组织图像的特征提取。其简单结构如下图所示,利用卷积神经网络(一种用于图像分类的神经网络)将原始病理组织图像结构为前景图(有细胞核)和背景图(有细胞质),之后通过对细胞核的位置表示为一个稀疏特征图来检测细胞核。


那么如何实现所谓的稀疏性呢?上述例子中的稀疏性与像素矩阵中非零值个数占总像素个数的比例有关,我们在这里介绍另一种常用的方法。对于稀疏性,大家自然会想到,在我们所优化的目标函数中加入某种惩罚项能够实现稀疏性,当我们的隐含层不够稀疏时或是和我们所期望的稀疏程度偏离较大时,惩罚增强。那具体如何构造符合要求的惩罚项呢?


对于隐含层中的每个节点,给定一个输入x,当我们的激活函数为Sigmoid函数时,其输出为0到1的一个值,可以理解为该节点输出为1的概率值(激活值),这个概率值越小,该节点等于0的概率值自然越大。但对于每一个节点来说,不仅仅有一个输入样本x(sample),对于多个样本,我们取均值即可。隐含层中第jj个节点的平均激活值的表达式为:

其中,m为数据中的样本个数,aj(x)为激活函数(Sigmoid函数)。 对于每一个节点的平均激活值,我们对其加一个约束:p̂j≈p0, 我们称p0为稀疏系数(sparsity parameter),一般取一个接近0的较小值,例如0.05,即我们希望每一个节点的平均激活值接近0.05,要满足这样的约束就需要大多数节点的激活值接近0,也就达到了我们想要的稀疏性。 上述过程的具体实现需要在我们的目标函数中加入合适的惩罚项,用于惩罚p̂j和p0偏离较大的情况。有很多惩罚项可以满足这个要求,我们这里介绍其中一种:KL散度(Kullback-Leibler Divergence,本节结尾部分对其做了简要介绍),该惩罚项的表达式为:

其中,n为隐含层中的节点个数。从该表达式我们可以看出当p0=p̂j时,KL(p0||p̂j)=0, 当p̂j偏离p0时,KL(p0||p̂j)单调递增。

加入该惩罚项后,我们的目标函数为:

其中 J(W,b)为传统神经网络的损失函数。


2 )去噪自编码器 (Denoising Autoencoder)

我们现在简单介绍另一种自编码器:去噪自编码器。去噪自编码器是一类接受损坏数据作为输入,并训练来预测原始未被损坏数据作为输出的自编码器。接受损坏数据作为输入又有什么意义呢?简单来说,去噪自编码器一方面是为了使隐含层学到更稳健的特征(robust features),能够在一定程度上处理原始数据的污染、缺失问题,另一方面是为了防止隐含层学习一个简单的恒等函数。

去噪自编码器中需要将原来的数据损坏,具体如何损坏有很多方法,我们这里对其中一种做简单介绍。对于每一个输入的样本x,随机选择一部分特征,把他们所对应的样本值设为0,其余的保持不变。这个过程实际上是从一个条件分布qD(x̃ |x)中采样得到损坏样本x̃


去噪自编码器包括以几个步骤(参考图示):

(1)从条件分布qD(x̃ |x)得到损坏样本x̃

(2)将损坏样本x̃映射到隐含层,y=fW,b(x̃ )=S(Wx+b)。            

      (注:这里y表示前文中的隐含层h,只是为了和图示保持一致)

(3)基于隐含层的输出y,得到重构z=gW′,b′(y)=S(W′y+b′)

这些步骤中涉及到的所要参数通过最小化损失函数L(x,z)得到,L(x,z)=L(x,g(f(x̃ )))

3 )收缩自编码器(Contractive Antoencoder)

收缩自编码器类似于去噪自编码器,也是为了保证模型对输入数据一定程度下的扰动具有不变性,即稳健性。而收缩自编码器的实现方法类似于稀疏自编码器---在目标函数中加入一个惩罚项,收缩自编码器中的惩罚项表达式为:


具体如何惩罚呢?这个惩罚项数学上又叫做映射f(x)雅可比矩阵的Frobenius范数,用来度量表达(representation)h=f(x)对某一输入样本x的敏感性(sensitivity)。该惩罚项能使特征映射尽可能的收缩在训练数据附近,因为当表达h=f(x)对于输入x过于敏感,会导致Frobenius范数增大,即惩罚增强。 收缩自编码器的目标函数为:

与去噪自编码器相比,收缩自编码器是为了提高表达f(x)的稳健性,而去噪自编码器则是为了提高重构表达g(f(x))的稳健性。这一属性使得收缩自编码器在提取特征时有更好的表现,因为对于最终的分类任务,我们只用到了编码器(encoder)部分,因此自编码器所提取的特征的稳健性比重构表达的稳健性更重要。另外,去噪自编码器是通过对输入添加随机噪声,经过编码解码来获得稳健重构;而收缩自编码器对扰动的稳健性是通过惩罚雅克比矩阵的Frobenius范数来实现的,换句话说去噪自编码器通过外部因素提高特征提取的稳健性,收缩自编码器则是抓住内部因素提高特征提取稳健性。


下图展示了一个有趣的网络结构,该结构结合了去噪自编码器和收缩自编码器。具体怎么学习多层自编码器我们也已经在堆叠编码器那一节中有所介绍,需要注意的是,根据不同应用场景,自编码器中的隐层节点个数可多可少,对其数量并没有固定要求。对此感兴趣的同学可以进一步学习参考文献[6]。


5. 小结


自编码器的优势是能够实现特征提取和特征降维,但训练一个自编码器,往往需要有大量数据,训练时间也较长,也需要调整很多超参数,因此需要大量时间和精力才能得到一个比较好的自编码器。在实际应用中,你训练得到的自编码器很可能没有用处,也许你只是从隐含层得到了输入样本的均值或是就是原来的输入样本。在某些情况下,你用自编码器会把问题变得更复杂,更抽象,例如隐含层的解读性很差,像一个黑盒,我们并不知道一个深度神经网络的隐含层具体在做些什么,而此时通过正常的统计分析,统计模型寻找合适的特征往往显得更直观,更有说服力和实用性。因此,在实际工作当中,最关键的还是对问题和需求的整体把控,基于已有数据寻求最合适的方法和来解决实际问题。


6. 参考文献


[1] http://ufldl.stanford.edu/wiki/index.php/UFLDL_Tutorial

[2] Vincent, P., et al. Extracting and Composing Robust Features with Denoising Autoencoders. in the proceedings of the 25th international conference on Machine Learning. 2008.

[3] Schölkopf B, Platt J, Hofmann T. Greedy Layer-Wise Training of Deep Networks[C] International Conference on Neural Information Processing Systems. MIT Press, 2006:153-160.

[4] Rifai S, Vincent P, Muller X, et al. Contractive Auto-Encoders: Explicit Invariance During Feature Extraction[C] ICML. 2011.

[5] Hou L, Nguyen V, Samaras D, et al. Sparse Autoencoder for Unsupervised Nucleus Detection and Representation in Histopathology Images[J]. 2017.

[6] Sankaran A, Vatsa M, Singh R, et al. Group Sparse Autoencoder[J]. Image & Vision Computing, 2017.




小编的话:今天深度学习的科普知识就到这里了,希望可以对大家有所帮助哇~结尾依旧是插播宣传,深度学习的相关课程和案例实践都可以在数据嗨客的平台上进行哦,以下附上课程链接:

http://hackdata.cn/learn/course/7/

(点击阅读原文可跳转)