自编码器 订阅
自编码器(autoencoder, AE)是一类在半监督学习和非监督学习中使用的人工神经网络(Artificial Neural Networks, ANNs),其功能是通过将输入信息作为学习目标,对输入信息进行表征学习(representation learning) [1-2]  。自编码器包含编码器(encoder)和解码器(decoder)两部分 [2]  。按学习范式,自编码器可以被分为收缩自编码器(undercomplete autoencoder)、正则自编码器(regularized autoencoder)和变分自编码器(Variational AutoEncoder, VAE),其中前两者是判别模型、后者是生成模型 [2]  。按构筑类型,自编码器可以是前馈结构或递归结构的神经网络。自编码器具有一般意义上表征学习算法的功能,被应用于降维(dimensionality reduction)和异常值检测(anomaly detection) [2]  。包含卷积层构筑的自编码器可被应用于计算机视觉问题,包括图像降噪(image denoising) [3]  、神经风格迁移(neural style transfer)等 [4]  。 展开全文
自编码器(autoencoder, AE)是一类在半监督学习和非监督学习中使用的人工神经网络(Artificial Neural Networks, ANNs),其功能是通过将输入信息作为学习目标,对输入信息进行表征学习(representation learning) [1-2]  。自编码器包含编码器(encoder)和解码器(decoder)两部分 [2]  。按学习范式,自编码器可以被分为收缩自编码器(undercomplete autoencoder)、正则自编码器(regularized autoencoder)和变分自编码器(Variational AutoEncoder, VAE),其中前两者是判别模型、后者是生成模型 [2]  。按构筑类型,自编码器可以是前馈结构或递归结构的神经网络。自编码器具有一般意义上表征学习算法的功能,被应用于降维(dimensionality reduction)和异常值检测(anomaly detection) [2]  。包含卷积层构筑的自编码器可被应用于计算机视觉问题,包括图像降噪(image denoising) [3]  、神经风格迁移(neural style transfer)等 [4]  。
信息
外文名
autoencoder, AE
提出时间
1987年 [5]
提出者
Yann LeCun [5]
类    型
机器学习算法,神经网络算法
中文名
自编码器
学    科
人工智能
应    用
降维,降噪,异常值检测
自编码器历史
自编码器在其研究早期是为解决表征学习中的“编码器问题(encoder problem)”,即基于神经网络的降维问题而提出的联结主义模型的学习算法。1985年,David H. Ackley、Geoffrey E. Hinton和Terrence J. Sejnowski在玻尔兹曼机上对自编码器算法进行了首次尝试,并通过模型权重对其表征学习能力进行了讨论 [6]  。在1986年反向传播算法(Back-Propagation, BP)被正式提出后,自编码器算法作为BP的实现之一,即“自监督的反向传播(Self-supervised BP)”得到了研究 [7]  ,并在1987年被Jeffrey L. Elman和David Zipser用于语音数据的表征学习试验 [8]  。自编码器作为一类神经网络结构(包含编码器和解码器两部分)的正式提出,来自1987年Yann LeCun发表的研究 [5]  。LeCun (1987)使用多层感知器(Multi-Layer Perceptron, MLP)构建了包含编码器和解码器的神经网络,并将其用于数据降噪。此外,在同一时期,Bourlard and Kamp (1988)使用MLP自编码器对数据降维进行的研究也得到了关注 [9]  。1994年,Hinton和Richard S. Zemel通过提出“最小描述长度原理(Minimum Description Length principle, MDL)”构建了第一个基于自编码器的生成模型 [10]  。
收起全文
精华内容
下载资源
问答
  • 自动编码器

    2018-05-18 16:21:34
    用于深度学习,自编码器的网络编程源码,请自行下载哦
  • 自编码器

    2020-09-11 09:09:52
    文章目录自编码器简介特点应用结构分层训练方法香草自编码器栈式自编码器1.捆绑权重2.一次训练一个自编码器3.进行无监督预训练去噪自编码器 简介 神经网络就是一种特殊的自编码器,区别在于自编码器的输出和输入是...

    自编码器

    简介

    神经网络就是一种特殊的自编码器,区别在于自编码器的输出和输入是相同的,是一个自监督的过程,通过训练自编码器,得到每一层中的权重参数,自然地我们就得到了输入x的不同的表示(每一层代表一种)这些就是特征,自动编码器就是一种尽可能复现原数据的神经网络。

    自编码器通过简单地学习将输入复制到输出来工作。这一任务(就是输入训练数据, 再输出训练数据的任务)听起来似乎微不足道,但通过不同方式对神经网络增加约束,可以使这一任务变得极其困难。比如,可以限制内部表示的尺寸(这就实现降维了),或者对训练数据增加噪声并训练自编码器使其能恢复原有。这些限制条件防止自编码器机械地将输入复制到输出,并强制它学习数据的高效表示。简而言之,编码(就是输入数据的高效表示)是自编码器在一些限制条件下学习恒等函数(identity function)的副产品。

    特点

    跟数据相关程度很高,这意味着自动编码器只能压缩与训练数据相似的数据,因为使用神经网络提取的特征一般是高度相关于原始的训练集。

    压缩后数据是有损的,这是因为降维的过程中不可避免地丢失信息,解压之后的输出和原始的输入相比是退化的。

    应用

    数据去噪,进行可视化降维生成数据

    结构

    image-20200910102458671

    通常使用神经网络作为编码器和解码器,输入的数据经过神经网络降维到一个编码(code),接着又通过另外一个神经网络去解码得到一个与输入原数据一模一样的生成数据,然后通过比较这两个数据,最小化它们之间的差异来训练这个网络中编码器和解码器的参数。

    分层训练方法

    多层的训练方法:先进行第一层的code的训练,我们将第一层输出的code当成第二层的输入信号,同样最小化重构误差,就会得到第二层的参数,并且得到第二层输出的code,也就是原输入信息的第二个表达了。其他层就同样的方法炮制就行了

    image-20200910104425629

    当input的维度大于code的维度的时候,表示该变换是一种降维的操作

    当input的维度小于code的维度的时候,即稀疏编码器

    香草自编码器

    香草自编码器(Vanilla Autoencoder),只有三层网络,即只有一个隐藏层的神经网络。它的输入和输出是相同的,可通过使用Adam优化器和均方误差损失函数,来学习如何重构输入。

    隐藏层的压缩维度为32,小于输入维度784,因此这个编码器是有损的,通过这个约束,来迫使神经网络来学习数据的压缩表征

    栈式自编码器

    和其他的神经网络一样,自编码器可以有多个隐层,这被称作栈式自编码器(或者深度自编码器)。增加隐层可以学到更复杂的编码,但千万不能使自编码器过于强大

    栈式自编码器的架构一般是关于中间隐层对称的。

    image-20200911085436438

    1.捆绑权重

    如果一个自编码器的层次是严格轴对称的,一个常用的技术是将decoder层的权重捆绑到encoder层。这使得模型参数减半,加快了训练速度并降低了过拟合风险

    2.一次训练一个自编码器

    与之前训练整个栈式自编码器不同,可以训练多个浅层的自编码器,然后再将它们合并为一体,这样要快得多。

    例如:第一个自编码器学习去重建输入。然后,第二个自编码器学习去重建第一个自编码器隐层的输出。最后,这两个自编码器被整合到一起,如图15-4。可以使用这种方式,创建一个很深的栈式自编码器。

    image-20200911085841417

    3.进行无监督预训练

    如果有一个很大的数据集但绝大部分是未标注数据,可以使用所有的数据先训练一个栈式自编码器,然后复用低层来完成真正的任务。

    image-20200911090153809

    去噪自编码器

    制自编码器学习有用特征的方式是在输入增加噪声,通过训练之后得到无噪声的输出。这防止了自编码器简单的将输入复制到输出,从而提取出数据中有用的模式

    噪声可以是添加到输入的纯高斯噪声,也可以是随机丢弃输入层的某个特征,类似于dropout。

    image-20200911090335415

    变分自编码器

    我们想利用现有的样本去生成一些新的样本,从而扩大数据量。如果我们能知道原始数据集x的分布p(x),那么我们直接从这个分布中采样就可以得到新的样本。而在现实中,我们无法得到数据集的真实分布,于是变分编码器利用了一个隐分布z,通过z来生成新的样本,从概率角度来说就是p(x) = p(z)×p(x|z)。通过构造隐变量,让我们可以近似等于从原始分布中采样来组成新样本,而效果的好坏就靠模型来实现了。
    首先想到的是用神经网络来训练参数,那么当训练好模型后,我们输入x,可以生成新的样本x’,且他们近似都是从原始数据集分布中采样出来的,故可以参与训练其他模型,也就完成了数据增强。那么第一个损失函数就应运而生,即比较生成的x’和原始样本x的差距,差距越小效果越好。
    但是这样自然是不可行的,因为既然训练的目的是使输出样本和原样本相似度最高,那么我们直接拷贝一份原数据就行了,就不需要训练了。也就是说,数据增强的目的不仅要保证增强的数据都服从和源数据一样的分布,而且要有多样性,即有一些源数据没有的特征,这样才能达到数据增强的目的。
    于是我们考虑采样,因为采样的数据服从同一分布,但又各不相同,就可以满足多样性这一要求。
    考虑从隐分布z来进行数据采样,一个很自然的想法就是采用标准正态分布,但是如果对于所有的样本,训练的时候我们都从z中进行采样,然后用于训练,那么也就和原始的输入数据没什么关系了,即采样出的z不知道是由哪一个原始数据x生成的,这样也就没法进行损失计算,也就没法训练神经网络了。于是考虑如何把生成的数据和原始数据能一一对应起来,变分编码器让每个样本都服从一个正态分布,但这个正态分布又各不相同,即正态分布的两个参数均值和方差各不相同,那么这样输入输出就可以一一对应了
    那么如何学习输入的每个样本服从的正态分布的均值和方差呢,这个时候就要用到神经网络了,一切不好计算的都用神经网络去拟合,于是对于每个输入样本经过一层或多层神经网络,分别输出均值和方差,然后再从服从此均值和方差的正态分布中去随机采样生成新的样本。

    看似已经可以完成数据增强的目的了,但是仔细想想问题还有很多。首先既然损失函数是输出样本和输入样本的相似度,那么网络肯定往减少输出样本和输入样本的差异上去拟合,我们记得输出样本是通过在正态分布上采样得到的,我们知道正态分布的方差越大,则数据越分散,采样得到的数据噪声越大,导致输出样本和输入样本的相似度很小,于是网络训练会尽量减小正态分布的方差,直到接近0,那么还是那个问题,方差接近0,则生成的数据的多样性又减少了。所以这个问题还是没有解决。
    变分编码器使神经网络学到的正态分布尽量趋近于标准正态分布,即学到的均值和方差分别趋近于0和1。如何做到呢,那就是再增加一个损失函数。增加的损失函数是衡量网络学习到的正态分布和标准正态分布的差异性,即使用了KL散度。这样,神经网路一方面要学习输入输出的相似性,还要考虑增加一定的噪音,即不使正态分布的方差趋紧于0,也就增加了输出的多样性。

    image-20200916095141435

    image-20200916095205332

    参考:

    https://blog.csdn.net/h__ang/article/details/90720579?ops_request_misc=&request_id=&biz_id=102&utm_term=pytorch%E5%AE%9E%E7%8E%B0%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduweb~default-1-90720579

    https://www.cnblogs.com/LXP-Never/p/10921257.html#%E5%9F%BA%E6%9C%AC%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8

    https://www.cnblogs.com/royhoo/p/Autoencoders.html

    https://blog.csdn.net/bobobe/article/details/87543892?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522160021902919724839820054%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=160021902919724839820054&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v3~rank_business_v1-1-87543892.ecpm_v3_rank_business_v1&utm_term=%E5%8F%98%E5%88%86%E8%87%AA%E7%BC%96%E7%A0%81%E5%99%A8&spm=1018.2118.3001.4187

    展开全文
  • 自编码器及其变形很多,本篇博客目前主要基于普通自编码器、欠完备自编码器、稀疏自编码器和去噪自编码器,会提供理论+实践(有的理论本人没有完全理解,就先没有写上,后更)。另外,关于收缩自编码器、变分自编码...

    写在前面

    因为时间原因本文有些图片自己没有画,来自网络的图片我尽量注出原链接,但是有的链接已经记不得了,如果有使用到您的图片,请联系我,必注释。

    自编码器及其变形很多,本篇博客目前主要基于普通自编码器、栈式自编码器、欠完备自编码器、稀疏自编码器和去噪自编码器,会提供理论+实践(有的理论本人没有完全理解,就先没有写上,后更)。另外,关于收缩自编码器、变分自编码器、CNN自编码器、RNN自编码器及其自编码器的应用,后更。

    本文展示的所有完整代码详见:完整代码
    (目前只有Keras版本,有时间会写Tensorflow版本)

    文章较长,PDF版点击链接:PDF版

    一、自编码器(Autoencoder, AE)

    1、自编码器的结构和思想

    自编码器是一种无监督的数据维度压缩和数据特征表达方法。
    自编码器是神经网络的一种,经过训练后能尝试将输入复制到输出。自编码器由编码器和解码器组成,如下图所示(图片来源:深度学习浅层理解(三)— 常用模型之自编码器):

    h=f(x)h=f(x)表示编码器,r=g(h)=g(f(x))r=g(h)=g(f(x))表示解码器,自编码的目标便是优化损失函数L(x,g(f(x))L(x,g(f(x)),也就是减小图中的Error。

    2、自编码器和前馈神经网络的比较

    二者的区别和联系如下:

    (1)自编码器是前馈神经网络的一种,最开始主要用于数据的降维以及特征的抽取,随着技术的不断发展,现在也被用于生成模型中,可用来生成图片等。
    (2)前馈神经网络是有监督学习,其需要大量的标注数据。自编码器是无监督学习,数据不需要标注因此较容易收集。
    (3)前馈神经网络在训练时主要关注的是输出层的数据以及错误率,而自编码的应用可能更多的关注中间隐层的结果。

    3、自编码器和受限玻尔兹曼机的比较

    关于受限玻尔兹曼机的博客请参见:[受限玻尔兹曼机] 原理、求解、深度信念网络
    二者的区别和联系如下:

    (1)自编码器和受限自编码器的相同点如下:①都起到了降维的作用;②都可以用来对神经网络进行预训练;③训练都是无监督的。
    (2)自编码器和受限自编码器的不同点如下:①自编码器希望通过非线性变换找到输入数据的特征表示,其重构的是输入分布与reconstruct分布的KL距离,它是某种确定论性的模型;而RBM则是围绕概率分布进行的,它通过输入数据的概率分布来提取中间层表示,它是某种概率论性的模型。②AE使用的是BP算法进行优化,而RBM是基于概率模型,使用CD算法进行优化。

    4、普通自编码器存在的问题

    在普通的自编码器中,输入和输出是完全相同的,因此输出对我们来说没有什么应用价值,所以我们希望利用中间隐层的结果,比如,可以将其作为特征提取的结果、利用中间隐层获取最有用的特性等。
    但是如果只使用普通的自编码器会面临什么问题呢?比如,输入层和输出层的维度都是5,中间隐层的维度也是5,那么我们使用相同的输入和输出来不断优化隐层参数,最终得到的参数可能是这样:x1>a1x2>a2x1->a1,x2->a2,…的参数为1,其余参数为0,也就是说,中间隐层的参数只是完全将输入记忆下来,并在输出时将其记忆的内容完全输出即可,神经网络在做恒等映射,产生数据过拟合。如下图所示(图片来源:Introduction to autoencoders.):

    上图是隐层单元数等于输入维度的情况,当然,如果是隐层单元数大于输入维度,也会发生类似的情况,即当隐层单元数大于等于输入维度时,网络可以采用完全记忆的方式,虽然这种方式在训练时精度很高,但是复制的输出对我们来说毫无意义
    因此,我们会给隐层加一些约束,如限制隐藏单元数、添加正则化等,后面后介绍。

    5、自编码器实现与结果分析

    (1)实现框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def train(x_train):
        """
        build autoencoder.
        :param x_train:  the train data
        :return: encoder and decoder
        """
        # input placeholder
        input_image = Input(shape=(ENCODING_DIM_INPUT, ))
    
        # encoding layer
        hidden_layer = Dense(ENCODING_DIM_OUTPUT, activation='relu')(input_image)
        # decoding layer
        decode_output = Dense(ENCODING_DIM_INPUT, activation='relu')(hidden_layer)
    
        # build autoencoder, encoder, decoder
        autoencoder = Model(inputs=input_image, outputs=decode_output)
        encoder = Model(inputs=input_image, outputs=hidden_layer)
    
        # compile autoencoder
        autoencoder.compile(optimizer='adam', loss='mse')
    
        # training
        autoencoder.fit(x_train, x_train, epochs=EPOCHS, batch_size=BATCH_SIZE, shuffle=True)
    
        return encoder, autoencoder
    

    (4)代码分析:
    Keras封装的比较厉害,所以傻瓜式编程,这里是最简单的自编码器,其输入维度是28*28=784,中间单隐层的维度是2,使用的激活函数是Relu,返回encoder和autoencoder。encoder部分可以用于降维后的可视化,或者降维之后接分类等,autoencoder可以用来生成图片等(这部分代码git上都有)。结构见图如下:

    (5)结果展示:

    (i)Eencoder结果的可视化如图:

    上图中不同表示表示不同的数字,由图可知,自编码器降维之后的结果并不能很好地表示10个数字。

    (ii)autoencoder还原之后的图片和原图片对比如下:

    上图说明,autoencoder的生成结果不是很清晰。

    二、栈式自编码器(Stack Autoencoder)

    1、栈式自编码器思想

    栈式自编码器又称为深度自编码器,其训练过程和深度神经网络有所区别,下面是基于栈式自编码器的分类问题的训练过程(图片来自台大李宏毅老师的PPT):
    栈式自编码器训练过程
    即过程如下:
    首先,训练784->1000->784的自编码器,而后已经固定已经训练好的参数和1000维的结果,训练第二个自编码器:1000->1000->1000,而后固定已经训练好的参数和训练的中间层结果,训练第三个自编码器:1000->500->1000,固定参数和中间隐层的结果。此时,前3层的参数已经训练完毕,此时,最后一层接一个分类器,将整体网络使用反向传播进行训练,对参数进行微调。这便是使用栈式自编码器进行分类的整体过程。
    注:encoder和decoder的参数可以是对称的,也可以是非对称的。

    2、栈式自编码器的特点

    ①增加隐层可以学到更复杂的编码,每一层可以学习到不同的信息维度。
    ②若层数太深,encoder过于强大,可以将学习将输入映射为任意数(然后decoder学习其逆映射)。这一编码器可以很好的重建数据,但它并没有在这一过程中学到有用的数据表示。

    3、栈式自编码器和深度信念网络的异同点

    ①自编码器栈式自编码器;受限玻尔兹曼机深度信念网络
    ②栈式自编码器和深度信念网络都是逐层训练。
    ③栈式自编码器和深度信念网络的训练方法不同,栈式自编码器使用BP算法训练参数,深度信念网络使用的是对比散度算法。

    4、栈式自编码器实现与结果分析

    (1)实现框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def train(x_train):
    
        # input placeholder
        input_image = Input(shape=(ENCODING_DIM_INPUT, ))
    
        # encoding layer
        encode_layer1 = Dense(ENCODING_DIM_LAYER1, activation='relu')(input_image)
        encode_layer2 = Dense(ENCODING_DIM_LAYER2, activation='relu')(encode_layer1)
        encode_layer3 = Dense(ENCODING_DIM_LAYER3, activation='relu')(encode_layer2)
        encode_output = Dense(ENCODING_DIM_OUTPUT)(encode_layer3)
    
        # decoding layer
        decode_layer1 = Dense(ENCODING_DIM_LAYER3, activation='relu')(encode_output)
        decode_layer2 = Dense(ENCODING_DIM_LAYER2, activation='relu')(decode_layer1)
        decode_layer3 = Dense(ENCODING_DIM_LAYER1, activation='relu')(decode_layer2)
        decode_output = Dense(ENCODING_DIM_INPUT, activation='tanh')(decode_layer3)
    
        # build autoencoder, encoder
        autoencoder = Model(inputs=input_image, outputs=decode_output)
        encoder = Model(inputs=input_image, outputs=encode_output)
    
        # compile autoencoder
        autoencoder.compile(optimizer='adam', loss='mse')
    
        # training
        autoencoder.fit(x_train, x_train, epochs=EPOCHS, batch_size=BATCH_SIZE, shuffle=True)
    
        return encoder, autoencoder
    

    栈式自编码器相当于深度网络的过程,主要注意维度对应即可,另外,这里设置的encoder和decoder的维度是对称的。其架构图如下:

    (4)结果展示:

    (i)Eencoder结果的可视化如图:

    上图中不同表示表示不同的数字,由图可知,栈式自编码器的效果相比较普通自编码器好很多,这里基本能将10个分类全部分开。

    (ii)autoencoder还原之后的图片和原图片对比如下:

    三、欠完备自编码器(Undercomplete Autoencoder)

    1、欠完备自编码器的思想

    由上述自编码器的原理可知,当隐层单元数大于等于输入维度时,网络会发生完全记忆的情况,为了避免这种情况,我们限制隐层的维度一定要比输入维度小,这就是欠完备自编码器,如下图所示(图片来源:Introduction to autoencoders.)。 学习欠完备的表示将强制自编码器捕捉训练数据中最显著的特征。

    2、欠完备自编码器和主成分分析(PCA)的比较

    实际上,若同时满足下列条件,欠完备自编码器的网络等同于PCA,其会学习出于PCA相同的生成子空间:

    • 每两层之间的变换均为线性变换。
    • 目标函数L(x,g(f(x))L(x,g(f(x))为均方误差。

    因此,拥有非线性编码器函数ff和非线性解码器函数gg的自编码器能够学习出比PCA更强大的知识,其是PCA的非线性推广。下图是在二维空间中PCA算法和自编码器同时作用在二维点上做映射的结果(图片来源:Introduction to autoencoders.) ,从图中可以看出,自编码器具有更好的表达能力,其可以映射到非线性函数。

    3、欠完备自编码器特点

    • 防止过拟合,并且因为隐层编码维数小于输入维数,可以学习数据分布中最显著的特征。
    • 若中间隐层单元数特别少,则其表达信息有限,会导致重构过程比较困难。

    四、稀疏自编码器(Sparse Autoencoder)

    1、稀疏自编码器思想

    稀疏自编码器是加入正则化的自编码器,其未限制网络接收数据的能力,即不限制隐藏层的单元数。
    所谓稀疏性限制是指:

    若激活函数是sigmoid,则当神经元的输出接近于1的时候认为神经元被激活,输出接近于0的时候认为神经元被抑制。使得大部分神经元别抑制的限制叫做稀疏性限制。若激活函数是tanh,则当神经元的输出接近于-1的时候认为神经元是被抑制的。

    如上图所示(图片来源:Introduction to autoencoders. ),浅色的神经元表示被抑制的神经元,深色的神经元表示被激活的神经元。通过稀疏自编码器,我们没有限制隐藏层的单元数,但是防止了网络过度记忆的情况。
    稀疏自编码器损失函数的基本表示形式如下:
    Lsparse(x,g(f(x)))=L(x,g(f(x)))+Ω(h) L_{sparse}(x, g(f(x)))=L(x, g(f(x))) + \Omega (h)
    其中g(h)g(h)是解码器的输出,通常hh是编码器的输出,即h=f(x)h=f(x)

    2、损失函数和BP函数推导

    损失函数可以加入L1正则化,也可以加入KL散度,下面是对加入KL散度的损失函数的分析。
    损失函数的分析如下:
    假设aj(2)(x)a_j^{(2)}(x)表示在给定输入xx的情况下,自编码网络隐层神经元jj的激活度,则神经元在所有训练样本上的平均激活度为:
    ρj^=1mi=1m[aj(2)(xi)] \hat{\rho_j}=\frac{1}{m}\sum_{i=1}^{m}[a_j^{(2)}(x^{i})]
    其中,aj(2)=f(wj(1)x(i)+bj(1))a_j^{(2)}=f(w_j^{(1)}x^{(i)}+b_j^{(1)}),我们的目的使得网络激活神经元稀疏,所以可以引入一个稀疏性参数ρ\rho,通常ρ\rho是一个接近于0的值(即表示隐藏神经元中激活神经元的占比)。则若可以使得ρj^=ρ\hat{\rho_j}=\rho,则神经元在所有训练样本上的平均激活度ρj^\hat{\rho_j}便是稀疏的,这就是我们的目标。为了使得ρj^=ρ\hat{\rho_j}=\rho,我们使用KL散度衡量二者的距离,两者相差越大,KL散度的值越大,KL散度的公式如下:
    j=1s2KL(ρρj^)=j=1s2[ρlogρρj^+(1ρ)log1ρ1ρj^] \sum_{j=1}^{s_2}KL(\rho||\hat{\rho_j})=\sum_{j=1}^{s_2} [\rho \log \frac{\rho}{\hat{\rho_j}} + (1-\rho) \log \frac{1-\rho}{1-\hat{\rho_j}}]
    ρ\rho表示平均激活度的目标值。因此损失函数如下:
    Jsparse(W,b)=J(W,b)+βj=1s2KL(ρρj^) J_{sparse}(W,b)=J(W,b)+\beta \sum_{j=1}^{s_2}KL(\rho||\hat{\rho_j})
    其中J(W,b)J(W, b)便是NN网络中的普通的代价函数,可以使用均方误差等。

    反向传播的分析如下:
    上式代价函数,左部分就是之前BP的结果,结果如下:
    J(W,b)zi(2)=j=1s2Wji(2)J(W,b)zi(3)f(zi(2)) \frac{\partial J(W,b)}{ \partial z_i^{(2)}} = \sum_{j=1}^{s_2}W_{ji}^{(2)}\frac{\partial J(W,b)}{ \partial z_i^{(3)}}{f}'(z_i^{(2)})
    可参考反向传导算法

    右部分的求导如下:

    j=1s2KL(ρρj^)zi(2)=KL(ρρi^)zi(2)=KL(ρρi^)ρi^ρi^zi(2)=(ρlogρρi^+(1ρ)log1ρ1ρi^)ρi^ρi^zi(2)=(ρρi^+1ρ1ρi^)f(zi(2)) \begin{aligned} \frac{\partial \sum_{j=1}^{s_2}KL(\rho||\hat{\rho_j})}{\partial z_i^{(2)}} &= \frac{\partial KL(\rho||\hat{\rho_i})}{\partial z_i^{(2)}} \newline \\ &= \frac{\partial KL(\rho||\hat{\rho_i})}{\partial \hat{\rho_i}}\cdot \frac{\partial \hat{\rho_i}}{\partial z_i^{(2)}} \\ &= \frac{\partial(\rho \log \frac{\rho}{\hat{\rho_i}}+(1-\rho) \log \frac{1-\rho}{1-\hat{\rho_i}})}{\partial\hat{\rho_i}}\cdot \frac{\partial \hat{\rho_i}}{\partial z_i^{(2)}} \\ &= (-\frac{\rho}{\hat{\rho_i}} + \frac{1-\rho}{1-\hat{\rho_i}}) \cdot {f}'(z_i^{(2)}) \end{aligned}
    因此Jsparse(W,b)J_{sparse}(W,b)的求导结果如下:
    Jsparse(W,b)zi(2)=((j=1s2Wji(2)J(W,b)zi(3))+β(ρρi^+1ρ1ρi^))f(zi(2)) \frac{\partial J_{sparse}(W,b)}{ \partial z_i^{(2)}}= ((\sum_{j=1}^{s_2}W_{ji}^{(2)}\frac{\partial J(W,b)}{ \partial z_i^{(3)}})+ \beta(-\frac{\rho}{\hat{\rho_i}} + \frac{1-\rho}{1-\hat{\rho_i}})){f}'(z_i^{(2)})
    此即反向传播的方程,根据此方程可以参数WWbb进行更新。

    3、Mini-Batch的情况

    平均激活度是根据所有样本计算出来的,所以在计算任何单元的平均激活度之前,需要对所有样本计算一下正向传播,从而获得平均激活度,所以使用小批量时计算效率很低。要解决这个问题,可采取的方法是只计算Mini-Batch中包含的训练样本的平均激活度,然后在Mini-Batch之间计算加权值
    ρ^jt=λρ^jt1+(1λ)ρ^jt \hat{\rho}_j^t=\lambda\hat{\rho}_j^{t-1}+(1-\lambda)\hat{\rho}_j^t
    其中,ρ^jt\hat{\rho}_j^t是时刻tt的Mini-Batch的平均激活度,ρ^jt1\hat{\rho}_j^{t-1}是时刻t-1的Mini-Batch的平均激活度。若\lambda大,则时刻t1t-1的Mini-Batch的平均激活度所占比重大,否则,时刻t的Mini-Batch的平均激活度所占比重大。

    4、稀疏限制和L1/L2正则化的关系

    ①稀疏限制是对激活函数的结果增加限制,使得尽量多的激活函数的结果为0(如果激活函数是tanh,则为-1)
    ②L2/L1是对参数增加限制,使得尽可能多的参数为0。
    若自编码器编码函数f(wx+b)f(wx+b),若ff是一个线性函数,则编码器便可以写成wx+bwx+b,限制激活函数的结果尽量为0,即是限制ww尽量为0,此时稀疏限制和正则化限制相同。

    5、稀疏自编码器在分类中的应用

    稀疏自编码器一般用来学习特征,以便用于像分类这样的任务。如下图(图片来源:为什么稀疏自编码器很少见到多层的?):

    上述过程不是一次训练的,可以看到上面只有编码器没有解码器,因此其训练过程是自编码器先使用数据训练参数,然后保留编码器,将解码器删除并在后面接一个分类器,并使用损失函数来训练参数已达到最后效果。

    5、稀疏编码器实现与结果分析

    (1)框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def train(x_train):
    
        # input placeholder
        input_image = Input(shape=(ENCODING_DIM_INPUT, ))
    
        # encoding layer
        # *****!!! this code is changed compared with Autoencoder, adding the activity_regularizer to make the input sparse.
        encode_layer1 = Dense(ENCODING_DIM_LAYER1, activation='relu', activity_regularizer=regularizers.l1(10e-6))(input_image)
        # *******************************************************
        encode_layer2 = Dense(ENCODING_DIM_LAYER2, activation='relu')(encode_layer1)
        encode_layer3 = Dense(ENCODING_DIM_LAYER3, activation='relu')(encode_layer2)
        encode_output = Dense(ENCODING_DIM_OUTPUT)(encode_layer3)
    
        # decoding layer
        decode_layer1 = Dense(ENCODING_DIM_LAYER3, activation='relu')(encode_output)
        decode_layer2 = Dense(ENCODING_DIM_LAYER2, activation='relu')(decode_layer1)
        decode_layer3 = Dense(ENCODING_DIM_LAYER1, activation='relu')(decode_layer2)
        decode_output = Dense(ENCODING_DIM_INPUT, activation='tanh')(decode_layer3)
    
        # build autoencoder, encoder
        autoencoder = Model(inputs=input_image, outputs=decode_output)
        encoder = Model(inputs=input_image, outputs=encode_output)
    
        # compile autoencoder
        autoencoder.compile(optimizer='adam', loss='mse')
    
        # training
        autoencoder.fit(x_train, x_train, epochs=EPOCHS, batch_size=BATCH_SIZE, shuffle=True)
    
        return encoder, autoencoder
    

    这里是以多层的自编码器举例,单隐层的同样适用,主要是在第一层加一个正则化项,activity_regularizer=regularizers.l1(10e-6)说明加入的是L1正则化项,10e-6是正则化项系数,完整代码可参见最开始的git。其架构如下:

    (4)结果展示:
    (i)Encoder结果的可视化如图:

    上图中不同颜色表示不同的数字,由图可知,这个编码器的分类效果还可以,比自编码器好很多,但是看起来还是作用不大,因为大部分作用需要归功于栈式自编码器。

    (ii)autoencoder还原之后的图片和原图片对比如下:

    五、去噪自编码器(Denoising Autoencoder)

    1、去噪自编码器思想

    去噪自编码器是一类接受损失数据作为输入,并训练来预测原始未被损坏的数据作为输出的自编码器。 如下图所示(图片来自花书):

    其训练过程如下:
    引入一个损坏过程C(x~x)C(\tilde{x}|x),这个条件分布代表给定数据样本xx产生损坏样本x~\tilde{x}的概率。自编码器学习重构分布preconstruct(xx~)p_{reconstruct}(x|\tilde{x}):

    • 从训练数据中采一个训练样本xx
    • C(x~X=x)C(\tilde{x}|X=x)采一个损坏样本x~\tilde{x}
    • (x~,x)(\tilde{x}, x)作为训练样本来估计自编码器的重构分布preconstruct(xx~)=pdecoder(xh)p_{reconstruct}(x|\tilde{x})=p_{decoder}(x|h),其中hh是编码器f(x~)f(\tilde{x})的输出,pdecoderp_{decoder}根据解码函数g(h)g(h)定义。

    去噪自编码器中作者给出的直观解释是:和人体感官系统类似,比如人的眼睛看物体时,如果物体的某一小部分被遮住了,人依然能够将其识别出来,所以去噪自编码器就是破坏输入后,使得算法学习到的参数仍然可以还原图片。
    注: 噪声可以是添加到输入的纯高斯噪声,也可以是随机丢弃输入层的某个特性。

    2、去噪自编码器和Dropout

    噪声可以是添加到输入的纯高斯噪声,也可以是随机丢弃输入层的某个特性,即如果C(x~X=x)C(\tilde{x}|X=x)是一个二项分布,则其表现为下图所示内容,即经过处理的xx的结果是保留或者舍掉,也就是说,C(x~X=x)C(\tilde{x}|X=x)会舍去一部分内容,保留一部分内容:

    这个思想类似于Dropout,但是二者还有一些区别:

    (1) 去噪自编码器操作的是输入数据,相当于对输入数据去掉一部分内容;而Dropout操作的是网络隐藏层,相当于去掉隐藏层的一部分单元。
    (2) Dropout在分层预训练权值的过程中是不参与的,只是后面的微调部分会加入;而去噪自编码器是在每层预训练的过程中作为输入层被引入,在进行微调时不参与

    3、去噪自编码器和PCA

    去噪自编码器来源于论文[Vincent P, Larochelle H, Bengio Y, et al. Extracting and composing robust features with denoising autoencoders[C]//Proceedings of the 25th international conference on Machine learning. ACM, 2008: 1096-1103.]

    上图是去噪自编码器从流形角度的原理,图中黑色的曲线表示原始的局部流型,我们通过C(x~X=x)C(\tilde{x}|X=x)将其映射到一个圆的某一点,x~\tilde{x}表示添加噪声之后数据点。我们的目标是使得添加噪声之后的点能够映射到原始点,这样损失值为最小,即:图中红色箭头是噪声添加的向量场,而紫色部分是重构过程中需要不断查找的向量场。
    因此,可以理解为,去噪自编码器的局部就是简化的PCA原理,其是对PCA的非线性扩展。
    除此之外,文章还从信息论文、随机算子等角度理论上证明了去噪自编码器的可行性,有兴趣的读者可以参考上面提到的论文。

    4、去噪自编码器效果

    论文中的实验基于Minst数据集,其实验结果如下:

    其中,第一个和第二个baseline是使用高斯核和多项式核的SVM,DBN-1是1层隐层单元的深度信念网络,DBN-3是3层隐层单元的深度信念网络,SAA-3是使用栈式自编码器初始化之后的3层深度网络,最后的Sda-3是3层的栈式去噪自编码器。从表中可以看出,使用去噪自编码器的结果优于其他网络。
    除此之外,网站Denoising Autoencoders (dA)有去噪自编码器的代码和实验,其去噪前和去噪后过滤器的对比结果如下:

    左图是去噪之前的过滤器数据,右图是去噪之后的过滤器数据,从图中可以看出,去噪自编码器学习到的特征更具代表性。。

    5、去噪自编码器特点

    • 普通的自编码器的本质是学一个相等函数,即输入和输出是同一个内容,这种相等函数的缺点便是当测试样本和训练样本不符合同一个分布时,在测试集上效果不好,而去噪自编码器可以很好地解决这个问题。
    • 欠完备自编码器限制学习容量,而去噪自编码器允许学习容量很高,同时防止在编码器和解码器学习一个无用的恒等函数。
    • 经过了加入噪声并进行降噪的训练过程,能够强迫网络学习到更加鲁棒的不变性特征,获得输入的更有效的表达。

    6、去噪编码器实现与结果分析

    (1)框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def addNoise(x_train, x_test):
        """
        add noise.
        :return:
        """
        x_train_noisy = x_train + NOISE_FACTOR * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)
        x_test_noisy = x_test + NOISE_FACTOR * np.random.normal(loc=0.0, scale=1.0, size=x_test.shape)
    
        x_train_noisy = np.clip(x_train_noisy, 0., 1.)     # limit into [0, 1]
        x_test_noisy = np.clip(x_test_noisy, 0., 1.)   # limit into [0, 1]
    
        return x_train_noisy, x_test_noisy
    

    去噪自编码器主要是对输入添加噪声,所以训练过程是不需要改变的,只需要改变输入和输出。上述便是对输入添加噪声的过程,NOISE_FACTOR * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)便是添加的噪声。 np.clip()是截取函数,将数值限制在0~1之间。其架构如下:

    (4)结果展示:
    (i)Eencoder结果的可视化如图:

    上图中不同表示表示不同的数字,这里不是很直观,看下面的图片对比

    (ii)autoencoder还原之后的图片和原图片对比如下:

    上图是添加噪声的效果对比,第一行表示原数据,第二行表示噪声处理过后的数据。

    上图根据噪声数据还原图片的对比,第一行表示噪声处理过后的数据,第二行表示去噪自编码器decoder还原之后的结果,上图可以看出,去噪自编码器的效果还是可以的。

    六、卷积自编码器(convolutional Autoencoder)

    1、卷积自编码器思想

    卷积自编码器和普通自编码器的区别在于其encoder和decoder都是卷积神经网络,相应的,encoder使用的是卷积操作和池化操作,而decoder中使用的反卷积操作和反卷积操作,关于卷积、反卷积、池化和反池化的内容详见:[CNN] 卷积、反卷积、池化、反池化

    2、去噪编码器实现与结果分析

    (1)框架: Keras
    (2)数据集: Mnist手写数字识别
    (3)关键代码:

    def train(x_train):
        """
        build autoencoder.
        :param x_train:  the train data
        :return: encoder and decoder
        """
        # input placeholder
        input_image = Input(shape=(28, 28, 1))
    
        # encoding layer
        x = Conv2D(CHANNEL_1, (3, 3), activation='relu', padding="same")(input_image)
        x = MaxPool2D((2, 2), padding='same')(x)
        x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(x)
        encoded = MaxPool2D((2, 2), padding='same')(x)
    
        # decoding layer
        x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(encoded)
        x = UpSampling2D((2, 2))(x)
        x = Conv2D(CHANNEL_1, (3, 3),activation='relu', padding='same')(x)
        x = UpSampling2D((2, 2))(x)
        decoded = Conv2D(CHANNEL_OUTPUT, (3, 3), activation='sigmoid', padding='same')(x)
    
        # build autoencoder, encoder, decoder
        autoencoder = Model(inputs=input_image, outputs=decoded)
        encoder = Model(inputs=input_image, outputs=encoded)
    
        # compile autoencoder
        autoencoder.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    
        # training
        # need return history, otherwise can not use history["acc"]
        history_record = autoencoder.fit(x_train, x_train, epochs=EPOCHS, batch_size=BATCH_SIZE, shuffle=True, )
    
        return encoder, autoencoder, history_record
    

    注意:

    i)在Keras编码中,反卷积的实现代码便是卷积操作,具体解释详见上述博客。
    ii) UpSampling2D()实现的是反平均卷积的操作。

    autoencoder.summary()如下:

    代码架构图如下:

    (4)结果展示:
    (i)autoencoder还原之后的图片和原图片对比如下:

    上图根据原图片和生成图片的对比,第一行表示原图片,第二行表示卷积自编码器decoder还原之后的结果,上图可以看出,效果还是不错的。

    (ii)loss变化图:

    由上图可以看出,虽然loss在不断降低,但是accuracy还不是非常高,一方面是和参数相关,因为性能原因,在此文章版本上对epochs设置为20,另外,网络的深度也不够,也没有加入一些其他的提高性能的小技巧。



    其他参考文章:
    [1] Kandeng. 自编码算法与稀疏性[EB/OL]. (2018/11/24)[ 2018/11/24] http://ufldl.stanford.edu/wiki/index.php/自编码算法与稀疏性
    [2] Goodfellow I, Bengio Y, Courville A, et al. Deep learning[M]. Cambridge: MIT press, 2016.
    [3] 山下隆义. 图解深度学习[M]. 人民邮电出版社,2018:68-78
    [4] Francois Chollet. Building Autoencoders in Keras[EB/OL]. (2018/11/24)[ 2018/11/25] https://blog.keras.io/building-autoencoders-in-keras.html

    展开全文
  • 自从Hinton 2006年的工作之后,越来越多的研究者开始关注各种自编码器模型相应的堆叠模型。实际上,自编码器(Auto-Encoder)是一个较早的概念了,比如Hinton等人在1986, 1989年的工作。(说来说去都是这些人呐。。...

    自从Hinton 2006年的工作之后,越来越多的研究者开始关注各种自编码器模型相应的堆叠模型。实际上,自编码器(Auto-Encoder)是一个较早的概念了,比如Hinton等人在1986, 1989年的工作。(说来说去都是这些人呐。。。)

    自编码器简介

    先暂且不谈神经网络、深度学习,仅是自编码器的话,其原理很简单。自编码器可以理解为一个试图去还原其原始输入的系统。如下图所示:

    图中,虚线蓝色框内就是一个自编码器模型,它由编码器(Encoder)和解码器(Decoder)两部分组成,本质上都是对输入信号做某种变换。编码器将输入信号x变换成编码信号y,而解码器将编码y转换成输出信号\widetilde{x},即:

    y=f(x)

    \widetilde{x} = g(y) = g(f(x))

    而自编码器的目的是,让输出\widetilde{x}尽可能复现输入x,即tries to copy its input to its output。但是,这样问题就来了——如果f和g都是恒等映射,那不就恒有\widetilde{x}=x了?不错,确实如此,但这样的变换——没有任何卵用啊!因此,我们经常对中间信号y(也叫作“编码”)做一定的约束,这样,系统往往能学出很有趣的编码变换f和编码y。

    这里强调一点,对于自编码器,我们往往并不关系输出是啥(反正只是复现输入),我们真正关心的是中间层的编码,或者说是从输入到编码的映射。可以这么想,在我们强迫编码y和输入x不同的情况下,系统还能够去复原原始信号x,那么说明编码y已经承载了原始数据的所有信息,但以一种不同的形式!这就是特征提取啊,而且是自动学出来的!实际上,自动学习原始数据的特征表达也是神经网络和深度学习的核心目的之一。

    为了更好的理解自编码器,下面结合神经网络加以介绍。

    自编码器与神经网络

    神经网络的知识不再详细介绍,相信了解自编码器的读者或多或少会了解一些。简单来讲,神经网络就是在对原始信号逐层地做非线性变换,如下图所示:

    该网络把输入层数据x∈Rn转换到中间层(隐层)h∈Rp,再转换到输出层y∈Rm。图中的每个节点代表数据的一个维度(偏置项图中未标出)。每两层之间的变换都是“线性变化”+“非线性激活”,用公式表示即为:

    h=f(W(1)x+b(1))
    y=f(W(2)h+b(2)) 

    神经网络往往用于分类,其目的是去逼近从输入层到输出层的变换函数。因此,我们会定义一个目标函数来衡量当前的输出和真实结果的差异,利用该函数去逐步调整(如梯度下降)系统的参数(W(1),b(1),W(2),b(2)),以使得整个网络尽可能去拟合训练数据。如果有正则约束的话,还同时要求模型尽量简单(防止过拟合)。

    那么,自编码器怎么表示呢?前面已说过,自编码器试图复现其原始输入,因此,在训练中,网络中的输出应与输入相同,即y=x,因此,一个自编码器的输入、输出应有相同的结构,即:

    我们利用训练数据训练这个网络,等训练结束后,这个网络即学习出了x→h→x的能力。对我们来说,此时的h是至关重要的,因为它是在尽量不损失信息量的情况下,对原始数据的另一种表达。结合神经网络的惯例,我们再将自编码器的公式表示如下:(假设激活函数是sigmoid,用s表示)

    y = f\theta (x) = s(Wx+b)

    \widetilde{x} = g\theta '(y) = s(W'y+b')

    L(x,\widetilde{x}) = L(x,g(f(x)))

    其中,L表示损失函数,结合数据的不同形式,可以是二次误差(squared error loss)或交叉熵误差(cross entropy loss)。如果W' = W^{T},一般称为tied weights。

    为了尽量学到有意义的表达,我们会给隐层加入一定的约束。从数据维度来看,常见以下两种情况:

    • n>p,即隐层维度小于输入数据维度。也就是说从x→h的变换是一种降维的操作,网络试图以更小的维度去描述原始数据而尽量不损失数据信息。实际上,当每两层之间的变换均为线性,且监督训练的误差是二次型误差时,该网络等价于PCA!没反应过来的童鞋可以反思下PCA是在做什么事情。

     

    • n<p,即隐层维度大于输入数据维度。这又有什么用呢?其实不好说,但比如我们同时约束h的表达尽量稀疏(有大量维度为0,未被激活),此时的编码器便是大名鼎鼎的“稀疏自编码器”。可为什么稀疏的表达就是好的?这就说来话长了,有人试图从人脑机理对比,即人类神经系统在某一刺激下,大部分神经元是被抑制的。个人觉得,从特征的角度来看更直观些,稀疏的表达意味着系统在尝试去特征选择,找出大量维度中真正重要的若干维。

    堆叠自编码器

    有过深度学习基础的童鞋想必了解,深层网络的威力在于其能够逐层地学习原始数据的多种表达。每一层的都以底一层的表达为基础,但往往更抽象,更加适合复杂的分类等任务。

    堆叠自编码器实际上就在做这样的事情,如前所述,单个自编码器通过虚构x→h→x的三层网络,能够学习出一种特征变化h=fθ(x)(这里用θ表示变换的参数,包括W,b和激活函数)。实际上,当训练结束后,输出层已经没什么意义了,我们一般将其去掉,即将自编码器表示为:

    之前之所以将自编码器模型表示为3层的神经网络,那是因为训练的需要,我们将原始数据作为假想的目标输出,以此构建监督误差来训练整个网络。等训练结束后,输出层就可以去掉了,我们关心的只是从x到h的变换。

    接下来的思路就很自然了——我们已经得到特征表达h,那么我们可不可以将h再当做原始信息,训练一个新的自编码器,得到新的特征表达呢?当然可以!这就是所谓的堆叠自编码器(Stacked Auto-Encoder, SAE)。Stacked就是逐层垒叠的意思,跟“栈”有点像。UFLDL教程将其翻译为“栈式自编码”,anyway,不管怎么称呼,都是这个东东,别被花里胡哨的专业术语吓到就行。当把多个自编码器Stack起来之后,这个系统看起来就像这样:

    亦可赛艇!这个系统实际上已经有点深度学习的味道了,即learning multiple levels of representation and abstraction(Hinton, Bengio, LeCun, 2015)。需要注意的是,整个网络的训练不是一蹴而就的,而是逐层进行。按题主提到的结构n,m,k结构,实际上我们是先训练网络n→m→n,得到n→m的变换,然后再训练m→k→m,得到m→k的变换。最终堆叠成SAE,即为n→m→k的结果,整个过程就像一层层往上盖房子,这便是大名鼎鼎的layer-wise unsuperwised pre-training(逐层非监督预训练),正是导致深度学习(神经网络)在2006年第3次兴起的核心技术。

    关于逐层预训练与深度学习,将在本文最后探讨。

    自编码器的变种形式

    上述介绍的自编码器是最基本的形式。善于思考的童鞋可能已经意识到了这个问题:隐层的维度到底怎么确定?为什么稀疏的特征比较好?或者更准确的说,怎么才能称得上是一个好的表达(What defines a good representation)?

    事实上,这个问题回答并不唯一,也正是从不同的角度去思考这个问题,导致了自编码器的各种变种形式出现。目前常见的几种模型总结如下(有些术语实在不好翻译,看英文就好。。。)

    下面简介下其中两种模型,以对这些变种模型有个直观感受。

    稀疏自编码器

    UFLDL-自编码算法与稀疏性对该模型有着比较详细的介绍。如前所示,这种模型背后的思想是,高维而稀疏的表达是好的。一般而言,我们不会指定隐层表达h中哪些节点是被抑制的(对于sigmoid单元即输出为0),而是指定一个稀疏性参数ρ,代表隐藏神经元的平均活跃程度(在训练集上取平均)。比如,当ρ=0.05时,可以认为隐层节点在95%的时间里都是被一直的,只有5%的机会被激活。实际上,为了满足这一条件,隐层神经元的活跃度需要接近于0。

    那么,怎么从数学模型上做到这点呢?思路也不复杂,既然要求平均激活度为ρ,那么只要引入一个度量,来衡量神经元ii的实际激活度\widetilde{\rho _{a}}与期望激活度ρ之间的差异即可,然后将这个度量添加到目标函数作为正则,训练整个网络即可。那么,什么样的度量适合这个任务呢?有过概率论、信息论基础的同学应该很容易想到它——相对熵,也就是KL散度(KL divergence)。因此,整个网络所添加的惩罚项即为:

    \sum_{i\in h}KL(\rho ||\widetilde{\rho _{a}} )

    具体的公式不再展开,可以从下图(摘自UFLDL)中直观理解KL散度作为惩罚项的含义。图中假设平均激活度ρ=0.2。

    可以看出,当^ρiρ^i一旦偏离期望激活度ρρ,这种误差便急剧增大,从而作为惩罚项添加到目标函数,指导整个网络学习出稀疏的特征表达。

    降噪自编码器

    关于降噪自编码器,强烈推荐其作者Pascal Vincent的论文Stacked Denoising Autoencoders: Learning Useful Representations in a Deep Network with a Local Denoising Criterion。DAE的核心思想是,一个能够从中恢复出原始信号的表达未必是最好的,能够对“被污染/破坏”的原始数据编码、解码,然后还能恢复真正的原始数据,这样的特征才是好的。

    稍微数学一点,假设原始数据x被我们“故意破坏”,比如加入高斯白噪,或者把某些维度数据抹掉,变成了\overline{x},然后再对\overline{x}编码、解码,得到恢复信号\widetilde{x} = g(f(x)),该恢复信号尽可能逼近未被污染的数据xx。此时,监督训练的误差从L(x,g(f(x)))变成了L(x,g(f(\widetilde{x}))。

    直观上理解,DAE希望学到的特征变换尽可能鲁棒,能够在一定程度上对抗原始数据的污染、缺失。Vincent论文里也对DAE提出了基于流行的解释,并且在图像数据上进行测试,发现DAE能够学出类似Gabor边缘提取的特征变换。注意,这一切都是在我们定义好规则、误差后,系统自动学出来的!从而避免了领域专家费尽心力去设计这些性能良好的特征。

    DAE的系统结构如下图(摘自Vincent论文)所示:

    现在使用比较多的noise主要是mask noise,即原始数据中部分数据缺失,这是有着很强的实际意义的,比如图像部分像素被遮挡、文本因记录原因漏掉了一些单词等等。

    其他的模型就不再展开了,总之,每遇到一个自编码器的一个变种模型时,搞清楚其背后的思想(什么样的表达才是好的),就很容易掌握了。套用V的”Behind this mask is a man, and behind this man is an idea, and ideas are bulletproof”,我们可以说,”Behind this auto-encoder is a model, and behind this model is an idea, and ideas are bulletproof”。

    转自:https://www.zhihu.com/question/41490383/answer/103006793

    展开全文
  • 主要介绍了keras自动编码器实现系列之卷积自动编码器操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,606
精华内容 5,042
关键字:

自编码器