专栏首页相约机器人在TensorFlow 2.0中实现自动编码器

在TensorFlow 2.0中实现自动编码器

作者 | Abien Fred Agarap

来源 | Medium

编辑 | 代码医生团队

Google宣布对全球最受欢迎的开源机器学习库TensorFlow进行重大升级,承诺注重简单性和易用性,eager execution,直观的高级API以及在任何平台上灵活构建模型。

这篇文章是一个尝试,为TensorFlow 2.0工作的实体做出贡献。将讨论自动编码器的子类API实现。

https://www.tensorflow.org/guide/keras#model_subclassing

要安装TensorFlow 2.0,建议为其创建虚拟环境,

pip install tensorflow==2.0.0-alpha

或者如果系统中有GPU,

pip install tensorflow-gpu==2.0.0-alpha

其安装的更多细节请查看tensorflow.org上的指南。

https://www.tensorflow.org/install

在深入研究代码之前,首先讨论一下自动编码器是什么。

自动编码器

处理机器学习中的大量数据,这自然会导致更多的计算。但是可以选择对模型学习贡献最大的数据部分,从而减少计算量。选择数据重要部分的过程称为特征选择,它是自动编码器的用例之一。

究竟什么是自动编码器?首先回忆一下,一个神经网络是一个用于计算模型找到一个函数 描述的关系数据之间的特征 x和其值(一个回归任务)或标签(一个分类任务) y ,即( y = f(x))。自动编码器也是一个神经网络。而不是找到函数映射的功能 x到其相应的值或标签y,它的目的是找到函数映射功能x本身x。

自动编码器内部会发生什么。用一个自动编码器的图形说明。

自动编码器是一种人工神经网络,旨在学习如何重建数据。

从上图可以看出,自动编码器由两部分组成:(1)学习数据表示的编码器,即数据的重要特征z,以及(2)基于其如何根据其思想z重建数据的解码器结构化。

确定自动编码器想要找到将x映射到x的函数。它通过其组件实现。在数学上,

z是编码器从输入数据x获知的学习数据。

x-hat是解码器基于学习的表示z的重建数据。

所述编码器 H-SUB-E学习数据表示z从输入特征x,则所述表示作为输入到解码器 H-SUB-d ,以重构原始数据x。

下面进一步剖析这个模型。

编码器

第一个组件,即编码器,类似于传统的前馈网络。但是它不负责预测值或标签。相反它的任务是了解数据的结构,即数据表示z。

所述编码器学习给定的数据的表示。

该编码是通过将数据输入完成X到编码器的隐蔽层h为了学习数据表示z = f(h(x)) 。可以Encoder按如下方式实现该层

class Encoder(tf.keras.layers.Layer):

  def __init__(self, intermediate_dim):

    super(Encoder, self).__init__()

    self.hidden_layer = tf.keras.layers.Dense(units=intermediate_dim, activation=tf.nn.relu)

    self.output_layer = tf.keras.layers.Dense(units=intermediate_dim, activation=tf.nn.relu)



  def call(self, input_features):

    activation = self.hidden_layer(input_features)

    return self.output_layer(activation)

该编码器的层自动编码写入TensorFlow 2.0子类API。

首先定义一个Encoder 继承的类,将tf.keras.layers.Layer其定义为层而不是模型。为什么是图层而不是模型?回想一下,编码器是一个组件的的自动编码器模型。

通过代码,该Encoder层被定义为具有单个隐藏的神经元层(self.hidden_layer)以学习输入特征的激活。然后将隐藏层连接到一个层(self.output_layer),该层将数据表示编码为较低维度,其中包含它认为重要的特征。因此Encoder层的“输出” 是输入数据x的学习数据表示z。

解码器

第二个组件即解码器也类似于前馈网络。但是它不是将数据减少到较低维度,而是将数据从其较低维度表示z重建为其原始维度x。

所述解码器学习从其低维表示重构数据。

该解码是通过将低维表示完成z到解码器的隐藏层h为了重建数据到其原始尺寸x = f(h(z))。可以按如下方式实现解码器

class Decoder(tf.keras.layers.Layer):

  def __init__(self, intermediate_dim, original_dim):

    super(Decoder, self).__init__()

    self.hidden_layer = tf.keras.layers.Dense(units=intermediate_dim, activation=tf.nn.relu)

    self.output_layer = tf.keras.layers.Dense(units=original_dim, activation=tf.nn.relu)



  def call(self, code):

    activation = self.hidden_layer(code)

    return self.output_layer(activation)

该解码器的层自动编码写入TensorFlow 2.0子类API。

定义一个Decoder也继承了它的类tf.keras.layers.Layer。

