目录
- 一、自动编码器介绍
- 1.1 自动编码器介绍
- 1.2 自动编码器特点
- 1.3 自动编码器伪代码实现
- 1.4 自动编码器的应用
- 二、利用自动编码器实现生成模型
- 三、自动编码器的Python代码实现与结果显示
- 四、自动编码器的不足与改进
一、自动编码器介绍
1.1 自动编码器介绍
自动编码器是一种神经网络模型,该模型的最初意义是为了能够对数据进行压缩。下图是一个标准的自动编码器,它的基本结构是一个多层感知器的神经网络,从输入层到输出层之间有多个隐含层,它的结构特点在于输入层与输出层拥有相同的节点数量,中间编码层的节点数量需要小于输入层与输出层的节点数。
该网络结构希望能够在输出层产生的数据X‘良好的还原输入层的数据X,由于中间的编码层数据z拥有的维度数量低于输入层与输出层的维度,所以如果输出层可以还原输入层的话相当于对输入数据进行了降维,也就是前面所说的数据压缩。
在自动编码器中,我们把输入层到编码层的网络部分(也就是整个神经网络的前半部分)称为编码器,把编码层到输出层的网络部分(后半部分)称为解码器。编码器的作用是可以实现数据的压缩,将高维度数据压缩成低维度数据,解码器则可以将压缩数据还原成原始数据,当然由于对数据进行了降维处理,所以在还原的过程中数据会产生一些损失。
1.2 自动编码器特点
自动编码器的特点为:
1)自动编码器是数据相关的(data-specific 或 data-dependent),这意味着自动编码器只能压缩那些与训练数据类似的数据。自动编码器与一般的压缩算法,如MPEG-2,MP3等压缩算法不同,一般的通用算法只假设了数据是“图像”或“声音”,而没有指定是哪种图像或声音。比如,使用人脸训练出来的自动编码器在压缩别的图片,比如树木时性能很差,因为它学习到的特征是与人脸相关的。
2)自动编码器是有损的,意思是解压缩的输出与原来的输入相比是退化的,MP3,JPEG等压缩算法也是如此。这与无损压缩算法不同。
3)自动编码器是从数据样本中自动学习的,这意味着很容易对指定类的输入训练出一种特定的编码器,而不需要完成任何新工作。
1.3 自动编码器伪代码实现
搭建一个自动编码器需要完成下面三样工作:搭建编码器,搭建解码器,设定一个损失函数,用以衡量由于压缩而损失掉的信息。编码器和解码器一般都是参数化的方程,并关于损失函数可导,典型情况是使用神经网络。编码器和解码器的参数可以通过最小化损失函数而优化,例如SGD。
自动编码器的训练过程需要将编码器与解码器绑定在一起进行训练,训练数据一般是无标签数据,因为我们会把数据本身作为它自身的标签。大致训练过程如下:
伪代码实现:
while 循环输入数据X do
前向传输通过所有隐含层,得到输出层数据X‘;
计算X’与X的偏差程度;
反向传输误差值,从而更新网络参数;
end while
- 1
- 2
- 3
- 4
- 5
1.4 自动编码器的应用
自动编码器在实际应用中用的很少,2012年人们发现在卷积神经网络中使用自编码器做逐层预训练可以训练深度网络,但很快人们发现良好的初始化策略在训练深度网络上要比费劲的逐层预训练有效得多,2014年出现的Batch Normalization技术使得更深的网络也可以被有效训练,到了2015年底,通过使用残差学习(ResNet)我们基本上可以训练任意深度的神经网络。
目前自编码器的应用主要有两个方面,第一是数据去噪,第二是为进行可视化而降维。配合适当的维度和稀疏约束,自编码器可以学习到比PCA等技术更有意思的数据投影。
二、利用自动编码器实现生成模型
除了数据压缩的功能外,还可以利用自动编码器实现生成模型的功能。当我们使用如上训练过程对自动编码器进行了某类型的训练后,编码器和解码器分别具备了此类型数据的编码/解码能力。在训练之后,我们可以单独使用解码器作为生成模型,在编码层输入任意数据,解码器都可以产生对应的生成数据。
下图展示的是自动编码器在手写数字数据集上的应用,可以看到原始输入数据的手写数字“2”在经过编码器后形成了一组压缩形式的编码,而这项编码经过解码器之后输出了一个与原始数据非常接近的输出图像,虽然有些许模糊,但是基本还原了手写数字“2”的形态。
在生成模型的应用中,我们仅仅使用模型的后边部分(解码器),当我们对解码器输入任意编码时,解码器会给出相应的输出数据。由于受到训练数据集的限制,生成的数据往往也是与输入数据相关的内容。
三、自动编码器的Python代码实现与结果显示
代码实现:
from keras.layers import Input,Dense
from keras.models import Model
from keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt
# 加载mnist数据集
(x_train, _), (x_test, _) = mnist.load_data()
# MNIST数据集归一化为【0,1】
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
# MNIST数据集转为向量形式
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) # (60000,784)
# print(x_test.shape) # (10000,784)
# 建立一个全连接的编码器
encoding_dim = 32 # 编码大小
input_img = Input(shape=(784,))
encoded = Dense(encoding_dim, activation='relu')(input_img) # 编码器
decoded = Dense(784, activation='sigmoid')(encoded) # 解码器
autoencoder = Model(inputs=input_img, outputs=decoded) # 将输入映射到其重建
encoder = Model(inputs=input_img, outputs=encoded) # 将输入映射到其编码表示
encoded_input = Input(shape=(encoding_dim,)) # 编码输入
decoder_layer = autoencoder.layers[-1] # 自动编码器模型最后一层
decoder = Model(input=encoded_input, output=decoder_layer(encoded_input)) # 解码器模型
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy') # 利用自动编码器重构MNIST中的数字
autoencoder.fit(x_train, x_train, epochs=50, batch_size=256,
shuffle=True, validation_data=(x_test, x_test))
#可视化重构出来的输出
encoded_imgs = encoder.predict(x_test)
decoded_imgs = decoder.predict(encoded_imgs)
n = 10 #展示数字数量
plt.figure(figsize=(18, 4))#指定长宽
for i in range(n):
#展示原始数字
ax = plt.subplot(2, n, i+1)
plt.imshow(x_test[i].reshape(28, 28))
plt.gray() #转化为灰度图像显示
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
#展示重构后的数字
ax = plt.subplot(2, n, i+1+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()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
输出结果:
四、自动编码器的不足与改进
自动编码器看起来似乎是生成模型的一个不错的实现方案,但在实际使用中存在许多问题,导致自动编码器其实并不太适合用来做数据生成,现在的自动编码器网络结构仅仅能够记录数据,除了通过编码器意外我们无法产生任何隐含编码(latent code)用来生成数据。比如对于手写数字数据集而言,当我们对解码器输入一个训练集重未出现过的编码时,我们可能会发现输出的内容居然是噪声,也就是说与手写数字数据集完全没有关系。
针对以上问题,提出了自动编码器的升级版本——变分自动编码器(Variattional Auto-Encoder,VAE)。
参考:
【1】/
【2】/en/latest/legacy/blog/autoencoder/
【3】/mago2015/article/details/86164668