未验证 提交 d6c6053e 编写于 作者: T tangwei12 提交者: GitHub

Merge branch 'master' into add_readme

...@@ -129,8 +129,8 @@ python -m paddlerec.run -m paddlerec.models.rank.dnn ...@@ -129,8 +129,8 @@ python -m paddlerec.run -m paddlerec.models.rank.dnn
### 进阶教程 ### 进阶教程
* [自定义Reader](doc/custom_reader.md) * [自定义Reader](doc/custom_reader.md)
* [自定义模型](doc/development.md) * [自定义模型](doc/model_develop.md)
* [自定义流程](doc/development.md) * [自定义流程](doc/trainer_develop.md)
* [yaml配置说明](doc/yaml.md) * [yaml配置说明](doc/yaml.md)
* [PaddleRec设计文档](doc/design.md) * [PaddleRec设计文档](doc/design.md)
......
...@@ -4,17 +4,13 @@ ...@@ -4,17 +4,13 @@
## PaddleRec 整体设计概览 ## PaddleRec 整体设计概览
PaddleRec将推荐模型的训练与预测流程,整体抽象为了五个大模块: PaddleRec将推荐模型的训练与预测流程,整体抽象为了五个大模块:
* [Engine 流程执行引擎](#engine) - [PaddleRec 设计](#paddlerec-设计)
* [Trainer 流程具体定义](#trainer) - [PaddleRec 整体设计概览](#paddlerec-整体设计概览)
* [Model 模型组网定义](#model) - [Engine](#engine)
* [Reader 数据读取定义](#reader) - [Trainer](#trainer)
* [Metric 精度指标打印](#metric) - [Model](#model)
- [Reader](#reader)
层级结构,以及一键启动训练时的调用关系如下图所示: - [Metric](#metric)
<p align="center">
<img align="center" src="imgs/design.png">
<p>
core的文件结构如下,后续分别对各个模块进行介绍。 core的文件结构如下,后续分别对各个模块进行介绍。
``` ```
...@@ -50,7 +46,7 @@ Engine是整体训练的执行引擎,与组网逻辑及数据无关,只与 ...@@ -50,7 +46,7 @@ Engine是整体训练的执行引擎,与组网逻辑及数据无关,只与
运行设备是指: 运行设备是指:
- CPU - CPU
- GPU - GPU
- AI芯片 - 其他AI芯片
在用户调用`python -m paddlerec.run`时,首先会根据`yaml`文件中的配置信息选择合适的执行引擎, 以下代码位于[run.py](../run.py) 在用户调用`python -m paddlerec.run`时,首先会根据`yaml`文件中的配置信息选择合适的执行引擎, 以下代码位于[run.py](../run.py)
```python ```python
...@@ -62,15 +58,36 @@ engine.run() ...@@ -62,15 +58,36 @@ engine.run()
我们以`single engine`为例,概览engine的行为: 我们以`single engine`为例,概览engine的行为:
```python ```python
def single_engine(args): def single_train_engine(args):
trainer = get_trainer_prefix(args) + "SingleTrainer" _envs = envs.load_yaml(args.model)
run_extras = get_all_inters_from_yaml(args.model, ["train.", "runner."])
trainer_class = run_extras.get(
"runner." + _envs["mode"] + ".trainer_class", None)
if trainer_class:
trainer = trainer_class
else:
trainer = "GeneralTrainer"
executor_mode = "train"
fleet_mode = run_extras.get("runner." + _envs["mode"] + ".fleet_mode",
"ps")
device = run_extras.get("runner." + _envs["mode"] + ".device", "cpu")
selected_gpus = run_extras.get(
"runner." + _envs["mode"] + ".selected_gpus", "0")
selected_gpus_num = len(selected_gpus.split(","))
if device.upper() == "GPU":
assert selected_gpus_num == 1, "Single Mode Only Support One GPU, Set Local Cluster Mode to use Multi-GPUS"
single_envs = {} single_envs = {}
single_envs["selsected_gpus"] = selected_gpus
single_envs["FLAGS_selected_gpus"] = selected_gpus
single_envs["train.trainer.trainer"] = trainer single_envs["train.trainer.trainer"] = trainer
single_envs["fleet_mode"] = fleet_mode
single_envs["train.trainer.executor_mode"] = executor_mode
single_envs["train.trainer.threads"] = "2" single_envs["train.trainer.threads"] = "2"
single_envs["train.trainer.engine"] = "single"
single_envs["train.trainer.device"] = args.device
single_envs["train.trainer.platform"] = envs.get_platform() single_envs["train.trainer.platform"] = envs.get_platform()
print("use {} engine to run model: {}".format(trainer, args.model)) single_envs["train.trainer.engine"] = "single"
set_runtime_envs(single_envs, args.model) set_runtime_envs(single_envs, args.model)
trainer = TrainerFactory.create(args.model) trainer = TrainerFactory.create(args.model)
...@@ -91,34 +108,29 @@ Engine的自定义实现,可以参考[local_cluster.py](../core/engine/local_c ...@@ -91,34 +108,29 @@ Engine的自定义实现,可以参考[local_cluster.py](../core/engine/local_c
`Trainer`是训练与预测流程的具体实现,会run模型中定义的各个流程,与model、reader、metric紧密相关。PaddleRec以有限状态机的逻辑定义了训练中的各个阶段,不同的Trainer子类会分别实现阶段中的特殊需求。有限状态机的流程在`def processor_register()`中注册。 `Trainer`是训练与预测流程的具体实现,会run模型中定义的各个流程,与model、reader、metric紧密相关。PaddleRec以有限状态机的逻辑定义了训练中的各个阶段,不同的Trainer子类会分别实现阶段中的特殊需求。有限状态机的流程在`def processor_register()`中注册。
我们以SingleTrainer为例,概览Trainer行为: 我们以GeneralTrainer为例,概览Trainer行为:
```python ```python
class SingleTrainer(TranspileTrainer): class SingleTrainer(TranspileTrainer):
def processor_register(self): def processor_register(self):
print("processor_register begin")
self.regist_context_processor('uninit', self.instance) self.regist_context_processor('uninit', self.instance)
self.regist_context_processor('init_pass', self.init) self.regist_context_processor('network_pass', self.network)
self.regist_context_processor('startup_pass', self.startup) self.regist_context_processor('startup_pass', self.startup)
if envs.get_platform() == "LINUX" and envs.get_global_env("dataset_class", None, "train.reader") != "DataLoader": self.regist_context_processor('train_pass', self.runner)
self.regist_context_processor('train_pass', self.dataset_train)
else:
self.regist_context_processor('train_pass', self.dataloader_train)
self.regist_context_processor('infer_pass', self.infer)
self.regist_context_processor('terminal_pass', self.terminal) self.regist_context_processor('terminal_pass', self.terminal)
``` ```
SingleTrainer首先注册了完成任务所需的步骤,各步骤首先按照注册顺序加入`Trainer`基类中名为`status_processor`的字典,运行的先后顺序,可以在每个执行步骤中改变`context['status']`的值,指定下一步运行哪个步骤。 SingleTrainer首先注册了完成任务所需的步骤,各步骤首先按照注册顺序加入`Trainer`基类中名为`status_processor`的字典,运行的先后顺序,可以在每个执行步骤中改变`context['status']`的值,指定下一步运行哪个步骤。
SingleTrainer指定了以下6个步骤: SingleTrainer指定了以下5个步骤:
1. uninit:默认排在首位,通过环境变量决定model的对象 1. uninit:默认排在首位,通过环境变量启动paddle分布式的实例,执行在模型训练前的所有操作。
1. init_pass:调用model_的接口,生成模型的组网,初始化fetch及metric的变量 2. network_pass:根据模型组网生成训练的program
2. startup_pass:初始化模型组网中的各个参数,run(fluid.default_startup_program) 3. startup_pass:初始化模型组网中的各个参数,以及加载模型
3. train_pass:会根据环境分别调用`dataset``dataloader`进行训练的流程。 4. train_pass:会根据环境分别调用`dataset``dataloader`进行训练的流程。
4. infer_pass:在训练结束后,会对训练保存的模型在测试集上验证效果 5. terminal_pass:停止worker,以及执行模型训练后的所有操作
5. terminal_pass:打印全局变量及预测结果等自定义的信息。
Trainer的自定义实现,可以参照[single_trainer.py](../core/trainers/single_trainer.py) Trainer的自定义实现,可以参照[general_trainer.py](../core/trainers/general_trainer.py)
## Model ## Model
......
...@@ -9,7 +9,7 @@ mode: runner_infer # 执行名为 runner1 的运行器 ...@@ -9,7 +9,7 @@ mode: runner_infer # 执行名为 runner1 的运行器
runner: runner:
- name: runner_infer # 定义 runner 名为 runner1 - name: runner_infer # 定义 runner 名为 runner1
class: single_infer # 执行单机预测 class = single_infer class: infer # 执行单机预测 class = infer
device: cpu # 执行在 cpu 上 device: cpu # 执行在 cpu 上
init_model_path: "init_model" # 指定初始化模型的地址 init_model_path: "init_model" # 指定初始化模型的地址
print_interval: 10 # 预测信息的打印间隔,以batch为单位 print_interval: 10 # 预测信息的打印间隔,以batch为单位
......
...@@ -9,7 +9,7 @@ mode: runner_train # 执行名为 runner_train 的运行器 ...@@ -9,7 +9,7 @@ mode: runner_train # 执行名为 runner_train 的运行器
runner: runner:
- name: runner_train # 定义 runner 名为 runner_train - name: runner_train # 定义 runner 名为 runner_train
class: single_train # 执行单机训练 class = single_train class: train # 执行单机训练 class = train
device: cpu # 执行在 cpu 上 device: cpu # 执行在 cpu 上
epochs: 10 # 训练轮数 epochs: 10 # 训练轮数
......
# PaddleRec 启动训练 # PaddleRec 启动训练
## 启动方法 ## 启动方法
### 1. 启动内置模型的默认配置训练 ### 1. 启动内置模型的默认配置训练
...@@ -27,29 +29,34 @@ python -m paddlerec.run -m paddlerec.models.recall.word2vec ...@@ -27,29 +29,34 @@ python -m paddlerec.run -m paddlerec.models.recall.word2vec
- **没有改动模型组网** - **没有改动模型组网**
假如你将paddlerec代码库克隆在了`/home/PaddleRec`,并修改了`/home/PaddleRec/models/rank/dnn/config.yaml`,则如下启动训练 假如你将paddlerec代码库克隆在了`/home/PaddleRec`,并修改了`/home/PaddleRec/models/rank/dnn/config.yaml`,则如下启动训练
```shell ```shell
python -m paddlerec.run -m /home/PaddleRec/models/rank/dnn/config.yaml python -m paddlerec.run -m /home/PaddleRec/models/rank/dnn/config.yaml
``` ```
paddlerec 运行的是在paddlerec库安装目录下的组网文件(model.py) paddlerec 运行的是在paddlerec库安装目录下的组网文件(model.py),但个性化配置`config.yaml`是用的是指定路径下的yaml文件。
- **改动了模型组网** - **改动了模型组网**
假如你将paddlerec代码库克隆在了`/home/PaddleRec`,并修改了`/home/PaddleRec/models/rank/dnn/model.py`, 以及`/home/PaddleRec/models/rank/dnn/config.yaml`,则首先需要更改`yaml`中的`workspace`的设置: 假如你将paddlerec代码库克隆在了`/home/PaddleRec`,并修改了`/home/PaddleRec/models/rank/dnn/model.py`, 以及`/home/PaddleRec/models/rank/dnn/config.yaml`,则首先需要更改`yaml`中的`workspace`的设置:
```yaml ```yaml
workspace: /home/PaddleRec/models/rank/dnn/ workspace: /home/PaddleRec/models/rank/dnn/
``` ```
再执行: 再执行:
```shell ```shell
python -m paddlerec.run -m /home/PaddleRec/models/rank/dnn/config.yaml python -m paddlerec.run -m /home/PaddleRec/models/rank/dnn/config.yaml
``` ```
paddlerec 运行的是绝对路径下的组网文件(model.py)以及个性化配置文件(config.yaml)
paddlerec 运行的是绝对路径下的组网文件(model.py)
## yaml训练配置
### yaml中训练相关的概念 ### yaml中训练相关的概念
...@@ -58,19 +65,18 @@ paddlerec 运行的是绝对路径下的组网文件(model.py) ...@@ -58,19 +65,18 @@ paddlerec 运行的是绝对路径下的组网文件(model.py)
- **`runner`** : runner是训练的引擎,亦可称之为运行器,在runner中定义执行设备(cpu、gpu),执行的模式(训练、预测、单机、多机等),以及运行的超参,例如训练轮数,模型保存地址等。 - **`runner`** : runner是训练的引擎,亦可称之为运行器,在runner中定义执行设备(cpu、gpu),执行的模式(训练、预测、单机、多机等),以及运行的超参,例如训练轮数,模型保存地址等。
- **`phase`** : phase是训练中的阶段的概念,是引擎具体执行的内容,该内容是指:具体运行哪个模型文件,使用哪个reader。 - **`phase`** : phase是训练中的阶段的概念,是引擎具体执行的内容,该内容是指:具体运行哪个模型文件,使用哪个reader。
PaddleRec每次运行时,只会执行一个运行器,通过`mode`指定`runner`的名字。但每个运行器可以执行多个`phase`,所以PaddleRec支持一键启动多阶段的训练。 PaddleRec每次运行时,会执行一个运行器,通过`mode`指定`runner`的名字。每个运行器可以执行多个`phase`,所以PaddleRec支持一键启动多阶段的训练。
### 单机CPU训练
### 单机训练启动配置 下面我们开始定义一个单机CPU训练的`runner`:
下面我们开始定义一个单机训练的`runner`:
```yaml ```yaml
mode: runner_train # 执行名为 runner_train 的运行器 mode: single_cpu_train # 执行名为 single_cpu_train 的运行器
runner: runner:
- name: runner_train # 定义 runner 名为 runner_train - name: single_cpu_train # 定义 runner 名为 single_cpu_train
class: single_train # 执行单机训练 class = single_train class: train # 执行单机训练,亦可为 single_train
device: cpu # 执行在 cpu 上 device: cpu # 执行在 cpu 上
epochs: 10 # 训练轮数 epochs: 10 # 训练轮数
...@@ -101,3 +107,48 @@ dataset: ...@@ -101,3 +107,48 @@ dataset:
dense_slots: "dense_var:13" # dense参数的维度定义 dense_slots: "dense_var:13" # dense参数的维度定义
``` ```
### 单机单卡GPU训练
具体执行内容与reader与前述相同,下面介绍需要改动的地方
```yaml
mode: single_gpu_train # 执行名为 single_gpu_train 的运行器
runner:
- name: single_gpu_train # 定义 runner 名为 single_gpu_train
class: train # 执行单机训练,亦可为 single_train
device: gpu # 执行在 gpu 上
selected_gpus: "0" # 默认选择在id=0的卡上执行训练
epochs: 10 # 训练轮数
```
### 单机多卡GPU训练
具体执行内容与reader与前述相同,下面介绍需要改动的地方
```yaml
mode: single_multi_gpu_train # 执行名为 single_multi_gpu_train 的运行器
runner:
- name: single_multi_gpu_train # 定义 runner 名为 single_multi_gpu_train
class: train # 执行单机训练,亦可为 single_train
device: gpu # 执行在 gpu 上
selected_gpus: "0,1,2,3" # 选择多卡执行训练
epochs: 10 # 训练轮数
```
### 本地模拟参数服务器训练
具体执行内容与reader与前述相同,下面介绍需要改动的地方
```yaml
mode: local_cluster_cpu_train # 执行名为 local_cluster_cpu_train 的运行器
runner:
- name: local_cluster_cpu_train # 定义 runner 名为 runner_train
class: local_cluster # 执行本地模拟分布式——参数服务器训练
device: cpu # 执行在 cpu 上(paddle后续版本会支持PS-GPU)
worker_num: 1 # (可选)worker进程数量,默认1
server_num: 1 # (可选)server进程数量,默认1
epochs: 10 # 训练轮数
```
# 如何添加自定义流程
模型训练的流程也可以像`model``reader`一样,由用户自定义,并在`config.yaml`中指定路径,由PaddleRec调用。
PaddleRec可自定义的流程有如下5个:
1. **instance**: 执行训练前的所有操作
2. **network**:执行组网的前向/反向,训练策略的添加
3. **startup**:执行模型的初始化,加载
4. **runnner**: 执行模型的训练
5. **terminal**: 执行训练后的所有操作
## instance
instance由GeneralTrainer首先调用,执行模型组网前的所有操作。用户可以在这里进行下载数据,import不同的包,配置环境变量等操作。instance的官方实现位于[instance.py](../core/trainers/framework/instance.py),instance基类定义如下:
```python
class InstanceBase(object):
def __init__(self, context):
pass
def instance(self, context):
pass
```
您需要继承`InstanceBase`并命名为`Instance`,完成`instance`的实现,通过上下文信息字典`context`拿到模型所需信息,及保存相关配置。
## network
network将在instanc后调用,执行模型的组网。network的官方实现位于[network.py](../core/trainers/framework/network.py),network基类定义如下:
```python
class NetworkBase(object):
def __init__(self, context):
pass
def build_network(self, context):
pass
```
可参照其他模式的实现方式,自定其中的部分步骤。您需要您需要继承`NetworkBase`并命名为`Network`,完成`build_network`的实现,通过上下文信息字典`context`拿到模型所需信息,并在context中保存模型的program与scope信息,例如:
```python
context["model"][model_dict["name"]][
"main_program"] = train_program
context["model"][model_dict["name"]][
"startup_program"] = startup_program
context["model"][model_dict["name"]]["scope"] = scope
context["model"][model_dict["name"]]["model"] = model
context["model"][model_dict["name"]][
"default_main_program"] = train_program.clone()
```
## startup
startup执行网络参数的初始化,抑或模型的热启动,主要功能是执行`exe.run(fluid.default_startup_program())`。 startup的官方实现在[startup](../core/trainers/framework/startup.py)
```python
class StartupBase(object):
def __init__(self, context):
pass
def startup(self, context):
pass
def load(self, context, is_fleet=False, main_program=None):
dirname = envs.get_global_env(
"runner." + context["runner_name"] + ".init_model_path", None)
if dirname is None or dirname == "":
return
print("going to load ", dirname)
if is_fleet:
context["fleet"].load_persistables(context["exe"], dirname)
else:
fluid.io.load_persistables(
context["exe"], dirname, main_program=main_program)
```
自定义startup流程,您需要您需要继承`StartupBase`并命名为`Startup`,实现该类型中startup成员函数。
## runner
runner是运行的主要流程,主要功能是reader的运行,网络的运行,指标的打印以及模型的保存。以参数服务器Runner为示例,如下:
```python
class PSRunner(RunnerBase):
def __init__(self, context):
print("Running PSRunner.")
pass
def run(self, context):
# 通过超参拿到迭代次数
epochs = int(
envs.get_global_env("runner." + context["runner_name"] +
".epochs"))
# 取第一个phase的模型与reader
model_dict = context["env"]["phase"][0]
for epoch in range(epochs):
begin_time = time.time()
# 调用run进行训练
self._run(context, model_dict)
end_time = time.time()
seconds = end_time - begin_time
print("epoch {} done, use time: {}".format(epoch, seconds))
with fluid.scope_guard(context["model"][model_dict["name"]][
"scope"]):
train_prog = context["model"][model_dict["name"]][
"main_program"]
startup_prog = context["model"][model_dict["name"]][
"startup_program"]
with fluid.program_guard(train_prog, startup_prog):
# 保存模型
self.save(epoch, context, True)
context["status"] = "terminal_pass"
```
自定义runner需要参照官方实现[runner.py](../core/trainers/framework/startup.py),继承基类`RunnerBase`,命名为`Runner`,并实现`run`成员函数。
## terminal
terminal主要进行分布式训练结束后的`stop worker`,以及其他需要在模型训练完成后进行的工作,比如数据整理,模型上传等等。
```python
class TerminalBase(object):
def __init__(self, context):
pass
def terminal(self, context):
print("PaddleRec Finish")
```
自定义terminal需要继承`TerminalBase`命名为`Terminal`,并实现成员函数`terminal`
## 自定义流程参与训练
假如我们自定义了某个流程,将其与model/reader一样,放在workspace下,并同时更改yaml配置中的runner相关选项,PaddleRec会自动用指定的流程替换原始的类别。
```yaml
runner:
- name: train_runner
class: single_train
epochs: 2
device: cpu
instance_class_path: "{workspace}/your_instance.py"
network_class_path: "{workspace}/your_network.py"
startup_class_path: "{workspace}/your_startup.py"
runner_class_path: "{workspace}/your_runner.py"
terminal_class_path: "{workspace}/your_terminal.py"
print_interval: 1
```
## 示例
官方模型中的TDM是一个很好的示例,该模型自定义了`startup`的实现,可以参考[tdm_startup.py](../models/treebased/tdm/tdm_startup.py)
```python
class Startup(StartupBase):
def startup(self, context):
logger.info("Run TDM Trainer Startup Pass")
if context["engine"] == EngineMode.SINGLE:
self._single_startup(context)
else:
self._cluster_startup(context)
context['status'] = 'train_pass'
def _single_startup(self, context):
# single process
def _cluster_startup(self, context):
# cluster process
```
于此同时,在yaml中更改了默认的startup执行类:
```yaml
runner:
- name: runner1
class: single_train
startup_class_path: "{workspace}/tdm_startup.py"
epochs: 10
device: cpu
```
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册