该Decoder层还被定义为具有单个隐藏的神经元层,以通过编码器从学习的表示重建输入特征。然后将其隐藏层连接到一个层,该层将数据表示从较低维度解码为其原始维度。因此解码器层的“输出”是来自数据表示z的重建数据x。最终解码器的输出是自动编码器的输出。

现在已经定义了autoencoder的组件,最终可以构建模型。

构建Autoencoder模型

现在可以通过实例化层和层来构建自动编码器模型。EncoderDecoder

class Autoencoder(tf.keras.Model):

  def __init__(self, intermediate_dim, original_dim):

    super(Autoencoder, self).__init__()

    self.encoder = Encoder(intermediate_dim=intermediate_dim)

    self.decoder = Decoder(intermediate_dim=intermediate_dim, original_dim=original_dim)



  def call(self, input_features):

    code = self.encoder(input_features)

    reconstructed = self.decoder(code)

    return reconstructed

用TensorFlow 2.0子类化API编写的自动编码器模型。

如上所述使用编码器层的输出作为解码器层的输入。就是这样了?不,不完全是。

到目前为止只讨论了自动编码器的组件以及如何构建它,但还没有讨论它是如何实际学习的。到目前为止所知道的只是数据流 ; 从输入层到学习数据表示的编码器层,并使用该表示作为重构原始数据的解码器层的输入。

与其他神经网络一样,自动编码器通过反向传播进行学习。然而不是比较模型的值或标签,而是比较重建数据 x-hat和原始数据x。将这个比较称为重建误差函数,它由下式给出,

在这种情况下,重建损失是您可能熟悉的均方误差函数。

在TensorFlow中,上述等式可表示如下,

def loss(model, original):

  reconstruction_error = tf.reduce_mean(tf.square(tf.subtract(model(original), original)))

  return reconstruction_error

使用TensorFlow核心操作编写的重建损失。

还有一些要添加的东西。现在已经定义了损失函数,最终可以为模型编写训练函数。

def train(loss, model, opt, original):

  with tf.GradientTape() as tape:

    gradients = tape.gradient(loss(model, original), model.trainable_variables)

    gradient_variables = zip(gradients, model.trainable_variables)

    opt.apply_gradients(gradient_variables)

训练函数用TensorFlow 2.0编写,遵循通过使用GradientTape强制编写前向传递的范例。

这种实现反向传播的方式能够跟踪梯度以及优化算法的应用。

http://ruder.io/optimizing-gradient-descent/

在此之前,实例化一个Autoencoder之前定义的类,以及一个要使用的优化算法。然后加载想要重建的数据。这篇文章使用MNIST手写数字数据集。

http://yann.lecun.com/exdb/mnist/

可以使用TensorBoard可视化训练结果,需要使用为结果定义摘要文件编写器tf.summary.create_file_writer。

autoencoder = Autoencoder(intermediate_dim=64, original_dim=784)

opt = tf.optimizers.SGD(learning_rate=learning_rate, momentum=momentum)



(training_features, _), (test_features, _) = tf.keras.datasets.mnist.load_data()

training_features = training_features / np.max(training_features)

training_features = training_features.reshape(training_features.shape[0],

                                              training_features.shape[1] * training_features.shape[2]).astype(np.float32)

training_dataset = tf.data.Dataset.from_tensor_slices(training_features).batch(batch_size)



writer = tf.summary.create_file_writer('tmp')



with writer.as_default():

  with tf.summary.record_if(True):

    for epoch in range(epochs):

      for step, batch_features in enumerate(training_dataset):

        train(loss, autoencoder, opt, batch_features)

        loss_values = loss(autoencoder, batch_features)

        original = tf.reshape(batch_features, (batch_features.shape[0], 28, 28, 1))

        reconstructed = tf.reshape(autoencoder(tf.constant(batch_features)), (batch_features.shape[0], 28, 28, 1))

        tf.summary.scalar('loss', loss_values, step=step)

        tf.summary.image('original', original, max_outputs=10, step=step)

        tf.summary.image('reconstructed', reconstructed, max_outputs=10, step=step)

实例化自动编码器模型和优化功能。加载MNIST数据集。最后循环训练自编码器模型。

接下来使用定义的摘要文件编码器,并使用记录训练摘要tf.summary.record_if。

终于可以(现在真实地)训练模型,通过为它提供小批量数据,并通过之前定义的train函数计算其每次迭代的损失和梯度,该函数接受定义的误差函数,自动编码器模型,优化算法,以及小批量的数据。

在训练模型的每次迭代之后,计算的重建误差应该减小以查看模型是否实际学习(就像在其他神经网络中一样)。最后为了在TensorBoard中记录训练摘要,使用tf.summary.scalar记录重建误差值,以及tf.summary.image记录原始数据和重建数据的小批量。

在一些epochs之后,可以开始看到MNIST图像的相对良好的重建。

MNIST手写数字数据集的结果。顶行的图像是原始图像,而底行的图像是重建的图像。

重建的图像可能足够好,但它们非常模糊。可以做很多事情来改善这个结果,例如添加更多层和/或神经元,或者使用卷积神经网络架构作为自动编码器模型的基础,或者使用不同类型的自动编码器。

总结

自动编码器对降低维数非常有用。但它也可以用于数据去噪,以及用于学习数据集的分布。希望在本文中已经涵盖了足够的内容,让您了解有关自动编码器的更多信息!

完整代码链接

https://gist.github.com/AFAgarap/326af55e36be0529c507f1599f88c06e

参考

  • MartínAbadi,Ashish Agarwal,Paul Barham,Eugene Brevdo,Zhifeng Chen,Craig Citro,Greg S. Corrado,Andy Davis,Jeffrey Dean,Matthieu Devin,Sanjay Ghemawat,Ian Goodfellow,Andrew Harp,Geoffrey Irving,Michael Isard,Rafal Jozefowicz, Yangqing Jia,Lukasz Kaiser,Manjunath Kudlur,Josh Levenberg,DanMané,Mike Schuster,Rajat Monga,Sherry Moore,Derek Murray,Chris Olah,Jonathon Shlens,Benoit Steiner,Ilya Sutskever,Kunal Talwar,Paul Tucker,Vincent Vanhoucke,Vijay Vasudevan ,FernandaViégas,Oriol Vinyals,Pete Warden,Martin Wattenberg,Martin Wicke,Yuan Yu和Zhengqiang Zheng。TensorFlow:

2015 年异构系统上的大规模机器学习。

  • Chollet,F。(2016年5月14日)。在Keras建立自动编码器。2019年3月19日检索自

https://blog.keras.io/building-autoencoders-in-keras.html

  • Goodfellow,I.,Bengio,Y。,&Courville,A。(2016)。深度学习。麻省理工学院出版

本文分享自微信公众号 - 相约机器人(xiangyuejiqiren),作者:代码医生

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-03-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Auto-Tinder-训练AI玩打火机刷卡游戏

    Auto Tinder是一个纯粹出于娱乐和教育目的而创建的概念项目。绝不能滥用它来伤害任何人或向平台发送垃圾邮件。自动绑定脚本不应与您的绑定文件一起使用,因为它...

    代码医生工作室
  • 使用BERT和TensorFlow构建搜索引擎

    基于神经概率语言模型的特征提取器,例如与多种下游NLP任务相关的BERT提取特征。因此它们有时被称为自然语言理解(NLU)模块。

    代码医生工作室
  • 在MNIST数据集上使用Pytorch中的Autoencoder进行维度操作

    现在根据深度学习书,自动编码器是一种神经网络,经过训练旨在将其输入复制到其输出。在内部,它有一个隐藏层,用于描述用于表示输入的代码。网络可被视为由两部分组成:编...

    代码医生工作室
  • 安装mysql8.0.11以及修改root密码、连接navicat for mysql。

      最近在学习node.js,少不得要跟数据库打交道,于是打算安装一个数据库软件,在mongedb和mysql之间选择了mysql。作为一个数据库新人不敢评论孰...

    拓荒者
  • 安装mysql8.0.11以及修改root密码、连接navicat for mysql

     最近在学习node.js,少不得要跟数据库打交道,于是打算安装一个数据库软件,在mongedb和mysql之间选择了mysql。作为一个数据库新人不敢评论孰...

    拓荒者
  • scRNA_seq:单细胞转录组测序简介

    在传统的测序技术中,上机测序的样本是由多个细胞构成的,最后分析得出的结论也只是基于所有细胞的平均水平,但是我们知道细胞是具有异质性的,对于大脑等复杂组织而言,其...

    生信修炼手册
  • 码农技术炒股之路——数据库管理器、正则表达式管理器

            我选用的数据库是Mysql。选用它是因为其可以满足我的需求,而且资料多。因为作为第三方工具,难免有一些配置问题。所以本文也会讲解一些和Mysql...

    方亮
  • 动态规划之三维01背包问题

    动态规划问题是学习算法时一个尤为重要的内容,在讲解什么是动态规划之前,首先来讲一下分而治之。

    不可言诉的深渊
  • tensorflow: 打印内存中的变量

    Petrichor_
  • 大数据HelloWorld-Flink实现WordCount

    开始Flink之前先在本机尝试安装一下Flink,当然FLink正常情况下是部署的集群方式。作者比较穷,机器配置太低开不了几个虚拟机。所以只能先演示个单机的安装...

    CainGao

扫码关注云+社区

领取腾讯云代金券