Tensorflow实践之MNIST数据集上的Autoencoder

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qwe1257/article/details/83412190

在学习Tensorflow的时候,我用的是github上一个比较好的项目,这个项目有两万多个star,然后里面的模型都是使用的MNIST数据集,我们的上一篇博客讲的怎么导入MNIST数据集,然后前几天实现了项目上的一个自编码器的项目,现在终结一下。

自编码器网络结构

在这里插入图片描述
如图所示,自编码器其实是一种不需要标注的监督学习,输入即输出,其中有四个隐藏层,前两个隐藏层为编码器,后两个称为解码器,这个自编码器是对称结构,因为这样更容易解码。关于自编码器的应用,我不想多聊,因为我也没用过,但是有一个用途从我们的这个网络结构就可以看出来,如果从encoder_2层到输出层还能够还原原来的X的话,那么我们就知道了encoder_2层的表示可以作为输入表示的替代,也就是说我们在不失去信息的情况下对数据降维了,由输入的四维降到了encoder_2的两维。那可能有人就想这样能不能将数据在不损失信息的情况下降到任意维,答案肯定是否定的,因为如果你中间隐藏层的神经元个数太小,你无法得到和输入一样的输出,此时也就是丢失了大量的信息,但是可能尽可能的保留网络认为的重要的信息。

MNIST数据可视化

我们应该都知道MNIST是手写数字识别的数据集,但是给我们的是压缩包,我们能不能打印看看图片吗,答案是当然可以。
我们先看看训练集和测试集的大小:

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./MNIST/",one_hot=True)
print (mnist.train.images.shape)
print (mnist.test.images.shape)
'''
(55000, 784)
(10000, 784)
'''

784是28×28,所以可以知道训练集是55000张28×28大小的图片,测试机是10000张28×28大小的图片。
我们尝试打印一张图片看看:

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./MNIST/",one_hot=True)
plt.imshow(mnist.train.images[0,:].reshape(28,28))
plt.show()

在这里插入图片描述
训练集的第一张图片就是这样的,改变那个0,可以查看其他图片是什么样。

tensorflow实现

我们可能都知道网络很简单,但是自己想实现却不知道怎么实现,我们是直接继承了那个github项目中的代码,多看是实现大牛的代码,坐着坐着你也成了大牛。
首先是网络的一些超参数,我会详细的用中文说明这些超参数的含义:

learning_rate = 0.01 #梯度下降的学习率
num_steps = 30000  #一个batch为一轮,这是训练的轮数
batch_size = 256  #每个batch的大小
display_step = 1000  #每隔1000轮输出一下loss,让我们直观的看看loss怎么下降

num_hidden_1=  256  #第一个隐藏层的神经元数目,因为对称,也是第四个隐藏层神经元个数
num_hidden_2 = 128  #第二个隐藏层神经元数目,因为对称,也是第三个隐藏层神经元个数
num_input = 784 #输入的特征维度,我们刚才看到输入的矩阵是[55000,784],其中55000为输入的图片数目,784为像素,也就是我们的特征

接下来是定义X和Y(这里的X就是Y)的placeholder和参数w和b的tensor,如果不知什么是placeholder和tensor可以看一下tensorflow的placeholder官方教程Tensor的官方教程

X = tf.placeholder(tf.float32,[None,num_input])
weights ={
    "encoder_h1":tf.Variable(tf.random_normal([num_input,num_hidden_1])),
    "encoder_h2":tf.Variable(tf.random_normal([num_hidden_1,num_hidden_2])),
    "decoder_h1":tf.Variable(tf.random_normal([num_hidden_2,num_hidden_1])),
    "decoder_h2":tf.Variable(tf.random_normal([num_hidden_1,num_input]))
}
biases = {
    "encoder_b1":tf.Variable(tf.random_normal([num_hidden_1])),
    "encoder_b2":tf.Variable(tf.random_normal([num_hidden_2])),
    "decoder_b1":tf.Variable(tf.random_normal([num_hidden_1])),
    "decoder_b2":tf.Variable(tf.random_normal([num_input]))
}

然后写出网络的前向传播,后向传播会直接由tensorflow自动生成,这就是框架的好处,不用我们再求导了:

