一文教你如何使用自动编码器进行图像去噪
磐创AI介绍让我们从理解术语“图像去噪”的含义来开始我们的讨论,这也是我们的文章标题——
图像去噪是从图像中去除噪声的过程
图像中存在的噪声可能是由实际上难以处理的各种内在或外在条件引起的。图像去噪问题是图像处理和计算机视觉领域的一个非常基本的挑战 。因此,它在许多领域中发挥着重要作用,获取原始图像对于鲁棒性能非常重要。
让我们看看存在噪声的图像是什么样子的:
带有噪声的图像示例
因此,在本文中,我们将看到如何使用自动编码器或编码器-解码器网络从带有噪声的图像中去除噪声。
在本文中,我将使用深度人工神经网络实现自动编码器。我的下一篇文章中,我还将针对相同的问题陈述使用深度卷积神经网络来描述自动编码器。所以,试试这个项目,并在我的下一个教程中继续关注我们。
现在,让我们也看看去除噪声后图像的外观:
对顽皮狗图像进行降噪之前和降噪之后
现在,让我们通过了解一些关于自动编码器的基本概念来开始我们的讨论。
编码器-解码器网络(自动编码器)概述自编码器是一种无监督的人工神经网络,经过训练可以将其输入复制到输出。对于图像数据,自动编码器将首先将图像编码为低维表示,然后将该表示解码回图像。编码器-解码器包含以下两种结构:编码器 - 该网络将数据下采样到较低的维度。解码器 -该网络从较低维度的表示中重建原始数据。较低维度(即编码器网络的输出)表示通常称为 潜在空间表示。关于自动编码器,我们必须记住的一件事是,它们只能压缩与它们接受过训练的数据相似的数据。它们本质上也是有损的,这意味着相对于原始输入,输出将降级。
它们通过反向传播进行类似于人工神经网络的训练。
让我们开始吧!!加载必要的库
第一步是加载必要的 Python 库。我们将导入诸如numpy 之类的库,用于优化矩阵乘法,matplotlib用于数据可视化,例如绘制图像。来自 Keras 的序列模型为我们提供了一个空的架构,根据我们的架构,我们将在其中添加几个全连接层,Dense在我们的网络中创建全连接层,直接从Keras导入MNIST数据集。
import numpy
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense
from keras.datasets import mnist
现在,我们完成了导入必要库的第一步,让我们继续以 numpy 的形式加载数据集。
以 Numpy 格式加载数据集
在本文中,我们将使用 MNIST 数据集,这是一个简单的计算机视觉数据集。它由灰度形式的手写数字图像组成。它还包括每个图像的标签,告诉我们它是哪个数字(即每个图像的输出)。这意味着我们手中有一个标记数据可以使用。MNIST 数据集中的每个图像都是 28 x 28 像素。
让我们看看 MNIST 数据集中的一些图像:
我们将把我们的 MNIST 数据分成两部分:
训练数据集: 60,000 个数据点属于训练数据集
测试数据集: 10,000 个数据点属于测试数据集
(X_train, y_train), (X_test, y_test) = mnist.load_data()
输出:
让我们借助以下代码行来看看我们的 NumPy 数组的形状:
X_train.shape
输出:
(60000, 28, 28)
上面的输出表明我们有 60,000 张训练图像,每张图像由 28 x 28 像素组成。
X_test.shape
输出:
(10000, 28, 28)
上面的输出表明我们有 10,000 个测试图像,每个图像由 28 x 28 像素组成。将图像绘制为灰度图像现在,到上述部分,我们将加载完整的数据集,并将其分为训练集和测试集。因此,在本节中,我们将使用matplotlib库绘制一些我们的数据集图像,具体而言,我们使用的是matplotlib库的 subplot 函数同时绘制多个图像。
plt.subplot(221)
plt.imshow(X_train[0], cmap=plt.get_cmap('gray'))
plt.subplot(222)
plt.imshow(X_train[1], cmap=plt.get_cmap('gray'))
plt.subplot(223)
plt.imshow(X_train[2], cmap=plt.get_cmap('gray'))
plt.subplot(224)
plt.imshow(X_train[3], cmap=plt.get_cmap('gray'))
# show the plot
plt.show()
输出:
格式化 Keras 数据我们可以将二维图像数组展平为28×28=784 个数字的向量。只要我们在图像之间保持一致,这与我们如何展平阵列无关。从这个角度来看,MNIST 图像只是784 维向量空间中的一堆点 。但数据应始终采用“ (数据点数,数据点维度)”格式。在这种情况下,训练数据的格式为60,000×784。
num_pixels = X_train.shape[1] * X_train.shape[2]
X_train = X_train.reshape(X_train.shape[0], num_pixels).astype('float32')
X_test = X_test.reshape(X_test.shape[0], num_pixels).astype('float32')
X_train = X_train / 255
X_test = X_test / 255
让我们借助以下几行代码再次看看我们的 NumPy 数组的形状:
X_train.shape
输出:
(60000, 784)
X_test.shape
输出:
(10000, 784)
给图像添加噪点在解决问题陈述时,我们必须记住我们的目标是制作一个能够对图像执行噪声去除的模型。为了能够做到这一点,我们将使用现有图像并给它们添加随机噪声。在这里,我们将原始图像作为输入,我们将噪声图像作为输出,我们的模型(即自动编码器)将学习干净图像和噪声图像之间的关系,并学习如何清理噪声图像。因此,让我们创建 MNIST 数据集的噪声版本,并将其作为解码器网络的输入。我们首先定义一个噪声因子,它是一个超参数。噪声因子乘以均值为 0.0 且标准差为 1.0 的随机矩阵。该矩阵将从正态(高斯)分布中抽取样本。在添加噪声时,我们必须记住正态随机数组的形状与你将添加噪声的数据的形状类似。
noise_factor = 0.2
x_train_noisy = X_train + noise_factor * numpy.random.normal(loc=0.0, scale=1.0, size=X_train.shape)
x_test_noisy = X_test + noise_factor * numpy.random.normal(loc=0.0, scale=1.0, size=X_test.shape)
x_train_noisy = numpy.clip(x_train_noisy, 0., 1.)
x_test_noisy = numpy.clip(x_test_noisy, 0., 1.)
看到上面的代码,你可能会想,这里为什么要用这个clip函数呢?为了确保我们最终的图像数组项值在 0 到 1 的范围内,我们可以使用**np.clip ** 方法。clip 是numpy的函数,用于剪辑min - max范围之外的值,并用指定的最小或最大值替换它们。
让我们看看噪声图像是什么样子的:
手写数字的噪声图像定义编码器-解码器网络它将有一个 784 个神经元的输入层,因为我们的图像大小为 784,因为存在 28 x 28 个像素(即我们有 784 个神经元的输入维度和输出层)。
# create model
model = Sequential()
model.add(Dense(500, input_dim=num_pixels, activation='relu'))
model.add(Dense(300, activation='relu'))
model.add(Dense(100, activation='relu'))
model.add(Dense(300, activation='relu'))
model.add(Dense(500, activation='relu'))
model.add(Dense(784, activation='sigmoid'))
编译模型一旦定义了模型,我们就必须编译它。在编译时,我们提供要使用的损失函数、优化器和任何指标。对于我们的问题陈述,我们将为我们的模型使用Adam 优化器和均方误差。
# Compile the model
model.compile(loss='mean_squared_error', optimizer='adam')
训练或拟合模型现在模型已准备好接受训练。我们将向网络提供训练数据。此外,我们将指定验证数据,仅在其上验证模型。
# Training model
model.fit(x_train_noisy, X_train, validation_data=(x_test_noisy, X_test), epochs=2, batch_size=200)
输出:
在这里,我们只运行我们的模型两个时期,但你可以根据你的问题陈述更改此数字。你能想出当我们改变时期数量时会发生什么吗?请考虑一下,将在文章的最后解释这一点。
评估模型最后,我们将在测试数据集上评估我们的训练模型,该数据集是我们在加载数据集的部分中创建的。
# Final evaluation of the model
pred = model.predict(x_test_noisy)
pred.shape
输出:
(10000, 784)
X_test.shape
输出:
(10000, 784)
X_test = numpy.reshape(X_test, (10000,28,28)) *255
pred = numpy.reshape(pred, (10000,28,28)) *255
x_test_noisy = numpy.reshape(x_test_noisy, (-1,28,28)) *255
plt.figure(figsize=(20, 4))
print("Test Images")
for i in range(10,20,1):
plt.subplot(2, 10, i+1)
plt.imshow(X_test[i,:,:], cmap='gray')
curr_lbl = y_test[i]
plt.title("(Label: " + str(curr_lbl) + ")")
plt.show()
plt.figure(figsize=(20, 4))
print("Test Images with Noise")
for i in range(10,20,1):
plt.subplot(2, 10, i+1)
plt.imshow(x_test_noisy[i,:,:], cmap='gray')
plt.show()
plt.figure(figsize=(20, 4))
print("Reconstruction of Noisy Test Images")
for i in range(10,20,1):
plt.subplot(2, 10, i+1)
plt.imshow(pred[i,:,:], cmap='gray')
plt.show()
输出:
在上面的输出中,图像:
第一行是原始测试图像,
第二行是嘈杂的图像,
第三行用于清理(重建)图像。
查看清理后的图像如何与原始图像相似。
但是如果你仔细观察重建的图像,那么它可能会显得有些模糊。那么你能不能想出一些可能的原因! 为什么这些图像在解码器网络的输出中变得模糊。重建图像中出现这种模糊的可能原因之一是在训练我们的模型时使用较少的 epoch。因此,现在你的任务是增加时期数的值,然后再次观察这些图像并与这些图像进行比较。
如果我们想在一张图中总结整个过程,下图是最好的。
我们的实现到此结束!
在本教程中,你已经构建了一个自动编码器模型,该模型可以成功清除之前从未见过的噪声图像(我们使用了测试数据集)。显然,这些图像中存在一些未恢复的失真。然而,如果你考虑噪声图像的变形程度,我们可以说我们的模型在恢复失真图像方面非常成功。
你可以考虑扩展这个自动编码器并将其嵌入到照片增强应用程序中,这可以增加照片的清晰度。