0


Keras深度学习实战(10)——迁移学习

Keras深度学习实战(10)——迁移学习

0. 前言

在《卷积神经网络的局限性》中,我们看到从零开始训练卷积神经网络 (

  1. Convolutional Neural Network

,

  1. CNN

) 模型时,可能会遇到以下一些问题:

  • 训练数据集中图像数量不足,使得模型难以学习
  • 当图像尺寸很大时,卷积可能无法学习图像中的所有特征

第一个问题可以通过对增加数据集中的数据量来解决(即数据增强),第二个问题可以通过在更深的网络架构上训练更多的

  1. epoch

来解决(即增加训练量)。尽管我们能够通过执行所有这些操作来解决上述问题,但通常情况下,我们可能无法获取更多的训练数据。在这种情况下,使用预先训练完成的模型进行迁移学习将能够快速解决上述问题。

1. 迁移学习

1.1 迁移学习原理

迁移学习 (

  1. Transfer Learning

) 是机器学习中的一个重要研究方向,研究如何将在任务

  1. A

上学到的知识迁移至任务

  1. B

,例如任务

  1. A

为猫狗分类,任务

  1. B

为牛马分类,任务

  1. A

和任务

  1. B

中存在大量的可共享知识,例如动物的毛发、体型、形态等。因此在任务

  1. A

训练获得的模型已经掌握了这些知识,在训练任务

  1. B

的模型时,可以不必从零开始训练,而是在任务

  1. A

上获得的知识的基础上面进行训练或微调 (

  1. Fine-tuning

)。和从零开始训练卷积神经网络相比,利用迁移学习,只需要少量样本即可训练得到性能较好的模型。
简单而言,迁移学习是指将一个预训练的模型重新用于另一个任务中。如下图所示,我们可以重用建立在不同数据集上的卷积神经网络,卷积层已经学习了图像中的各种特征(由于预训练模型使用了大量的图片,因此这些特征对于所有图像而言都具有极大程度上的通用性)。因此,网络的前面数层可以重用,网络后面的数层可以根据具体的任务设定从零开始训练,以便我们可以在新的数据集中预测图像类别。

  1. Keras

中提供了多个由不同研究人员提出的预训练模型,本文我们将使用预训练的

  1. VGG16

模型利用迁移学习进行性别分类任务实战。

迁移学习

1.2 ImageNet 数据集介绍

在开始实战迁移学习之前,我们首先了解下

  1. Keras

中集成的预训练模型所使用的数据集

  1. ImageNet

  1. ImageNet

是一项权威性的图像识别竞赛,要求参与者预测图像所属类别,数据集中有数百万个图像,其中包含尺寸不同的多种类别的图像。有大量的研究团队参与了此竞赛,他们提出了不同的神经网络模型预测图像类别。鉴于有数百万个图像,因此数据集中的数据量不成问题,同时研究团队为了获取优异的模型性能构建了庞大的神经网络网络体系,因此也解决了在前言中所述的第二个问题。

2. 利用预训练 VGG16 模型进行性别分类

2.1 VGG16 架构

我们将学习如何利用

  1. VGG16

预训练网络进行性别分类,在此之前,我们首先查看

  1. VGG16

模型的体系架构信息,以便对模型架构有所了解:

  1. Model: "vgg16"
  2. _________________________________________________________________
  3. Layer (type) Output Shape Param # =================================================================
  4. input_1 (InputLayer)[(None, 256, 256, 3)]0
  5. _________________________________________________________________
  6. block1_conv1 (Conv2D)(None, 256, 256, 64)1792
  7. _________________________________________________________________
  8. block1_conv2 (Conv2D)(None, 256, 256, 64)36928
  9. _________________________________________________________________
  10. block1_pool (MaxPooling2D)(None, 128, 128, 64)0
  11. _________________________________________________________________
  12. block2_conv1 (Conv2D)(None, 128, 128, 128)73856
  13. _________________________________________________________________
  14. block2_conv2 (Conv2D)(None, 128, 128, 128)147584
  15. _________________________________________________________________
  16. block2_pool (MaxPooling2D)(None, 64, 64, 128)0
  17. _________________________________________________________________
  18. block3_conv1 (Conv2D)(None, 64, 64, 256)295168
  19. _________________________________________________________________
  20. block3_conv2 (Conv2D)(None, 64, 64, 256)590080
  21. _________________________________________________________________
  22. block3_conv3 (Conv2D)(None, 64, 64, 256)590080
  23. _________________________________________________________________
  24. block3_pool (MaxPooling2D)(None, 32, 32, 256)0
  25. _________________________________________________________________
  26. block4_conv1 (Conv2D)(None, 32, 32, 512)1180160
  27. _________________________________________________________________
  28. block4_conv2 (Conv2D)(None, 32, 32, 512)2359808
  29. _________________________________________________________________
  30. block4_conv3 (Conv2D)(None, 32, 32, 512)2359808
  31. _________________________________________________________________
  32. block4_pool (MaxPooling2D)(None, 16, 16, 512)0
  33. _________________________________________________________________
  34. block5_conv1 (Conv2D)(None, 16, 16, 512)2359808
  35. _________________________________________________________________
  36. block5_conv2 (Conv2D)(None, 16, 16, 512)2359808
  37. _________________________________________________________________
  38. block5_conv3 (Conv2D)(None, 16, 16, 512)2359808
  39. _________________________________________________________________
  40. block5_pool (MaxPooling2D)(None, 8, 8, 512)0=================================================================
  41. Total params: 14,714,688
  42. Trainable params: 14,714,688
  43. Non-trainable params: 0
  44. __________________________________________________________________

