TensorFlow上实现AutoEncoder自编码器

本文介绍了AutoEncoder的基本原理,并通过MNIST数据集演示了特征压缩与解压的过程,同时展示了如何使用AutoEncoder进行数据可视化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概述

AutoEncoder大致是一个将数据的高维特征进行压缩降维编码,再经过相反的解码过程的一种学习方法。学习过程中通过解码得到的最终结果与原数据进行比较,通过修正权重偏置参数降低损失函数,不断提高对原数据的复原能力。学习完成后,前半段的编码过程得到结果即可代表原数据的低维“特征值”。通过学习得到的自编码器模型可以实现将高维数据压缩至所期望的维度,原理与PCA相似。


二、模型实现

1. AutoEncoder

首先在MNIST数据集上,实现特征压缩和特征解压并可视化比较解压后的数据与原数据的对照。

先看代码:
[python]  view plain  copy
  1. import tensorflow as tf  
  2. import numpy as np  
  3. import matplotlib.pyplot as plt  
  4.   
  5. # 导入MNIST数据  
  6. from tensorflow.examples.tutorials.mnist import input_data  
  7. mnist = input_data.read_data_sets("MNIST_data/", one_hot=False)  
  8.   
  9. learning_rate = 0.01  
  10. training_epochs = 10  
  11. batch_size = 256  
  12. display_step = 1  
  13. examples_to_show = 10  
  14. n_input = 784  
  15.   
  16. # tf Graph input (only pictures)  
  17. X = tf.placeholder("float", [None, n_input])  
  18.   
  19. # 用字典的方式存储各隐藏层的参数  
  20. n_hidden_1 = 256 # 第一编码层神经元个数  
  21. n_hidden_2 = 128 # 第二编码层神经元个数  
  22. # 权重和偏置的变化在编码层和解码层顺序是相逆的  
  23. # 权重参数矩阵维度是每层的 输入*输出,偏置参数维度取决于输出层的单元数  
  24. weights = {  
  25.     'encoder_h1': tf.Variable(tf.random_normal([n_input, n_hidden_1])),  
  26.     'encoder_h2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2])),  
  27.     'decoder_h1': tf.Variable(tf.random_normal([n_hidden_2, n_hidden_1])),  
  28.     'decoder_h2': tf.Variable(tf.random_normal([n_hidden_1, n_input])),  
  29. }  
  30. biases = {  
  31.     'encoder_b1': tf.Variable(tf.random_normal([n_hidden_1])),  
  32.     'encoder_b2': tf.Variable(tf.random_normal([n_hidden_2])),  
  33.     'decoder_b1': tf.Variable(tf.random_normal([n_hidden_1])),  
  34.     'decoder_b2': tf.Variable(tf.random_normal([n_input])),  
  35. }  
  36.   
  37. # 每一层结构都是 xW + b  
  38. # 构建编码器  
  39. def encoder(x):  
  40.     layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['encoder_h1']),  
  41.                                    biases['encoder_b1']))  
  42.     layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['encoder_h2']),  
  43.                                    biases['encoder_b2']))  
  44.     return layer_2  
  45.   
  46.   
  47. # 构建解码器  
  48. def decoder(x):  
  49.     layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['decoder_h1']),  
  50.                                    biases['decoder_b1']))  
  51.     layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['decoder_h2']),  
  52.                                    biases['decoder_b2']))  
  53.     return layer_2  
  54.   
  55. # 构建模型  
  56. encoder_op = encoder(X)  
  57. decoder_op = decoder(encoder_op)  
  58.   
  59. # 预测  
  60. y_pred = decoder_op  
  61. y_true = X  
  62.   
  63. # 定义代价函数和优化器  
  64. cost = tf.reduce_mean(tf.pow(y_true - y_pred, 2)) #最小二乘法  
  65. optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)  
  66.   
  67. with tf.Session() as sess:  
  68.     # tf.initialize_all_variables() no long valid from  
  69.     # 2017-03-02 if using tensorflow >= 0.12  
  70.     if int((tf.__version__).split('.')[1]) < 12 and int((tf.__version__).split('.')[0]) < 1:  
  71.         init = tf.initialize_all_variables()  
  72.     else:  
  73.         init = tf.global_variables_initializer()  
  74.     sess.run(init)  
  75.     # 首先计算总批数,保证每次循环训练集中的每个样本都参与训练,不同于批量训练  
  76.     total_batch = int(mnist.train.num_examples/batch_size) #总批数  
  77.     for epoch in range(training_epochs):  
  78.         for i in range(total_batch):  
  79.             batch_xs, batch_ys = mnist.train.next_batch(batch_size)  # max(x) = 1, min(x) = 0  
  80.             # Run optimization op (backprop) and cost op (to get loss value)  
  81.             _, c = sess.run([optimizer, cost], feed_dict={X: batch_xs})  
  82.         if epoch % display_step == 0:  
  83.             print("Epoch:"'%04d' % (epoch+1), "cost=""{:.9f}".format(c))  
  84.     print("Optimization Finished!")  
  85.   
  86.     encode_decode = sess.run(  
  87.         y_pred, feed_dict={X: mnist.test.images[:examples_to_show]})  
  88.     f, a = plt.subplots(210, figsize=(102))  
  89.     for i in range(examples_to_show):  
  90.         a[0][i].imshow(np.reshape(mnist.test.images[i], (2828)))  
  91.         a[1][i].imshow(np.reshape(encode_decode[i], (2828)))  
  92.     plt.show()  
