您将使用 FVC2002 指纹数据集来训练您的网络。为了观察模型的有效性,您将使用两种不同的指纹传感器数据集(即 Secugen 和 Lumidigm 传感器)对模型进行测试。
注意 :本教程主要涵盖卷积自编码器的实践实现。因此,如果您尚未了解卷积神经网络(CNN)和自编码器,您可能需要先查看 CNN 和 自编码器 教程。
概括来说,今天的教程将涉及以下主题:
首先了解指纹 数据集:它包含什么类型的图像、如何读取图像、创建图像数组、探索指纹图像,并最终对其进行预处理以便输入模型。
在卷积自编码器的实现中:您将把预处理后的数据拟合 到模型中,可视化训练与验证损失曲线,并最终在测试集上进行预测。
接下来,您将使用两个不同的数据集(secugen 和 lumidigm)测试已训练模型的鲁棒性 。
理解指纹数据集
在继续加载数据之前,最好先看看您究竟要处理什么!FVC2002 指纹数据集是指纹验证竞赛(Fingerprint Verification Competition)的数据集,该竞赛分别于 2000 年和 2002 年举办。该数据集由四种不同传感器的指纹组成,即低成本光学传感器、低成本电容传感器、光学传感器和合成生成器,每种传感器的图像尺寸各不相同。数据集的 A 集共有 3200 张图像,每个传感器 800 张。稍后当您加载数据时可以再次核对!;)
该指纹数据集并未在 Keras 或 TensorFlow 框架中预定义,因此您需要从此来源 下载数据。下一节将向您展示如何操作!
注意 :在开始之前,请注意模型将在配备 Nvidia 1080 Ti GPU、Xeon e5 GeForce 处理器和 32GB 内存的系统上训练。如果您使用 Jupyter Notebook,需要添加三行代码,通过名为 os 的模块指定 CUDA 设备顺序和可见设备。
在下面的代码中,您基本上是使用 os.environ 在笔记本中设置环境变量。建议在初始化 Keras 之前执行以下操作,以限制 Keras 后端 TensorFlow 使用第一个 GPU。如果您训练的机器将 GPU 置于 0 号,请确保使用 0 而不是 1。您可以在终端中运行一个简单命令进行检查:例如 nvidia-smi
import os
os. environ[ "CUDA_DEVICE_ORDER" ] = "PCI_BUS_ID"
os. environ[ "CUDA_VISIBLE_DEVICES" ] = "1"
技术支持
加载数据
首先,导入所有必需的模块,如 cv2、numpy、matplotlib,最重要的是 keras,因为本教程将使用该框架!
import cv2
import matplotlib. pyplot as plt
% matplotlib inline
from skimage. filters import threshold_otsu
import numpy as np
from glob import glob
from scipy import misc
from matplotlib. patches import Circle, Ellipse
from matplotlib. patches import Rectangle
import os
from PIL import Image
技术支持
import keras
from matplotlib import pyplot as plt
import numpy as np
import gzip
% matplotlib inline
from keras. layers import Input, Conv2D, MaxPooling2D, UpSampling2D
from keras. models import Model
from keras. optimizers import RMSprop
from keras. layers. normalization import BatchNormalization
技术支持
Using TensorFlow backend.
技术支持
data = glob( 'FVC2002/Db*/*' )
技术支持
len ( data)
技术支持
3200
技术支持
images = [ ]
def read_images ( data) :
for i in range ( len ( data) ) :
img = misc. imread( data[ i] )
img = misc. imresize( img, ( 224 , 224 ) )
images. append( img)
return images
技术支持
images = read_images( data)
技术支持
images_arr = np. asarray( images)
images_arr = images_arr. astype( 'float32' )
技术支持
images_arr. shape
技术支持
( 3200 , 224 , 224 )
技术支持
一旦数据加载完成,您就可以开始分析数据,从而对今天要处理的数据集建立一些直观认识!
数据探索
现在,让我们分析数据集中图像的外观,并借助 NumPy 数组的 .shape 属性查看图像的维度:
print ( "Dataset (images) shape: {shape}" . format ( shape= images_arr. shape) )
技术支持
Dataset ( images) shape: ( 3200 , 224 , 224 )
技术支持
从上面的输出可以看到,数据的形状为 3200 x 224 x 224,因为共有 3200 个样本,每个样本是一个 224 x 224 的矩阵。
现在,让我们看一看数据集中的几张图像:
for i in range ( 2 ) :
plt. figure( figsize= [ 5 , 5 ] )
curr_img = np. reshape( images_arr[ i] , ( 224 , 224 ) )
plt. imshow( curr_img, cmap= 'gray' )
plt. show( )
技术支持
上述两个图像输出均来自该数据集。您可以看到这些指纹并不是很清晰,看看卷积自编码器是否能够学习到特征并正确重建这些图像将会很有趣。
数据预处理
数据集中的图像确实是灰度图,像素值范围为 0 到 255,尺寸为 224 x 224,因此在将数据输入模型之前,对其进行预处理非常重要。您将首先把数据集中每张 224 x 224 的图像转换为大小为 224 x 224 x 1 的矩阵,然后输入网络:
images_arr = images_arr. reshape( - 1 , 224 , 224 , 1 )
技术支持
images_arr. shape
技术支持
( 3200 , 224 , 224 , 1 )
技术支持
接下来,请务必检查 NumPy 数组的数据类型;应为 float32 格式,如果不是,需要将其转换为该格式;同时还需将像素值重新缩放到 0 - 1 的范围(含端点)。让我们开始吧!
首先,验证数据类型:
images_arr. dtype
技术支持
dtype ( 'float32' )
技术支持
然后,利用数据中图像的最大像素值对数据进行缩放:
np. max ( images_arr)
技术支持
255.0
技术支持
images_arr = images_arr / np. max ( images_arr)
技术支持
让我们验证数据的最大值和最小值,缩放后应分别为 1.0 和 0.0!
np. max ( images_arr) , np. min ( images_arr)
技术支持
( 1.0 , 0.0 )
技术支持
完成以上步骤后,划分数据集同样重要。为了使您的模型具有良好的泛化能力,您将数据分成两部分:训练集和验证集。您将用 80% 的数据训练模型,并用剩余 20% 的数据进行验证。
这也有助于降低过拟合的可能性,因为您会在训练阶段未见过的数据上验证模型。
您可以使用 scikit-learn 的 train_test_split 模块来正确划分数据:
from sklearn. model_selection import train_test_split
train_X, valid_X, train_ground, valid_ground = train_test_split( images_arr,
images_arr,
test_size= 0.2 ,
random_state= 13 )
技术支持
注意 :对于此任务,您不需要训练和测试标签。这就是为什么您会将训练图像传入两次。训练图像将同时作为输入和真实值(类似于分类任务中的标签)。
现在,您已经准备好定义网络并将数据输入网络了。事不宜迟,让我们进入下一步!
网络:卷积自编码器
图像尺寸为 224 x 224 x 1,即一个 50,176 维的向量。您将图像矩阵转换为数组,将其缩放到 0 到 1 之间,重塑为 224 x 224 x 1 的尺寸,并将其作为输入馈送到网络中。
此外,您将使用 128 的批量大小;使用更大的批量大小(如 256 或 512)也可以,这取决于训练模型的系统。批量大小对学习参数的确定影响很大,也会影响预测精度。您将训练网络 50 个周期。
batch_size = 128
epochs = 200
inChannel = 1
x, y = 224 , 224
input_img = Input( shape = ( x, y, inChannel) )
技术支持
如您所知,自编码器分为两部分:编码器和解码器。
编码器
第一层包含 32 个 3 x 3 的卷积核,随后是一个下采样(最大池化)层,
第二层包含 64 个 3 x 3 的卷积核,随后是另一个下采样层,
编码器的最后一层包含 128 个 3 x 3 的卷积核。
解码器
第一层包含 128 个 3 x 3 的卷积核,随后是一个上采样层,
第二层包含 64 个 3 x 3 的卷积核,随后是另一个上采样层,
解码器的最后一层包含一个 3 x 3 的卷积核。
最大池化层每次使用时都会将输入下采样两倍,而上采样层每次使用时都会将输入上采样两倍。
注意 :卷积核数量与大小、层数、训练的周期数等均为超参数,应基于您的直觉进行设定。您可以自由尝试调整这些超参数并衡量模型的性能。通过这样的实验,您将逐步掌握深度学习的“艺术”!
def autoencoder ( input_img) :
conv1 = Conv2D( 32 , ( 3 , 3 ) , activation= 'relu' , padding= 'same' ) ( input_img)
pool1 = MaxPooling2D( pool_size= ( 2 , 2 ) ) ( conv1)
conv2 = Conv2D( 64 , ( 3 , 3 ) , activation= 'relu' , padding= 'same' ) ( pool1)
pool2 = MaxPooling2D( pool_size= ( 2 , 2 ) ) ( conv2)
conv3 = Conv2D( 128 , ( 3 , 3 ) , activation= 'relu' , padding= 'same' ) ( pool2)
conv4 = Conv2D( 128 , ( 3 , 3 ) , activation= 'relu' , padding= 'same' ) ( conv3)
up1 = UpSampling2D( ( 2 , 2 ) ) ( conv4)
conv5 = Conv2D( 64 , ( 3 , 3 ) , activation= 'relu' , padding= 'same' ) ( up1)
up2 = UpSampling2D( ( 2 , 2 ) ) ( conv5)
decoded = Conv2D( 1 , ( 3 , 3 ) , activation= 'sigmoid' , padding= 'same' ) ( up2)
return decoded
技术支持
创建模型后,您需要将其编译,优化器使用 RMSProp。
同时需要通过 loss 参数指定损失类型。在这里使用均方误差,因为每个批次后的损失将以像素为单位,在预测输出与真实值之间使用均方误差计算:
autoencoder = Model( input_img, autoencoder( input_img) )
autoencoder. compile ( loss= 'mean_squared_error' , optimizer = RMSprop( ) )
技术支持
让我们使用 summary 函数可视化您在上一步创建的各层;这将显示每一层中的参数(权重和偏置)数量以及模型的参数总数。
autoencoder. summary( )
技术支持
_________________________________________________________________
Layer ( type) Output Shape Param #
=== === === === === === === === === === === === === === === === === === === === === ==
input_1 ( InputLayer) ( None, 224 , 224 , 1 ) 0
_________________________________________________________________
conv2d_1 ( Conv2D) ( None, 224 , 224 , 32 ) 320
_________________________________________________________________
max_pooling2d_1 ( MaxPooling2 ( None, 112 , 112 , 32 ) 0
_________________________________________________________________
conv2d_2 ( Conv2D) ( None, 112 , 112 , 64 ) 18496
_________________________________________________________________
max_pooling2d_2 ( MaxPooling2 ( None, 56 , 56 , 64 ) 0
_________________________________________________________________
conv2d_3 ( Conv2D) ( None, 56 , 56 , 128 ) 73856
_________________________________________________________________
conv2d_4 ( Conv2D) ( None, 56 , 56 , 128 ) 147584
_________________________________________________________________
up_sampling2d_1 ( UpSampling2 ( None, 112 , 112 , 128 ) 0
_________________________________________________________________
conv2d_5 ( Conv2D) ( None, 112 , 112 , 64 ) 73792
_________________________________________________________________
up_sampling2d_2 ( UpSampling2 ( None, 224 , 224 , 64 ) 0
_________________________________________________________________
conv2d_6 ( Conv2D) ( None, 224 , 224 , 1 ) 577
=== === === === === === === === === === === === === === === === === === === === === ==
Total params: 314 , 625
Trainable params: 314 , 625
Non- trainable params: 0
_________________________________________________________________
技术支持
终于到了用 Keras 的 fit() 函数训练模型的时候了!模型训练 200 个周期。fit() 函数会返回一个 history 对象;将其结果存储在 fashion_train 中后,您可以稍后绘制训练与验证损失曲线,以帮助您直观分析模型性能。
训练模型
autoencoder_train = autoencoder. fit( train_X, train_ground, batch_size= batch_size, epochs= epochs, verbose= 1 , validation_data= ( valid_X, valid_ground) )
技术支持
Train on 2560 samples, validate on 640 samples
Epoch 1 / 200
2560 / 2560 [ === === === === === === === === === === ] - 17s - loss: 0.0677 - val_loss: 0.0498
Epoch 2 / 200
2560 / 2560 [ === === === === === === === === === === ] - 11s - loss: 0.0369 - val_loss: 0.0287
...
2560 / 2560 [ === === === === === === === === === === ] - 11s - loss: 0.0029 - val_loss: 0.0024
Epoch 200 / 200
2560 / 2560 [ === === === === === === === === === === ] - 11s - loss: 0.0027 - val_loss: 0.0028
技术支持
太好了!您已经在指纹数据集上训练了 200 个周期。现在,让我们绘制训练与验证数据之间的损失曲线,以可视化模型表现。
loss = autoencoder_train. history[ 'loss' ]
val_loss = autoencoder_train. history[ 'val_loss' ]
epochs = range ( 200 )
plt. figure( )
plt. plot( epochs, loss, 'bo' , label= 'Training loss' )
plt. plot( epochs, val_loss, 'b' , label= 'Validation loss' )
plt. title( 'Training and validation loss' )
plt. legend( )
plt. show( )
技术支持
最后,您可以看到验证损失与训练损失基本保持一致。这表明模型没有过拟合:验证损失在下降而不是上升,并且尤其在第 40 个周期之后,训练与验证损失之间几乎没有差距。
因此,可以认为模型的泛化能力较好。
最后,是时候使用 Keras 的 predict() 函数重建测试图像,并查看模型在测试数据上的重建效果了。
保存模型
现在让我们保存训练好的模型。这是在进行深度学习时非常重要的一步。因为权重是解决当前问题的核心!
您随时可以在同一模型中加载已保存的权重,并从中断处继续训练。例如,如果再次训练上述模型,诸如权重、偏置、损失函数等参数将不会从头开始,因此这将不再是一次全新的训练。
只需一行代码,您就可以将权重保存到模型中或从模型中加载回来。
autoencoder = autoencoder. save_weights( 'autoencoder.h5' )
技术支持
autoencoder = Model( input_img, autoencoder( input_img) )
技术支持
autoencoder. load_weights( 'autoencoder.h5' )
技术支持
autoencoder. compile ( loss= 'mean_squared_error' , optimizer = RMSprop( ) )
技术支持
在验证数据上预测
由于这里您没有测试数据,让我们使用刚刚训练的模型在验证数据上进行预测。
您将对剩余的 640 张验证图像进行预测,并绘制部分重建图像,以直观查看模型对验证图像的重建效果。
pred = autoencoder. predict( valid_X)
技术支持
plt. figure( figsize= ( 20 , 4 ) )
print ( "Test Images" )
for i in range ( 5 ) :
plt. subplot( 1 , 5 , i+ 1 )
plt. imshow( valid_ground[ i, . . . , 0 ] , cmap= 'gray' )
plt. show( )
plt. figure( figsize= ( 20 , 4 ) )
print ( "Reconstruction of Test Images" )
for i in range ( 5 ) :
plt. subplot( 1 , 5 , i+ 1 )
plt. imshow( pred[ i, . . . , 0 ] , cmap= 'gray' )
plt. show( )
技术支持
Test Images
技术支持
Reconstruction of Test Images
技术支持
从上图可以看出,您的模型对测试图像的重建效果非常出色。至少从视觉上看,测试图像与重建图像几乎一模一样。
使用已训练模型对两种不同传感器数据进行预测
正如您在训练与验证曲线中所见,模型在未见过的数据上具有良好的泛化能力。现在是时候用完全不同的传感器数据来测试其鲁棒性了。
您将用两种不同类型的传感器对模型进行测试。
首先,让我们在低质量的指纹传感器数据(即 Secugen )上测试您的模型,看看模型表现如何!
sec = glob( 'Secugen/*' )
技术支持
images = [ ]
def read_images ( data) :
for i in range ( len ( data) ) :
img = misc. imread( data[ i] )
img = misc. imresize( img, ( 224 , 224 ) )
images. append( img)
return images
技术支持
images = read_images( sec)
技术支持
secugen = np. asarray( images)
secugen = secugen. astype( 'float32' )
技术支持
images_arr. shape
技术支持
( 48 , 224 , 224 , 1 )
技术支持
secugen = secugen / np. max ( secugen)
技术支持
secugen = secugen. reshape( - 1 , 224 , 224 , 1 )
技术支持
pred = autoencoder. predict( secugen)
技术支持
plt. figure( figsize= ( 20 , 4 ) )
print ( "Test Secugen Images" )
for i in range ( 5 ) :
plt. subplot( 1 , 5 , i+ 1 )
plt. imshow( secugen[ i, . . . , 0 ] , cmap= 'gray' )
plt. show( )
plt. figure( figsize= ( 20 , 4 ) )
print ( "Reconstruction of Test Secugen Images" )
for i in range ( 5 ) :
plt. subplot( 1 , 5 , i+ 1 )
plt. imshow( pred[ i, . . . , 0 ] , cmap= 'gray' )
plt. show( )
技术支持
Test Secugen Images
技术支持
Reconstruction of Test Secugen Images
技术支持
从上图可以看出,您的模型对使用训练模型预测的 Secugen 图像进行了很好的重建。是不是很棒?
现在,让我们在质量更高一些的传感器图像(即 Lumidigm )上测试您的模型。
lum = glob( 'Lumidigm/*' )
技术支持
images = [ ]
def read_images ( data) :
for i in range ( len ( data) ) :
img = misc. imread( data[ i] )
img = misc. imresize( img, ( 224 , 224 ) )
images. append( img)
return images
技术支持
images = read_images( lum)
技术支持
lumidigm = np. asarray( images)
lumidigm = lumidigm. astype( 'float32' )
技术支持
lumidigm. shape
技术支持
( 48 , 224 , 224 )
技术支持
lumidigm = lumidigm / np. max ( lumidigm)
技术支持
lumidigm = lumidigm. reshape( - 1 , 224 , 224 , 1 )
技术支持
pred = autoencoder. predict( lumidigm)
技术支持
plt. figure( figsize= ( 20 , 4 ) )
print ( "Test Lumidigm Images" )
for i in range ( 5 ) :
plt. subplot( 1 , 5 , i+ 1 )
plt. imshow( lumidigm[ i, . . . , 0 ] , cmap= 'gray' )
plt. show( )
plt. figure( figsize= ( 20 , 4 ) )
print ( "Reconstruction of Test Lumidigm Images" )
for i in range ( 5 ) :
plt. subplot( 1 , 5 , i+ 1 )
plt. imshow( pred[ i, . . . , 0 ] , cmap= 'gray' )
plt. show( )
技术支持
Test Lumidigm Images
技术支持
Reconstruction of Test Lumidigm Images
技术支持
从上图可以看出,您的模型再次很好地重建了使用训练模型预测的 Lumidigm 图像。
更进一步!
本教程是一个很好的起点,帮助您从零开始学习如何读取图像、分析、预处理并将其输入模型(以指纹数据集为例)。它向您展示了自编码器的一个很好的实际应用。如果您能够顺利跟进,或即便是稍费些力气完成了,也要为自己点赞!
在下一篇教程中,您将学习如何读取 T-1 模态的医学图像,并使用自编码器对其进行重建!
仍有很多内容值得继续深入,不妨学习 DataCamp 的Python 深度学习入门 课程(如果您还没有学过的话)。您将从基础开始,逐步走向掌握深度学习领域;在学习如何使用 Python 处理卷积神经网络、如何检测人脸、物体等方面,这无疑将成为不可或缺的资源。
您将使用 FVC2002 指纹数据集来训练您的网络。为了观察模型的有效性,您将使用两种不同的指纹传感器数据集(即 Secugen 和 Lumidigm 传感器)对模型进行测试。
注意:本教程主要涵盖卷积自编码器的实践实现。因此,如果您尚未了解卷积神经网络(CNN)和自编码器,您可能需要先查看 CNN 和 自编码器 教程。
概括来说,今天的教程将涉及以下主题:
理解指纹数据集
在继续加载数据之前,最好先看看您究竟要处理什么!FVC2002 指纹数据集是指纹验证竞赛(Fingerprint Verification Competition)的数据集,该竞赛分别于 2000 年和 2002 年举办。该数据集由四种不同传感器的指纹组成,即低成本光学传感器、低成本电容传感器、光学传感器和合成生成器,每种传感器的图像尺寸各不相同。数据集的 A 集共有 3200 张图像,每个传感器 800 张。稍后当您加载数据时可以再次核对!;)
该指纹数据集并未在 Keras 或 TensorFlow 框架中预定义,因此您需要从此来源下载数据。下一节将向您展示如何操作!
注意:在开始之前,请注意模型将在配备 Nvidia 1080 Ti GPU、Xeon e5 GeForce 处理器和 32GB 内存的系统上训练。如果您使用 Jupyter Notebook,需要添加三行代码,通过名为 os 的模块指定 CUDA 设备顺序和可见设备。
在下面的代码中,您基本上是使用 os.environ 在笔记本中设置环境变量。建议在初始化 Keras 之前执行以下操作,以限制 Keras 后端 TensorFlow 使用第一个 GPU。如果您训练的机器将 GPU 置于 0 号,请确保使用 0 而不是 1。您可以在终端中运行一个简单命令进行检查:例如 nvidia-smi
加载数据
首先,导入所有必需的模块,如 cv2、numpy、matplotlib,最重要的是 keras,因为本教程将使用该框架!
一旦数据加载完成,您就可以开始分析数据,从而对今天要处理的数据集建立一些直观认识!
数据探索
现在,让我们分析数据集中图像的外观,并借助 NumPy 数组的 .shape 属性查看图像的维度:
从上面的输出可以看到,数据的形状为 3200 x 224 x 224,因为共有 3200 个样本,每个样本是一个 224 x 224 的矩阵。
现在,让我们看一看数据集中的几张图像:
上述两个图像输出均来自该数据集。您可以看到这些指纹并不是很清晰,看看卷积自编码器是否能够学习到特征并正确重建这些图像将会很有趣。
数据预处理
数据集中的图像确实是灰度图,像素值范围为 0 到 255,尺寸为 224 x 224,因此在将数据输入模型之前,对其进行预处理非常重要。您将首先把数据集中每张 224 x 224 的图像转换为大小为 224 x 224 x 1 的矩阵,然后输入网络:
接下来,请务必检查 NumPy 数组的数据类型;应为 float32 格式,如果不是,需要将其转换为该格式;同时还需将像素值重新缩放到 0 - 1 的范围(含端点)。让我们开始吧!
首先,验证数据类型:
然后,利用数据中图像的最大像素值对数据进行缩放:
让我们验证数据的最大值和最小值,缩放后应分别为 1.0 和 0.0!
完成以上步骤后,划分数据集同样重要。为了使您的模型具有良好的泛化能力,您将数据分成两部分:训练集和验证集。您将用 80% 的数据训练模型,并用剩余 20% 的数据进行验证。
这也有助于降低过拟合的可能性,因为您会在训练阶段未见过的数据上验证模型。
您可以使用 scikit-learn 的 train_test_split 模块来正确划分数据:
注意:对于此任务,您不需要训练和测试标签。这就是为什么您会将训练图像传入两次。训练图像将同时作为输入和真实值(类似于分类任务中的标签)。
现在,您已经准备好定义网络并将数据输入网络了。事不宜迟,让我们进入下一步!
网络:卷积自编码器
图像尺寸为 224 x 224 x 1,即一个 50,176 维的向量。您将图像矩阵转换为数组,将其缩放到 0 到 1 之间,重塑为 224 x 224 x 1 的尺寸,并将其作为输入馈送到网络中。
此外,您将使用 128 的批量大小;使用更大的批量大小(如 256 或 512)也可以,这取决于训练模型的系统。批量大小对学习参数的确定影响很大,也会影响预测精度。您将训练网络 50 个周期。
如您所知,自编码器分为两部分:编码器和解码器。
编码器
解码器
最大池化层每次使用时都会将输入下采样两倍,而上采样层每次使用时都会将输入上采样两倍。
注意:卷积核数量与大小、层数、训练的周期数等均为超参数,应基于您的直觉进行设定。您可以自由尝试调整这些超参数并衡量模型的性能。通过这样的实验,您将逐步掌握深度学习的“艺术”!
创建模型后,您需要将其编译,优化器使用 RMSProp。
同时需要通过 loss 参数指定损失类型。在这里使用均方误差,因为每个批次后的损失将以像素为单位,在预测输出与真实值之间使用均方误差计算:
让我们使用 summary 函数可视化您在上一步创建的各层;这将显示每一层中的参数(权重和偏置)数量以及模型的参数总数。
终于到了用 Keras 的 fit() 函数训练模型的时候了!模型训练 200 个周期。fit() 函数会返回一个 history 对象;将其结果存储在 fashion_train 中后,您可以稍后绘制训练与验证损失曲线,以帮助您直观分析模型性能。
训练模型
太好了!您已经在指纹数据集上训练了 200 个周期。现在,让我们绘制训练与验证数据之间的损失曲线,以可视化模型表现。
最后,您可以看到验证损失与训练损失基本保持一致。这表明模型没有过拟合:验证损失在下降而不是上升,并且尤其在第 40 个周期之后,训练与验证损失之间几乎没有差距。
因此,可以认为模型的泛化能力较好。
最后,是时候使用 Keras 的 predict() 函数重建测试图像,并查看模型在测试数据上的重建效果了。
保存模型
现在让我们保存训练好的模型。这是在进行深度学习时非常重要的一步。因为权重是解决当前问题的核心!
您随时可以在同一模型中加载已保存的权重,并从中断处继续训练。例如,如果再次训练上述模型,诸如权重、偏置、损失函数等参数将不会从头开始,因此这将不再是一次全新的训练。
只需一行代码,您就可以将权重保存到模型中或从模型中加载回来。
在验证数据上预测
由于这里您没有测试数据,让我们使用刚刚训练的模型在验证数据上进行预测。
您将对剩余的 640 张验证图像进行预测,并绘制部分重建图像,以直观查看模型对验证图像的重建效果。
从上图可以看出,您的模型对测试图像的重建效果非常出色。至少从视觉上看,测试图像与重建图像几乎一模一样。
使用已训练模型对两种不同传感器数据进行预测
正如您在训练与验证曲线中所见,模型在未见过的数据上具有良好的泛化能力。现在是时候用完全不同的传感器数据来测试其鲁棒性了。
您将用两种不同类型的传感器对模型进行测试。
首先,让我们在低质量的指纹传感器数据(即 Secugen)上测试您的模型,看看模型表现如何!
从上图可以看出,您的模型对使用训练模型预测的 Secugen 图像进行了很好的重建。是不是很棒?
现在,让我们在质量更高一些的传感器图像(即 Lumidigm)上测试您的模型。
从上图可以看出,您的模型再次很好地重建了使用训练模型预测的 Lumidigm 图像。
更进一步!
本教程是一个很好的起点,帮助您从零开始学习如何读取图像、分析、预处理并将其输入模型(以指纹数据集为例)。它向您展示了自编码器的一个很好的实际应用。如果您能够顺利跟进,或即便是稍费些力气完成了,也要为自己点赞!
在下一篇教程中,您将学习如何读取 T-1 模态的医学图像,并使用自编码器对其进行重建!
仍有很多内容值得继续深入,不妨学习 DataCamp 的Python 深度学习入门课程(如果您还没有学过的话)。您将从基础开始,逐步走向掌握深度学习领域;在学习如何使用 Python 处理卷积神经网络、如何检测人脸、物体等方面,这无疑将成为不可或缺的资源。