Skip to content

  • 体验新版
    • 正在加载...
  • 登录
  • PaddlePaddle
  • PaddleRec
  • 合并请求
  • !22

P
PaddleRec
  • 项目概览

PaddlePaddle / PaddleRec

通知 68
Star 12
Fork 5
  • 代码
    • 文件
    • 提交
    • 分支
    • Tags
    • 贡献者
    • 分支图
    • Diff
  • Issue 27
    • 列表
    • 看板
    • 标记
    • 里程碑
  • 合并请求 10
  • Wiki 1
    • Wiki
  • 分析
    • 仓库
    • DevOps
  • 项目成员
  • Pages
P
PaddleRec
  • 项目概览
    • 项目概览
    • 详情
    • 发布
  • 仓库
    • 仓库
    • 文件
    • 提交
    • 分支
    • 标签
    • 贡献者
    • 分支图
    • 比较
  • Issue 27
    • Issue 27
    • 列表
    • 看板
    • 标记
    • 里程碑
  • 合并请求 10
    • 合并请求 10
  • Pages
  • 分析
    • 分析
    • 仓库分析
    • DevOps
  • Wiki 1
    • Wiki
  • 成员
    • 成员
  • 收起侧边栏
  • 动态
  • 分支图
  • 创建新Issue
  • 提交
  • Issue看板

Refactor Trainer !22

  • Report abuse
!22 已关闭 5月 31, 2020 由 saxon_zh@saxon_zh 创建
#<User:0x00007f7e10a931f8>
  • 概览 19
  • 提交 30
  • 变更 195

Created by: MrChengmo

PaddleRec Trainer重构设计

整合重复代码

之前存在的问题

  1. 代码冗余: 如single_train/single_infer/cluster 中大量相同的代码段
  2. 修改不便,发现一处bug,得同时修多个trainer

因此,首先做的工作是,将single_train/single_infer/cluster三个trainer合并为一个general_trainer,可以支持多种应用场景。

梳理Trainer逻辑

Trainer的设计是串行的有限状态机,使用processor_register接口注册各个步骤所调用的函数,依次执行,可在步骤中使用context['status']指定下一个运行流程。

之前所有流程的实现都在同一个类中, 也只能在同一个类中实现,依赖于self的成员变量,各个流程的耦合度高,不利于面向对象的灵活开发(如自由组合流程代码,构建一个新的trainer)

因此第二个工作是将各个步骤拆为独立的类,trainer只负责调用各个类,并将上下文词典context作为信息的载体在各个流程中传递。

基于之前的设计,将trainer的流程拆为了四个大类及两个附属的小类:

大类

  • instance:执行环境的初始化

    独立的初衷是为了区分PS与Collective不同的fleet调用,在此处亦可支持用户进行训练前的自由操作,如手动下载数据模型 etc.

    class PSInstance(InstanceBase):
        def instance(self, context):
            from paddle.fluid.incubate.fleet.parameter_server.distribute_transpiler import fleet
    
    class CollectiveInstance(InstanceBase):
        def instance(self, context):
            from paddle.fluid.incubate.fleet.collective import fleet
  • network:构建program,不同的模式差别极大:

    1. 如单机可以多阶段,分布式只能一阶段
    2. 分布式需要调用distributed_optimizer
    3. PS与collective的strategy差别较大
    4. PS需要在构建完progrm后根据role执行不同的startup
  • startup:执行参数的初始化

    独立的主要目的有很多操作需要在run program前完成,如load参数,手动Set某些变量

  • runner:执行训练

    各模式相差较大, 同时也有着dataset与dataloader的区别

小类

  • dataset: 将dataset与dataloader的代码单独抽象出来,供runner调用
  • terminal: 未在general_trainer中实现,给用户的自留地,方便进行训练结束后的处理,如计算特殊指标,文件的上传,本地的清理等等

预留扩展接口

之前存在的问题

  1. 修改不便: 如果想修改流程中的某个步骤,比如SetZero Auc,在model.py中无法更改,必须在了解Trainer设计的基础上,找到trainer的加载模型的位置,加入set的代码,并且有可能同时需要改三个文件single_train/single_infer/cluster才能保证单机多机训练及预测的一致性
  2. 代码冗长: trainer.py过长,过多if else对二次开发及debug不友好

基于Trainer中各个流程的抽象,现在用户想要进行训练流程的自定义,变得方便许多。

  • 首先:用户只需继承各个流程的基类,从头实现自己的逻辑,或在基本的逻辑上进行修改,即可组成一个完整的trainer
  • 其次:用户无需完整的实现所有流程步骤,只需实现自己个性化的步骤
  • 最后:用户的代码无需参与paddlerec库的编包,可以指定路径,加载他的代码,参与组网运行,方便用户调试

统一开发风格

我们在添加PaddleRec的模型时,会写以下的代码

from paddlerec.core.model import ModelBase
class Model(ModelBase):
    # Build Network

from paddlerec.core.reader import ReaderBase
class TrainReader(ReaderBase):
    # Define Reader

并在yaml文件中添加

model: "{workspace}/model.py"
data_converter: "{workspace}/reader.py"

可以总结基本规律

  1. 继承后缀为Base的基类,实现自己的逻辑
  2. 在yaml文件中添加py文件的地址,由paddlerec.core调用

以上流程已被大家接受,并且使用十分方便。因此,Trainer的个性化也使用上述方法进行调用。

首先继承startup的基类,实现custom_startup

from paddlerec.core.trainers.framework.startup import StartupBase
class Startup(StartupBase):
    # Define Startup Process

随后在yaml文件中指定文件位置

startup_class_path: "{workspace}/custom_startup.py"

paddlerec即可调用用户的自定义逻辑,并且无需编包

示例

以TDM为例,实现了个性化的Startup,在训练开始前需要手动Set相关的参数,并且单机多机逻辑不一致。

可以根据context字典的上下文信息,获取必要的超参。

tdm_startup.py

from paddlerec.core.trainers.framework.startup import StartupBase

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

config.yaml

在runner中指定startup_class的路径

workspace: "paddlerec.models.treebased.tdm"

runner:
- name: runner1
  class: single_train
  startup_class_path: "{workspace}/tdm_startup.py"
  epochs: 10
  device: cpu

Todo

  1. 目前各个流程的命名还需斟酌,runner和trainer有些傻傻分不清,并且流程runner与yaml文件中的runner有歧义
  2. collective的实现及测试
指派人
分配到
审核者
Request review from
无
里程碑
无
分配里程碑
工时统计
标识: paddlepaddle/PaddleRec!22
Source branch: github/fork/MrChengmo/doc_v5
渝ICP备2023009037号

京公网安备11010502055752号

网络110报警服务 Powered by GitLab CE v13.7
开源知识
Git 入门 Pro Git 电子书 在线学 Git
Markdown 基础入门 IT 技术知识开源图谱
帮助
使用手册 反馈建议 博客
《GitCode 隐私声明》 《GitCode 服务条款》 关于GitCode
Powered by GitLab CE v13.7