目录

  • 一.原理
  • 二.为什么要使用自编码器
  • 三.代码实现
    • 1.原始自编码器
    • 2.多层(堆叠)自编码器
    • 3.卷积自编码器
    • 4.正则自编码器
      • 4.1稀疏自编码器
  • 四.降噪自编码器
  • 五. 逐层贪婪训练堆叠自编码器
  • 参考

一.原理

自编码器由两部分组成:
编码器(encoder):这部分能将输入压缩成潜在空间表征,可以用编码函数h=f(x)表示。
解码器(decoder):这部分重构来自潜在空间表征的输入,可以用解码函数r=g(h)表示。
因此,整个自编码器可以用函数g(f(x)) = r 来描述,其中输出r与原始输入x相近。

自编码器(Auto Encoder)可以认为是只有一层隐含层的神经网络,通过压缩和还原实现对特征的重构。输入数据是特征,输入层到隐含层是编码器,能将输入压缩成潜在空间表征;隐含层到输出层是解码器,重构来自潜在空间表征的输入。其中自编码器的输入输出神经元个数都等于特征维度。训练这个自编码器,使得输出的特征和输入的特征尽可能一致。自编码器试图复现其原始输入,因此,在训练中,网络中的输出应与输入相同,即y=x,因此,一个自编码器的输入、输出应有相同的结构。我们利用训练数据训练这个网络,等训练结束后,这个网络即学习出了x→h→x的能力。对我们来说,此时的h是至关重要的,因为它是在尽量不损失信息量的情况下,对原始数据的另一种表达。
其结构如下:

二.为什么要使用自编码器

我们希望通过训练输出值等于输入值的自编码器,让潜在表征h将具有价值属性。从自编码器获得有用特征的一种方法是,限制h的维度使其小于输入x, 这种情况下称作有损自编码器。通过训练有损表征,使得自编码器能学习到数据中最重要的特征。

三.代码实现

以手写数字识别为例

1.原始自编码器

input_size = 784
hidden_size = 64
output_size = 784x = Input(shape=(input_size,))# Encoder
h = Dense(hidden_size, activation='relu')(x)# Decoder
r = Dense(output_size, activation='sigmoid')(h)autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')

2.多层(堆叠)自编码器

input_size = 784
hidden_size = 128
code_size = 64x = Input(shape=(input_size,))# Encoder
hidden_1 = Dense(hidden_size, activation='relu')(x)
h = Dense(code_size, activation='relu')(hidden_1)# Decoder
hidden_2 = Dense(hidden_size, activation='relu')(h)
r = Dense(input_size, activation='sigmoid')(hidden_2)autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')

3.卷积自编码器

除了全连接层,自编码器也可以应用到卷积层,原理是一样的,但是要使用3D矢量(如图像)而不是展平后的一维矢量。对输入图像进行下采样,以提供较小维度的潜在表征,来迫使自编码器从压缩后的数据进行学习。

x = Input(shape=(28, 28,1)) # Encoder
conv1_1 = Conv2D(16, (3, 3), activation='relu', padding='same')(x)
pool1 = MaxPooling2D((2, 2), padding='same')(conv1_1)
conv1_2 = Conv2D(8, (3, 3), activation='relu', padding='same')(pool1)
pool2 = MaxPooling2D((2, 2), padding='same')(conv1_2)
conv1_3 = Conv2D(8, (3, 3), activation='relu', padding='same')(pool2)
h = MaxPooling2D((2, 2), padding='same')(conv1_3)# Decoder
conv2_1 = Conv2D(8, (3, 3), activation='relu', padding='same')(h)
up1 = UpSampling2D((2, 2))(conv2_1)
conv2_2 = Conv2D(8, (3, 3), activation='relu', padding='same')(up1)
up2 = UpSampling2D((2, 2))(conv2_2)
conv2_3 = Conv2D(16, (3, 3), activation='relu')(up2)
up3 = UpSampling2D((2, 2))(conv2_3)
r = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(up3)autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')

4.正则自编码器

除了施加一个比输入维度小的隐含层,一些其他方法也可用来约束自编码器重构,如正则自编码器。

