去噪自编码器(DAE)
去噪自编码器(DAE)
- 0. 前言
- 1. 去噪自编码器原理
- 2. 实现去噪自编码器
- 3. 去噪结果分析
0. 前言
在本节中,我们将构建一个具有实际应用价值的自编码器。首先设想一个场景:MNIST
手写数字图像受到噪声污染,导致人类难以辨认。我们可以构建一个去噪自编码器 (denoising autoencoder
, DAE
) 来消除这些图像中的噪声。下图展示了三组 MNIST
数字样本:每组顶行为原始图像,中间行显示的是输入 DAE
的含噪图像(人类已难以辨识),最后一行则呈现了 DAE
处理后的输出结果。
1. 去噪自编码器原理
去噪自编码器的网络结构与 MNIST 自编码器基本相同。输入可以定义为:
x=xorig+noisex = x_{orig} + noise x=xorig+noise
xorigx_{orig}xorig 表示被噪声 noisenoisenoise 破坏的原始 MNIST
图像。编码器的目的是发现潜向量 zzz,以使解码器能够通过最小化差异损失函数(例如均方误差)来恢复 xorigx_{orig}xorig:
L(xorig,x~)=MSE=1m∑i=1m(xorigi−x~i)2\mathcal L(x_{orig}, \tilde x) = MSE =\frac 1m \sum_{i=1}^m(x_{orig_i} - \tilde x_i)^2 L(xorig,x~)=MSE=m1i=1∑m(xorigi−x~i)2
其中,mmm 表示输出维度,xorigix_{orig_i}xorigi 和 x~i\tilde x_ix~i 分别是 xorigx_{orig}xorig 和 x~\tilde xx~ 的元素。
2. 实现去噪自编码器
为实现去噪自编码器,我们需要对自编码器进行几处调整。首先,训练输入数据添加噪声的 MNIST
数字。训练输出数据是原始干净 MNIST
数字。
import numpy as np
import tensorflow as tf
from tensorflow import keras
from matplotlib import pyplot as plt
from PIL import Imagenp.random.seed(1234)(x_train,_),(x_test,_) = keras.datasets.mnist.load_data()#数据预处理
image_size = x_train.shape[1]
x_train = np.reshape(x_train,[-1,image_size,image_size,1])
x_test = np.reshape(x_test,[-1,image_size,image_size,1])
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.#产生高斯分布的噪声
noise = np.random.normal(loc=0.5,scale=0.5,size=x_train.shape)
x_train_noisy = x_train + noise
noise = np.random.normal(loc=0.5,scale=0.5,size=x_test.shape)
x_test_noisy = x_test + noise
x_train_noisy = np.clip(x_train_noisy,0.0,1.0)
x_test_noisy = np.clip(x_test_noisy,0.0,1.0)#超参数
input_shape = (image_size,image_size,1)
batch_size = 32
kernel_size = 3
latent_dim = 16
layer_filters = [32,64]#encoder
inputs = keras.layers.Input(shape=input_shape,name='encoder_input')
x = inputs
for filters in layer_filters:x = keras.layers.Conv2D(filters=filters,kernel_size=kernel_size,strides=2,activation='relu',padding='same')(x)
shape = keras.backend.int_shape(x)x = keras.layers.Flatten()(x)
latent = keras.layers.Dense(latent_dim,name='latent_vector')(x)
encoder = keras.Model(inputs,latent,name='encoder')
encoder.summary()#decoder
latent_inputs = keras.layers.Input(shape=(latent_dim,),name='decoder_input')
x = keras.layers.Dense(shape[1]*shape[2]*shape[3])(latent_inputs)
x = keras.layers.Reshape((shape[1],shape[2],shape[3]))(x)
for filters in layer_filters[::-1]:x = keras.layers.Conv2DTranspose(filters=filters,kernel_size=kernel_size,strides=2,padding='same',activation='relu')(x)
outputs = keras.layers.Conv2DTranspose(filters=1,kernel_size=kernel_size,padding='same',activation='sigmoid',name='decoder_output')(x)
decoder = keras.Model(latent_inputs,outputs,name='decoder')
decoder.summaryautoencoder = keras.Model(inputs,decoder(encoder(inputs)),name='autoencoder')
autoencoder.summary()autoencoder.compile(loss='mse',optimizer='adam')
autoencoder.fit(x_train_noisy,x_train,validation_data=(x_test_noisy,x_test),epochs=10,batch_size=batch_size)x_decoded = autoencoder.predict(x_test_noisy)rows,cols = 3,9
num = rows * cols
imgs = np.concatenate([x_test[:num],x_test_noisy[:num],x_decoded[:num]])
imgs = imgs.reshape((rows * 3, cols, image_size, image_size))
imgs = np.vstack(np.split(imgs,rows,axis=1))
imgs = imgs.reshape((rows * 3,-1,image_size,image_size))
imgs = np.vstack([np.hstack(i) for i in imgs])
imgs = (imgs * 255).astype(np.uint8)
plt.figure()
plt.axis('off')
plt.imshow(imgs,interpolation='none',cmap='gray')
plt.show()
3. 去噪结果分析
我们通过添加随机噪声来模拟图像污染,所使用的噪声为均值 μ=0.5μ=0.5μ=0.5、标准差 σ=0.5σ=0.5σ=0.5 的高斯分布。为防止像素值超出有效范围 [0,1]
,对生成值进行了截断处理。采用均方误差损失函数和 Adam
优化器,下图展示了 DAE
在不同噪声强度下的鲁棒性表现:当噪声标准差升至 0.75
时模型仍能有效复原图像,但当 σ=1.0σ=1.0σ=1.0 时,部分数字已无法正确重建。