前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在TensorFlow 2.0中实现自动编码器

在TensorFlow 2.0中实现自动编码器

作者头像
代码医生工作室
发布2019-06-21 17:40:55
3.2K2
发布2019-06-21 17:40:55
举报
文章被收录于专栏:相约机器人相约机器人

作者 | Abien Fred Agarap

来源 | Medium

编辑 | 代码医生团队

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

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

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

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

代码语言:javascript
复制
pip install tensorflow==2.0.0-alpha

或者如果系统中有GPU,

代码语言:javascript
复制
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按如下方式实现该层

代码语言:javascript
复制
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))。可以按如下方式实现解码器

代码语言:javascript
复制
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

代码语言:javascript
复制
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中,上述等式可表示如下,

代码语言:javascript
复制
def loss(model, original):

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

  return reconstruction_error

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

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

代码语言:javascript
复制
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。

代码语言:javascript
复制
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)。深度学习。麻省理工学院出版
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-03-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 相约机器人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档