深度学习中的迁移学习与预训练模型应用
1. 学习目标与概述
在深度学习的实际应用中,我们常常不会从头开始构建卷积神经网络(CNN),而是借助迁移学习和预训练模型来完成任务。通过学习,我们需要掌握以下几个方面:
- 解释迁移学习和预训练模型的概念。
- 对预训练模型应用特征提取。
- 使用预训练模型进行图像分类。
- 对预训练模型进行微调。
这里我们主要会用到 VGG16 和 ResNet50 模型,在深入了解这些模型之前,我们先来认识迁移学习。
2. 迁移学习与预训练模型
迁移学习的概念类似于人类通过经验学习,将在一个情境中获得的知识应用到相似的情境中。例如,一个会开小型两厢车的人去学习开 SUV,虽然 SUV 的尺寸大很多,但两厢车的驾驶经验,如对离合器、油门和刹车的操作知识,在学习开 SUV 时仍然非常有用。
在机器学习中,迁移学习就是存储并利用在一项活动中获得的知识来学习另一项相似活动。以判断一张图片是猫还是狗为例,我们有两种方法:一是从头构建一个深度学习模型,然后将新图片输入网络;二是使用已经用猫和狗的图像训练好的预训练深度学习神经网络模型,这样可以节省计算时间和资源。而且,预训练网络还有一些意想不到的好处,比如可以识别图片中除猫狗之外的其他物体,像树木、天空和家具等。
预训练网络是在非常大的数据集上训练的保存好的网络(在深度学习中通常是神经网络),主要用于图像分类问题。要使用预训练网络,我们需要了解特征提取和微调的概念。
3. 特征提取
为了理解特征提取,我们先回顾一下卷积神经网络的架构。一个完整的 CNN 架构通常包括:
- 卷积层
- 池化和扁平化层
- 人工神经网络(ANN)
我们可以将 CNN 架构分为两部分:第一部分是除 ANN 之外的所有部分,称为卷积基;第二部分仅包含 ANN,称为分类器。
在特征提取中,我们会重复使用卷积基,而改变分类器。这样可以保留卷积层学到的知识,并在卷积层之上应用不同的分类器,如猫狗分类、自行车与汽车分类,甚至医学 X 光图像中的肿瘤和感染分类等。
一般来说,不建议像重用卷积基一样重用分类器。因为卷积基学到的知识更具通用性,更易于重用;而分类器学到的知识大多特定于模型训练的类别。此外,卷积基层的泛化学习量取决于层的深度。例如,在识别猫的模型中,初始层学习到的是边缘和背景等一般特征,而较高层可能学习到眼睛、耳朵或鼻子形状等更具体的细节。如果新数据集与原始数据集差异很大,比如从识别猫改为识别水果,那么最好只使用卷积基层的一些初始层,而不是整个层。
预训练学习的一个重要特性是冻结预训练网络的某些层。冻结意味着停止某些卷积层的权重更新过程。因为我们使用的是预训练网络,网络初始层中存储的信息很重要,如果在训练过程中更新这些信息,可能会丢失预训练网络中学习和存储的一些通用概念。为避免信息衰减,我们将这些层设置为不可训练。
4. 预训练网络的微调
微调是指调整我们的神经网络,使其更适合当前的任务。我们可以冻结网络的一些初始层,以保留其中存储的通用且有用的信息。在分类器学习时冻结这些层,之后再解冻并进行微调,使其更贴合当前问题。
微调有三个步骤:
- 在预训练系统之上添加一个分类器(ANN)。
- 冻结卷积基并训练网络。
- 联合训练添加的分类器和未冻结的卷积基部分。
5. ImageNet 数据集与预训练网络
在实际工作中,我们很少自己构建基础卷积模型,通常会使用预训练模型。对于视觉计算,常用的数据集是 ImageNet。它是一个大型视觉数据库,用于视觉对象识别,包含超过 1400 万张带有对象名称标签的图像,有超过 20000 个类别。
在 Keras 中有一些预训练网络,可将其视为基础卷积层,我们可以在这些网络上添加分类器(ANN),例如:
| 预训练网络 | 创建者 |
| ---- | ---- |
| VGG16 | - |
| Inception V3 | Google |
| Xception | - |
| ResNet50 | Microsoft |
| Mobilenet | Google |
在后续内容中,我们将重点使用 VGG16 和 ResNet50 进行实践操作。
6. 使用 VGG16 网络识别图像
下面我们通过一个具体的例子来展示如何使用 VGG16 网络识别图像。假设我们有一张穿西装的人的图片,要使用 VGG16 网络对其进行处理和识别。操作步骤如下:
# 1. 导入库
import numpy as np
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
# 2. 初始化模型
classifier = VGG16()
# 3. 加载图像
new_image = image.load_img('../Data/Prediction/man_in_suit.jpg', target_size=(224, 224))
# 4. 将图像转换为数组
transformed_image = image.img_to_array(new_image)
# 5. 扩展图像维度
transformed_image = np.expand_dims(transformed_image, axis=0)
# 6. 预处理图像
transformed_image = preprocess_input(transformed_image)
# 7. 创建预测变量
y_pred = classifier.predict(transformed_image)
# 8. 检查图像形状
print(y_pred.shape)
# 9. 选择图像的前五个可能性
from keras.applications.vgg16 import decode_predictions
print(decode_predictions(y_pred, top=5))
# 10. 以人类可读的形式输出预测结果
label = decode_predictions(y_pred)
decoded_label = label[0][0]
print('%s (%.2f%%)' % (decoded_label[1], decoded_label[2]*100 ))
通过上述代码,我们可以看到,模型以 82.9% 的概率预测图片是西装,这表明 ImageNet 数据库中存在与我们图片相对相似的对象,算法表现出色。
7. 利用 VGG16 网络训练深度学习网络识别图像
给定一张猫的图像,使用 VGG16 网络进行预测,步骤如下:
1. 导入所需库和 VGG16 网络。
2. 初始化预训练的 VGG16 模型。
3. 加载要分类的图像。
4. 对图像进行预处理。
5. 创建预测变量进行图像预测。
6. 对图像进行标记和分类。
8. 对 ImageNet 数据库中不存在的图像进行分类
现在我们来处理一个不在 VGG16 网络 1000 个标签中的图像,比如金字塔图像。操作步骤与前面类似:
# 1. 导入库
import numpy as np
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
# 2. 初始化模型
classifier = VGG16()
print(classifier.summary())
# 3. 加载图像
new_image = image.load_img('../Data/Prediction/pyramid.jpg', target_size=(224, 224))
# 4. 将图像转换为数组
transformed_image = image.img_to_array(new_image)
# 5. 扩展图像维度
transformed_image = np.expand_dims(transformed_image, axis=0)
# 6. 预处理图像
transformed_image = preprocess_input(transformed_image)
# 7. 创建预测变量
y_pred = classifier.predict(transformed_image)
# 8. 检查图像形状
print(y_pred.shape)
# 9. 选择图像的前五个可能性
from keras.applications.vgg16 import decode_predictions
print(decode_predictions(y_pred, top=5))
# 10. 以人类可读的形式输出预测结果
label = decode_predictions(y_pred)
decoded_label = label[0][0]
print('%s (%.2f%%)' % (decoded_label[1], decoded_label[2]*100 ))
结果显示,网络以接近 28% 的准确率预测图像是谷仓,显然图像是金字塔而不是谷仓。为了避免这种情况,我们可以冻结 VGG16 的现有层并添加自己的层,例如添加包含谷仓和金字塔图像的层,以获得更好的输出。
9. 微调 VGG16 模型
接下来我们进行一个微调 VGG16 模型的练习。步骤如下:
# 1. 导入库
import numpy as np
import keras
from keras.layers import Dense
# 2. 初始化模型
vgg_model = keras.applications.vgg16.VGG16()
# 3. 查看模型摘要
vgg_model.summary()
# 4. 移除最后一层
last_layer = str(vgg_model.layers[-1])
classifier = keras.Sequential()
for layer in vgg_model.layers:
if str(layer) != last_layer:
classifier.add(layer)
# 5. 重新检查摘要
classifier.summary()
# 6. 冻结层
for layer in classifier.layers:
layer.trainable = False
# 7. 添加新层并检查摘要
classifier.add(Dense(1, activation='sigmoid'))
classifier.summary()
# 8. 编译网络
classifier.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
# 9. 处理图像并拟合 ANN
from keras.preprocessing.image import ImageDataGenerator
generate_train_data = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
generate_test_data = ImageDataGenerator(rescale = 1./255)
training_dataset = generate_train_data.flow_from_directory('dataset/training_set',
target_size = (224, 224),
batch_size = 32,
class_mode = 'binary')
test_datasetset = generate_test_data.flow_from_directory('dataset/test_set',
target_size = (224, 224),
batch_size = 32,
class_mode = 'binary')
classifier.fit_generator(training_dataset,
steps_per_epoch = 100,
epochs = 10,
validation_data = test_datasetset,
validation_steps = 30)
# 10. 预测新图像
import numpy as np
from keras.preprocessing import image
new_image = image.load_img('../Data/Prediction/test_image_1.jpg', target_size = (224, 224))
new_image = image.img_to_array(new_image)
new_image = np.expand_dims(new_image, axis = 0)
result = classifier.predict(new_image)
training_set.class_indices
if result[0][0] == 1:
prediction = 'It is a Dog'
else:
prediction = 'It is a Cat'
print(prediction)
通过上述步骤,我们将 VGG16 的最后一层替换为自定义层,用于猫狗分类,从而提高模型在猫狗图像分类上的准确性。
综上所述,迁移学习和预训练模型在深度学习中具有重要作用,通过特征提取和微调等技术,可以灵活应用预训练模型解决各种图像分类问题。
深度学习中的迁移学习与预训练模型应用(续)
10. 微调 VGG16 模型的详细分析
在前面的微调 VGG16 模型练习中,每一个步骤都有其重要意义。下面我们详细分析一下这些步骤。
- 导入库 :
import numpy as np
import keras
from keras.layers import Dense
这里我们导入了
numpy
用于数值计算,
keras
作为深度学习框架,
Dense
层用于构建全连接层。
- 初始化模型 :
vgg_model = keras.applications.vgg16.VGG16()
初始化 VGG16 预训练模型,这个模型已经在大规模数据集上进行了训练,包含了丰富的特征信息。
- 查看模型摘要 :
vgg_model.summary()
通过查看模型摘要,我们可以了解模型的结构,包括各层的名称、输出形状和参数数量等信息,有助于我们后续对模型进行修改。
- 移除最后一层 :
last_layer = str(vgg_model.layers[-1])
classifier = keras.Sequential()
for layer in vgg_model.layers:
if str(layer) != last_layer:
classifier.add(layer)
原始的 VGG16 模型最后一层是用于 1000 个类别的分类,我们要进行猫狗分类,所以移除最后一层,然后将前面的层添加到新的
classifier
模型中。
- 重新检查摘要 :
classifier.summary()
再次查看模型摘要,确认最后一层已经被移除。
- 冻结层 :
for layer in classifier.layers:
layer.trainable = False
冻结前面的卷积层,这样在训练过程中这些层的权重不会被更新,保留了预训练模型学到的通用特征。
- 添加新层并检查摘要 :
classifier.add(Dense(1, activation='sigmoid'))
classifier.summary()
添加一个新的全连接层,使用
sigmoid
激活函数,用于二分类(猫狗分类)。再次查看摘要,确认新层已经添加。
- 编译网络 :
classifier.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
使用
adam
优化器,
binary_crossentropy
损失函数,因为是二分类问题。同时关注准确率指标。
- 处理图像并拟合 ANN :
from keras.preprocessing.image import ImageDataGenerator
generate_train_data = ImageDataGenerator(rescale = 1./255,
shear_range = 0.2,
zoom_range = 0.2,
horizontal_flip = True)
generate_test_data = ImageDataGenerator(rescale = 1./255)
training_dataset = generate_train_data.flow_from_directory('dataset/training_set',
target_size = (224, 224),
batch_size = 32,
class_mode = 'binary')
test_datasetset = generate_test_data.flow_from_directory('dataset/test_set',
target_size = (224, 224),
batch_size = 32,
class_mode = 'binary')
classifier.fit_generator(training_dataset,
steps_per_epoch = 100,
epochs = 10,
validation_data = test_datasetset,
validation_steps = 30)
使用
ImageDataGenerator
对训练集和测试集进行数据增强和归一化处理。然后使用
fit_generator
方法对模型进行训练,指定训练集、训练步数、训练轮数、验证集和验证步数。
- 预测新图像 :
import numpy as np
from keras.preprocessing import image
new_image = image.load_img('../Data/Prediction/test_image_1.jpg', target_size = (224, 224))
new_image = image.img_to_array(new_image)
new_image = np.expand_dims(new_image, axis = 0)
result = classifier.predict(new_image)
training_set.class_indices
if result[0][0] == 1:
prediction = 'It is a Dog'
else:
prediction = 'It is a Cat'
print(prediction)
加载新的图像,进行预处理后使用训练好的模型进行预测,根据预测结果输出是猫还是狗。
11. 迁移学习的优势与挑战
迁移学习在深度学习中具有诸多优势,但也面临一些挑战。以下是一个简单的对比表格:
| 优势 | 挑战 |
|---|---|
| 节省计算资源和时间,无需从头训练模型 | 新数据集与预训练数据集差异过大时,效果可能不佳 |
| 可以利用预训练模型学到的通用特征 | 可能需要大量的领域知识来调整模型 |
| 提高模型的泛化能力 | 冻结层和微调的策略需要仔细选择 |
12. 不同预训练模型的选择
在实际应用中,我们可以根据具体任务选择不同的预训练模型。以下是一些常见预训练模型的特点和适用场景:
| 预训练模型 | 特点 | 适用场景 |
|---|---|---|
| VGG16 | 结构简单,易于理解和修改 | 对模型解释性要求较高的场景 |
| Inception V3 | 采用了多分支结构,能提取更丰富的特征 | 对特征提取要求较高的场景 |
| ResNet50 | 引入了残差连接,解决了深度网络的梯度消失问题 | 需要训练深度网络的场景 |
| Mobilenet | 模型体积小,计算效率高 | 对模型大小和计算资源有限制的场景 |
13. 总结与展望
迁移学习和预训练模型为深度学习带来了巨大的便利和效率提升。通过特征提取和微调等技术,我们可以灵活地应用预训练模型解决各种图像分类问题。
在未来,随着数据集的不断丰富和模型结构的不断创新,迁移学习的应用范围将会更加广泛。同时,如何更好地处理不同领域之间的知识迁移,以及如何自动选择最优的预训练模型和微调策略,将是未来研究的重要方向。
我们可以通过以下 mermaid 流程图来总结整个迁移学习和预训练模型应用的流程:
graph TD;
A[选择预训练模型] --> B[特征提取];
B --> C[微调模型];
C --> D[数据预处理];
D --> E[模型训练];
E --> F[模型评估];
F --> G[模型应用];
通过这个流程图,我们可以清晰地看到从选择预训练模型到最终应用模型的整个过程,每个步骤都紧密相连,共同构成了迁移学习和预训练模型应用的完整流程。
超级会员免费看

被折叠的 条评论
为什么被折叠?



