kinggerui 2018-08-10
在本教程中,我们将探索一种名为Autoencoders的无监督学习神经网络。
自动编码器是用于在输出层再现输入的深度神经网络,即输出层中的神经元数量与输入层中的神经元数量完全相同。考虑下面的图像
这张图片代表了一个典型的深层自动编码器的结构。autoencoder体系结构的目标是在输出层创建输入的表示,使两者尽可能接近(相似)。但是,自动编码器的实际使用是为了确定输入数据的压缩版本,而数据的损失是最低的。我的意思是:在开发机器学习项目时,你一定听说过一个术语,叫做主成分分析。PCA的概念是在数据集有大量参数的情况下,为模型的训练找到最好的相关参数。
自动编码器以类似的方式工作。体系结构的编码器部分将输入数据分解为压缩版本,以确保重要数据不会丢失,但数据的总体大小将显著降低。这个概念叫做降维。
这个概念的缺点是,压缩数据是黑盒子,即我们无法确定其压缩版本中的数据结构。请记住,假设我们有一个包含5个参数的数据集,我们在这些数据上训练一个自动编码器。编码器不会省略某些参数以获得更好的表示,但它将参数融合在一起以创建压缩版本但参数更少(从5开始将参数数量减少到3)。
自动编码器有两个部分,即编码器和解码器。
编码器压缩输入数据,并且解码器反过来产生数据的未压缩版本以尽可能准确地创建输入的重建。
我们将使用Tensorflow创建一个自动编码器神经网络并在mnist数据集上对其进行测试。
首先,我们导入相关的库并读入mnist数据集。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.contrib.layers import fully_connected
mnist=input_data.read_data_sets("/MNIST_data/",one_hot=True)
接下来,我们为方便起见创建一些常量,并事先声明我们的激活函数。mnist数据集中的图像大小为28x28像素,即784像素,我们将其压缩为196像素。您可以随时更深入地进一步缩小像素大小。但是,压缩太多可能会导致自动编码器丢失信息。
num_inputs=784 #28x28 pixels
num_hid1=392
num_hid2=196
num_hid3=num_hid1
num_output=num_inputs
lr=0.01
actf=tf.nn.relu
现在,我们为每个图层的权重和偏差创建变量。然后,我们使用先前声明的激活函数创建层
X=tf.placeholder(tf.float32,shape=[None,num_inputs])
initializer=tf.variance_scaling_initializer()
w1=tf.Variable(initializer([num_inputs,num_hid1]),dtype=tf.float32)
w2=tf.Variable(initializer([num_hid1,num_hid2]),dtype=tf.float32)
w3=tf.Variable(initializer([num_hid2,num_hid3]),dtype=tf.float32)
w4=tf.Variable(initializer([num_hid3,num_output]),dtype=tf.float32)
b1=tf.Variable(tf.zeros(num_hid1))
b2=tf.Variable(tf.zeros(num_hid2))
b3=tf.Variable(tf.zeros(num_hid3))
b4=tf.Variable(tf.zeros(num_output))
hid_layer1=actf(tf.matmul(X,w1)+b1)
hid_layer2=actf(tf.matmul(hid_layer1,w2)+b2)
hid_layer3=actf(tf.matmul(hid_layer2,w3)+b3)
output_layer=actf(tf.matmul(hid_layer3,w4)+b4)
通常不使用tf.variance_scaling_initializer()。但是,我们在这里使用它是因为我们要处理输入大小的变化。因此, the placeholder tensor shape根据输入大小的形状自行调整,这就防止了我们遇到任何维数错误。隐藏层是通过简单地将之前的隐藏层作为输入输入到激活函数(ReLu)中而创建的。
我们将使用这个神经网络的MSE损失函数,并通过一个Adam优化器传递它。
loss=tf.reduce_mean(tf.square(output_layer-X))
optimizer=tf.train.AdamOptimizer(lr)
train=optimizer.minimize(loss)
init=tf.global_variables_initializer()
现在,我们定义epochs和batch size并运行会话。我们使用mnist中的实用程序函数来获取每个新批次:mnist.train.next_batch() 。此外,我们将在每个时期之后输出训练损失以监控其训练。
num_epoch=5
batch_size=150
num_test_images=10
with tf.Session() as sess:
sess.run(init)
for epoch in range(num_epoch):
num_batches=mnist.train.num_examples//batch_size
for iteration in range(num_batches):
X_batch,y_batch=mnist.train.next_batch(batch_size)
sess.run(train,feed_dict={X:X_batch})
train_loss=loss.eval(feed_dict={X:X_batch})
print("epoch {} loss {}".format(epoch,train_loss))
最后,我们将编写一个小的绘图函数来绘制原始图像和重建图,以查看我们的模型的工作情况。
results=output_layer.eval(feed_dict={X:mnist.test.images[:num_test_images]})
#Comparing original images with reconstructions
f,a=plt.subplots(2,10,figsize=(20,4))
for i in range(num_test_images):
a[0][i].imshow(np.reshape(mnist.test.images[i],(28,28)))
a[1][i].imshow(np.reshape(results[i],(28,28)))
在这里,我们可以看到重建并不完美,但非常接近原始图像。注意,2的重建看起来像是3,这是由于压缩时信息丢失造成的。
我们可以通过超参数调整来改进自动编码器模型,并且还可以通过在GPU加速器上进行训练来改进它。