AutoEncoder自编码器的详情介绍
AutoEncoder自编码器的详情介绍
什么是AutoEncoder自编码器
自编码器,又称AutoEncoder,是一种无监督的人工神经网络;对训练数据进行压缩再解压的过程,保证最终解压后的数据和训练数据基本一致。打个比方,将一张图片放入一个网络中,自编码器的encoder对图片进行压缩,再使用decoder进行解码,从而复现原图的过程。
同时,自编码器有三个特性1:
- 数据相关性 ,自动编码器只能压缩与训练数据相关的数据。使用花草图片训练出来的自动编码器在压缩人脸的图片,其性能会很差,因为encoder学习到的特征是与花草相关的;
- 数据有损的,最终解压后的数据和训练数据会有一定的损失;
- 从样本中自动学习,很容易对指定类的输入训练出一种特定的编码器,而不需要完成任何新工作。
为什么要使用AutoEncoder
类似于PCA,AutoEncoder对训练数据的特征属性进行降维,提取最有代表性的信息,帮助资料分类、视觉化、储存。在实际应用中,通常会用到自编码前半部分(encoder)。
AutoEncoder的实现步骤
AutoEncoder实现有三个步骤1:
- 搭建编码器(encoder),一般是参数化的方程,对训练数据进行压缩编码;
- 搭建解码器(decoder),一般是参数化的方程,对压缩后的数据进行解码;
- 设定一个损失函数,衡量压缩后损失掉的信息,其参数可以通过最小化损失函数而优化。
自编码器的种类
本文主要介绍自编码器的五大类型2:
- 简易自动编码器(AutoEncoder);
- 稀疏自编码器(Sparse AutoEncoder);
- 深度自编码器(Deep AutoEncoder);
- 卷积自动编码器(Convolutional AutoEncoder);
- 变分自动编码器(Variational AutoEncoder)。
简易自动编码器(AutoEncoder)
一、 原理
简易AutoEncoder的架构由Encoder(编码器)和Decoder(解码器)组成,如图:
二、代码
- 先建立一个全连接的自解码器
from keras.layers import Input, Dense
from keras.models import Model
# this is the size of our encoded representations
encoding_dim = 32 # 32 floats -> compression of factor 24.5, assuming the input is 784 floats
# this is our input placeholder
input_img = Input(shape=(784,))
# "encoded" is the encoded representation of the input
encoded = Dense(encoding_dim, activation='relu')(input_img)
# "decoded" is the lossy reconstruction of the input
decoded = Dense(784, activation='sigmoid')(encoded)
# this model maps an input to its reconstruction
autoencoder = Model(input=input_img, output=decoded)
- 单独创建编码器和解码器
# create the encoder model
encoder = Model(input=input_img, output=encoded)
# create a placeholder for an encoded (32-dimensional) input
encoded_input = Input(shape=(encoding_dim,))
# retrieve the last layer of the autoencoder model
decoder_layer = autoencoder.layers[-1]
# create the decoder model
decoder = Model(input=encoded_input, output=decoder_layer(encoded_input))
- 使用逐像素的交叉熵作为损失函数,优化器为adam
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
- 准备MNIST数据,将其归一化和向量化
from keras.datasets import mnist
import numpy as np
# discard the labels (since we're only interested in encoding/decoding the input images)
(x_train, _), (x_test, _) = mnist.load_data()
# normalize all values between 0 and 1
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
# flatten the 28x28 images into vectors of size 784
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
print(x_train.shape)
print(x_test.shape)
- 将训练集进行训练
# train our autoencoder for 50 epochs
autoencoder.fit(x_train, x_train,
nb_epoch=50,
batch_size=256,
shuffle=True,
validation_data=(x_test, x_test))
- 将测试集进行预测
# method 1
encoded_imgs = encoder.predict(x_test)
decoded_imgs = decoder.predict(encoded_imgs)
# method 2
decoded_imgs = autoencoder.predict(x_test)
- 可视化一下重构出来的输出
import matplotlib.pyplot as plt
n = 10 # how many digits we will display
plt.figure(figsize=(20, 4))
for i in range(n):
# display original
ax = plt.subplot(2, n, i)
plt.imshow(x_test[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# display reconstruction
ax = plt.subplot(2, n, i + n)
plt.imshow(decoded_imgs[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
稀疏自动编码器(Sparse AutoEncoder)
一、原理
为了限制每次得到的编码器尽量稀疏,迫使每次训练数据表示少量节点的组合;每个神经元都会训练特定数据,进而过滤无用的信息。
二、代码
通过添加一个正则化activity_regularizer达到对某层激活值进行稀疏约束的目的。
由于添加正则化,模型不太可能过度适应,可以进行更长时间的训练;因此可以对模型进行100个时期的训练。
与简易版代码不同之处在于:
from keras import regularizers
encoding_dim = 32
input_img = Input(shape=(784,))
# add a Dense layer with a L1 activity regularizer
encoded = Dense(encoding_dim, activation='relu',
activity_regularizer=regularizers.activity_l1(10e-5))(input_img)
decoded = Dense(784, activation='sigmoid')(encoded)
autoencoder = Model(input=input_img, output=decoded)
深度自编码器(Deep AutoEncoder)
一、原理
我们不局限于单层编码器或解码器,可以把自编码器叠加起来,这称为深度自编码器。
二、 代码
与简易版代码不同之处在于:
input_img = Input(shape=(784,))
encoded = Dense(128, activation='relu')(input_img)
encoded = Dense(64, activation='relu')(encoded)
encoded = Dense(32, activation='relu')(encoded)
decoded = Dense(64, activation='relu')(encoded)
decoded = Dense(128, activation='relu')(decoded)
decoded = Dense(784, activation='sigmoid')(decoded)
卷积自动编码器(Convolutional AutoEncoder)
一、原理
卷积自编码器的编码器部分由卷积层(Convolution2D)和MaxPooling层(MaxPooling2D)构成,MaxPooling负责空域下采样。而解码器由卷积层(Convolution2D)和上采样层(UpSampling2D)构成。
处理图像的自编码器一般都是卷积自编码器,它们的性能要好得多。
二、 代码
- 创建一个编码器和解码器
import keras
from keras import layers
input_img = keras.Input(shape=(28, 28, 1))
x = layers.Conv2D(16, (3, 3), activation='relu', padding='same')(input_img)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
encoded = layers.MaxPooling2D((2, 2), padding='same')(x)
# at this point the representation is (4, 4, 8) i.e. 128-dimensional
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(encoded)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(8, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(16, (3, 3), activation='relu')(x)
x = layers.UpSampling2D((2, 2))(x)
decoded = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
autoencoder = keras.Model(input_img, decoded)
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
- 使用带有形状的原始 MNIST 数字(样本,3,28,28) ,并且我们只将0和1之间的像素值标准化
from keras.datasets import mnist
import numpy as np
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
- 训练模型,传递 TensorBoard 回调的一个实例。在每个历元之后,这个回调函数将把日志写入\tmp\autoencoder,这可以被 TensorBoard 服务器读取。
在cmd中输入tensorboard --logdir=\tmp\autoencoder的路径;通过 TensorBoard 网络界面监控训练(通过导航到 http://0.0.0.0:6006)。
from keras.callbacks import TensorBoard
autoencoder.fit(x_train, x_train,
epochs=50,
batch_size=128,
shuffle=True,
validation_data=(x_test, x_test),
callbacks=[TensorBoard(log_dir=r'\tmp\autoencoder')])
- 可视化结果
decoded_imgs = autoencoder.predict(x_test)
n = 10
plt.figure(figsize=(20, 4))
for i in range(1, n + 1):
# Display original
ax = plt.subplot(2, n, i)
plt.imshow(x_test[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# Display reconstruction
ax = plt.subplot(2, n, i + n)
plt.imshow(decoded_imgs[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
图像去噪的应用
把卷积自动编码器应用到图像去噪的问题,学习对图片进行去噪的过程。在训练数据中添加随机noise,最终解码获取去噪的图片,以获取去噪自动编码器,使模型学会去噪的能力。
二、 代码
- 训练数据添加高斯噪声,再把像素值clip到0~1
from keras.datasets import mnist
import numpy as np
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 1, 28, 28))
x_test = np.reshape(x_test, (len(x_test), 1, 28, 28))
noise_factor = 0.5
x_train_noisy = x_train + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)
x_test_noisy = x_test + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_test.shape)
x_train_noisy = np.clip(x_train_noisy, 0., 1.)
x_test_noisy = np.clip(x_test_noisy, 0., 1.)
- 查看噪音数字的样子
import matplotlib.pyplot as plt
n = 10
plt.figure(figsize=(20, 2))
for i in range(1, n + 1):
ax = plt.subplot(1, n, i)
plt.imshow(x_test_noisy[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
- 为了提高重建的质量,使用改进后的卷积自动编码器
import keras
from keras import layers
from keras.callbacks import TensorBoard
input_img = keras.Input(shape=(28, 28, 1))
x = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(input_img)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(x)
encoded = layers.MaxPooling2D((2, 2), padding='same')(x)
# At this point the representation is (7, 7, 32)
x = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(encoded)
x = layers.UpSampling2D((2, 2))(x)
x = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = layers.UpSampling2D((2, 2))(x)
decoded = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
autoencoder = keras.Model(input_img, decoded)
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
- 训练100个epochs
autoencoder.fit(x_train_noisy, x_train,
epochs=100,
batch_size=128,
shuffle=True,
validation_data=(x_test_noisy, x_test),
callbacks=[TensorBoard(log_dir=r'\tmp\tb', histogram_freq=0, write_graph=False)])
- 可视化结果
decoded_imgs = autoencoder.predict(x_test_noisy)
n = 10
plt.figure(figsize=(20, 4))
for i in range(1, n + 1):
# Display original
ax = plt.subplot(2, n, i)
plt.imshow(x_test_noisy[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
# Display reconstruction
ax = plt.subplot(2, n, i + n)
plt.imshow(decoded_imgs[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
结果展示:
变分自动编码器(Variational AutoEncoder)
一、原理
与简易版的自编码不同之处在于变分自动编码器在编码中添加一些限制,在解码的过程中,提取压缩过程中的mean均值和standard deviation标准方差,通过一系列运算成为解码器。
变分自动编码器的内部操作:
- 从编码器输出两个向量,分别是均值mean(如图mi)和标准方差standard deviation(如图σi);
- 从正态分布生成第三个变量(如图ei);
- 使用exp(σi) ✖ ei + mi公式获取ci,即为中间层的隐含向量。
变分自编码的优势在于可以解读每个向量的含义及其计算,因此可以灵活调整想要生成的图片。
二、代码
具体代码见2
x = Input(batch_shape=(batch_size, original_dim))
h = Dense(intermediate_dim, activation='relu')(x)
- 从编码器中获取均值、标准方差,进而计算
z_mean = Dense(latent_dim)(h)
z_log_sigma = Dense(latent_dim)(h)
def sampling(args):
z_mean, z_log_sigma = args
epsilon = K.random_normal(shape=(batch_size, latent_dim),
mean=0., std=epsilon_std)
return z_mean + K.exp(z_log_sigma) * epsilon