自编码器(Autoencoder) :
自编码器(Autoencoder) 是一种数据的压缩算法,它可以在保留数据的大部分特征的情况下将数据的特征矩阵压缩的更小,以减小后续数据的处理量。其中数据的encode和decode模型是数据相关的、有损的、从样本中自动学习的。
自编码器由两部分组成:
编码器(encoder):这部分能将输入压缩成潜在空间表征,可以用编码函数h=f(x)表示。
解码器(decoder):这部分重构来自潜在空间表征的输入,可以用解码函数r=g(h)表示。
整个自编码器可以用函数g(f(x)) = r 来描述,其中输出r与原始输入x相近。
自编码器(Autoencoder) 的重要应用:
自编码器(Autoencoder) 的一种重要应用是图片的降噪处理,通过encoder提取图片的主要特征,然后decoder图片还原成图片初始的feature数量,经过这样处理后,可以消去图片上的大部分噪点。注意降噪处理时用的是有损自编码器,即编码器的输出维度小于其输入维度。
自编码器(Autoencoder) 另一种重要应用是为进行可视化而降维。配合适当的维度和稀疏约束,自编码器可以学习到比PCA等技术更有意思的数据投影。比如我们下面的更高层次的自编码器(Autoencoder)网络就是一个例子。
自编码器(Autoencoder)的特点:
自编码器是数据相关的(data-specific 或 data-dependent),这意味着自动编码器只能压缩那些与训练数据类似的数据。如,使用人脸训练出来的自动编码器在压缩别的图片,比如树木时性能很差;
自编码器是有损的,意思是解压缩的输出与原来的输入相比是退化的,这与无损压缩算法不同;
自编码器是从数据样本中自动学习的,我们可以自动地训练encode和decode函数模型。
搭建一个自编码器的步骤:
搭建编码器函数模型,设定其权重初值;
搭建解码器函数模型,设定其权重初值;
设定一个loss函数和一个优化器,用优化器去训练编码器函数模型和解码器函数模型。
注意:
自编码器是一个自监督的算法,其标签就是输入的x数据。(也有人因此称其为无监督学习的算法,因为输入只有x数据,没有y数据(y数据即标签))
Tensorflow第一个自编码器(Autoencoder)网络:
我们设计encode()和decode()函数。
使用encode()把初始图片的784Features经过第一个隐藏层压缩至256个Features,再经过第二个隐藏层压缩至128个Features。
使用decode()函数可以将128个Features还原至256个Features,再经过一步还原至784个Features。
训练20个epochs,根据cost函数值来优化我们的encode()和decode()函数的W和b参数;
对比原始图片和还原的图片(都是784个features,可以用matplotlib把图画出来)。
代码如下:
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import os
from tensorflow.examples.tutorials.mnist import input_data
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
# 还是用mnist数据集来做例子
mnist = input_data.read_data_sets("MNIST_data", one_hot=False)
# 超参数
learning_rate = 0.01
training_epochs = 20
train_batch_size = 256
# 最后用来比较decoder后的图片与原始图片的数量,一共比较10张
examples_to_show_number = 10
# 我们每次autoencoder都是对一张一张的图片进行的,图片的像素点数为28X28=784个
n_input = 784
# X占位符
X = tf.placeholder("float", [None, n_input])
# 每个隐藏层的神经元数量
n_hidden_1 = 256
n_hidden_2 = 128
# 设置encoder和decoder的隐藏层每层的w和b权重矩阵,encoder和decoder都是两层隐藏层
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])),
}
# 定义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']))
# Decoder 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
# 定义decoder模型
def decoder(x):
# Encoder 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输入数据,然后将encoder输出的数据再decoder
encoder_op = encoder(X)
decoder_op = decoder(encoder_op)
# MNIST数据每张图片大小是 28x28 pix,即784Features
# encoder环节:我们要把784个Features不断压缩,经过第一个隐藏层压缩至256Features,再经过第二个隐藏层压缩至128Features
# encoder环节:我们将128个Features还原至256个Features,再经过一步还原至784个Features。
# 在对比环节:比较原始数据与还原后的拥有784 Features的数据还原出来的图片
# 预测值和真实值,由于我们这里是先编码压缩然后解码,所以输入的X数据本身就是标签,通过模型先编码再解码后的输出值就是预测值
y_pred = decoder_op
y_true = X
# loss函数用方差平均值,优化器使用Adam算法
cost = tf.reduce_mean(tf.pow(y_true - y_pred, 2))
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
# 按照我们设置的train_batch_size,计算出整个数据集有多少个这样batch_size的样本组
training_iteration = int(mnist.train.num_examples / train_batch_size)
# 进行epochs轮训练,即理论上讲整个数据集使用training_epochs遍,每次都只用train_batch_size个样本来训练
for epoch in range(training_epochs):
for i in range(training_iteration):
train_batch_x_data, train_batch_y_data = mnist.train.next_batch(train_batch_size)
# 在这个模型中train_batch_y_data不需要,因为需要的y标签就是x值本身
_, loss = sess.run([optimizer, cost], feed_dict={X: train_batch_x_data})
# 每轮epoch结束时都打印一下loss值
if i > 0 and i % (training_iteration - 1) == 0:
# 每轮epoch的开始和结束时打印一下loss值
# {:>04d}即向右对齐,左边不足位数填充0
print("training_epochs:{:>04d},cost:{:.9f}".format(epoch, loss))
print("Training Model Finished!")
# 训练好模型后,我们用模型来编码压缩后再解码,看看和原图相比的效果
encode_decode = sess.run(y_pred, feed_dict={X: mnist.test.images[:examples_to_show_number]})
# 将解码后的图片与原始图片做比较,这里只比较10张
# 把图像的幕布分成2行10列,figsize=(10, 2), dpi=100即创建一张1000X200像素的图
f, a = plt.subplots(2, 10, figsize=(10, 2), dpi=100)
for i in range(examples_to_show_number):
a[0][i].imshow(np.reshape(mnist.test.images[i], (28, 28)))
a[1][i].imshow(np.reshape(encode_decode[i], (28, 28)))
plt.show()
运行结果如下:
training_epochs:0000,cost:0.078172207
training_epochs:0001,cost:0.067158930
training_epochs:0002,cost:0.064087376
training_epochs:0003,cost:0.056633547
training_epochs:0004,cost:0.055994198
training_epochs:0005,cost:0.055794511
training_epochs:0006,cost:0.051473632
training_epochs:0007,cost:0.053771909
training_epochs:0008,cost:0.051773846
training_epochs:0009,cost:0.051344920
training_epochs:0010,cost:0.050927226
training_epochs:0011,cost:0.049859058
training_epochs:0012,cost:0.049218342
training_epochs:0013,cost:0.047742166
training_epochs:0014,cost:0.048279013
training_epochs:0015,cost:0.046720915
training_epochs:0016,cost:0.044014841
training_epochs:0017,cost:0.047796708
training_epochs:0018,cost:0.044845022
training_epochs:0019,cost:0.047400281
Training Model Finished!
我们用训练好的模型encode再decode10张图片,然后对比原始图片和decode后的图片:
自编码器(Autoencoder)网络可视化降维实例:
我们还可以进一步将图片原有的784个features压缩到2个features,并且用这2个features作为x轴和y轴坐标,我们将一批图片的2个features的坐标画在同一张图上,可以发现同样标签的图片总是聚集在同一块区域里,实现了类似聚类的可视化效果。
代码如下:
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import os
from tensorflow.examples.tutorials.mnist import input_data
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
# 还是用mnist数据集来做例子
mnist = input_data.read_data_sets("MNIST_data", one_hot=False)
# 超参数
learning_rate = 0.005 # 0.01 this learning rate will be better! Tested
training_epochs = 40
train_batch_size = 128
# 我们每次autoencoder都是对一张一张的图片进行的,图片的像素点数为28X28=784个
n_input = 784
# X占位符
X = tf.placeholder("float", [None, n_input])
# 每个隐藏层的神经元数量
n_hidden_1 = 128
n_hidden_2 = 64
n_hidden_3 = 10
n_hidden_4 = 2
# 设置encoder和decoder的隐藏层每层的w和b权重矩阵,encoder和decoder都是两层隐藏层
weights = {
'encoder_h1': tf.Variable(tf.truncated_normal([n_input, n_hidden_1], )),
'encoder_h2': tf.Variable(tf.truncated_normal([n_hidden_1, n_hidden_2], )),
'encoder_h3': tf.Variable(tf.truncated_normal([n_hidden_2, n_hidden_3], )),
'encoder_h4': tf.Variable(tf.truncated_normal([n_hidden_3, n_hidden_4], )),
'decoder_h1': tf.Variable(tf.truncated_normal([n_hidden_4, n_hidden_3], )),
'decoder_h2': tf.Variable(tf.truncated_normal([n_hidden_3, n_hidden_2], )),
'decoder_h3': tf.Variable(tf.truncated_normal([n_hidden_2, n_hidden_1], )),
'decoder_h4': tf.Variable(tf.truncated_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])),
'encoder_b3': tf.Variable(tf.random_normal([n_hidden_3])),
'encoder_b4': tf.Variable(tf.random_normal([n_hidden_4])),
'decoder_b1': tf.Variable(tf.random_normal([n_hidden_3])),
'decoder_b2': tf.Variable(tf.random_normal([n_hidden_2])),
'decoder_b3': tf.Variable(tf.random_normal([n_hidden_1])),
'decoder_b4': tf.Variable(tf.random_normal([n_input])),
}
# 定义encoder模型
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']))
layer_3 = tf.nn.sigmoid(tf.add(tf.matmul(layer_2, weights['encoder_h3']), biases['encoder_b3']))
layer_4 = tf.add(tf.matmul(layer_3, weights['encoder_h4']), biases['encoder_b4'])
return layer_4
# 定义decoder模型
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']))
layer_3 = tf.nn.sigmoid(tf.add(tf.matmul(layer_2, weights['decoder_h3']), biases['decoder_b3']))
layer_4 = tf.nn.sigmoid(tf.add(tf.matmul(layer_3, weights['decoder_h4']), biases['decoder_b4']))
return layer_4
# 先encoder输入数据,然后将encoder输出的数据再decoder
encoder_op = encoder(X)
decoder_op = decoder(encoder_op)
# MNIST数据每张图片大小是 28x28 pix,即784Features
# encoder环节:我们要把784个Features不断压缩,经过多个隐藏层最后压缩到2个features
# encoder环节:我们将2个Features经过多个隐藏层还原至784个Features。
# 预测值和真实值,由于我们这里是先编码压缩然后解码,所以输入的X数据本身就是标签,通过模型先编码再解码后的输出值就是预测值
y_pred = decoder_op
y_true = X
# loss函数用方差平均值,优化器使用Adam算法
cost = tf.reduce_mean(tf.pow(y_true - y_pred, 2))
optimizer = tf.train.AdamOptimizer(learning_rate).minimize(cost)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
# 按照我们设置的train_batch_size,计算出整个数据集有多少个这样batch_size的样本组
training_iteration = int(mnist.train.num_examples / train_batch_size)
# 进行epochs轮训练,即理论上讲整个数据集使用training_epochs遍,每次都只用train_batch_size个样本来训练
for epoch in range(training_epochs):
for i in range(training_iteration):
train_batch_x_data, train_batch_y_data = mnist.train.next_batch(train_batch_size)
# 在这个模型中train_batch_y_data不需要,因为需要的y标签就是x值本身
_, loss = sess.run([optimizer, cost], feed_dict={X: train_batch_x_data})
# 每轮epoch结束时都打印一下loss值
if i > 0 and i % (training_iteration - 1) == 0:
# 每轮epoch的开始和结束时打印一下loss值
# {:>04d}即向右对齐,左边不足位数填充0
print("training_epochs:{:>04d},cost:{:.9f}".format(epoch, loss))
print("Training Model Finished!")
# 训练好模型后,我们将测试集的图片都压缩成2个features,然后作为x和y值显示到一张图上
encoder_result = sess.run(encoder_op, feed_dict={X: mnist.test.images})
# 画点,每个点代表一张图
# c:表示的是颜色,默认是蓝色'b',表示的是标记的颜色,
# c也可以是一个表示颜色的字符,或者是一个长度为n的表示颜色的序列,但是c不可以是一个单独的RGB数字,也不可以是一个RGBA的序列。
# c可以是他们的2维数组(只有一行)。
plt.scatter(encoder_result[:, 0], encoder_result[:, 1], c=mnist.test.labels)
# 让图上的点随着x轴和y轴的值的变化颜色也逐渐改变
plt.colorbar()
plt.show()
运行结果如下:
training_epochs:0000,cost:0.059315890
training_epochs:0001,cost:0.052934788
training_epochs:0002,cost:0.046577428
training_epochs:0003,cost:0.046515398
training_epochs:0004,cost:0.046095360
training_epochs:0005,cost:0.047667164
training_epochs:0006,cost:0.045452371
training_epochs:0007,cost:0.041207865
training_epochs:0008,cost:0.043470949
training_epochs:0009,cost:0.039567158
training_epochs:0010,cost:0.039852798
training_epochs:0011,cost:0.039323948
training_epochs:0012,cost:0.037798576
training_epochs:0013,cost:0.040977363
training_epochs:0014,cost:0.041816168
training_epochs:0015,cost:0.040627927
training_epochs:0016,cost:0.043382403
training_epochs:0017,cost:0.040975209
training_epochs:0018,cost:0.035220686
training_epochs:0019,cost:0.038107634
training_epochs:0020,cost:0.039811201
training_epochs:0021,cost:0.038627565
training_epochs:0022,cost:0.039158355
training_epochs:0023,cost:0.037800219
training_epochs:0024,cost:0.038565591
training_epochs:0025,cost:0.039120730
training_epochs:0026,cost:0.037348770
training_epochs:0027,cost:0.038857017
training_epochs:0028,cost:0.035938673
training_epochs:0029,cost:0.037698362
training_epochs:0030,cost:0.037364423
training_epochs:0031,cost:0.038803719
training_epochs:0032,cost:0.038623627
training_epochs:0033,cost:0.041696161
training_epochs:0034,cost:0.036853123
training_epochs:0035,cost:0.036360890
training_epochs:0036,cost:0.035169691
training_epochs:0037,cost:0.036442343
training_epochs:0038,cost:0.036035273
training_epochs:0039,cost:0.037545353
Training Model Finished!
生成一张图片:
可以看到不同标签的图片都聚集在同一块区域。