在前面的文章中,我们介绍了如何使用 Keras 构建和训练全连接神经网络(MLP)、卷积神经网络(CNN)和循环神经网络(RNN)。本文将带你深入学习如何使用 迁移学习(Transfer Learning) 来加速和提升模型性能。我们将使用 Keras 和预训练的卷积神经网络(如 VGG16)来完成一个图像分类任务。
目录
- 什么是迁移学习
- 环境准备
- 导入必要的库
- 加载和预处理数据
- 加载预训练模型
- 构建迁移学习模型
- 编译模型
- 训练模型
- 评估模型
- 保存和加载模型
- 总结
1. 什么是迁移学习
迁移学习 是一种机器学习技术,它利用在一个任务上训练的模型来解决另一个相关任务。通过迁移学习,我们可以:
- 加速训练: 利用预训练模型的特征提取能力,减少训练时间。
- 提高性能: 在数据量有限的情况下,迁移学习可以显著提高模型的泛化能力。
- 减少数据需求: 预训练模型已经在大规模数据集上训练过,可以减少对新数据的需求。
在图像分类任务中,迁移学习通常涉及使用在 ImageNet 等大型数据集上预训练的卷积神经网络(如 VGG16、ResNet、Inception 等),并将其应用到新的图像分类任务中。
2. 环境准备
确保你已经安装了 Python(推荐 3.6 及以上版本)和 TensorFlow(Keras 已集成在 TensorFlow 中)。如果尚未安装,请运行以下命令:
pip install tensorflow
3. 导入必要的库
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, models, applications
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import matplotlib.pyplot as plt
import numpy as np
- tensorflow: 深度学习框架,Keras 已集成其中。
- ImageDataGenerator: 用于数据增强和预处理。
- applications: 预训练模型模块,包含 VGG16、ResNet 等。
4. 加载和预处理数据
我们将使用 猫狗数据集(Cats vs Dogs),这是一个二分类图像数据集,包含 25,000 张猫和狗的图片。我们将使用 Keras 的 ImageDataGenerator
进行数据增强和预处理。
# 数据集路径
train_dir = 'data/train'
validation_dir = 'data/validation'# 图像参数
img_height, img_width = 150, 150
batch_size = 32# 训练数据生成器(数据增强)
train_datagen = ImageDataGenerator(rescale=1./255, # 归一化rotation_range=40, # 随机旋转width_shift_range=0.2, # 随机水平平移height_shift_range=0.2, # 随机垂直平移shear_range=0.2, # 随机剪切zoom_range=0.2, # 随机缩放horizontal_flip=True, # 随机水平翻转fill_mode='nearest' # 填充方式
)# 测试数据生成器(仅归一化)
test_datagen = ImageDataGenerator(rescale=1./255)# 加载训练数据
train_generator = train_datagen.flow_from_directory(train_dir,target_size=(img_height, img_width),batch_size=batch_size,class_mode='binary' # 二分类
)# 加载验证数据
validation_generator = test_datagen.flow_from_directory(validation_dir,target_size=(img_height, img_width),batch_size=batch_size,class_mode='binary'
)
说明:
- 使用
ImageDataGenerator
进行数据增强,可以提高模型的泛化能力。 flow_from_directory
方法从目录中加载数据,目录结构应为train_dir/class1/
和train_dir/class2/
。
5. 加载预训练模型
我们将使用预训练的 VGG16 模型,并冻结其卷积基(convolutional base),只训练顶部的全连接层。
# 加载预训练的 VGG16 模型,不包括顶部的全连接层
conv_base = applications.VGG16(weights='imagenet',include_top=False,input_shape=(img_height, img_width, 3))# 冻结卷积基
conv_base.trainable = False# 查看模型结构
conv_base.summary()
说明:
weights='imagenet'
: 使用在 ImageNet 数据集上预训练的权重。include_top=False
: 不包括顶部的全连接层,以便我们添加自己的分类器。conv_base.trainable = False
: 冻结卷积基,防止其权重在训练过程中被更新。
6. 构建迁移学习模型
我们将添加自己的全连接层来进行分类。
model = models.Sequential([conv_base, # 预训练的卷积基layers.Flatten(), # 展平层layers.Dense(256, activation='relu'), # 全连接层layers.Dropout(0.5), # Dropout 层,防止过拟合layers.Dense(1, activation='sigmoid') # 输出层,二分类
])# 查看模型结构
model.summary()
说明:
- 添加
Flatten
层将多维输出展平。 - 添加
Dense
层和Dropout
层进行分类。 - 输出层使用
sigmoid
激活函数进行二分类。
7. 编译模型
model.compile(optimizer=keras.optimizers.Adam(),loss='binary_crossentropy',metrics=['accuracy'])
说明:
- 使用 Adam 优化器和二元交叉熵损失函数。
- 评估指标为准确率。
8. 训练模型
# 设置训练参数
epochs = 10# 训练模型
history = model.fit(train_generator,steps_per_epoch=train_generator.samples // batch_size,epochs=epochs,validation_data=validation_generator,validation_steps=validation_generator.samples // batch_size
)
说明:
steps_per_epoch
: 每个 epoch 的步数,通常为训练样本数除以批量大小。validation_steps
: 每个 epoch 的验证步数,通常为验证样本数除以批量大小。
9. 评估模型
test_loss, test_acc = model.evaluate(validation_generator, steps=validation_generator.samples // batch_size)
print(f"\n测试准确率: {test_acc:.4f}")
10. 保存和加载模型
# 保存模型
model.save("cats_vs_dogs_transfer_learning.h5")# 加载模型
new_model = keras.models.load_model("cats_vs_dogs_transfer_learning.h5")
11. 可视化训练过程
# 绘制训练 & 验证的准确率和损失值
plt.figure(figsize=(12,4))# 准确率
plt.subplot(1,2,1)
plt.plot(history.history['accuracy'], label='训练准确率')
plt.plot(history.history['val_accuracy'], label='验证准确率')
plt.xlabel('Epoch')
plt.ylabel('准确率')
plt.legend(loc='lower right')
plt.title('训练与验证准确率')# 损失值
plt.subplot(1,2,2)
plt.plot(history.history['loss'], label='训练损失')
plt.plot(history.history['val_loss'], label='验证损失')
plt.xlabel('Epoch')
plt.ylabel('损失')
plt.legend(loc='upper right')
plt.title('训练与验证损失')plt.show()
12. 解冻部分卷积基进行微调
为了进一步提高模型性能,可以解冻部分卷积基,进行微调。
# 解冻最后几个卷积层
conv_base.trainable = True# 查看可训练的参数
for layer in conv_base.layers:if layer.name == 'block5_conv1':breaklayer.trainable = False# 重新编译模型
model.compile(optimizer=keras.optimizers.Adam(1e-5), # 使用较低的学习率loss='binary_crossentropy',metrics=['accuracy'])# 继续训练模型
history_fine = model.fit(train_generator,steps_per_epoch=train_generator.samples // batch_size,epochs=5,validation_data=validation_generator,validation_steps=validation_generator.samples // batch_size
)
说明:
- 解冻部分卷积层,并使用较低的学习率进行微调。
- 继续训练模型以微调预训练模型的权重。
13. 课程回顾
本文其实不算什么知识点,只是利用迁移学习来加速训练的一个实际操作的例子。
作者简介
前腾讯电子签的前端负责人,现 whentimes tech CTO,专注于前端技术的大咖一枚!一路走来,从小屏到大屏,从 Web 到移动,什么前端难题都见过。热衷于用技术打磨产品,带领团队把复杂的事情做到极简,体验做到极致。喜欢探索新技术,也爱分享一些实战经验,帮助大家少走弯路!
温馨提示:可搜老码小张公号联系导师