來源:百度 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]))