来源:百度 PaddlePaddlepython
迁移学习 (Transfer Learning) 是属于深度学习的一个子研究领域,该研究领域的目标在于利用数据、任务、或模型之间的类似性,将在旧领域学习过的知识,迁移应用于新领域中。迁移学习吸引了不少研究者投身其中,由于它可以很好的解决深度学习中的如下几个问题:git
为了让开发者更便捷地应用迁移学习,百度 PaddlePaddle 开源了预训练模型管理工具 PaddleHub。开发者用使用仅仅十余行的代码,就能完成迁移学习。本文将为读者全面介绍 PaddleHub 并其应用方法。github
项目地址:https://github.com/PaddlePaddle/PaddleHubshell
PaddleHub 介绍浏览器
PaddleHub 是基于 PaddlePaddle 开发的预训练模型管理工具,能够借助预训练模型更便捷地开展迁移学习工做,旨在让 PaddlePaddle 生态下的开发者更便捷体验到大规模预训练模型的价值。网络
PaddleHub 目前的预训练模型覆盖了图像分类、目标检测、词法分析、Transformer、情感分析五大类别。将来会持续开放更多类型的深度学习模型,如语言模型、视频分类、图像生成等预训练模型。PaddleHub 的功能全景如图 1 所示。架构
图 1 PaddleHub 功能全景框架
PaddleHub 主要包括两个功能:命令行工具和 Fine-tune API。工具
命令行工具性能
PaddleHub 借鉴了 Anaconda 和 PIP 等软件包管理的理念,开发了命令行工具,能够方便快捷的完成模型的搜索、下载、安装、预测等功能,对应的关键的命令分别是 search,download,install,run 等。咱们以 run 命令为例,介绍如何经过命令行工具进行预测。
Run 命令用于执行 Module 的预测,这里分别举一个 NLP 和 CV 的例子。
对于 NLP 任务:输入数据经过--input_text 指定。以百度 LAC 模型(中文词法分析)为例,能够经过如下命令实现单行文本分析。
# 单文本预测
$ hub run lac --input_text "今天是个好日子"
对于 CV 任务:输入数据经过--input_path 指定。以 SSD 模型(单阶段目标检测)为例子,能够经过如下命令实现单张图片的预测
# 使用SSD检测模型对图片进行目标检测,第一条命令是下载图片,第二条命令是执行预测,用户也能够自
# 己准备图片
$ wget --no-check-certificate https://paddlehub.bj.bcebos.com/resources/test_img_bird.jpg
$ hub run ssd_mobilenet_v1_pascal --input_path test_img_bird.jpg
更多的命令用法,请读者参考文首的 Github 项目连接。
Fine-tune API
PaddleHub 提供了基于 PaddlePaddle 实现的 Fine-tune API, 重点针对大规模预训练模型的 Fine-tune 任务作了高阶的抽象,让预训练模型能更好服务于用户特定场景的应用。经过大规模预训练模型结合 Fine-tune,能够在更短的时间完成模型的收敛,同时具有更好的泛化能力。PaddleHub API 的全景如图 2 所示。
图 2 PaddleHub Fine-tune API 全景
基于以上介绍的 PaddleHub 两大功能,用户能够实现:
如下将从实战角度,教你如何使用 PaddleHub 进行图像分类迁移。
PaddleHub 实战
1. 安装
PaddleHub 是基于 PaddlePaddle 的预训练模型管理框架,使用 PaddleHub 前须要先安装 PaddlePaddle,若是你本地已经安装了 CPU 或者 GPU 版本的 PaddlePaddle,那么能够跳过如下安装步骤。
$ pip install paddlepaddle #CPU 安装命令
或者
$ pip install paddlepaddle-gpu # GPU 安装
推荐使用大于 1.4.0 版本的 PaddlePaddle。
经过如下命令来安装 PaddleHub
$ pip install paddlehub
2. 选择合适的模型
首先导入必要的 python 包
# -*- coding: utf8 -*-
import paddlehub as hub
import paddle.fluid as fluid
接下来咱们要在 PaddleHub 中选择合适的预训练模型来 Fine-tune,因为猫狗分类是一个图像分类任务,所以咱们使用经典的 ResNet-50 做为预训练模型。PaddleHub 提供了丰富的图像分类预训练模型,包括了最新的神经网络架构搜索类的 PNASNet,咱们推荐你尝试不一样的预训练模型来得到更好的性能。
module_map = {
"resnet50": "resnet_v2_50_imagenet",
"resnet101": "resnet_v2_101_imagenet",
"resnet152": "resnet_v2_152_imagenet",
"mobilenet": "mobilenet_v2_imagenet",
"nasnet": "nasnet_imagenet",
"pnasnet": "pnasnet_imagenet"
}
module_name = module_map["resnet50"]
module = hub.Module(name = module_name)
3. 数据准备
接着须要加载图片数据集。为了快速体验,咱们直接加载 PaddleHub 提供的猫狗分类数据集,若是想要使用自定义的数据进行体验,请查看自定义数据。
# 直接用PaddleHub提供的数据集
dataset = hub.dataset.DogCat()
4. 自定义数据
本节说明如何组装自定义的数据,若是想使用猫狗数据集进行体验,能够直接跳过本节。
使用自定义数据时,咱们须要本身切分数据集,将数据集且分为训练集、验证集和测试集。
同时使用三个文本文件来记录对应的图片路径和标签,此外还须要一个标签文件用于记录标签的名称。
├─data: 数据目录
├─train_list.txt:训练集数据列表
├─test_list.txt:测试集数据列表
├─validate_list.txt:验证集数据列表
├─label_list.txt:标签列表
└─……
训练/验证/测试集的数据列表文件的格式以下
图片 1 路径 图片 1 标签
图片 2 路径 图片 2 标签
...
标签列表文件的格式以下
分类 1 名称
分类 2 名称
...
使用以下的方式进行加载数据,生成数据集对象
注意事项:
# 使用本地数据集
class MyDataSet(hub.dataset.base_cv_dataset.ImageClassificationDataset):
def __init__(self):
self.base_path = "/test/data"
self.train_list_file = "train_list.txt"
self.test_list_file = "test_list.txt"
self.validate_list_file = "validate_list.txt"
self.label_list_file = "label_list.txt"
self.label_list = None
self.num_labels = 2
5. 生成 Reader
接着生成一个图像分类的 reader,reader 负责将 dataset 的数据进行预处理,接着以特定格式组织并输入给模型进行训练。
当咱们生成一个图像分类的 reader 时,须要指定输入图片的大小
data_reader = hub.reader.ImageClassificationReader(
image_width=module.get_expected_image_width(),
image_height=module.get_expected_image_height(),
images_mean=module.get_pretrained_images_mean(),
images_std=module.get_pretrained_images_std(),
dataset=dataset)
6. 组建 Fine-tune Task
有了合适的预训练模型和准备要迁移的数据集后,咱们开始组建一个 Task。
因为猫狗分类是一个二分类的任务,而咱们下载的 cv_classifer_module 是在 ImageNet 数据集上训练的千分类模型,因此咱们须要对模型进行简单的微调,把模型改造为一个二分类模型:
input_dict, output_dict, program = module.context(trainable=True)
img = input_dict["image"]
feature_map = output_dict["feature_map"]
task = hub.create_img_cls_task(
feature=feature_map, num_classes=dataset.num_labels)
feed_list = [img.name, task.variable("label").name]
7. 选择运行时配置
在进行 Fine-tune 前,咱们能够设置一些运行时的配置,例如以下代码中的配置,表示:
更多运行配置,请查看文首的 Github 项目连接。
config = hub.RunConfig(
use_cuda=False,
num_epoch=1,
checkpoint_dir="cv_finetune_turtorial_demo",
batch_size=32,
log_interval=10,
eval_interval=50,
strategy=hub.finetune.strategy.DefaultFinetuneStrategy())
8. 开始 Fine-tune
咱们选择 Fine-tune_and_eval 接口来进行模型训练,这个接口在 Fine-tune 的过程当中,会周期性的进行模型效果的评估,以便咱们了解整个训练过程的性能变化。
hub.finetune_and_eval(
task, feed_list=feed_list, data_reader=data_reader, config=config)
9. 查看训练过程的效果
训练过程当中的性能数据会被记录到本地,咱们能够经过 visualdl 来可视化这些数据。
咱们在 shell 中输入如下命令来启动 visualdl,其中${HOST_IP} 为本机 IP,须要用户自行指定
$ visualdl --logdir ./ cv_finetune_turtorial_demo/vdllog --host ${HOST_IP} --port 8989
启动服务后,咱们使用浏览器访问${HOST_IP}:8989,能够看到训练以及预测的 loss 曲线和 accuracy 曲线,以下图所示。
10. 使用模型进行预测
当 Fine-tune 完成后,咱们使用模型来进行预测,整个预测流程大体能够分为如下几步:
经过如下命令来获取测试的图片(适用于猫狗分类的数据集)
$ wget --no-check-certificate https://PaddleHub.bj.bcebos.com/resources/test_img_cat.jpg
$ wget --no-check-certificate https://PaddleHub.bj.bcebos.com/resources/test_img_dog.jpg
注意:其余数据集所用的测试图片请自行准备。
完整预测代码以下:
import osimport numpy as npimport paddle.fluid as fluidimport paddlehub as hub# Step 1: build Programmodule_map = { "resnet50": "resnet_v2_50_imagenet", "resnet101": "resnet_v2_101_imagenet", "resnet152": "resnet_v2_152_imagenet", "mobilenet": "mobilenet_v2_imagenet", "nasnet": "nasnet_imagenet", "pnasnet": "pnasnet_imagenet"}module_name = module_map["resnet50"]module = hub.Module(name = module_name)input_dict, output_dict, program = module.context(trainable=False)img = input_dict["image"]feature_map = output_dict["feature_map"]dataset = hub.dataset.DogCat()task = hub.create_img_cls_task( feature=feature_map, num_classes=dataset.num_labels)feed_list = [img.name]# Step 2: create data readerdata = [ "test_img_dog.jpg", "test_img_cat.jpg"]data_reader = hub.reader.ImageClassificationReader( image_width=module.get_expected_image_width(), image_height=module.get_expected_image_height(), images_mean=module.get_pretrained_images_mean(), images_std=module.get_pretrained_images_std(), dataset=None)predict_reader = data_reader.data_generator( phase="predict", batch_size=1, data=data)label_dict = dataset.label_dict()# Step 3: switch to inference programwith fluid.program_guard(task.inference_program()): # Step 4: load pretrained parameters place = fluid.CPUPlace() exe = fluid.Executor(place) pretrained_model_dir = os.path.join("cv_finetune_turtorial_demo", "best_model") fluid.io.load_persistables(exe, pretrained_model_dir) feeder = fluid.DataFeeder(feed_list=feed_list, place=place) # Step 5: predict for index, batch in enumerate(predict_reader()): result, = exe.run( feed=feeder.feed(batch), fetch_list=[task.variable('probs')]) predict_result = np.argsort(result[0])[::-1][0] print("input %i is %s, and the predict result is %s" % (index+1, data[index], label_dict[predict_result]))