正则自编码器不需要使用浅层的编码器和解码器以及小的编码维数来限制模型容量,而是使用损失函数来鼓励模型学习其他特性(除了将输入复制到输出)。这些特性包括稀疏表征、小导数表征、以及对噪声或输入缺失的鲁棒性。

即使模型容量大到足以学习一个无意义的恒等函数,非线性且过完备的正则自编码器仍然能够从数据中学到一些关于数据分布的有用信息。

在实际应用中,常用到两种正则自编码器,分别是稀疏自编码器和降噪自编码器

4.1稀疏自编码器

一种用来约束自动编码器重构的方法,是对其损失函数施加约束。比如,可对损失函数添加一个正则化约束,这样能使自编码器学习到数据的稀疏表征。

要注意,在隐含层中,我们还加入了L1正则化,作为优化阶段中损失函数的惩罚项。与香草自编码器相比,这样操作后的数据表征更为稀疏。

input_size = 784
hidden_size = 64
output_size = 784x = Input(shape=(input_size,))# Encoder
h = Dense(hidden_size, activation='relu', activity_regularizer=regularizers.l1(10e-5))(x)#施加在输出上的L1正则项# Decoder
r = Dense(output_size, activation='sigmoid')(h)autoencoder = Model(input=x, output=r)
autoencoder.compile(optimizer='adam', loss='mse')

四.降噪自编码器

降噪自动编码器就是在自动编码器的基础之上,为了防止过拟合问题而对输入层的输入数据加入噪音,以一定概率分布(通常使用二项分布)去擦除原始input矩阵,即每个值都随机置0,这样看起来部分数据的部分特征是丢失了。向训练数据加入噪声,并使自编码器学会去除这种噪声来获得没有被噪声污染过的真实输入。因此,这就迫使编码器学习提取最重要的特征并学习输入数据中更加鲁棒的表征,这也是它的泛化能力比一般编码器强的原因。

这里不是通过对损失函数施加惩罚项,而是通过改变损失函数的重构误差项来学习一些有用信息。

向训练数据加入噪声(高斯噪声或者随机置0),并使自编码器学会去除这种噪声来获得没有被噪声污染过的真实输入。因此,这就迫使编码器学习提取最重要的特征并学习输入数据中更加鲁棒的表征,这也是它的泛化能力比一般编码器强的原因。

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))# 添加噪声
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.)# 自编码器
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')# 训练自编码器
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='/tmp/tb', histogram_freq=0, write_graph=False)])

五. 逐层贪婪训练堆叠自编码器

这种方法一定程度上能解决梯度消失梯度爆炸的问题,但现在很少用了。

每次训练都只训练一个自编码器,训练完该自编码器后,抛弃输入层跟输出层,将隐含层作为下一个自编码器的输入层,然后训练下一个自编码器。当训练完多个自编码器后,比如4个,训练了4个隐含层结构,将这4个隐含层结构和参数提取出来作为神经网络的隐含层结构和初始化参数。最后,在神经网络添加输出层预测平均接受信号功率,微调这个网络。

逐层贪婪算法的主要思路是每次只训练网络中的一层,即我们首先训练一个只含一个隐藏层的网络,仅当这层网络训练结束之后才开始训练一个有两个隐藏层的网络,以此类推。在每一步中,我们把已经训练好的前k-1层固定,然后增加第k层(也就是将我们已经训练好的前k-1的输出作为输入)。每一层的训练可以是有监督的(例如,将每一步的分类误差作为目标函数),但更通常使用无监督方法(例如自动编码器,我们会在后边的章节中给出细节)。这些各层单独训练所得到的权重被用来初始化最终(或者说全部)的深度网络的权重,然后对整个网络进行“微调”(即把所有层放在一起来优化有标签训练集上的训练误差)。

参考

自编码器(AutoEncoder)入门及TensorFlow实现
自编码器(Autoencoders)
keras实现各种自编码器
tensorflow 1.0+版本的代码实现