def encoder(X):
    layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(X,weights["encoder_h1"]),biases["encoder_b1"]))
    layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1,weights["encoder_h2"]),biases["encoder_b2"]))
    return layer_2
def decoder(X):
    layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(X,weights["decoder_h1"]),biases["decoder_b1"]))
    layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1,weights["decoder_h2"]),biases["decoder_b2"]))
    return layer_2
encoder_op = encoder(X)
decoder_op = decoder(encoder_op)

然后定义损失函数和优化方法,这里的损失函数是平方损失函数,而优化方式是rmsprop算法:

y_train = decoder_op
y_true = X
loss = tf.reduce_mean(tf.pow(y_true-y_train,2))
optimizer = tf.train.RMSPropOptimizer(learning_rate).minimize(loss)

然后就是tensorflow.Session()运行刚才构建的图并查看结果:

init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    for i in range(1,num_steps+1):
        X_batch,_ = mnist.train.next_batch(batch_size)
        _,l = sess.run([optimizer,loss],feed_dict={X:X_batch})
        if i%display_step==0 or i==1:
            print ("MiniBatch loss after %i is %f" %(i,l))
    n = 4
    canvas_orig = np.empty((28*n,28*n))
    canvas_recon = np.empty((28*n,28*n))
    for i  in range(n):
        X_batch,_ = mnist.test.next_batch(n)
        g = sess.run(decoder_op,feed_dict={X:X_batch})
        for j in range(n):
            canvas_orig[i*28:(i+1)*28,j*28:(j+1)*28] = X_batch[j].reshape(28,28)
        for j in range(n):
            canvas_recon[i*28:(i+1)*28,j*28:(j+1)*28] = g[j].reshape(28,28)
    print ("Original Images")
    plt.figure(figsize=(n,n))
    plt.imshow(canvas_orig,origin="upper",cmap="gray")
    plt.show()
    print ("Reconstructed Images")
    plt.figure(figsize=(n,n))
    plt.imshow(canvas_recon,origin="upper",cmap="gray")
    plt.show()

训练过程:

MiniBatch loss after 1 is 0.439250
MiniBatch loss after 1000 is 0.118592
MiniBatch loss after 2000 is 0.101509
MiniBatch loss after 3000 is 0.095219
MiniBatch loss after 4000 is 0.089146
MiniBatch loss after 5000 is 0.086151
MiniBatch loss after 6000 is 0.083348
MiniBatch loss after 7000 is 0.078410
MiniBatch loss after 8000 is 0.077592
MiniBatch loss after 9000 is 0.071425
MiniBatch loss after 10000 is 0.069894
MiniBatch loss after 11000 is 0.066917
MiniBatch loss after 12000 is 0.065995
MiniBatch loss after 13000 is 0.064769
MiniBatch loss after 14000 is 0.062543
MiniBatch loss after 15000 is 0.062631
MiniBatch loss after 16000 is 0.059229
MiniBatch loss after 17000 is 0.058978
MiniBatch loss after 18000 is 0.055369
MiniBatch loss after 19000 is 0.056187
MiniBatch loss after 20000 is 0.050991
MiniBatch loss after 21000 is 0.051912
MiniBatch loss after 22000 is 0.051403
MiniBatch loss after 23000 is 0.048605
MiniBatch loss after 24000 is 0.048961
MiniBatch loss after 25000 is 0.048916
MiniBatch loss after 26000 is 0.048469
MiniBatch loss after 27000 is 0.048156
MiniBatch loss after 28000 is 0.046060
MiniBatch loss after 29000 is 0.045244
MiniBatch loss after 30000 is 0.045483

我们可以看一下结果,训练前的16张图片:
在这里插入图片描述
进过训练完成的网络输出的16张图片:
在这里插入图片描述
大体上还是可以辨认的,这里又可以看出它的一个应用,再图像处理中,如果可以扩充数据集,理论上会有更好的泛化效果,所以自编码器解码后的结果可以用来扩充数据集。
如果有什么问题欢迎留言讨论!

展开阅读全文

没有更多推荐了,返回首页