自动编码(AE)器的简单实现
二.自动编码器的发展简述
三. 实验
3.1 传统的自动编码器实验结果
3.2 堆叠降噪自编码器
3.3 卷积自编码器
3.4 变分自编码器
传统的自动编码器是一种数据的压缩算法,其算法包括编码阶段和解码阶段,且拥有对称的结构。
目前自编码器的应用主要有两个方面,第一是数据去噪,第二是为进行可视化而降维。配合适当的维度和稀疏约束,自编码器可以学习到比PCA等技术更有意思的数据投影。
传统编码器的编解码过程描述如图:
评价:
学界评价:传统自编码器的目的是使输出与输入尽量相同,这完全可以通过学习两个恒等函数来完成,但是这样的变换没有任何意义,因为我们真正关心的是隐层表达,而不是实际输出。因此,针对自编码器的很多改进方法都是对隐层表达增加一定的约束,迫使隐层表达与输入不同。
自编码器真正关心的是隐藏层的特征表达,一个好的表达能够捕获输入信号的稳定结构,以该目的为出发出现了降噪自动编码器。降噪自动编码器,首先对干净的输入信号加入噪声产生一个受损的信号。然后将受损信号送入传统的自动编码器中,使其重建回原来的无损信号。
降噪自编码器的编解码过程描述如图:
降噪自编码器与传统的自动编码器的主要区别在于:
评价:
学界评价:降噪自编码器通过对输入信号人为地进行损坏,主要是为了达到两个目的,首先是为了避免使隐层单元学习一个传统自编码器中没有实际意义的恒等函数,其次就是为了使隐层单元可以学习到一个更加具有鲁棒性的特征表达。
降噪自编码器最大的优点在于,重建信号对输入中的噪声具有一定的鲁棒性,而最大的缺陷在于每次进行网络训练之前,都需要对干净输入信号人为地添加噪声,以获得它的损坏信号,这无形中就增加了该模型的处理时间。
参考深度置信网络的方法,将降噪自编码器进行堆叠可以构造成堆叠降噪自编码器。与自编码器和降噪自编码器不同,堆叠降噪自编码器的提出是为了解决。
降噪自编码器的编解码过程描述如图:
其中,编码器 分别对应的是预先训练好的降噪自编码器到的编码函数.
每个子问题的训练过程与降噪自编码器自编码器相同.
整个堆叠降噪自编码器的训练过程如下:
堆叠降噪自编码器与降噪自编码器的区别在于:
评价:
学界评价:堆叠降噪自编码器是降噪自编码器的一个应用方法.
全卷积网络是一种面向特定应用(图像语义分割)的卷积神经网络,其结构图如下图所示:
与经典的CNN在卷积层之后使用全连接层得到固定长度的特征向量进行分类(全联接层+softmax输出)不同,FCN可以接受任意尺寸的输入图像,采用反卷积层对最后一个卷积层的feature map进行上采样, 使它恢复到输入图像相同的尺寸,从而可以对每个像素都产生了一个预测, 同时保留了原始输入图像中的空间信息, 最后在上采样的特征图上进行逐像素分类。
与全卷积网络类似的一种无监督方法称为卷机自动编码器.
由于卷积神经网络所取得的各种优异表现,直接推动了卷积自编码器的产生.卷积自编码器属于传统自编码器的一个特例.它使用卷积层和池化层替代了原来的全连接层.卷积
自编码器能很好的保留二维信号的空间信息.
学界评价:其主要差别在于卷积自编码器采用卷积方式对输入信号进行线性变换,并且其权重是共享的,这点与卷积神经网络一样。因此,重建过程就是基于隐藏编码的基本图像块的线性组合。
我实现后的感受:
变分自编码器是一种主要用于数据生成的自编码器的变体.当作为生成模型时,首先利用数据训练变分自编码器,然后只使用变分自编码器的解码部分,自动生成与训练数据类似的输出.
其结构图如图所示:
整个结构可以分成三个部分,分别是编码部分,解码部分和生成部分.编码部分和解码部分同时进行训练,目标函数是从KL散度的概念中推倒得到的.
其中代表了输入数据,代表了隐变量(latent varibles)(一个类似隐层输出的概率描述),
变分编码器的目标可以描述为最大化生成的概率
其中 为模型的参数,也是优化的对象.一般选取
loss函数的推导过程:
首先我们希望编码器部分生成的随机变量与理想的尽量接近,因此使用KL散度的概念对两个随机变量的相似性进行描述.
其中,为散度符号.利用贝叶斯公式将上述公式展开得到:
经过变换可以得到:
该公式正好是变分自编码器的目标函数.目标函数可以分成两个部分,分别约束了中间的隐变量受到一个标准分布的约束和输出图像尽量与原图相同.
编码器名称 | 提出时间 | 改进点 | 目的 |
---|---|---|---|
传统自编码器 | 1986 | 无 | 无 |
降噪自编码器 | 2008 | 将带有噪声的损坏信息作为输入信号 | 使重建信号鲁棒性更强 |
堆叠自编码器 | 2008 | 将多层结构和栈式训练引入自编码器 | 使自编码器可以训练更高层数 |
卷积自编码器 | 2011 | 将卷积层引入自编码器 | 更好的处理图片数据,得到更好的效果 |
变分自编码器 | 2014 | 相当于在传统自编码器的隐层表达上增加一个对隐变量的约束,提出了一种将概率模型和神经网络结构的方法 | 使编码器产生的隐层表达满足正态分布,能够更好的生成图像模型 |
模型结构与实现代码
传统的自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:
模型分为三个子模块,由上至下分别为输入层,编码器层和解码器层,编码器将输入维度为784(28 28)的mnint灰度值转化为一个维度为2的值.编码器将维度为2的值解码回维度为784(28 28)的mnint灰度值.
使用python-keras代码实现关键代码如下.
def __init__(self, ENCODING_DIM_INPUT=784, ENCODING_DIM_OUTPUT=2, Name = "ae"):
input_image = Input(shape=(ENCODING_DIM_INPUT, ))
# encoding layer
hidden_layer = Dense(ENCODING_DIM_OUTPUT, activation='relu')(input_image)
# decoding layer
decode_output = Dense(ENCODING_DIM_INPUT, activation='relu')(hidden_layer)
# build autoencoder, encoder, decoder
autoencoder = Model(inputs=input_image, outputs=decode_output)
encoder = Model(inputs=input_image, outputs=hidden_layer)
# compile autoencoder
autoencoder.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
self.autoencoder = autoencoder
self.encoder = encoder
训练过程
本实验讨论使用relu和tanh两种激活函数的自监督训练的情况.训练的loss函数选择为方均根误差.
训练过程的loss变化图像如下.
使用tanh作为激活函数时,loss变化情况如下.
可以观察到,loss收敛到0.0685,效果较好.使用relu作为激活函数同样能够有效收敛,不过误差数值相对较大.由于篇幅原因不将图片在此进行展示.误差数值相对较大的原因将在下一节进行讨论.
编码器输出的可视化结果
本节将从重建图像和编码器输出层的二维可视化图像两部分进行展示,分别展示使用tanh和relu两种损失函数的训练结果.
训练好的自动编码器重建图像(使用relu激活函数)如下图:
训练好的自动编码器重建图像(使用tanh激活函数)如下图:
两者对比可以发现relu函数训练出的模型存在一些像素颗粒,这也验证了上一节loss函数较大的实验结果.为了解释该问题,展示编码器输出层的二维可视化图片.
训练好的编码器输出图像(使用relu激活函数)如下图:
训练好的编码器输出图像(使用tanh激活函数)如下图:
以上两张图片是 编码器-解码器 结构中编码器部分的输出绘制成的二维可视化图片,不同的颜色代表了不同的数字,对应的数字在右边的图例中进行了显示.从以上两张图片中可以得到:
说明与讨论
传统自编码器有很大的改进空间,改进空间的可以从几个方面阐述:
模型结构与实现代码
传统的自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:
模型分为三个子模块,由上至下分别为输入层,多层编码器层和多层解码器层,编码器将输入维度为784(28 28)的mnint灰度值转化为一个维度为2的值.编码器将维度为2的值解码回维度为784(28 28)的mnint灰度值
使用python-keras代码实现关键代码如下.
class DAE(ae.AE):
def __init__(
self, ENCODING_DIM_INPUT=784, ENCODING_DIM_LAYER1=128,
ENCODING_DIM_LAYER2=64, ENCODING_DIM_LAYER3=10,
ENCODING_DIM_OUTPUT=2,Name="dae" ):
# input placeholder
input_image = Input(shape=(ENCODING_DIM_INPUT, ))
# encoding layer
encode_layer1 = Dense(ENCODING_DIM_LAYER1,
activation='relu')(input_image)
encode_layer2 = Dense(ENCODING_DIM_LAYER2,
activation='relu')(encode_layer1)
encode_layer3 = Dense(ENCODING_DIM_LAYER3,
activation='relu')(encode_layer2)
encode_output = Dense(ENCODING_DIM_OUTPUT)(encode_layer3)
# decoding layer
decode_layer1 = Dense(ENCODING_DIM_LAYER3,
activation='relu')(encode_output)
decode_layer2 = Dense(ENCODING_DIM_LAYER2,
activation='relu')(decode_layer1)
decode_layer3 = Dense(ENCODING_DIM_LAYER1,
activation='relu')(decode_layer2)
decode_output = Dense(ENCODING_DIM_INPUT,
activation='tanh')(decode_layer3)
# build surprised learning model
SL_output = Dense(10, activation='softmax')(encode_output)
# build autoencoder, encoder
autoencoder = Model(inputs=input_image, outputs=decode_output)
encoder = Model(inputs=input_image, outputs=encode_output)
SL_model = Model(inputs=input_image, outputs=SL_output)
# compile autoencoder
autoencoder.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
代码定义了三个模型,分别是用于自监督训练的 autoencoder, 用于二维化的编码器 encoder 和用于进行有监督训练的 SL_model.
训练过程
堆叠降噪自动编码器分为无监督的预训练过程和有监督的训练过程两部分.
本部分分别进行说明.
自监督的预训练过程loss变化情况如下.
无监督的训练过程正确率acc变化情况如下.
可以看到,在两个训练阶段,方法可以有效的达到收敛.
以下几点需要指出:
编码器输出的可视化结果
本节将从重建图像和编码器输出层的二维可视化图像两部分进行展示
预训练部分
重建图像
下图展示了添加噪声的效果(第一行原图,第二行增加噪声的图).
下图展示了,对添加噪声的图片进行重构的结果(第一行增加噪声的图,第二行重构图)
编码器输出层的二维可视化图像
下图展示了添加噪声的效果(第一行原图,第二行增加噪声的图).
以下几点需要指出:
有监督训练部分
经过有监督的训练
重建图像(因为不是目标,所以必然走样)
下图展示了,对添加噪声的图片进行重构的结果(第一行增加噪声的图,第二行重构图)
编码器输出层的二维可视化图像
经过有监督学习,二维可视化图中各个组的界限更加清晰.
说明与讨论
堆叠降噪自编码器的改进有以下启发:
模型结构与实现代码
卷积自编码器自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:
使用python-keras代码实现关键代码如下.
def __init__(self,CHANNEL_1 = 16,CHANNEL_2 = 8,CHANNEL_OUTPUT = 1, Name="cae"):
# input placeholder
input_image = Input(shape=(28, 28, 1))
# encoding layer
x = Conv2D(CHANNEL_1, (3, 3), activation='relu', padding="same")(input_image)
x = MaxPool2D((2, 2), padding='same')(x)
x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(x)
encode_output = MaxPool2D((2, 2), padding='same')(x)
# decoding layer
x = Conv2D(CHANNEL_2, (3, 3), activation='relu', padding='same')(encode_output)
x = UpSampling2D((2, 2))(x)
x = Conv2D(CHANNEL_1, (3, 3),activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
decode_output = Conv2D(CHANNEL_OUTPUT, (3, 3), activation='sigmoid', padding='same')(x)
# build surprised learning model
encode_output_flatten = Flatten()(decode_output)
SL_output = Dense(10, activation='softmax')(encode_output_flatten)
# build autoencoder, encoder
autoencoder = Model(inputs=input_image, outputs=decode_output)
encoder = Model(inputs=input_image, outputs=encode_output)
SL_model = Model(inputs=input_image, outputs=SL_output)
# compile autoencoder
autoencoder.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
训练过程
堆叠降噪自动编码器分为无监督的预训练过程和有监督的训练过程两部分.
本部分分别进行说明.
在自监督的预训练过程loss变化情况如下.
图像显示,自监督的训练loss收敛于0.07左右,该误差比降噪自编码器的0.09要小.与传统自编码器的训练误差相差不多.但是从下文可知其训练效果明显优于传统自动编码器.
在有监督的训练过程正确率acc变化情况如下.
图像显示,有监督训练过程的正确率上升到0.99,比降噪自动编码器的正确(0.95)率更高.
因此在mnist数据集中的重建任务和分类任务中,卷积自动编码器有一定优势.
不过以下几点需要指出:
编码器输出的可视化结果
可以看到和stacked AE的主要区别在于局部卷积连接,而不所有层都是全连接。对图像和某些其他数据影响在空间局部的问题,比全连接更合适.因此效果更加优秀.
于降噪自动编码器相同,首先对图片增加噪声:
然后对增加噪声的图片进行去噪:
去噪结果比较优秀,与上文中所有的结果相比是最优秀的.
模型结构与实现代码
变分自动编码器的结构最为复杂,并且在模型中引入了隐变量,和KL散度等概率论概念.对模型的实现造成了一定的影响.
自动编码器分为编码器部分和解码器部分,整体模型结构如图所示:
上图中并没有展开编码器和解码器的结构,编码器(encoder) 与 解码器(decoder)的形式分别如下:
encoder:
decoder:
使用python-keras代码实现关键代码如下.
class VAE(ae.AE):
def __init__(
self,
ENCODING_DIM_INPUT = 784,
intermediate_dim = 512,
batch_size = 128,
latent_dim = 2,
mse_loss = True,
Name="vae"
):
self.name = Name
# input placeholder
input_image = Input(shape=(ENCODING_DIM_INPUT,), name='encoder_input')
# VAE model = encoder + decoder
# encoding layer
x = Dense(intermediate_dim, activation='relu')(input_image)
z_mean = Dense(latent_dim, name='z_mean')(x)
z_log_var = Dense(latent_dim, name='z_log_var')(x)
z = Lambda(sampling, output_shape=(latent_dim,), name='z')([z_mean, z_log_var])
# build decoder model
latent_inputs = Input(shape=(latent_dim,), name='z_sampling')
x = Dense(intermediate_dim, activation='relu')(latent_inputs)
outputs = Dense(ENCODING_DIM_INPUT, activation='sigmoid')(x)
# # build surprised learning model
# SL_output = Dense(10, activation='softmax')()
# build autoencoder, encoder
encoder = Model(input_image, [z_mean, z_log_var, z], name='encoder')
decoder = Model(latent_inputs, outputs, name='decoder')
# SL_model = Model(inputs=input_image, outputs=SL_output)
outputs = decoder(encoder(input_image)[2])
autoencoder = Model(input_image, outputs, name='vae_mlp')
# compile autoencoder
# VAE loss = mse_loss or xent_loss + kl_loss
if mse_loss:
reconstruction_loss = mse(input_image, outputs)
else:
reconstruction_loss = binary_crossentropy(input_image,outputs)
reconstruction_loss *= ENCODING_DIM_INPUT
kl_loss = 1 + z_log_var - K.square(z_mean) - K.exp(z_log_var)
kl_loss = K.sum(kl_loss, axis=-1)
kl_loss *= -0.5
vae_loss = K.mean(reconstruction_loss + kl_loss)
autoencoder.add_loss(vae_loss)
autoencoder.compile(optimizer='adam')
autoencoder.summary()
# SL_model.compile(optimizer='adam', loss='mse', metrics=['accuracy'])
self.autoencoder = autoencoder
self.encoder = encoder
self.decoder = decoder
训练过程
由于,变分自动编码器主要应用于图像生成,而并非是提取与分类,因此变分降噪自动编码器只有自监督的训练过程..
在自监督的训练过程,使用 KL散度+交叉熵 作为loss函数,loss变化情况如下.
可以看散度可以收敛到145的情况,能够有效进行收敛.
在自监督的训练过程,使用 KL散度+方均根 作为loss函数,loss变化情况如下.
对于两种损失函数效果的讨论在下文中进行.
自编码器输出的可视化结果
使用 KL散度+交叉熵 作为损失函数
基于kl散度的loss训练结果二维可视化如下
使用生成器对图像进行生成可以得到如下结果.
使用 KL散度+方均根 作为损失函数
基于kl散度的loss训练结果二维可视化如下
使用生成器对图像进行生成可以得到如下结果.
由于方均根与交叉熵的区别在于 解码器重现误差上面的区别,在编码器部分同样使用kl散度作为loss,因此两者的可视化结果类似.
以下几点需要指出:
原文链接
本文为云栖社区原创内容,未经允许不得转载。