如何用Keras在Python中实现迁移学习?
迁移学习(Transfer Learning)是一种利用已经训练好的模型,通过微调原模型的层,来应用在新的任务中的机器学习方法。这个技术已经在深度学习领域内被广泛应用,特别是在小数据集上表现良好。在本文中,我们将介绍如何使用Keras来实现迁移学习。
更多Python文章,请阅读:Python 教程
迁移学习简介
迁移学习在工业界和学术界中获得了广泛的认可和应用,它可以极大地提高我们的深度学习模型的可行性和实际应用。本质上,迁移学习借鉴了生物学中神经系统的工作原理,它利用已训练好的神经网络在新任务中复用所学到的知识,通过修改少量的权重,使其能够适应新的任务。
迁移学习的分类
迁移学习可以被划分为三个主要类别: 情景迁移、领域迁移和任务迁移。其中,情景迁移是将已经学到的知识在相似的场景中进行复用;领域迁移是将已经学习的知识在不同的领域中进行复用,如将图片识别模型的知识应用到语音识别上;任务迁移是将已经学习的知识应用到不同的任务场景中,如将一个情感分类模型应用到商品推荐中。
Keras概述
Keras 始于 2015 年 3 月,是由 François Chollet 开发的一个 Python 的深度学习框架。Keras 具有代码清晰、易读、简洁的特点,并且非常适合初学者。它被称为 TensorFlow 的用户界面,TF在内部实现的一些东西,在Keras里面被屏蔽掉了。Keras 可以运行在 TensorFlow、Theano 和 CNTK 等后端框架之上。
迁移学习的实现
在本文中,我们将使用VGG16作为我们的基础模型,采用ImageNet上的预训练参数。我们以Keras为工具进行实现。通过微调原模型,并在拓展的网络中加入新的层,我们可以快速构建适用于小样本数据集的性能强大的模型。
在这里,我们采用Keras的函数式API来创建模型。
首先我们需要导入相关的包:
from keras.applications.vgg16 import VGG16
from keras.models import Model
from keras.layers import Flatten, Dense
from keras.optimizers import Adam
from keras.preprocessing.image import ImageDataGenerator
接下来,我们定义如下函数来为模型传递图像数据。我们将载入的图像作为输入,将VGG16网络作为基础模型,自定义的模型将在其上构建。在这里,我们为最后的全连接层定义了两个神经元,以将其用于分类问题.
def prepare_model():
# 使用ImageNet上的权重作为基础模型,但不包含顶部的全连接层
base_model = VGG16(weights='imagenet', include_top=False)
# 自定义模型的顶部部分
x = Flatten()(base_model.output)
x = Dense(1024, activation='relu')(x)
x = Dense(2, activation='softmax')(x)
# 组合基础模型和新模型的顶部
custom_model = Model(inputs=base_model.input, outputs=x)
# 固定VGG16的前15个层
for layer in custom_model.layers[:15]:
layer.trainable = False
# 编译模型
custom_model.compile(optimizer=Adam(lr=1e-5), loss='categorical_crossentropy', metrics=['accuracy'])
return custom_model
接下来,我们需要定义一个函数,用于读取图像并进行数据增强。在本例中,我们将图像进行随机旋转、水平翻转、垂直翻转、以及缩放。为了防止过拟合,我们还将应用 dropout 正则化。
def prepare_data():
# 设置训练和验证数据的图像增强参数
train_datagen = ImageDataGenerator(rotation_range=20,
width_shift_range=0.1,
height_shift_range=0.1,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest',
preprocessing_function=preprocess_input,
dtype='float32')
valid_datagen = ImageDataGenerator(preprocessing_function=preprocess_input, dtype='float32')
# 读取数据
train_generator = train_datagen.flow_from_directory(
'train_images/',
target_size=(224, 224),
batch_size=32,
class_mode='categorical')
valid_generator = valid_datagen.flow_from_directory(
'valid_images/',
target_size=(224, 224),
batch_size=32,
class_mode='categorical')
return train_generator, valid_generator
现在我们已经定义了所有必要的函数。下一步是使用这些函数构建我们的模型,并使用它进行训练和验证。我们可以使用 keras.callbacks.ModelCheckpoint
回调函数自动保存模型。
from keras.callbacks import ModelCheckpoint
# 准备数据
train_generator, valid_generator = prepare_data()
# 准备模型
custom_model = prepare_model()
# 创建回调以保存模型并记录训练进度
model_checkpoint = ModelCheckpoint('best_model.h5',
save_best_only=True,
save_weights_only=True,
monitor='val_loss',
mode='min',
verbose=1)
# 训练模型
custom_model.fit(train_generator, validation_data=valid_generator,
epochs=10, callbacks=[model_checkpoint])
模型微调
在训练完自定义模型之后,我们可以尝试进一步提高性能,通过用较小的学习率微调预训练的模型权重。微调通常包括使用较小的学习率重新训练顶部层,然后解冻某些层,并使用更小的学习率降低底部的层。在这里,我们只尝试微调前两个卷积块。下面是微调模型的代码:
# 激活在微调期间能够让整个模型进行训练的层
for layer in custom_model.layers[:15]:
layer.trainable = True
# 编译带微调的模型
custom_model.compile(loss='categorical_crossentropy',
optimizer=Adam(lr=1e-7),
metrics=['accuracy'])
# 运行带微调的模型
custom_model.fit(train_generator, validation_data=valid_generator,
epochs=10, callbacks=[model_checkpoint])
微调后的模型将在训练集上进行逐层更正的微调,以适应数据集,提高模型的性能。这些固定的层会发挥不同的作用,例如学习通用的特征,形成更好的边缘检测,以及学习更高维度的特征,如边缘纹理等。
预测新图像
在模型训练和微调之后,我们可以使用训练好的模型来处理新的图像。下面是一个使用训练好的模型进行图像预测的示例,它可以用于对检测到的图像进行分类:
from keras.models import load_model
from keras.preprocessing import image
import numpy as np
# 载入模型权重
model = load_model('best_model.h5')
# 读取图片
img_path = 'test_image.jpg'
img = image.load_img(img_path, target_size=(224, 224))
# 把图片转换为数组
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
# 运行模型并预测图像分类
preds = model.predict(x)
print('Predicted:', preds)
结论
通过使用Keras,我们可以在Python中非常简单地实现迁移学习。使用预训练的模型,我们可以轻松地在小数据集上建立性能强大的模型,而微调可以进一步提高模型的性能。Keras简洁清晰、易于学习和使用,为深度学习入门者提供了一个很好的起点。