引言
在深度学习领域,迁移学习是一种强大的技术,它允许我们利用预训练模型的知识来解决新的问题。在本博客中,我们将通过一个有趣的项目——为前美国总统奥巴马的宠物狗Bo定制智能狗门——来探索迁移学习的实际应用。
迁移学习简介
迁移学习是一种机器学习技术,它涉及将从一个任务学到的模型应用到另一个不同但相关的任务上。当我们面对数据量不足或训练资源有限的情况时,迁移学习尤其有用。
目标
在本节中,您将学习到如何:
- 准备预训练模型以进行迁移学习。
- 使用自己的小型数据集对预训练模型进行迁移学习。
- 优化模型以获得更好的性能。
个性化的狗门
我们将创建一个智能狗门,它只允许Bo进入,而将其他动物或物体排除在外。由于我们只有Bo的30张图片,从头开始训练一个模型很可能会导致过拟合。但是,我们可以从一个已经擅长检测狗的预训练模型开始,利用迁移学习解决这个问题。
下载预训练模型
我们将使用Keras库中的VGG16模型,这是一个在ImageNet数据集上预训练过的模型,非常适合作为迁移学习的基础。
from tensorflow import keras
# 加载VGG16模型,不包括顶层(因为我们将添加自己的顶层)
base_model = keras.applications.VGG16(
weights='imagenet',
input_shape=(224, 224, 3),
include_top=False
)
冻结基础模型
在添加新层之前,我们需要冻结基础模型的层,以保留通过ImageNet数据集训练获得的知识。
# 冻结基础模型的层
base_model.trainable = False
添加新层
我们将添加一个全局平均池化层和一个新的密集连接层,后者将作为我们的输出层,用于二分类任务(Bo或非Bo)。
from tensorflow.keras import Input, Model
# 输入层
inputs = Input(shape=(224, 224, 3))
# 利用预训练模型的输出
x = base_model(inputs, training=False)
# 添加全局平均池化层
x = keras.layers.GlobalAveragePooling2D()(x)
# 添加一个具有单个单元的输出层,用于二分类
outputs = keras.layers.Dense(1, activation='sigmoid')(x)
# 创建带有输入和输出的模型
model = Model(inputs, outputs)
编译模型
由于这是一个二分类问题,我们将使用二元交叉熵作为损失函数,并使用二元精度作为评估指标。
model.compile(
optimizer=keras.optimizers.RMSprop(lr=0.00001), # 非常低的学习率
loss='binary_crossentropy',
metrics=['binary_accuracy']
)
数据增强
为了使我们的模型更具鲁棒性,我们将使用数据增强技术来人为地扩充训练集。
from tensorflow.keras.preprocessing.image import ImageDataGenerator
# 创建数据增强对象
datagen = ImageDataGenerator(
samplewise_center=True,
rotation_range=10,
zoom_range=0.1,
width_shift_range=0.1,
height_shift_range=0.1,
horizontal_flip=True,
vertical_flip=False # Bo不太可能上下颠倒
)
加载数据
我们将从文件夹中直接加载图像数据,这是Keras flow_from_directory
函数的用法。
# 加载训练数据集
train_it = datagen.flow_from_directory(
'data/presidential_doggy_door/train/',
target_size=(224, 224),
color_mode='rgb',
class_mode='binary',
batch_size=8
)
# 加载验证数据集,不进行数据增强
valid_it = ImageDataGenerator(samplewise_center=True).flow_from_directory(
'data/presidential_doggy_door/valid/',
target_size=(224, 224),
color_mode='rgb',
class_mode='binary',
batch_size=8
)
训练模型
现在,我们可以训练模型,看看它的表现如何。
model.fit(
train_it,
steps_per_epoch=12,
validation_data=valid_it,
validation_steps=4,
epochs=20
)
微调模型
一旦新层被训练,我们可以通过解冻基础模型并使用非常低的学习率重新训练模型来进一步改进模型,这个过程称为微调。
# 解冻基础模型
base_model.trainable = True
# 重新编译模型,使用非常低的学习率
model.compile(
optimizer=keras.optimizers.RMSprop(lr=0.00001),
loss='binary_crossentropy',
metrics=['binary_accuracy']
)
# 继续训练模型
model.fit(
train_it,
steps_per_epoch=12,
validation_data=valid_it,
validation_steps=4,
epochs=10
)
检查预测结果
让我们检查模型对一些图像的预测结果。
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from tensorflow.keras.preprocessing import image as image_utils
from tensorflow.keras.applications.imagenet_utils import preprocess_input
def show_image(image_path):
image = mpimg.imread(image_path)
plt.imshow(image)
def make_predictions(image_path):
show_image(image_path)
image = image_utils.load_img(image_path, target_size=(224, 224))
image = image_utils.img_to_array(image)
image = image.reshape(1, 224, 224, 3)
image = preprocess_input(image)
preds = model.predict(image)
return preds
# 在几个图像上测试模型
make_predictions('data/presidential_doggy_door/valid/bo/bo_20.jpg')
make_predictions('data/presidential_doggy_door/valid/not_bo/121.jpg')
实现Bo的狗门
根据模型的预测结果,我们可以决定是否打开狗门。
def presidential_doggy_door(image_path):
preds = make_predictions(image_path)
if preds < 0:
print("It's Bo! Let him in!")
else:
print("That's not Bo! Stay out!")
# 测试Bo的狗门
presidential_doggy_door('data/presidential_doggy_door/valid/not_bo/131.jpg')
presidential_doggy_door('data/presidential_doggy_door/valid/bo/bo_29.jpg')
总结
通过本博客,您学习了如何使用迁移学习来构建一个高精度的模型,即使在数据集非常小的情况下。这种技术非常强大,可以在许多看似不可能的情况下取得成功。