5.2 自动编码器
学习目标
- 目标
- 了解自动编码器作用
- 说明自动编码器的结构
- 应用
- 使用自动编码器对Mnist手写数字进行数据降噪处理
5.2.1 自动编码器什么用
自编码器的应用主要有两个方面
- 数据去噪
- 进行可视化而降维
- 自编码器可以学习到比PCA等技术更好的数据投影
5.2.1 什么是自动编码器(Autoencoder)
5.2.1.1 定义
自动编码器是一种数据的压缩算法,一种使用神经网络学习数据值编码的无监督方式。
5.2.1.2 原理作用案例
搭建一个自动编码器需要完成下面三样工作:
- 搭建编码器
- 搭建解码器
- 设定一个损失函数,用以衡量由于压缩而损失掉的信息。
- 编码器和解码器一般都是参数化的方程,并关于损失函数可导,通常情况是使用神经网络。
5.2.1.3 类别
- 普通自编码器
- 编解码网络使用全连接层
- 多层自编码器
- 卷积自编码器
- 编解码器使用卷积结构
- 正则化自编码器
- 降噪自编码器
5.2.2 Keras快速搭建普通自编码器-基于Mnist手写数字
5.2.2.1 自编码器效果
- 迭代50次效果
Train on 60000 samples, validate on 10000 samples
Epoch 1/50
256/60000 [..............................] - ETA: 44s - loss: 0.6957
1280/60000 [..............................] - ETA: 11s - loss: 0.6867
2560/60000 [>.............................] - ETA: 6s - loss: 0.6699
3584/60000 [>.............................] - ETA: 5s - loss: 0.6493
...
...
...
55808/60000 [==========================>...] - ETA: 0s - loss: 0.0925
57088/60000 [===========================>..] - ETA: 0s - loss: 0.0925
58112/60000 [============================>.] - ETA: 0s - loss: 0.0925
59392/60000 [============================>.] - ETA: 0s - loss: 0.0925
60000/60000 [==============================] - 3s 47us/step - loss: 0.0925 - val_loss: 0.0914
5.2.2.2 流程
- 初始化自编码器结构
- 训练自编码器
- 获取数据
- 模型输入输出训练
- 显示自编码前后效果对比
5.2.2.3 代码编写
导入所需包
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
- 1、初始化自编码器结构
定义编码器:输出32个神经元,使用relu激活函数,(32这个值可以自己制定)
定义解码器:输出784个神经元,使用sigmoid函数,(784这个值是输出与原图片大小一致)
损失:
- 每个像素值的交叉熵损失(输出为sigmoid值(0,1),输入图片要进行归一化(0,1))
class AutoEncoder(object):
"""自动编码器
"""
def __init__(self):
self.encoding_dim = 32
self.decoding_dim = 784
self.model = self.auto_encoder_model()
def auto_encoder_model(self):
"""
初始化自动编码器模型
将编码器和解码器放在一起作为一个模型
:return: auto_encoder
"""
input_img = Input(shape=(784,))
encoder = Dense(self.encoding_dim, activation='relu')(input_img)
decoder = Dense(self.decoding_dim, activation='sigmoid')(encoder)
auto_encoder = Model(inputs=input_img, outputs=decoder)
auto_encoder.compile(optimizer='adam', loss='binary_crossentropy')
return auto_encoder
- 2、训练流程
- 读取Mnist数据,并进行归一化处理以及形状修改
- 模型进行fit训练
- 指定迭代次数
- 指定每批次数据大小
- 是否打乱数据
- 验证集合
def train(self):
"""
训练自编码器
:param model: 编码器结构
:return:
"""
(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), np.prod(x_train.shape[1:])))
x_test = np.reshape(x_test, (len(x_test), np.prod(x_test.shape[1:])))
print(x_train.shape)
print(x_test.shape)
# 训练
self.model.fit(x_train, x_train,
epochs=5,
batch_size=256,
shuffle=True,
validation_data=(x_test, x_test))
- 3、显示模型生成的图片与原始图片对比
- 导入matplotlib包
def display(self):
"""
显示前后效果对比
:return:
"""
(x_train, _), (x_test, _) = mnist.load_data()
x_test = np.reshape(x_test, (len(x_test), np.prod(x_test.shape[1:])))
decoded_imgs = self.model.predict(x_test)
plt.figure(figsize=(20, 4))
# 显示5张结果
n = 5
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 + n + 1)
plt.imshow(decoded_imgs[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
5.2.3 基于Mnist手写数字-深度自编码器
- 将多个自编码进行重叠
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)
auto_encoder = Model(input=input_img, output=decoded)
auto_encoder.compile(optimizer='adam', loss='binary_crossentropy')
我们可以替换原来的编码器进行测试
59392/60000 [============================>.] - ETA: 0s - loss: 0.0860
最后的损失会较之前同样的epoch迭代好一些
5.2.4 基于Mnist手写数字-卷积自编码器
- 卷积编解码结构设计
- 编码器
- Conv2D(32, (3, 3), activation='relu', padding='same')
- MaxPooling2D((2, 2), padding='same')
- Conv2D(32, (3, 3), activation='relu', padding='same')
- MaxPooling2D((2, 2), padding='same')
- 输出大小为:Tensor("max_pooling2d_2/MaxPool:0", shape=(?, 7, 7, 32), dtype=float32)
- 解码器:反卷积过程
- Conv2D(32, (3, 3), activation='relu', padding='same')
- UpSampling2D((2, 2))
- Conv2D(32, (3, 3), activation='relu', padding='same')
- UpSampling2D((2, 2))
- Conv2D(1, (3, 3), activation='sigmoid', padding='same')
- 输出大小:Tensor("conv2d_5/Sigmoid:0", shape=(?, 28, 28, 1), dtype=float32)
- 编码器
input_img = Input(shape=(28, 28, 1))
x = Conv2D(32, (3, 3), activation='relu', padding='same')(input_img)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
encoded = MaxPooling2D((2, 2), padding='same')(x)
print(encoded)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(encoded)
x = UpSampling2D((2, 2))(x)
x = Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = UpSampling2D((2, 2))(x)
decoded = Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
print(decoded)
auto_encoder = Model(input_img, decoded)
auto_encoder.compile(optimizer='adam', loss='binary_crossentropy')
由于修改了模型的输入输出数据形状,所以在训练的地方同样也需要修改(显示的时候数据输入也要修改)
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
5.2.4 基于Mnist手写数字-降噪自编码器
- 降噪自编码器效果
- 过程
- 对原始数据添加噪音
- 随机加上正态分布的噪音
- x_train + np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)
# 添加噪音
x_train_noisy = x_train + np.random.normal(loc=0.0, scale=3.0, size=x_train.shape)
x_test_noisy = x_test + np.random.normal(loc=0.0, scale=3.0, size=x_test.shape)
# 重新进行限制每个像素值的大小在0~1之间
x_train_noisy = np.clip(x_train_noisy, 0., 1.)
x_test_noisy = np.clip(x_test_noisy, 0., 1.)
在进行显示的时候也要进行修改
# 获取数据改变形状,增加噪点数据
(x_train, _), (x_test, _) = mnist.load_data()
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
x_test_noisy = x_test + np.random.normal(loc=3.0, scale=10.0, size=x_test.shape)
# 预测结果
decoded_imgs = self.model.predict(x_test_noisy)
# 修改需要显示的图片变量
plt.imshow(x_test_noisy[i].reshape(28, 28))
5.2.5 总结
- 掌握自动编码器的结构
- 掌握正则化自动编码器结构作用