代码解读:

首先,导入将要使用到的各种库和数据集,定义各个参数如学习率、训练迭代次数等,清晰明了便于后期修改。由于自编码器的神经网络结构非常有规律性,都是xW + b的结构,故将每一层的权重W和偏置b的变量tf.Variable统一置于一个字典中,通过字典的key值更加清晰明了的描述。模型构建思路上,将编码器部分和解码器部分分开构建,每一层的激活函数使用Sigmoid函数,编码器通常与编码器使用同样的激活函数。通常编码器部分和解码器部分是一个互逆的过程,例如我们设计将784维降至256维再降至128维的编码器,解码器对应的就是从128维解码至256维再解码至784维。定义代价函数,代价函数表示为解码器的输出与原始输入的最小二乘法表达,优化器采用AdamOptimizer训练阶段每次循环将所有的训练数据都参与训练。经过训练,最终将训练结果与原数据可视化进行对照,如下图,还原度较高。如果增大训练循环次数或者增加自编码器的层数,可以得到更好的还原效果。

运行结果:

2. Encoder

Encoder编码器工作原理与AutoEncoder相同,我们将编码得到的低维“特征值”在低维空间中可视化出来,直观显示数据的聚类效果。具体地说,将784维的MNIST数据一步步的从784到128到64到10最后降至2维,在2维坐标系中展示遇上一个例子不同的是,在编码器的最后一层中我们不采用Sigmoid激活函数,而是将采用默认的线性激活函数,使输出为(-∞,+∞)。

