在数字摄影时代之前,冲洗照片是一个神秘的过程,只有摄影师和专家才能驾驭。只能看到被昏暗的红灯照亮的暗室。简而言之,获取照片是一个耗时的过程。随着数码相机革命的开始,再也没有回头!甚至不再费心打印照片了——大多数人的照片都在智能手机、笔记本电脑或某些云存储中。
可能想知道照片和自编码器有什么关系。嗯,正是自编码器使能够增强和改善数字照片的质量!即使现在,也会遇到(并点击)模糊、像素化和不清晰的图片。肯定对此感到内疚,知道很多人在点击完美照片时也遇到了困难。这就是深度学习和自编码器概念帮助地方。
将学习自编码器是什么以及它们是如何工作的。然后,将使用Python中的自编码器解决一个现实世界的问题——提高图像分辨率。
前提条件:熟悉Keras、使用神经网络进行图像分类和卷积层。如果需要复习这些概念,请查看这些资源:神经网络入门(免费课程)、构建第一个图像分类模型。
什么是自编码器?根据Pulkit Sharma的文章:“自编码器本质上是神经网络架构,其目标是学习输入数据的低维特征表示。”自编码器由两个连接的网络组成——编码器和解码器。编码器的目标是接收一个输入(x)并产生一个特征映射(z):
# 编码器的目标是接收一个输入(x)并产生一个特征映射(z)
encoder_input = Input(shape=(input_shape,))
encoded = encoder_model(encoder_input)
这个特征映射(z)的大小或长度通常比x小。认为为什么会这样?因为希望z只捕捉能够描述输入数据的有意义的变化因素,所以z的形状通常比x小。
现在,问题是,如何学习这个特征表示(z)?如何训练这个模型?为此,可以在提取的特征之上添加一个解码器网络,然后训练模型:
# 在提取的特征之上添加一个解码器网络
decoder_input = Input(shape=(encoded.shape[1],))
decoded = decoder_model(decoder_input)
这个网络被训练成可以使用特征(z)重建原始输入数据(x)。如果输出(Ẋ)与输入(x)不同,损失会惩罚它并帮助重建输入数据。
将解决的问题与图像去噪自编码器的工作原理相关。让详细了解自编码器如何被部署来从任何给定的图像中去除噪声。假设有一组手写数字图像,其中一些已经被破坏。以下是一些带有噪声(破坏)的图像:
从图像中去除这种噪声被称为图像去噪问题。期望的输出是干净的图像,其中大部分噪声已经被去除,如下所示:
但是自编码器如何从图像中去除这种噪声呢?正如在前一节已经看到的,自编码器试图重建输入数据。所以,如果将损坏的图像作为输入,自编码器将尝试重建噪声图像。那么现在应该做什么?改变架构?实际上并不是!只需要一个小小的调整。不是使用输入和重建的输出来计算损失,而是可以通过使用真实图像和重建图像来计算损失。这个图表很好地说明了观点:
# 使用真实图像和重建图像来计算损失
from keras.losses import mean_squared_error
def autoencoder_loss(y_true, y_pred):
return mean_squared_error(y_true, y_pred)
现在已经熟悉了去噪自编码器的工作原理,让继续解决想要使用自编码器解决的问题。
问题陈述——使用自编码器提高图像分辨率。一定对这个问题很熟悉。大多数人都在努力点击模糊的图像,并努力提高它们的分辨率。好吧,将在这里使用自编码器解决这个问题!假设有一组低分辨率的人脸图像。任务是提高这些图像的分辨率。这可以使用Photoshop等照片编辑工具完成。但是,当有成千上万的图像需要处理时,需要一种更智能的方式来完成这项任务。
让打开Jupyter笔记本并导入所需的库:
# 导入所需的库
import numpy as np
import glob
import matplotlib.pyplot as plt
from keras.preprocessing.image import ImageDataGenerator
将在流行的“Labeled Faces in the Wild”数据集上工作。这是一个为研究无约束人脸识别问题而设计的人脸照片数据库。然而,这里目标不是人脸识别,而是构建一个模型来提高图像分辨率。让下载并提取数据集:
# 下载并提取数据集
!wget http://vis-www.cs.umass.edu/lfw/lfw.tgz
!tar -xvzf lfw.tgz
这个数据集将被提取到多个文件夹中。因此,捕获所有图像的文件路径非常重要。可以很容易地使用glob库来做到这一点:
# 捕获图像的路径
face_images = glob.glob('lfw/**/*.jpg')
加载和预处理图像。图像的原始大小是250 x 250像素。然而,使用这些图像在配置适中的系统上会消耗相当多的计算能力。因此,将缩小所有图像的大小:
# 缩小所有图像的大小
from keras.preprocessing.image import img_to_array, load_img
from tqdm import tqdm
def load_and_preprocess_images(image_paths, image_size=(250, 250)):
images = []
for img_path in tqdm(image_paths):
img = load_img(img_path, target_size=image_size)
img = img_to_array(img)
images.append(img)
return np.array(images)
数据准备用于模型训练。接下来,将数据集(图像)分成两组——训练和验证。将使用训练集来训练模型,并使用验证集来评估模型的性能:
# 将数据集分成训练和验证集
from sklearn.model_selection import train_test_split
train_images, val_images = train_test_split(images, test_size=0.2, random_state=42)
让看看数据集中的一张图像:
这个练习的想法与去噪自编码器中使用的想法非常相似。将对输入图像进行一些修改,并使用原始图像计算损失。由于这是一个分辨率增强任务,将降低原始图像的分辨率并将其作为输入提供给模型。
# 降低原始图像的分辨率
from keras.preprocessing.image import img_to_array, load_img
def downsample_images(image_paths, image_size=(50, 50)):
images = []
for img_path in tqdm(image_paths):
img = load_img(img_path, target_size=image_size)
img = img_to_array(img)
images.append(img)
return np.array(images)
让降低所有图像的分辨率。将为训练集和验证集都这样做:
# 为训练集和验证集降低所有图像的分辨率
train_images_low_res = downsample_images(train_image_paths)
val_images_low_res = downsample_images(val_image_paths)
构建模型。让定义模型的结构:
# 定义模型结构
from keras.layers import Input, Dense
from keras.models import Model
encoder_input = Input(shape=(input_shape,))
encoded = Dense(128, activation='relu')(encoder_input)
decoded = Dense(input_shape, activation='sigmoid')(encoded)
autoencoder = Model(encoder_input, decoded)
可以随时修改这个架构。可以改变层的数量,改变层的类型,使用正则化等等。目前,让继续使用这个架构。
# 可视化模型架构
autoencoder.summary()
# 训练模型
autoencoder.compile(optimizer='adam', loss='mean_squared_error')
autoencoder.fit(train_images, train_images, epochs=50, batch_size=256, shuffle=True, validation_data=(val_images, val_images))
# 进行预测
predictions = autoencoder.predict(val_images_low_res)