基本自编码器
考虑监督学习神经网络模型:
y
=
f
θ
(
x
)
y=f_\theta(x)
y=fθ(x)
x是样本数据,y是通过x预测得到实际值。如果使用样本中数据x替代标签数据时有:
x
^
=
f
θ
(
x
)
\hat x=f_\theta(x)
x^=fθ(x)
即尝试着利用数据x本身作为监督信号来指导网络的训练,希望神经网络能够学习到映射𝑓𝜃:𝒙 → 𝒙,把网络𝑓𝜃切分为 2 个部分,前面的子网络尝试学习映射关 系:𝑔𝜃1:𝒙 → 𝒛,后面的子网络尝试学习映射关系ℎ𝜃2:𝒛 → 𝒙,(𝒛称为隐变量,是对𝒙的降维操作,体现了𝒙的分布)我们把𝑔𝜃1看成一个数据编码 (Encode)的过程,ℎ𝜃2看成数据解码(Decode)的过程,编码器和解码器共同完成了输入数据𝒙的编码和解码过程,我们把整个网络模型𝑓𝜃叫做自动编码器(Auto-Encoder),简称自编码器。
x
^
=
h
θ
(
g
θ
(
x
)
)
z
=
g
θ
(
x
)
\hat x = h_\theta(g_\theta(x)) \quad\quad\quad\quad z=g_\theta(x)
x^=hθ(gθ(x))z=gθ(x)
模型损失函数可采用方差表示:
l
o
s
s
=
∑
(
x
−
x
^
)
2
loss = \sum(x-\hat x)^2
loss=∑(x−x^)2
自编码器的模型性能一般不好量化评价,但我们最终希望获得还原度较高的重建样本。一般需要根据具体问题来讨论自编码器的学习效果,比如对于图片重建,一般依赖于人工主观评价图片生成的质量。
MNIST 图片重建实例
import numpy as np
import tensorflow as tf
import tensorflow.python.keras.datasets.mnist as mnist
import matplotlib.pyplot as plt
tf.compat.v1.disable_eager_execution()
TRAINING_STEPS = 10000
batch_size = 500
# 定义mnist数据加载初始化
def data_init():
(x_train, y_train), (x_test, y_test) = mnist.load_data("E://python//tensorflow_study//MNIST_data//mnist.npz")
x_train = np.reshape(x_train, (60000, 784))
x_test = np.reshape(x_test, (10000, 784))
x_train = (x_train - 255) / 255
x_test = (x_test - 255) / 255
# 5.5W训练集
x_train_np = np.array(x_train[5000:], dtype='float32')
# 1W测试集
x_test_np = np.array(x_test[:], dtype='float32')
return {"x_train": x_train_np, "x_test": x_test_np}
def getRandomIndex(n, x):
# 索引范围为[0, n),随机选x个不重复,注意replace=False不重复
if x > n:
x = n
index = np.random.choice(np.arange(n), size=x, replace=False)
return index
# 随机获取数据
def data_batch_set(input_data_feed, feed_name):
data_len = len(input_data_feed[feed_name])
index = getRandomIndex(data_len, batch_size)
return input_data_feed[feed_name][index]
# 定义层函数
def add_layer(input, in_size, out_size, active_function):
# input 输入矩阵
# in_size 输入矩阵列大小
# out_size 输出矩阵列大小
# active_function 激活函数
weighs = tf.Variable(tf.compat.v1.random_normal([in_size, out_size]))
# 定义L2正则化(定义刻画网络复杂度的损失函数,解决过拟合问题)
regularizers_L2 = tf.keras.regularizers.l2(0.000005)
weighs_loss = regularizers_L2(x=weighs)
# 加入集合,losses是集合的名字,第二个参数是要加入这个集合的内容。
tf.compat.v1.add_to_collection('losses', weighs_loss)
bais = tf.Variable(tf.compat.v1.random_normal([1, out_size]))
# 激励输入
z_i = tf.matmul(input, weighs) + bais
return active_function(z_i)
# 定义前向传播
def inference(input_tensor):
# 编码器部分
# 第一层输入NX784形状输入,输出为NX512
out_1 = add_layer(input=input_tensor, in_size=784, out_size=512, active_function=tf.nn.sigmoid)
# 第二层输入为NX512,输出为NX64
out_2 = add_layer(input=out_1, in_size=512, out_size=64, active_function=tf.nn.sigmoid)
# 第三层输入为NX64,输出为NX16
out_3 = add_layer(input=out_2, in_size=64, out_size=16, active_function=tf.nn.sigmoid)
# 解码器部分
# 第四层输入NX16形状输入,输出为NX64
out_4 = add_layer(input=out_3, in_size=16, out_size=64, active_function=tf.nn.sigmoid)
# 第五层输入为NX64,输出为NX512
out_5 = add_layer(input=out_4, in_size=64, out_size=512, active_function=tf.nn.sigmoid)
# 第六层输入为NX512,输出为NX784(最后输出图片)
out_6 = add_layer(input=out_5, in_size=512, out_size=784, active_function=tf.nn.sigmoid)
return out_6
# 定义模型训练过程
def train():
global_step = tf.Variable(0, trainable=False)
# 定义输入、标签。这里标签y_就是输入x
x = tf.compat.v1.placeholder(tf.float32, [None, 784])
y_ = tf.compat.v1.placeholder(tf.float32, [None, 784])
# 计算当前参数在神经网络上的结果
y = inference(x)
# 定义损失函数
loss_mean = tf.reduce_mean(tf.reduce_sum(tf.square(y - y_)))
# 将loss_mean加入损失集合。
tf.compat.v1.add_to_collection('losses', loss_mean)
# 总损失函数
loss = tf.add_n(tf.compat.v1.get_collection('losses'))
# 初始速率0.1,后面每训练100次后在学习速率基础上乘以0.96
learning_rate = tf.compat.v1.train.exponential_decay(0.9999, global_step, 5000, 0.9, staircase=True)
# 使用tf.train.GradientDescentOptimizer 优化算法来优化损失函数。
train_step = tf.compat.v1.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
# 加载样本数据
data_feed = data_init()
# 初始化会话并开始训练过程。
init_var = tf.compat.v1.global_variables_initializer()
with tf.compat.v1.Session() as sess:
sess.run(init_var)
for i in range(TRAINING_STEPS):
train_batch_x = data_batch_set(data_feed, feed_name='x_train')
# 标签就是样本x
sess.run(train_step, feed_dict={x: train_batch_x, y_: train_batch_x})
if i % 500 == 0:
# loss
loss_val = sess.run(loss, feed_dict={x: train_batch_x, y_: train_batch_x})
print("After %d training step(s) , loss=%f" % (i, loss_val))
# test
test_batch_x = data_batch_set(data_feed, feed_name='x_test')
# test_img
test_x = test_batch_x[0]
# 原图
test_x_img = test_x * 255
test_x_img = np.reshape(test_x_img, (28, 28))
# 重建后的图
# 转换为0-1之间的值
test_y = tf.nn.sigmoid(y)
test_y = sess.run(test_y, feed_dict={x: [test_x]})
test_y_img = test_y * 255
test_y_img = np.reshape(test_y_img, (28, 28))
plt.subplot(1, 2, 1)
plt.title('origin')
plt.imshow(test_x_img)
plt.subplot(1, 2, 2)
plt.title('forecast')
plt.imshow(test_y_img)
plt.show()
def main():
train()
if __name__ == '__main__':
main()
降噪自编码器
基于基本的自编码模型,将输入样本x加上噪声,作为输入,标签数据使用原生x去训练神经网络的一种模型。
x
=
x
+
ϵ
ϵ
−
N
(
0
,
σ
2
)
x = x + \epsilon \quad\quad\quad\quad\epsilon -~ N(0,\sigma^2)
x=x+ϵϵ− N(0,σ2)