完整代码:
[python]  view plain  copy
  1. import tensorflow as tf  
  2. import matplotlib.pyplot as plt  
  3.   
  4. from tensorflow.examples.tutorials.mnist import input_data  
  5. mnist = input_data.read_data_sets("MNIST_data/", one_hot=False)  
  6.   
  7. learning_rate = 0.01  
  8. training_epochs = 10  
  9. batch_size = 256  
  10. display_step = 1  
  11. n_input = 784  
  12. X = tf.placeholder("float", [None, n_input])  
  13.   
  14. n_hidden_1 = 128  
  15. n_hidden_2 = 64  
  16. n_hidden_3 = 10  
  17. n_hidden_4 = 2  
  18. weights = {  
  19.     'encoder_h1': tf.Variable(tf.truncated_normal([n_input, n_hidden_1],)),  
  20.     'encoder_h2': tf.Variable(tf.truncated_normal([n_hidden_1, n_hidden_2],)),  
  21.     'encoder_h3': tf.Variable(tf.truncated_normal([n_hidden_2, n_hidden_3],)),  
  22.     'encoder_h4': tf.Variable(tf.truncated_normal([n_hidden_3, n_hidden_4],)),  
  23.     'decoder_h1': tf.Variable(tf.truncated_normal([n_hidden_4, n_hidden_3],)),  
  24.     'decoder_h2': tf.Variable(tf.truncated_normal([n_hidden_3, n_hidden_2],)),  
  25.     'decoder_h3': tf.Variable(tf.truncated_normal([n_hidden_2, n_hidden_1],)),  
  26.     'decoder_h4': tf.Variable(tf.truncated_normal([n_hidden_1, n_input],)),  
  27. }  
  28. biases = {  
  29.     'encoder_b1': tf.Variable(tf.random_normal([n_hidden_1])),  
  30.     'encoder_b2': tf.Variable(tf.random_normal([n_hidden_2])),  
  31.     'encoder_b3': tf.Variable(tf.random_normal([n_hidden_3])),  
  32.     'encoder_b4': tf.Variable(tf.random_normal([n_hidden_4])),  
  33.     'decoder_b1': tf.Variable(tf.random_normal([n_hidden_3])),  
  34.     'decoder_b2': tf.Variable(tf.random_normal([n_hidden_2])),  
  35.     'decoder_b3': tf.Variable(tf.random_normal([n_hidden_1])),  
  36.     'decoder_b4': tf.Variable(tf.random_normal([n_input])),  
  37. }  
  38. def encoder(x):  
  39.     layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['encoder_h1']),  
  40.                                    biases['encoder_b1']))  
  41.     layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['encoder_h2']),  
  42.                                    biases['encoder_b2']))  
  43.     layer_3 = tf.nn.sigmoid(tf.add(tf.matmul(layer_2, weights['encoder_h3']),  
  44.                                    biases['encoder_b3']))  
  45.     # 为了便于编码层的输出,编码层随后一层不使用激活函数  
  46.     layer_4 = tf.add(tf.matmul(layer_3, weights['encoder_h4']),  
  47.                                     biases['encoder_b4'])  
  48.     return layer_4  
  49.   
  50. def decoder(x):  
  51.     layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(x, weights['decoder_h1']),  
  52.                                    biases['decoder_b1']))  
  53.     layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, weights['decoder_h2']),  
  54.                                    biases['decoder_b2']))  
  55.     layer_3 = tf.nn.sigmoid(tf.add(tf.matmul(layer_2, weights['decoder_h3']),  
  56.                                 biases['decoder_b3']))  
  57.     layer_4 = tf.nn.sigmoid(tf.add(tf.matmul(layer_3, weights['decoder_h4']),  
  58.                                 biases['decoder_b4']))  
  59.     return layer_4  
  60.   
  61. encoder_op = encoder(X)  
  62. decoder_op = decoder(encoder_op)  
  63.   
  64. y_pred = decoder_op  
  65. y_true = X  
  66.   
  67. cost = tf.reduce_mean(tf.pow(y_true - y_pred, 2))  
  68. optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)  
  69.   
  70. with tf.Session() as sess:  
  71.     # tf.initialize_all_variables() no long valid from  
  72.     # 2017-03-02 if using tensorflow >= 0.12  
  73.     if int((tf.__version__).split('.')[1]) < 12 and int((tf.__version__).split('.')[0]) < 1:  
  74.         init = tf.initialize_all_variables()  
  75.     else:  
  76.         init = tf.global_variables_initializer()  
  77.     sess.run(init)  
  78.     total_batch = int(mnist.train.num_examples/batch_size)  
  79.     for epoch in range(training_epochs):  
  80.         for i in range(total_batch):  
  81.             batch_xs, batch_ys = mnist.train.next_batch(batch_size)  # max(x) = 1, min(x) = 0  
  82.             _, c = sess.run([optimizer, cost], feed_dict={X: batch_xs})  
  83.         if epoch % display_step == 0:  
  84.             print("Epoch:"'%04d' % (epoch+1), "cost=""{:.9f}".format(c))  
  85.     print("Optimization Finished!")  
  86.   
  87.     encoder_result = sess.run(encoder_op, feed_dict={X: mnist.test.images})  
  88.     plt.scatter(encoder_result[:, 0], encoder_result[:, 1], c=mnist.test.labels)  
  89.     plt.colorbar()  
  90.     plt.show()  
实验结果:

由结果可知,2维编码特征有较好的聚类效果,图中每个颜色代表了一个数字,聚集性很好。

当然,本次实验所得到的结果只是对AutoEncoder做一个简单的介绍,要想得到期望的效果,还应该设计更加复杂的自编码器结构,得到区分性更好的特征。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值