提交 b340015d 编写于 作者: Z zhangxuefei

Merge branch 'develop' of https://github.com/PaddlePaddle/PaddleHub into fix-py2-py3-compatible

......@@ -14,6 +14,7 @@ PaddleHub是基于PaddlePaddle开发的预训练模型管理工具,可以借
2. 通过hub download命令,快速地获取PaddlePaddle生态下的所有预训练模型;
3. 借助PaddleHub Finetune API,使用少量代码完成迁移学习;
- 更多Demo可参考 [ERNIE文本分类](https://github.com/PaddlePaddle/PaddleHub/tree/develop/demo/text-classification) [图像分类迁移](https://github.com/PaddlePaddle/PaddleHub/tree/develop/demo/image-classification)
- 完整教程可参考 [文本分类迁移教程](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub%E6%96%87%E6%9C%AC%E5%88%86%E7%B1%BB%E8%BF%81%E7%A7%BB%E6%95%99%E7%A8%8B) [图像分类迁移教程](https://github.com/PaddlePaddle/PaddleHub/wiki/PaddleHub%E5%9B%BE%E5%83%8F%E5%88%86%E7%B1%BB%E8%BF%81%E7%A7%BB%E6%95%99%E7%A8%8B)
## 安装
......
----
# Dataset
----
PaddleHub
----
# Module
----
在PaddleHub中,Module代表了一个`可执行`的模型。这里的可执行指的是,Module可以直接通过命令行`hub run ${MODULE_NAME}`执行预测,或者通过context接口获取上下文后进行finetune。
## `class paddlehub.module.Module(name=None, module_dir=None)`
在生成一个Module时,支持通过名称、url或者路径创建Module
> ### 参数
> * name: 模块名称
>
> * module_dir: 模块路径
>
> ### 返回
> Module
>
> ### 示例
>
> ```python
> import paddlehub as hub
> # 根据模型名字创建Module
> hub.Module(name = "lac")
> ```
## `context(for_test=False, trainable=False, regularizer=None, learning_rate=1e-3)`
用于获取Module的上下文信息,得到输入、输出以及预训练的Paddle Program副本
> ### 参数
> * for_test: 是否用于测试,如果是用于预测,则设置为True,如果用于finetune,则设置为False。默认情况下,该参数被设置为False
>
> * trainable: 获取的Program副本中的参数是否为可训练的,设置为True表示可训练。默认情况下,该参数被设置为False
>
> * regularizer: 获取的Program副本中的参数的正则化项。默认情况下,该参数被设置为None
>
> * learning_rate: 获取的Program副本中的参数的学习率。默认情况下,该参数被设置为1e-3
>
> ### 示例
>
> ```python
> import paddlehub as hub
> resnet = hub.Module(name = "resnet_v2_50_imagenet")
> input_dict, output_dict, program = resnet.context(trainable=True)
> with fluid.program_guard(program):
> label = fluid.layers.data(name="label", dtype="int64", shape=[1])
> img = input_dict["image"]
> feature_map = output_dict["feature_map"]
> feed_list = [img.name, label.name]
> fc = fluid.layers.fc(input = feature_map, size = 2)
> feed_list = [img.name, label.name]
> # 添加fc层后,进行训练
> ...
> ```
----
# Reader
----
PaddleHub
----
# RunConfig
----
在PaddleHub中,RunConfig代表了在对[Task](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/Task.md)进行Finetune时的运行配置。包括运行的epoch次数、batch的大小、是否使用GPU训练等
## `class paddlehub.finetune.config.RunConfig(log_interval=10, eval_interval=100, save_ckpt_interval=None, use_cuda=False, checkpoint_dir=None, num_epoch=10, batch_size=None, enable_memory_optim=True, strategy=None)`
> ### 参数
> * log_interval: 打印训练日志的周期。默认为10
>
> * eval_interval: 进行评估的周期。默认为100
>
> * save_ckpt_interval: 保存checkpoint的周期。默认为None
>
> * use_cuda: 是否使用GPU训练和评估。默认为False
>
> * checkpoint_dir: checkpoint的保存目录。默认为None,此时会在工作目录下根据时间戳生成一个临时目录。
>
> * num_epoch: 运行的epoch次数。默认为10次
>
> * batch_size: batch大小。默认为None
>
> * enable_memory_optim: 是否进行内存优化。默认为True
>
> * strategy: finetune的策略。默认为None,此时会使用DefaultFinetuneStrategy策略
>
> ### 返回
> RunConfig
>
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig(
> use_cuda=True,
> num_epoch=10,
> batch_size=32)
> ```
## `log_interval`
获取RunConfig设置的log_interval属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> log_interval = config.log_interval()
> ```
## `eval_interval`
获取RunConfig设置的eval_interval属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> eval_interval = config.eval_interval()
> ```
## `save_ckpt_interval`
获取RunConfig设置的save_ckpt_interval属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> save_ckpt_interval = config.save_ckpt_interval()
> ```
## `use_cuda`
获取RunConfig设置的use_cuda属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> use_cuda = config.use_cuda()
> ```
## `checkpoint_dir`
获取RunConfig设置的checkpoint_dir属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> checkpoint_dir = config.checkpoint_dir()
> ```
## `num_epoch`
获取RunConfig设置的num_epoch属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> num_epoch = config.num_epoch()
> ```
## `batch_size`
获取RunConfig设置的batch_size属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> batch_size = config.batch_size()
> ```
## `strategy`
获取RunConfig设置的strategy属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> strategy = config.strategy()
> ```
## `enable_memory_optim`
获取RunConfig设置的enable_memory_optim属性
> ### 示例
>
> ```python
> import paddlehub as hub
>
> config = hub.RunConfig()
> enable_memory_optim = config.enable_memory_optim()
> ```
----
# Strategy
----
在PaddleHub中,Strategy代表了在对[Task](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/Task.md)进行Finetune时,应该使用怎样的策略。这里的策略,包含了对预训练参数使用怎样的学习率,使用哪种类型的优化器,使用什么类型的正则化等
## `class paddlehub.finetune.strategy.AdamWeightDecayStrategy(learning_rate=1e-4, lr_scheduler="linear_decay", warmup_proportion=0.0, weight_decay=0.01, optimizer_name=None)`
基于Adam优化器的学习率衰减策略
> ### 参数
> * learning_rate: 全局学习率。默认为1e-4
>
> * lr_scheduler: 学习率调度方法。默认为"linear_decay"
>
> * warmup_proportion: warmup所占比重
>
> * weight_decay: 学习率衰减率
>
> * optimizer_name: 优化器名称。默认为None,此时会使用Adam
>
> ### 返回
> AdamWeightDecayStrategy
>
> ### 示例
>
> ```python
> ...
> strategy = hub.AdamWeightDecayStrategy()
>
> config = hub.RunConfig(
> use_cuda=True,
> num_epoch=10,
> batch_size=32,
> checkpoint_dir="hub_finetune_ckpt",
> strategy=strategy)
> ```
## `class paddlehub.finetune.strategy.DefaultFinetuneStrategy(learning_rate=1e-4, optimizer_name=None, regularization_coeff=1e-3)`
默认的Finetune策略,该策略会对预训练参数增加L2正则作为惩罚因子
> ### 参数
> * learning_rate: 全局学习率。默认为1e-4
>
> * optimizer_name: 优化器名称。默认为None,此时会使用Adam
>
> * regularization_coeff: 正则化的λ参数。默认为1e-3
>
> ### 返回
> DefaultFinetuneStrategy
>
> ### 示例
>
> ```python
> ...
> strategy = hub.DefaultFinetuneStrategy()
>
> config = hub.RunConfig(
> use_cuda=True,
> num_epoch=10,
> batch_size=32,
> checkpoint_dir="hub_finetune_ckpt",
> strategy=strategy)
> ```
----
# Task
----
在PaddleHub中,Task代表了一个fine-tune的任务。任务中包含了执行该任务相关的program以及和任务相关的一些度量指标(如分类准确率accuracy、precision, recall, F1-score等)、m模型损失等。
## `class paddlehub.finetune.Task(task_type, graph_var_dict, main_program, startup_program)`
> ### 参数
> * task_type: 任务类型,用于在finetune时进行判断如何执行任务
>
> * graph_var_dict: 变量映射表,提供了任务的度量指标
>
> * main_program: 存储了模型计算图的Program
>
> * module_dir: 存储了模型参数初始化op的Program
>
> ### 返回
> Task
>
> ### 示例
>
> ```python
> import paddlehub as hub
> # 根据模型名字创建Module
> resnet = hub.Module(name = "resnet_v2_50_imagenet")
> input_dict, output_dict, program = resnet.context(trainable=True)
> with fluid.program_guard(program):
> label = fluid.layers.data(name="label", dtype="int64", shape=[1])
> feature_map = output_dict["feature_map"]
> task = hub.create_img_cls_task(
> feature=feature_map, label=label, num_classes=2)
> ```
## `variable(var_name)`
获取Task中的相关变量
> ### 参数
> * var_name: 变量名
>
> ### 示例
>
> ```python
> import paddlehub as hub
> ...
> task = hub.create_img_cls_task(
> feature=feature_map, label=label, num_classes=2)
> task.variable("loss")
> ```
## `main_program()`
获取Task对应的main_program
> ### 示例
>
> ```python
> import paddlehub as hub
> ...
> task = hub.create_img_cls_task(
> feature=feature_map, label=label, num_classes=2)
> main_program = task.main_program()
> ```
## `startup_program()`
获取Task对应的startup_program
> ### 示例
>
> ```python
> import paddlehub as hub
> ...
> task = hub.create_img_cls_task(
> feature=feature_map, label=label, num_classes=2)
> startup_program = task.startup_program()
> ```
## `inference_program()`
获取Task对应的inference_program
> ### 示例
>
> ```python
> import paddlehub as hub
> ...
> task = hub.create_img_cls_task(
> feature=feature_map, label=label, num_classes=2)
> inference_program = task.inference_program()
> ```
## `metric_variable_names()`
获取Task对应的所有相关的变量,包括loss、度量指标等
> ### 示例
>
> ```python
> import paddlehub as hub
> ...
> task = hub.create_img_cls_task(
> feature=feature_map, label=label, num_classes=2)
> metric_variable_names = task.metric_variable_names()
> ```
----
# create_img_cls_task
----
## `method paddlehub.finetune.task.create_img_cls_task(feature, label, num_classes, hidden_units=None):`
基于输入的特征,添加一个或多个全连接层来创建一个[图像分类](https://github.com/PaddlePaddle/PaddleHub/tree/develop/demo/image-classification)任务用于finetune
> ### 参数
> * feature: 输入的特征
>
> * labels: 标签Variable
>
> * num_classes: 最后一层全连接层的神经元个数
>
> * hidden_units: 隐藏单元的设置,预期值为一个python list,list中的每个元素说明了一个隐藏层的神经元个数
>
> ### 返回
> paddle.finetune.task.Task
>
> ### 示例
>
> ```python
> import paddlehub as hub
>
> module = hub.Module(name="resnet_v2_50_imagenet")
> inputs, outputs, program = module.context(trainable=True)
>
> with fluid.program_guard(program):
> label = fluid.layers.data(name="label", shape=[1], dtype='int64')
> feature_map = outputs['feature_map']
>
> cls_task = hub.create_img_cls_task(
> feature=feature_map, label=label, num_classes=2, hidden_units = [20, 10])
> ```
----
# create_seq_label_task
----
## `method paddlehub.finetune.task.create_seq_label_task(feature, labels, seq_len, num_classes)`
基于输入的特征,添加一个全连接层来创建一个[序列标注](https://github.com/PaddlePaddle/PaddleHub/tree/develop/demo/sequence-labeling)任务用于finetune
> ### 参数
> * feature: 输入的特征
>
> * labels: 标签Variable
>
> * seq_len: 序列长度Variable
>
> * num_classes: 全连接层的神经元个数
>
> ### 返回
> paddle.finetune.task.Task
>
> ### 示例
>
> ```python
> import paddlehub as hub
>
> max_seq_len = 20
> module = hub.Module(name="ernie")
> inputs, outputs, program = module.context(
> trainable=True, max_seq_len=max_seq_len)
>
> with fluid.program_guard(program):
> label = fluid.layers.data(name="label", shape=[max_seq_len, 1], dtype='int64')
> seq_len = fluid.layers.data(name="seq_len", shape=[1], dtype='int64')
> sequence_output = outputs["sequence_output"]
>
> seq_label_task = hub.create_seq_label_task(
> feature=sequence_output,
> labels=label,
> seq_len=seq_len,
> num_classes=dataset.num_labels)
> ```
----
# create_text_cls_task
----
## `method paddlehub.finetune.task.create_text_cls_task(feature, label, num_classes, hidden_units=None):`
基于输入的特征,添加一个或多个全连接层来创建一个[文本分类](https://github.com/PaddlePaddle/PaddleHub/tree/develop/demo/text-classification)任务用于finetune
> ### 参数
> * feature: 输入的特征
>
> * labels: 标签Variable
>
> * num_classes: 最后一层全连接层的神经元个数
>
> * hidden_units: 隐藏单元的设置,预期值为一个python list,list中的每个元素说明了一个隐藏层的神经元个数
>
> ### 返回
> paddle.finetune.task.Task
>
> ### 示例
>
> ```python
> import paddlehub as hub
>
> max_seq_len = 20
> module = hub.Module(name="ernie")
> inputs, outputs, program = module.context(
> trainable=True, max_seq_len=max_seq_len)
>
> with fluid.program_guard(program):
> label = fluid.layers.data(name="label", shape=[1], dtype='int64')
> pooled_output = outputs["pooled_output"]
>
> cls_task = hub.create_text_cls_task(
> feature=pooled_output, label=label, num_classes=2, hidden_units = [20, 10])
> ```
----
# finetune
----
## `method paddlehub.finetune.task.finetune(task, data_reader, feed_list, config=None):`
对一个Task进行finetune。在finetune的过程中,接口会定期的保存checkpoint(模型和运行数据),当运行被中断时,通过RunConfig指定上一次运行的checkpoint目录,可以直接从上一次运行的最后一次评估中恢复状态继续运行
> ### 参数
> * task: 需要执行的Task
>
> * data_reader: 提供数据的reader
>
> * feed_list: reader的feed列表
>
> * config: 运行配置
>
> ### 示例
>
> ```python
> import paddlehub as hub
> import paddle.fluid as fluid
>
> resnet_module = hub.Module(name="resnet_v2_50_imagenet")
> input_dict, output_dict, program = resnet_module.context(trainable=True)
> dataset = hub.dataset.Flowers()
> data_reader = hub.reader.ImageClassificationReader(
> image_width=resnet_module.get_excepted_image_width(),
> image_height=resnet_module.get_excepted_image_height(),
> dataset=dataset)
> img = input_dict[0]
> feature_map = output_dict[0]
>
> feed_list = [img.name, label.name]
>
> task = hub.create_img_cls_task(
> feature=feature_map, num_classes=dataset.num_labels)
> hub.finetune(
> task, feed_list=feed_list, data_reader=data_reader)
> ```
# finetune_and_eval
----
## `method paddlehub.finetune.task.finetune_and_eval(task, data_reader, feed_list, config=None):`
对一个Task进行finetune,并且定期进行验证集评估。在finetune的过程中,接口会定期的保存checkpoint(模型和运行数据),当运行被中断时,通过RunConfig指定上一次运行的checkpoint目录,可以直接从上一次运行的最后一次评估中恢复状态继续运行
> ### 参数
> * task: 需要执行的Task
>
> * data_reader: 提供数据的reader
>
> * feed_list: reader的feed列表
>
> * config: 运行配置
>
> ### 示例
>
> ```python
> import paddlehub as hub
> import paddle.fluid as fluid
>
> resnet_module = hub.Module(name="resnet_v2_50_imagenet")
> input_dict, output_dict, program = resnet_module.context(trainable=True)
> dataset = hub.dataset.Flowers()
> data_reader = hub.reader.ImageClassificationReader(
> image_width=resnet_module.get_excepted_image_width(),
> image_height=resnet_module.get_excepted_image_height(),
> dataset=dataset)
> img = input_dict["image"]
>
> feature_map = output_dict["feature_map"]
>
> feed_list = [img.name, label.name]
>
> task = hub.create_img_cls_task(
> feature=feature_map, num_classes=dataset.num_labels)
> hub.finetune_and_eval(
> task=task, feed_list=feed_list, data_reader=data_reader)
> ```
# PaddleHub Fine-tune API 全景图
![Fine-tune API 全景图](https://raw.githubusercontent.com/PaddlePaddle/PaddleHub/develop/docs/imgs/finetune_api_figure.png)
# 类
* 迁移任务 [Task](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/Task.md)
* 运行配置 [RunConfig](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/RunConfig.md)
* 优化策略 [Strategy](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/Strategy.md)
* 预训练模型 [Module](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/Module.md)
* 数据预处理 [Reader](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/Reader.md)
* 数据集 [Dataset](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/Dataset.md)
# 接口
* [create_seq_label_task](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/create_seq_label_task.md)
* [create_text_cls_task](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/create_text_cls_task.md)
* [create_img_cls_task](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/create_img_cls_task.md)
* [finetune_and_eval](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/finetune_and_eval.md)
# 安装相关问题
## 使用`pip install paddlehub`时提示`Could not find a version that satisfies the requirement paddlehub (from versions: )`
这可能是因为pip指向了一个pypi的镜像源,该镜像源没有及时同步paddlehub版本导致
使用如下命令来安装
```shell
$ pip install -i https://pypi.org/simple/ paddlehub
```
# 使用相关问题
## 使用paddlehub时,提示`ModuleNotFoundError: No module named 'paddle'`
这是因为PaddleHub依赖于PaddlePaddle,用户需要自行安装合适的PaddlePaddle版本
如果机器不支持GPU,那么使用如下命令来安装PaddlePaddle的CPU版本
```shell
$ pip install paddlepaddle
```
如果机器支持GPU,则使用如下命令来安装PaddlePaddle的GPU版本
```shell
$ pip install paddlepaddle-gpu
```
# PaddleHub 命令行介绍
PaddleHub为Module/Model(关于Model和Module的区别,请查看下方的介绍)的管理和使用提供了命令行工具,目前命令行支持以下10个命令:
## `install`
用于将Module安装到本地,默认安装在`${USER_HOME}/.paddlehub/module`目录下,当一个Module安装到本地后,用户可以通过其他命令操作该Module(例如,使用该Module进行预测),也可以使用PaddleHub提供的python API,将Module应用到自己的任务中,实现迁移学习
## `uninstall`
用于卸载本地Module
## `show`
用于查看本地已安装Module的属性或者指定目录下确定的Model或者Module的属性,包括其名字、版本、描述、作者等信息
## `download`
用于下载百度提供的Module/Model
`选项`
> `--output_path`:用于指定存放下载文件的目录,默认为当前目录
>
> `--uncompress`:是否对下载的压缩包进行解压,默认不解压
## `search`
通过关键字在服务端检索匹配的Module/Model,当想要查找某个特定模型的Module/Model时,使用search命令可以快速得到结果,例如`hub search ssd`命令,会查找所有包含了ssd字样的Module/Model,命令支持正则表达式,例如`hub search ^s.*`搜索所有以s开头的资源。
`注意`
如果想要搜索全部的Module/Model,使用`hub search *`并不生效,这是因为shell会自行进行通配符展开,将*替换为当前目录下的文件名。为了进行全局搜索,用户可以直接键入`hub search`
## `list`
列出本地已经安装的Module
## `run`
用于执行Module的预测,需要注意的是,并不是所有的模型都支持预测(同样,也不是所有的模型都支持迁移学习),更多关于run命令的细节,请查看下方的`关于预测`
## `help`
显示帮助信息
## `version`
显示PaddleHub版本信息
## `clear`
PaddleHub在使用过程中会产生一些缓存数据,这部分数据默认存放在${USER_HOME}/.paddlehub/cache目录下,用户可以通过clear命令来清空缓存
# 关于预测
PaddleHub尽量简化了用户在使用命令行预测时的理解成本,一般来讲,我们将预测分为NLP和CV两大类
## NLP类的任务
输入数据通过--input_text或者--input_file指定。以百度LAC模型(中文词法分析)为例,可以通过以下两个命令实现单行文本和多行文本的分析。
```shell
# 单文本预测
$ hub run lac --input_text "今天是个好日子"
```
```shell
# 多文本分析
$ hub run lac --input_file test.txt
```
其中test.txt的样例格式如下,每行是一个需要词法分析句子
```
今天是个好日子
天气预报说今天要下雨
下一班地铁马上就要到了
……更多行……
```
## CV类的任务
输入数据通过`--input_path`或者`--input_file`指定。以SSD模型(单阶段目标检测)为例子,可以通过以下两个命令实现单张图片和多张图片的预测
```shell
# 单张照片预测
$ hub run ssd_mobilenet_pascal --input_path test.jpg
```
```shell
# 多张照片预测
$ hub run ssd_mobilenet_pascal --input_file test.txt
```
其中test.txt的格式为
```
cat.jpg
dog.jpg
person.jpg
……更多行……
```
# 关于Model和Module
在PaddleHub中,我们明确区分开Module/Model两个概念
## Model
Model表示预训练好的参数和模型,当需要使用Model进行预测时,需要模型配套的代码,进行模型的加载,数据的预处理等操作后,才能进行预测。
PaddleHub为PaddlePaddle生态的预训练模型提供了统一的管理机制,用户可以使用`hub download`命令的获取到最新的Model,以便进行实验或者其他操作。
## Module
Module是Model的超集,是一个`可执行模块`,一个Module可以支持直接命令行预测,也可以配合PaddleHub Finetune API,通过少量代码实现迁移学习。
需要注意的是,不是所有的Module都支持命令行预测; (例如BERT/ERNIE Transformer类模型,一般需要搭配任务进行finetune)
也不是所有的Module都可用于finetune(例如LAC词法分析模型,我们不建议用户用于finetune)。
# 图像分类Fine-tune
Fine-tune是[迁移学习](https://github.com/PaddlePaddle/PaddleHub/blob/develop/docs/transfer_learning_turtorial.md)中使用得最多的技巧。
其主要理念在于,通过对预训练模型进行结构和参数的`微调`来实现模型迁移,从而达到迁移学习的目的。
本文以Kaggle的猫狗分类数据集为例子,详细了介绍如何在PaddleHub中进行CV方向的finetune
## 一、准备工作
在开始进行finetune前,我们需要完成以下几个工作准备
### 1. 安装PaddlePaddle
PaddleHub是基于PaddlePaddle的预训练模型管理框架,使用PaddleHub前需要先安装PaddlePaddle,如果您本地已经安装了cpu或者gpu版本的PaddlePaddle,那么可以跳过以下安装步骤。
```shell
# 安装cpu版本的PaddlePaddle
$ pip install paddlepaddle
```
我们推荐您使用大于1.3.0版本的PaddlePaddle,如果您本地版本较低,使用如下命令进行升级
```shell
$ pip install --upgrade paddlepaddle
```
在安装过程中如果遇到问题,您可以到[Paddle官方网站](http://www.paddlepaddle.org/)上查看解决方案
### 2. 安装PaddleHub
通过以下命令来安装PaddleHub
```shell
$ pip install paddlehub
```
如果在安装过程中遇到问题,您可以查看下[FAQ](https://github.com/PaddlePaddle/PaddleHub/blob/develop/docs/FAQ.md)来查找问题解决方案,如果无法解决,请在issue中反馈问题,我们会尽快分析解决
## 二、挑选合适的模型
首先导入必要的python包
```python
# -*- coding: utf8 -*-
import paddlehub as hub
import paddle.fluid as fluid
```
接下来我们要在PaddleHub中选择合适的预训练模型来Finetune,由于猫狗分类是一个图像分类任务,因此我们使用经典的resnet50作为预训练模型。PaddleHub提供了丰富的图像分类预训练模型,包括了最新的神经网络架构搜索类的NASNet,我们推荐您尝试不同的预训练模型来获得更好的性能。
```python
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"]
cv_classifer_module = hub.Module(name = module_name)
```
## 三、数据准备
接着需要加载图片数据集。我们需要自己切分数据集,将数据集且分为训练集、验证集和测试集。
同时使用三个文本文件来记录对应的图片路径和标签
```
├─data: 数据目录
  ├─train_list.txt:训练集数据列表
  ├─test_list.txt:测试集数据列表
  ├─validate_list:验证集数据列表
  └─……
```
每个文件的格式如下
```
图片1路径 图片1标签
图片2路径 图片2标签
……
```
使用如下的方式进行加载数据,生成数据集对象
```python
# 使用本地数据集
class mydataset(hub.ImageClassificationDataset):
self.base_path = "data"
self.train_list_file = "train_list.txt"
self.test_list_file = "test_list.txt"
self.validate_list_file = "validate_list.txt"
self.num_labels = 2
dataset = mydataset()
```
如果想要快速体验finetune的流程,可以直接加载paddlehub提供的猫狗分类数据集
```python
# 直接用PaddleHub提供的数据集
dataset = hub.dataset.DogCat()
```
接着生成一个图像分类的reader,reader负责将dataset的数据进行预处理,接着以特定格式组织并输入给模型进行训练。
当我们生成一个图像分类的reader时,需要指定输入图片的大小
```python
data_reader = hub.reader.ImageClassificationReader(
image_width=cv_classifer_module.get_expected_image_width(),
image_height=cv_classifer_module.get_expected_image_height(),
images_mean=cv_classifer_module.get_pretrained_images_mean(),
images_std=cv_classifer_module.get_pretrained_images_std(),
dataset=dataset)
```
## 四、组建Finetune Task
有了合适的预训练模型和准备要迁移的数据集后,我们开始组建一个Task。
由于猫狗分类是一个二分类的任务,而我们下载的cv_classifer_module是在ImageNet数据集上训练的千分类模型,所以我们需要对模型进行简单的微调,把模型改造为一个二分类模型:
1. 获取cv_classifer_module的上下文环境,包括输入和输出的变量,以及Paddle Program
2. 从输出变量中找到特征图提取层feature_map
3. 在feature_map后面接入一个全连接层,生成Task
```python
input_dict, output_dict, program = cv_classifer_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]
```
## 五、选择运行时配置
在进行Finetune前,我们可以设置一些运行时的配置,例如如下代码中的配置,表示:
`epoch`:要求Finetune的任务只遍历10次训练集
`batch_size`:每次训练的时候,给模型输入的每批数据大小为32,模型训练时能够并行处理批数据,因此batch_size越大,训练的效率越高,但是同时带来了内存的负荷,过大的batch_size可能导致内存不足而无法训练,因此选择一个合适的batch_size是很重要的一步。
`log_interval`:每隔10 step打印一次训练日志
`eval_interval`:每隔50 step在验证集上进行一次性能评估。
`checkpoint_dir`:将训练的参数和数据保存到cv_finetune_turtorial_demo目录中
更多运行配置,请查看[RunConfig](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/API/RunConfig.md)
```python
config = hub.RunConfig(
num_epoch=10,
checkpoint_dir="cv_finetune_turtorial_demo",
batch_size=32,
log_interval=10,
eval_interval=50)
```
## 六、开始Finetune
我们选择`finetune_and_eval`接口来进行模型训练,这个接口在finetune的过程中,会周期性的进行模型效果的评估,以便我们了解整个训练过程的性能变化。如果您并不关心中间过程数据,那么可以使用`finetune`接口来替代
```python
hub.finetune_and_eval(
task, feed_list=feed_list, data_reader=data_reader, config=config)
```
## 七、查看训练过程的效果
训练过程中的性能数据会被记录到本地,我们可以通过visualdl来可视化这些数据
我们在shell中输入以下命令来启动visualdl,其中`${HOST_IP}`为本机IP,需要用户自行指定
```shell
$ visualdl --logdir ./cv_finetune_turtorial_demo --host ${HOST_IP} --port 8989
```
启动服务后,我们使用浏览器访问`${HOST_IP}:8989`,可以看到训练以及预测的loss曲线和accuracy曲线
![img](https://paddlehub.bj.bcebos.com/resources/cv_turtorial_vdl_log.JPG)
## 八、使用模型进行预测
当Finetune完成后,我们使用模型来进行预测,整个预测流程大致可以分为以下几步:
1. 构建网络
2. 生成预测数据的Reader
3. 切换到预测的Program
4. 加载预训练好的参数
5. 运行Program进行预测
`注意`:预测所用的测试图片请自行准备
完整代码如下:
```python
import os
import numpy as np
# Step 1: build Program
input_dict, output_dict, program = cv_classifer_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]
# Step 2: create data reader
data = [
"test_img_dog.jpg",
"test_img_cat.jpg"
]
data_reader = hub.reader.ImageClassificationReader(
image_width=cv_classifer_module.get_expected_image_width(),
image_height=cv_classifer_module.get_expected_image_height(),
images_mean=cv_classifer_module.get_pretrained_images_mean(),
images_std=cv_classifer_module.get_pretrained_images_std(),
dataset=None)
predict_reader = data_reader.data_generator(
phase="predict", batch_size=1, data=data)
# Step 3: switch to inference program
with 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], predict_result))
```
# 如何使用PaddleHub完成文本分类迁移
文本分类迁移是NLP迁移学习中最常见的一个任务之一。教程以情感分析任务为例子,介绍下如何使用PaddleHub+Fine-tune API快速完成文本分类迁移任务。
## 教程前置条件
* 已完成PaddlePaddle和PaddleHub的安装
* 对BERT/ERNIE等Transformer类模型有基本的了解
## ERNIE介绍
ERNIE是百度开放的基于Transformer知识增强的语义表示模型(Enhanced Representation from kNowledge IntEgration)ERNIE预训练模型结合Fine-tuning,可以在中文情感分析任务上可以得到非常不错的效果。更多的介绍可以参考[ERNIE](https://github.com/PaddlePaddle/LARK/tree/develop/ERNIE)
## 快速开始
### 准备环境
```python
import paddle.fluid as fluid
import paddlehub as hub
```
### 加载预训练模型
通过PaddleHub,只需要一行代码,即可以获取到PaddlePaddle生态下的预训练模型。
```python
module = hub.Module(name="ernie")
inputs, outputs, program = module.context(trainable="True", max_seq_len=128)
```
* 通过`hub.Module(name="ernie")`PaddleHub会自动下载并加载ERNIE模型。
* `module.context`接口中,`trainable=True`则预训练模型的参数可以被训练,`trainble=False`则讲预训练模型参数不可修改,仅作为特征提取器使用。
* `max_seq_len`是ERNIE/BERT模型特有的参数,控制模型最大的序列识别长度,这一参数与任务相关,如果显存有限,切任务文本长度较短,可以适当调低这一参数。如果处理文本序列的unicode字符长度超过`max_seq_len`,则模型会对序列进行截断。通常来说,128是一个性能均衡的默认值。
#### ERNIE的输入输出结构
ERNIE模型与BERT在结构上类似,如下图所示:
![ERNIE结构图](https://raw.githubusercontent.com/PaddlePaddle/PaddleHub/develop/docs/imgs/ERNIE_input_output.png)
ERNIE的在PaddleHub中的的输入有4个Tensor,分别是:
* `input_ids`: 文本序列后切词的ID;
* `position_ids`: 文本序列的位置ID;
* `segment_ids`: 文本序列的类型;
* `input_mask`: 序列的mask信息,主要用于对padding的标识;
前三个输入与BERT模型的论文输入对应,第四个输入为padding所需的标识信息。更多细节信息可参考论文[BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding](https://arxiv.org/abs/1810.04805)
ERNIE的输出的话有两类,分别是
* `pooled_output`: 句子粒度特征,对应的shape为`[batch_size, hidden_size]`,可用于句子分类或句对分类任务。
* `sequence_output`: 词粒度的特征,对应的shape为`[batch_size, max_seq_len, hidden_size]`, 可用于序列标注任务。
通过以下代码即可获取到对应特征的Tensor,可用于后续的组网工作。
```python
pooled_output = outputs["pooled_output"]
sequence_output = outputs["sequence_output"]
```
### 准备数据及数据预处理
```python
ds = hub.dataset.ChnSentiCorp()
reader = hub.reader.ClassifyReader(dataset=ds, vocab_path=module.get_vocab_path(), max_seq_len=128)
```
通过`hub.dataset.ChnSentiCorp()`会自动获取数据集,可以通过以下代码查看训练集中的文本与标注:
```python
ds = hub.dataset.ChnSentiCorp()
for e in ds.get_train_examples():
print(e.text_a, e.label)
```
*TODO*: dataset一接口介绍,用户如何拓展使用自定义数据集
`ClassifyReader`是专门ERNIE/BERT模型的数据预处理器,会根据模型词典,进行字粒度的切词,其中英文以词粒度进行分割,而中文和其他字符采用unicode为单位的字粒度切词。因此与传统的中文分词器有所区别,详细代码可以参考 [tokenization.py](https://github.com/PaddlePaddle/PaddleHub/blob/develop/paddlehub/reader/tokenization.py)
`ClassifyReader`的参数有三个:
* `dataset`: 传入PaddleHub Dataset;
* `vocab_path`: 传入ERNIE/BERT模型对应的词表文件路径;
* `max_seq_len`: ERNIE模型的最大序列长度,若序列长度不足,会通过padding方式补到`max_seq_len`, 若序列长度大于该值,则会以截断方式让序列长度为`max_seq_len`;
### 创建迁移学习网络
```python
task = hub.create_text_cls_task(feature=pooled_output, num_classes=ds.num_labels)
```
### 配置优化策略
适用于ERNIE模型的优化策略为`AdamWeightDecayStrategy`
\ No newline at end of file
# PaddleHub Finetune API与迁移学习
## 简述
迁移学习(Transfer Learning)是属于机器学习的一个子研究领域,该研究领域的目标在于利用数据、任务、或模型之间的相似性,将在旧领域学习过的知识,迁移应用于新领域中
基于以下几个原因,迁移学习吸引了很多研究者投身其中:
* 一些研究领域只有少量标注数据,且数据标注成本较高,不足以训练一个足够鲁棒的神经网络
* 大规模神经网络的训练依赖于大量的计算资源,这对于一般用户而言难以实现
* 应对于普适化需求的模型,在特定应用上表现不尽如人意
目前在深度学习领域已经取得了较大的发展,本文让用户了解如何快速使用PaddleHub进行迁移学习。 更多关于Transfer Learning的知识,请参考:
http://cs231n.github.io/transfer-learning/
https://papers.nips.cc/paper/5347-how-transferable-are-features-in-deep-neural-networks.pdf
http://ftp.cs.wisc.edu/machine-learning/shavlik-group/torrey.handbook09.pdf
## PaddleHub中的迁移学习
PaddleHub提供了基于PaddlePaddle框架实现的Finetune API, 重点针对大规模预训练模型的Fine-tuning任务做了高阶的抽象,帮助用户使用最少的代码快速、稳定地完成预训练模型的fine-tuning。
教程会涵盖CV领域的图像分类迁移,和NLP文本分类迁移两种任务。
* [CV教程](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/turtorial/cv_finetune_tutorial.md)
* [NLP教程](https://github.com/PaddlePaddle/PaddleHub/tree/develop/docs/turtorial/nlp_finetune_tutorial.md)
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册