该模型的架构与我们在《使用卷积神经网络实现性别分类》中训练的

  1. CNN

模型类似,主要区别在于该模型更深,使用了更多的卷积、池化层,

  1. VGG16

网络的权重是通过对数百万个图像进行训练而获得的。
我们在使用预训练模型对图像中的人物进行性别分类时,确保冻结

  1. VGG16

权重的更新。尺寸为

  1. 256x256x3

的图像通过

  1. VGG16

网络后特征图形状为

  1. 8 x 8 x 512

。我们将保持原始网络中的权重不变,得到

  1. 8 x 8 x 512

输出,之后将其通过另一个卷积池化操作,然后通过展平层后,连接到全连接层,然后使用

  1. Sigmoid

激活函数确定图像中人物是男性还是女性。
本质上,通过使用

  1. VGG16

模型的卷积和池化层,我们使用了在数以百万计的数据集上训练的卷积核。最终,我们为要预测的图片对象微调 (

  1. fine-tuning

) 通过这些卷积和池化层得到的输出。

2.2 微调模型

本节中,我们使用

  1. Keras

实现以上分析的迁移学习策略。首先,导入所需库以及预训练的

  1. VGG16

模型。我们不使用

  1. VGG16

模型中的最后一层,即

  1. include_top=False

,这是为了之后我们针对要解决的问题微调

  1. VGG16

模型。另外,我们的指定输入图像形状为

  1. 256 X 256 X 3

  1. from keras.applications import VGG16
  2. from keras.applications.vgg16 import preprocess_input
  3. from glob import glob
  4. from skimage import io
  5. import cv2
  6. import numpy as np
  7. from sklearn.model_selection import train_test_split
  8. vgg16_model = VGG16(include_top=False, weights='imagenet', input_shape=(256,256,3))

预处理图像数据集。此预处理步骤用于预处理图像数据,以确保其可以作为预训练模型输入。例如,我们对其中一个名为

  1. img

的图像执行预处理,则使用

  1. preprocess_input

方法根据

  1. VGG16

中的预处理要求对图像进行预处理:

  1. from keras.applications.vgg16 import preprocess_input
  2. img = preprocess_input(img.reshape(1,256,256,3))

创建输入和输出数据集,首先加载图片,这一过程与《卷积神经网络进行性别分类》中加载数据的过程相同,然后增加了使用

  1. VGG16

模型提取特征的过程。
我们通过

  1. VGG16

模型提取每个图像特征,以便我们获取

  1. VGG16

的输出作为后续微调模型的输入。并且,图片在输入

  1. VGG16

之前需要使用

  1. preprocess_input

方法执行预处理过程,如下所示:

  1. x =[]
  2. y =[]for i in glob('man_woman/a_resized/*.jpg')[:800]:try:
  3. image = io.imread(i)
  4. x.append(image)
  5. y.append(0)except:continuefor i in glob('man_woman/b_resized/*.jpg')[:800]:try:
  6. image = io.imread(i)
  7. x.append(image)
  8. y.append(1)except:continue
  9. x_vgg16 =[]for i inrange(len(x)):
  10. img = x[i]
  11. img = preprocess_input(img.reshape((1,256,256,3)))# 将预处理后的输入传递给 VGG16 模型以提取特征
  12. img_feature = vgg16_model.predict(img)
  13. x_vgg16.append(img_feature)

在以上代码中,除了通过

  1. VGG16

模型处理输入图像外,我们还将提取到的特征

  1. img_feature

存储在列表

  1. x_vgg16

中,作为后续微调模型的输入。
然后,将输入和输出转换为

  1. NumPy

数组,并创建训练和测试数据集:

  1. x_vgg16 = np.array(x_vgg16)
  2. x_vgg16 = x_vgg16.reshape(x_vgg16.shape[0], x_vgg16.shape[2], x_vgg16.shape[3], x_vgg16.shape[4])
  3. y = np.array(y)
  4. x_train, x_test, y_train, y_test = train_test_split(x_vgg16, y, test_size=0.2)

构建并编译模型:

  1. from keras.models import Sequential
  2. from keras.layers import Conv2D, MaxPooling2D, Flatten, Dropout, Dense
  3. model_fine_tuning = Sequential()
  4. model_fine_tuning.add(Conv2D(512,
  5. kernel_size=(3,3),
  6. activation='relu',
  7. input_shape=(x_train.shape[1], x_train.shape[2], x_train.shape[3])))
  8. model_fine_tuning.add(MaxPooling2D(pool_size=(2,2)))
  9. model_fine_tuning.add(Flatten())
  10. model_fine_tuning.add(Dense(512, activation='relu'))
  11. model_fine_tuning.add(Dropout(0.5))
  12. model_fine_tuning.add(Dense(1, activation='sigmoid'))
  13. model_fine_tuning.summary()

