第十五章——自编码器(Autoencoders)[通俗易懂]

第十五章——自编码器(Autoencoders)[通俗易懂]本文介绍了一种人工神经网络——自编码器

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

自编码器是一种能够通过无监督学习,学到输入数据高效表示的人工神经网络。输入数据的这一高效表示称为编码(codings),其维度一般远小于输入数据,使得自编码器可用于降维(查看第八章)。更重要的是,自编码器可作为强大的特征检测器(feature detectors),应用于深度神经网络的预训练(查看第十一章)。此外,自编码器还可以随机生成与训练数据类似的数据,这被称作生成模型(generative model)。比如,可以用人脸图片训练一个自编码器,它可以生成新的图片。

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

15.1 高效的数据表示

下面有两组数字,哪组更容易记忆呢?

  • 40, 27, 25, 36, 81, 57, 10, 73, 19, 68
  • 50, 25, 76, 38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20

乍一看可能觉得第一行数字更容易记忆,毕竟更短。但仔细观察就会发现,第二组数字是有规律的:偶数后面是其二分之一,奇数后面是其三倍加一(这就是著名的hailstone sequence)。如果识别出了这一模式,第二组数据只需要记住这两个规则、第一个数字、以及序列长度。如果你的记忆能力超强,可以记住很长的随机数字序列,那你可能就不会去关心一组数字是否存在规律了。所以我们要对自编码器增加约束来强制它去探索数据中的模式。

记忆(memory)、感知(perception)、和模式匹配(pattern matching)的关系在1970s早期就被William Chase和Herbert Simon研究过。他们发现国际象棋大师观察棋盘5秒,就能记住所有棋子的位置,而常人是无法办到的。但棋子的摆放必须是实战中的棋局(也就是棋子存在规则,就像第二组数字),棋子随机摆放可不行(就像第一组数字)。象棋大师并不是记忆力优于我们,而是经验丰富,很擅于识别象棋模式,从而高效地记忆棋局。

和棋手的记忆模式类似,一个自编码器接收输入,将其转换成高效的内部表示,然后再输出输入数据的类似物。自编码器通常包括两部分:encoder(也称为识别网络)将输入转换成内部表示,decoder(也称为生成网络)将内部表示转换成输出。(如图15-1)

第十五章——自编码器(Autoencoders)[通俗易懂]

图15-1 象棋大师的记忆模式(左)和一个简单的自编码器

正如上图所示,自编码器的结构和多层感知机(查看第十章)类似,除了输入神经元和输出神经元的个数相等。在上图的例子中,自编码器只有一个包含两个神经元的隐层(encoder),以及包含3个神经元的输出层(decoder)。输出是在设法重建输入,损失函数是重建损失(reconstruction loss)。

由于内部表示(也就是隐层的输出)的维度小于输入数据(用2D取代了原来的3D), 这称为不完备自编码器(undercomplete autoencoder)。

undercomplete应该是个数学概率,不用深究了,毕竟在Wikipedia上面的解释只有一句话Describing a frame (in linear algebra) having a set of functions less than a basis

15.2 不完备线性自编码器实现PCA(Performing PCA with an Undercomplete Linear Autoencoder)

如果自编码器使用线性激活函数并且损失函数是均方差(Mean Squared Error,MSE),那它就可以用来实现主成分分析(查看第八章)。

下面的代码实现了一个简单的线性自编码器,将3D数据投影为2D:

import tensorflow as tf
from tensorflow.contrib.layers import fully_connected

n_inputs = 3 # 3D inputs
n_hidden = 2 # 2D codings
n_outputs = n_inputs

learning_rate = 0.01

X = tf.placeholder(tf.float32, shape=[None, n_inputs])
hidden = fully_connected(X, n_hidden, activation_fn=None)
outputs = fully_connected(hidden, n_outputs, activation_fn=None)

reconstruction_loss = tf.reduce_mean(tf.square(outputs - X)) # MSE

optimizer = tf.train.AdamOptimizer(learning_rate)
training_op = optimizer.minimize(reconstruction_loss)

init = tf.global_variables_initializer()

然后载入数据集,在训练集上训练模型,并对测试集进行编码(也就是投影为2D):

X_train, X_test = [...] # load the dataset

n_iterations = 1000
codings = hidden # the output of the hidden layer provides the codings

with tf.Session() as sess:
    init.run()
    for iteration in range(n_iterations):
        training_op.run(feed_dict={X: X_train}) # no labels (unsupervised)
    codings_val = codings.eval(feed_dict={X: X_test})

15.3 栈式自编码器(Stacked Autoencoders)

和其他的神经网络一样,自编码器可以有多个隐层,这被称作栈式自编码器(或者深度自编码器)。增加隐层可以学到更复杂的编码,但千万不能使自编码器过于强大。想象一下,一个encoder过于强大,它仅仅是学习将输入映射为任意数(然后decoder学习其逆映射)。很明显这一自编码器可以很好的重建数据,但它并没有在这一过程中学到有用的数据表示。(而且也不能推广到新的实例)

栈式自编码器的架构一般是关于中间隐层对称的,如图15-3所示。

第十五章——自编码器(Autoencoders)[通俗易懂]

图15-3 栈式自编码器

15.3.1 TensorFlow 实现

参考:本书代码

15.3.2 捆绑权重

如果一个自编码器的层次是严格轴对称的(如图15-3),一个常用的技术是将decoder层的权重捆绑到encoder层。这使得模型参数减半,加快了训练速度并降低了过拟合风险。具体的,假设自编码器一共有$N$层(不算输入层),$W_L$表示第$L$层的权重(例如,第一层是第一个隐层,第$\frac{2}{N}$层是编码层,第$N$层是输出层),那么decoder层的权重可以表示为$W_{N-L+1} = W_L^T \ , L = 1,2,\cdots ,\frac{N}{2}$。

