Tensorflow实战系列

(四)用tensorflow实现AutoEncoder

Posted by Stephen on August 3, 2017

Tensorflow 实现 AutoEncoder (自编码) 网络


有监督的神经网络需要数据是有标注(Labeled)的,然而神经网络的应用范围并不止于此,我们可以用它来处理无标注的数据: 其中的一种就是这篇Blog中介绍的AutoEncoder(自编码)网络


  • 自编码网络的结构如下图所示:

AutoEncoder

上面图中的AutoEncoder其实就是一个三层的神经网络,左侧是输入层,中间是隐藏层,最右侧为输出层。但是这个网络结果有两个特点:

  • 输入层和输出层的神经单元个数是相同的;
  • 隐藏层的神经单元要少于输出层。

AutoEncoder的结构为什么会有这样的特点呢?其实AutoEncoder的作用就是,将输入样本压缩到隐藏层,然后再在输出层重建样本,让输入层和输出层有如下的关系:

从上面就可以看出来,自编码网络就可以看作是,将数据压缩(压缩后的维度等于隐藏层的节点数),然后再在输出层以损失误差最小的方式将数据重建出来。

  • 要注意的是输出层的取值范围在0和1之间,所以对于输入层需要进行归一化

1.导入 tensorflow 包并下载 MNIST 数据

# Import MNIST data
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

# Import MNIST data
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

首先准备数据,如果本地已经下载好了数据,input_data下的read_data_sets则不会重新下载数据,而是将数据加载进来。
这里用到的 tensorflow 版本为 1.0.0,其他版本没有测试。这里引入了Matplotlib用于最后结果的显示。

2.定义训练参数和网络参数

# Parameters
learning_rate = 0.01
training_epochs = 20
batch_size = 256
display_step = 1
examples_to_show = 10

# Network Parameters
n_hidden_1 = 256 # 1st layer num features
n_hidden_2 = 128 # 2nd layer num features
n_input = 784 # MNIST data input (img shape: 28* 28)

参数说明:

  • 训练时的参数,比如学习率、训练轮数、训练批次的大小和结果显示的步长
  • 网络结构参数,隐藏层的单元数、网络的输入和输出数。这里其实用到了两个隐藏层,先将输入数据(784维)通过hidden layer1压缩到了256维,然后再通过hidden layer2将数据从256维压缩到了128维,输出是相反的过程。

3.定义模型的输入和权重、偏置

# tf Graph input (only pictures)
X = tf.placeholder("float", [None, n_input])

weights = {
    "encoder_h1": tf.Variable(tf.random_normal([n_input, n_hidden_1])),
    "encoder_h2": tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),
    "decoder_h1": tf.Variable(tf.random_normal([n_hidden_2, n_hidden_1])),
    "decoder_h2": tf.Variable(tf.random_normal([n_hidden_1, n_input])),
}

biases = {
    "encoder_b1": tf.Variable(tf.random_normal([n_hidden_1])),
    "encoder_b2": tf.Variable(tf.random_normal([n_hidden_2])),
    "decoder_b1": tf.Variable(tf.random_normal([n_hidden_1])),
    "decoder_b2": tf.Variable(tf.random_normal([n_input])),
}

这里用 placeholder 来装载输入变量,格式为 float

  • x: 训练数据集,维度为 _ * 784 (MNIST 的图像shape 为 28*28)

因为AutoEncoder是一种无监督的方式,所以并不需要输入数据的Label。

对于权重和偏置就都通过tf.Variable来定义,并进行正态随机初始化。

4.定义Encoder和Decoder

# Building the encoder
def encoder(x):
    # Encoder Hidden layer with sigmoid activation #1
    layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['encoder_h1']),
                                   biases['encoder_b1']))
    # Encoder Hidden layer with sigmoid activation #2
    layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['encoder_h2']),
                                   biases['encoder_b2']))
    return layer_2

# Building the decoder
def decoder(x):
    # Decoder Hidden layer with sigmoid activation #1
    layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['decoder_h1']),
                                   biases['decoder_b1']))
    # Decoder Hidden layer with sigmoid activation #2
    layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['decoder_h2']),
                                   biases['decoder_b2']))
    return layer_2

Encoder和Decoder和之前的文章中定义的网络没有什么不同,只是这里对每层的输出用sigmoid函数进行激励。

5.定义模型的损失函数和优化方式

# Construct model
encoder_op = encoder(X)
decoder_op = decoder(encoder_op)

# Prediction
y_pred = decoder_op
# Targets (Labels) are the input data
y_true = X

# Define loss and optimizer, minimize the suqared error
cost = tf.reduce_mean(tf.pow(y_true - y_pred, 2))
optimizer = tf.train.RMSPropOptimizer(learning_rate).minimize(cost)

# Initializing the variables
init = tf.global_variables_initializer()

这里使用Mean Square Loss,优化器使用RMSPropOptimizer。


6.模型训练、测试

# Launch the graph
# Using InteractiveSession ( more convenient while using Notebooks)
sess = tf.InteractiveSession()
sess.run(init)

total_batch = int(mnist.train.num_examples/batch_size)
# Training cycle
for epoch in range(training_epochs):
    # Loop over all batches
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        # Run optimization op (backprop) and cost op (to get loss value)
        _, c = sess.run([optimizer, cost], feed_dict={X: batch_xs})
    # Display logs per epoch step
    if epoch % display_step == 0:
        print ("Epoch:","%04d" % (epoch+1),\
               "cost=", "{:.9f}".format(c))

print ("Optimization Finished!")

# Applying encode and decode over test set
encode_decode = sess.run(
    y_pred, feed_dict={X: mnist.test.images[:examples_to_show]}
)

7.结果对比

Encoder过程其实就是将数据进行压缩,Decoder是对数据进行还原。
下面来看一下Encoder对图片进行压缩后和原始图片的对比:

Encoder