微调模型的简要结构信息输入如下:

  1. Model: "sequential"
  2. _________________________________________________________________
  3. Layer (type) Output Shape Param # =================================================================
  4. conv2d (Conv2D)(None, 6, 6, 512)2359808
  5. _________________________________________________________________
  6. max_pooling2d (MaxPooling2D)(None, 3, 3, 512)0
  7. _________________________________________________________________
  8. flatten (Flatten)(None, 4608)0
  9. _________________________________________________________________
  10. dense (Dense)(None, 128)589952
  11. _________________________________________________________________
  12. dropout (Dropout)(None, 128)0
  13. _________________________________________________________________
  14. dense_1 (Dense)(None, 1)129=================================================================
  15. Total params: 2,949,889
  16. Trainable params: 2,949,889
  17. Non-trainable params: 0
  18. _________________________________________________________________

编译并拟合模型:

  1. model_fine_tuning.compile(loss='binary_crossentropy',optimizer='adam',metrics=['acc'])
  2. history = model_fine_tuning.fit(x_train, y_train,
  3. batch_size=32,
  4. epochs=20,
  5. verbose=1,
  6. validation_data =(x_test, y_test))

在训练模型后,我们可以看到模型在测试数据集最终可以很快(大约需要

  1. 3-5

  1. epoch

)达到约

  1. 95

的准确率,而我们在《卷积神经网络进行性别分类》中训练的性别分类

  1. CNN

模型在任何情况下都无法在

  1. 5

  1. epoch

内达到

  1. 95

的分类准确率。:

性能检测

2.3 错误分类的图片示例

模型分类错误的一些图像样本如下:

  1. x = np.array(x)from sklearn.model_selection import train_test_split
  2. x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)
  3. x_test_vgg16 =[]for i inrange(len(x_test)):
  4. img = x_test[i]
  5. img = preprocess_input(img.reshape((1,256,256,3)))
  6. img_feature = model.predict(img)
  7. x_test_vgg16.append(img_feature)
  8. x_test_vgg16 = np.array(x_test_vgg16)
  9. x_test_vgg16 = x_test_vgg16.reshape(x_test_vgg16.shape[0], x_test_vgg16.shape[2], x_test_vgg16.shape[3], x_test_vgg16.shape[4])
  10. y_pred = model_fine_tuning.predict(x_test_vgg16)
  11. wrong = np.argsort(np.abs(y_pred.flatten()-y_test))print(wrong)
  12. y_test_char = np.where(y_test==0,'M','F')
  13. y_pred_char = np.where(y_pred>0.5,'F','M')
  14. plt.subplot(221)
  15. plt.imshow(x_test[wrong[-1]])
  16. plt.title('Actual: '+str(y_test_char[wrong[-1]])+', '+'Predicted: '+str((y_pred_char[wrong[-1]][0])))
  17. plt.subplot(222)
  18. plt.imshow(x_test[wrong[-2]])
  19. plt.title('Actual: '+str(y_test_char[wrong[-2]])+', '+'Predicted: '+str((y_pred_char[wrong[-2]][0])))
  20. plt.subplot(223)
  21. plt.imshow(x_test[wrong[-3]])
  22. plt.title('Actual: '+str(y_test_char[wrong[-3]])+', '+'Predicted: '+str((y_pred_char[wrong[-3]][0])))
  23. plt.subplot(224)
  24. plt.imshow(x_test[wrong[-4]])
  25. plt.title('Actual: '+str(y_test_char[wrong[-4]])+', '+'Predicted: '+str((y_pred_char[wrong[-4]][0])))
  26. plt.show()

错误分类的图片
可以看到,当输入图像是面部的一部分,或者图像中的面部占整个图像的比例较小时,则模型可能会错误分类。

小结

本节中,首先简单回顾了卷积神经网络的一些局限性,为了克服这些局限性,引入了迁移学习的概念。通过实战可以看到,和从零开始训练卷积神经网络相比,利用迁移学习,只需要少量样本即可训练得到性能较好的模型。

系列链接

Keras深度学习实战(1)——神经网络基础与模型训练过程详解
Keras深度学习实战(2)——使用Keras构建神经网络
Keras深度学习实战(3)——神经网络性能优化技术
Keras深度学习实战(4)——深度学习中常用激活函数和损失函数详解
Keras深度学习实战(5)——批归一化详解
Keras深度学习实战(6)——深度学习过拟合问题及解决方法
Keras深度学习实战(7)——卷积神经网络详解与实现
Keras深度学习实战(8)——使用数据增强提高神经网络性能
Keras深度学习实战(9)——卷积神经网络的局限性


本文转载自: https://blog.csdn.net/LOVEmy134611/article/details/124316211
版权归原作者 盼小辉丶 所有, 如有侵权,请联系我们删除。

“Keras深度学习实战(10)——迁移学习”的评论:

还没有评论