不过偏置项不会捆绑。

15.3.3 一次训练一个自编码器

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

第十五章——自编码器(Autoencoders)[通俗易懂]

图15-4 一次训练一个浅层自编码器

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

另一个实现方法首先创建一个包含完整栈式编码器的图,然后再每一个训练时期增加额外的操作,如图15-5:

第十五章——自编码器(Autoencoders)[通俗易懂]

图15-5 

其中,

  • 中间的一列是完整的栈式编码器,这部分在训练完成之后可以使用。
  • 左侧一列是最先需要训练的,它跳过第二和第三个隐层,直接创建一个输出层。这个输出层与栈式自编码器的输出层共享同样的权重和偏置。
  • 随后是右侧一列的训练。它使得第三个隐层的输出与第一个隐层的输出尽可能的接近。

15.4 使用栈式自编码器进行无监督预训练

正如第十一章所讨论的,如果我们要处理一个复杂的有监督学习问题又没有足够的标注数据,一个解决方案是找到一个解决类似任务的训练好的模型,复用低层。类似的,如果有一个很大的数据集但绝大部分是未标注数据,可以使用所有的数据先训练一个栈式自编码器,然后复用低层来完成真正的任务。如图15-8所示:

图15-8 使用自编码器进行无监督预训练

图15-8 使用自编码器进行无监督预训练

15.5 去噪自编码器

另一种强制自编码器学习有用特征的方式是最输入增加噪声,通过训练之后得到无噪声的输出。这防止了自编码器简单的将输入复制到输出,从而提取出数据中有用的模式。如图15-9左侧所示。

使用自编码器去燥的思想在1980s提出(比如,在1987年Yann LeCun的硕士论文中有所提及)。在一篇2008年的论文中,Pascal Vincent等人表明自编码器可用于特征提取。在一篇2010年的论文中,Vincent等人提出栈式去燥自编码器(stacked denoising autoencoders)。

噪声可以是添加到输入的纯高斯噪声,也可以是随机丢弃输入层的某个特征,类似于dropout。如图15-9右侧所示。

第十五章——自编码器(Autoencoders)[通俗易懂]

图15-9 图中自编码器,通过高斯噪声(左)或者Dropout(右)

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/166734.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 【spring】Spring事件监听器ApplicationListener的使用与源码分析

    【spring】Spring事件监听器ApplicationListener的使用与源码分析ApplicationEvent以及Listener是Spring为我们提供的一个事件监听、订阅的实现,内部实现原理是观察者设计模式,设计初衷也是为了系统业务逻辑之间的解耦,提高可扩展性以及可维护性。事件发布者并不需要考虑谁去监听,监听具体的实现内容是什么,发布者的工作只是为了发布事件而已。Spring提供的内置事件:ContextRefreshedEvent:容器刷新事件ContextStartedEvent:容器启动事件ContextStoppedEvent:容器停止事件ContextClo

    2025年6月30日
    4
  • set和list转换_list和set

    set和list转换_list和setset集合元素唯一,无序;list集合元素可以重复,有序。1、set转list:数据保持不变,顺序发生变化,可以使用Collections.sort进行排序(Collections.shuffle随机排序,Collections.reverse反转顺序)。2、list转set:去除重复数据,只保留一个。转成linkedHashSet时,原顺序不变;转成treeSet可以排序

    2022年10月10日
    4
  • qmake介绍

    qmake介绍文章目录简单介绍下qmake简要介绍关于pro文件构建一个项目使用第三方库预编译头文件让我们开始试试吧从一个简单的例子开始允许程序可以Debug添加特定平台的源文件设置当文件不存在的时候就停止qmake检查多个条件qmake可以帮助我们在跨平台构建应用程序的时候变得更简单,我们可以通过写简单的几行必要的信息来生成构建文件,我们可以在任何的软件项目中使用qmakeqmake基于pro文件生产构建…

    2022年5月19日
    87
  • springmvc过滤器和拦截器的区别_拦截器和过滤器的区别面试

    springmvc过滤器和拦截器的区别_拦截器和过滤器的区别面试SpringMVC中的过滤器和拦截器文章目录SpringMVC中的过滤器和拦截器一、过滤器二、拦截器三、小结一、过滤器​ 过滤器Filter是通过实现java.servlet.filter接口实现过滤器功能,作用是用于对传入的request和响应的response进行一些处理,比如对请求参数进行校验,或者设置、检验头部信息,再或者对一些非法行为进行校验。由实现的接口可知,过滤器是依赖于servlet容器。所以由于过滤器不依赖于spring容器,它也就无法获取到容器中的对象。创建一个过滤器类继承j

    2022年8月23日
    6
  • c# 操作ad域用户

    c# 操作ad域用户测试环境:win2008r2服务器ad域服务器安装参考:https://www.cnblogs.com/cnjavahome/p/9029665.html密码策略修改参考:https://blog.csdn.net/zouyujie1127/article/details/40857675工作机dns设置为ad域服务器的ipusing:usingSystem.DirectoryServ…

    2022年5月16日
    123
  • 本地数据库同步到云主机上

    本地数据库同步到云主机上同步前的准备:首先你本地跟云主机上都要有数据库、可视化的辅助工具(我用的NavicatPremium,其他的也都一个道理),这里靠的就是这个NavicatPremium工具1.首先在云主机上创建一个链接,建一个数据库,最好是与本地数据库同名2.在本地新建一个连接,可以点击下边的链接测试,测试一下看看是否能连接成功3.找到工具栏里的:工具->数据传输4.经过上述三步你最起码有了两个连接

    2022年5月25日
    41

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号