自编码器(Auto Encoder)原理及其python实现相关推荐

  1. 【人工智能概论】 变分自编码器(Variational Auto Encoder , VAE)

    [人工智能概论] 变分自编码器(Variational Auto Encoder , VAE) 文章目录 [人工智能概论] 变分自编码器(Variational Auto Encoder , VAE) ...

  2. 【深度学习】李宏毅2021/2022春深度学习课程笔记 - Auto Encoder 自编码器 + PyTorch实战

    文章目录 一.Basic Idea of Auto Encoder 1.1 Auto Encoder 结构 1.2 Auto Encoder 降维 1.3 Why Auto Encoder 1.4 D ...

  3. 11旋转编码器原理图_plc编程入门:浅谈编码器的工作原理!

    编码器(encoder)是将信号(如比特流)或数据进行编制.转换为可用以通讯.传输和存储的信号形式的设备.编码器把角位移或直线位移转换成电信号,前者称为码盘,后者称为码尺. 编码器主要是由码盘(圆光栅 ...

  4. Auto Encoder用于异常检测

    对基于深度神经网络的Auto Encoder用于异常检测的一些思考 from:https://my.oschina.net/u/1778239/blog/1861724 一.前言 现实中,大部分数据都 ...

  5. 4位格雷码的顺序编码_整理丨一文掌握编码器的工作原理!

    编码器的定义与功能 在数字系统里,常常需要将某一信息(输入)变换为某一特定的代码(输出).把二进制码按一定的规律编排,例如8421码.格雷码等,使每组代码具有一特定的含义(代表某个数字或控制信号)称为 ...

  6. 堆叠降噪自动编码器 Stacked Denoising Auto Encoder(SDAE)

    原文链接 自动编码器(Auto-Encoder,AE) 自动编码器(Auto-Encoder,AE)自编码器(autoencoder)是神经网络的一种,经过训练后能尝试将输入复制到输出.自编码器内部有 ...

  7. STM32——编码器测速原理及STM32编码器模式

    1. 编码器概述 编码器是一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感 器,我们可以通过编码器测量到底位移或者速度信息.编码器从输出数据类型上 分,可以分为增量式编码器和绝对式编码器. 从 ...

  8. Masked Auto Encoder总结

    Masked Auto Encoder总结 文章目录 Masked Auto Encoder总结 MAE简介 Random Mask random mask 逻辑 random mask 实现 Enc ...

  9. arduino编码器计数_旋转编码器的工作原理以及如何在Arduino中使用

    在本篇文章中,我们将学习旋转编码器的工作原理以及如何将其与Arduino开发板一起使用.旋转编码器是一种位置传感器,用于确定旋转轴的角度位置.它根据旋转运动产生模拟或数字电信号. Rotary-Enc ...

最新文章

  1. TOPAS 命令详解
  2. 上传问题总结(文件大小检测,大文件上传)
  3. jvm 常用调试工具和设置jvm GC方法和指令
  4. inputstream重新赋值之前需要close吗_变量提升真的搞懂了吗?打脸的一道题
  5. php调用webservice报错Class 'SoapClient' not found
  6. catia保存成stp文件时部件丢失_在线教学文件同步神器——坚果云
  7. 口腔取模过程及注意事项_为什么牙齿矫正前要拍片取模,没有拍片取模就设计不了详细方案!...
  8. 在xcode中用oc实现计算器
  9. bootstrap-table初始化配置
  10. Mp3原理及文件格式解析
  11. 手机测试SD卡读写速度的软件,手机存储SD卡读写测试:Cross Platfrom Disk Test
  12. 台式机黑苹果独显驱动
  13. 数据结构基础知识(一)
  14. 我的编程之路点滴记录(二)
  15. 【愚公系列】2022年02月 微信小程序-数据绑定
  16. 微信开发者工具创建vue项目步骤
  17. 转换率是什么?如何提升转换率(CVR)?
  18. Java将Unicode转换成中文
  19. 金海佳学C++primer 练习9.41
  20. pythonocc_pythonocc

热门文章

  1. 【struts2】名为dispatcher的ResultType
  2. 告诉大家一个------无敌命令
  3. VS2017-VC++校验和计算小工具
  4. mate30升级鸿蒙系数据会被清空吗,145直接升级鸿蒙会不会掉资料
  5. 论文《Attention Is All You Need》及Transformer模型
  6. R语言:常用函数总结
  7. DES算法C语言实现
  8. SAGE(SAGEMATH)密码学基本使用方法
  9. 一和零(二维01背包)
  10. 密码(图解密码技术)_第二章_历史上的密码