Deep Learning(深度学习)实验二:自编码器图像降噪
一、前期准备
- 自编码器: 自编码器是神经网络的一种,经过训练后能够将输入复制到输出。该网络可以看到由两部分组成:一个由函数h=f(x)表示的编码器和一个生成重构的解码器r=g(h)。
- 实现方法: 用CNN实现自编码器,通过学习从原始图片到加噪图片的映射,完成图像去噪任务。
- 使用的数据集: MNIST(手写数字识别数据集)
- 需要的包: Keras,数据集MNIST在Keras这个包里,而且这个包好像有点大,install用了一些时间。
- np.clip: np.clip是一个截取函数,用于截取数组中小于或者大于某值的部分,并使得被截取部分等于固定值。
np.clip(a, a_min, a_max, out=None)
a:输入矩阵;
a_min:被限定的最小值,所有比a_min小的数都会强制变为a_min;
a_max:被限定的最大值,所有比a_max大的数都会强制变为a_max;
out:可以指定输出矩阵的对象,shape与a相同 - Feature Map: Feature Map是卷积核卷出来的,你用各种情况下的卷积核去乘以原图,会得到各种各样的feature map。你可以理解为你从多个角度去分析图片。而不同的特征提取(核)会提取不同的feature,模型想要达成的目的是解一个最优化,来找到能解释现象的最佳的一组卷积核。
二、具体实验过程
-
导入需要用到的包:
from keras.datasets import mnist import numpy as np import matplotlib.pyplot as plt
这个降噪实验是基于mnist这个数据集来做的所有需要首先导入这个数据集。
from keras.datasets import mnist
-
加载MNIST数据,不需要对应的标签,所以只需要x不需要y,y表示图片上的数字具体是几
(x_train, _), (x_test, _) =mnist.load_data()
-
将像素值归一化到0-1,因为像素值原本是0-255,所以除以255归一
x_train = x_train.astype('float32') / 255 x_test = x_test.astype('float32') / 255
-
进行reshape,将其变成重塑为N128*28的四维tensor,x_train是原始数据 len(x_train)表示图片的个数 28表示高度 28表示宽度 1表示深度
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1)) x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
-
添加白噪声,使得添加噪声后图片的像素值仍处在0~1之间,noise_factor = 0.5表示添加的噪声比例
noise_factor = 0.5
-
噪声=原始数据+噪声比例*随机normal,loc=0.0均值是零,scale=1.0方差是1,size=x_train.reshape()数组大小和原始数据一样
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)
-
通过clip函数保证数据范围是0~1,不能有负数
x_train_noisy = np.clip(x_train_noisy, 0., 1.) x_test_noisy = np.clip(x_test_noisy, 0., 1.)
-
用matplotlib来展示加噪后的效果
n = 10 # 图片个数为10 plt.figure(figsize=(20, 2)) # 图片size是20*2 for i in range(n): ax = plt.subplot(1, n, i+1) # 1行 10列 获取第i+1个子图 plt.imshow(x_test_noisy[i].reshape(28, 28)) plt.gray() # 隐藏图片的x轴y轴 ax.get_xaxis().set_visible(False) ax.get_yaxis().set_visible(False) plt.show()
具体效果如下:
-
下一步需要考虑如何建立模型,使得x_train映射到x_train_noisy,x_test映射到x_test_noisy
-
导入新的所需的包
Input是输入层,Dense是全连接层,Conv2D是二维卷积,MaxPooling2D是二维池化,UpSampling2D是二维上采样from keras.layers import Input, Dense, Conv2D, MaxPooling2D, UpSampling2D
load_model
用于保存加载模型from keras.models import Model, load_model
-
在keras中,数据是以张量的形式表示的,张量的形状称之为shape,表示从最外层向量逐步到达最底层向量的降维解包过程。“维”的也叫“阶”,形状指的是维度数和每维的大小。比如,一个一阶的张量[1,2,3]的shape是(3,);一个二阶的张量[[1,2,3],[4,5,6]]的shape是(2,3);一个三阶的张量[[[1],[2],[3]],[[4],[5],[6]]]的shape是(2,3,1),input_shape就是指输入张量的shape。
-
(28, 28, 1,)表示(高度,宽度,深度,空出来的是不确定的数据个数)
input_img = Input(shape=(28, 28, 1,))
-
encoder部分:
-
Conv2D表示是二维的卷积,32表示tensor数组深度,(3, 3)表示卷积盒的大小,padding='same’表示卷积后图像尺寸不变,activation='relu’表示激活函数是relu,(input_img)表示输入
x = Conv2D(32, (3, 3), padding='same', activation='relu')(input_img) # 图片规格:28*28*32
-
MaxPooling2D表示二维的最大池化,size为(2, 2),输入为(x)
x = MaxPooling2D((2, 2), padding='same')(x) # 图片规格: 14*14*32
-
二次卷积
x = Conv2D(32, (3, 3), padding='same', activation='relu')(x) # 图片规格: 14*14*32
-
最大池化赋值给encoded
encoded = MaxPooling2D((2, 2), padding='same')(x) # 图片规格: 7*7*32
-
decoder部分:
-
上面的图片规格传下来是:7732
x = Conv2D(32, (3, 3), padding='same', activation='relu')(encoded) # 图片规格: 7*7*32
-
UpSampling2D表示上采样,与MaxPooling2D是相反的作用
x = UpSampling2D((2, 2))(x) # 图片规格: 14*14*32 x = Conv2D(32, (3, 3), padding='same', activation='relu')(x) # 图片规格: 14*14*32 x = UpSampling2D((2, 2))(x) # 图片规格:28*28*32 decoded = Conv2D(1, (3, 3), padding='same', activation='sigmoid')(x) # 图片规格:28*28*1
-
将输入和输出连接,构成自编码器并compile
input_img是整个模型的input,decoded是整个模型的outputautoencoder = Model(input_img, decoded)
-
optimizer:优化函数,loss:损失函数
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
-
# 用x_train作为输入和输出进行训练,用x_test进行校验
x_train_noisy:输入,x_train:输出,epochs=100训练一百轮迭代,shuffle=True:训练后随机打乱autoencoder.fit(x_train_noisy, x_train, epochs=100, batch_size=128, shuffle=True, validation_data=(x_test_noisy, x_test))
-
将训练后的模型保存下来
autoencoder.save('autoencoder1.h5') autoencoder = load_model('autoencoder1.h5') decoded_imgs = autoencoder.predict(x_test_noisy)
-
图片展示
n = 10 plt.figure(figsize=(20, 4)) for i in range(n): ax = plt.subplot(2, n, i+1) plt.imshow(x_test_noisy[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()
- 实验结果截图:
- 实验结果截图: