PaddlePaddle / Paddle2ONNX

ONNX Model Exporter for PaddlePaddle
Apache License 2.0
736 stars 173 forks source link

【开源任务】Paddle2ONNX适配Paddle IR完成常用模型转化 #1399

Open 0x3878f opened 2 months ago

0x3878f commented 2 months ago

1. 需求背景

ONNX是一种开放的深度学习模型交换格式,可让模型在不同平台和框架间无缝转换与部署,Paddle2ONNX开源仓库支持将飞桨的推理模型表示转换到ONNX算子协议以实现对接ONNX生态。飞桨在3.0Beta发布了新一代的中间表示(即Paddle IR),并升级了所有的算子定义形式,取代了2.x版本基于protobuf的中间表示。因此我们期望能够基于飞桨新一代Paddle IR的算子定义,升级Paddle2ONNX中的转换规则,支持Paddle IR 协议下的ONNX模型转换。

2. 当前进展

目前在Paddle2ONNX的test_pir 分支已经完成了基本的机制建设,包括PIR下对模型文件的解析,输入输出变量对齐,算子的注册机制,获取算子输入、输出、属性,PIR下单测执行等。Resnet50在当前机制下可以正确转化为onnx模型文件,并通过了精度验证。

3. 任务划分

Paddle2ONNX适配Paddle IR的模型转化任务按照算子级别进行划分

认领方式

填写Excel表进行认领 🚩任务认领登记表🚩

4. 开发流程

4.1 本地环境搭建

protobuf

paddle2onnx编译依赖protobuf,需要先在本地编译安装

git clone https://github.com/protocolbuffers/protobuf.git
cd protobuf
git checkout v4.22.0
git submodule update --init
mkdir build_source && cd build_source
cmake ../cmake -DCMAKE_INSTALL_PREFIX=`pwd`/installed_protobuf_lib -Dprotobuf_BUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -Dprotobuf_BUILD_TESTS=OFF -DCMAKE_BUILD_TYPE=Release
make -j
make install
export PATH=`pwd`/installed_protobuf_lib/bin:${PATH}

paddlepaddle

需要安装paddle最新的日包,满足paddlepaddle>=3.0.0.dev20240923

python -m pip install --pre paddlepaddle -i https://www.paddlepaddle.org.cn/packages/nightly/cpu/

paddle2onnx

git clone -b test_pir https://github.com/PaddlePaddle/Paddle2ONNX.git
cd Paddle2ONNX
git submodule update --init
git checkout -b your_branch_name
# build
export PIP_EXTRA_INDEX_URL="https://www.paddlepaddle.org.cn/packages/nightly/cpu/"
python -m build
python -m pip install dist/paddle2onnx-1.2.6-cp39-cp39-linux_x86_64.whl # wheel包名字可能不同

4.2 本地环境验证

得到模型和参数文件

可通过转化resnet50模型进行测试

# 在./resnet50文件夹下得到model.json和model.pdiparams
import paddle
model = paddle.vision.resnet50()
paddle.jit.save(model, "./resnet50/model", [paddle.static.InputSpec([-1, 3, 224, 224], dtype=paddle.float32)])

使用paddle2onnx转化

paddle2onnx --model_dir=./resnet50/ \
    --model_filename=model.pdmodel \
    --params_filename=model.pdiparams \
    --save_file=./resnet50/model.onnx \
    --enable_onnx_checker=True \
    --opset_version 16

如果没有错误发生说明本地环境正常

4.3 明确模型中需要支持的算子列表

在当前版本中,保留了对模型Program打印的信息,因此,开始时可以先直接使用paddle2onnx进行转化,当然肯定会有一些问题,但是在输出的日志中可以看到打印的Program信息,可以根据此信息列举该模型使用的所有算子,并完成所有算子的【4.4算子注册】和【4.5单测完善

4.4 算子注册

4.5 单测完善

4.6 开发示例

可以参考以下PR提供的开发示例进行开发,在该PR中完成了算子xxx的注册,并对相关单测进行了完善。新旧IR下算子的输入、输出、属性等信息可能发生改变,需要适当修改算子的mapper文件

开发示例 PR#1403

算子注册

  1. 在头文件中重载PIR下的构造函数

    // paddle2onnx/mapper/tensor/split.h
    SplitMapper(const PaddlePirParser& p, OnnxHelper* helper, int64_t i)
      : Mapper(p, helper, i) {
      in_pir_mode = true;
    // GetAttr("axis", &axis_); 
    // GetAttr("sections", &sections_);
    // GetAttr("num", &num_);
    }

    可以看到上面注释了获取属性axissectionsnum,是因为在PIR下paddle.split在模型结构中会以两种算子存在,一种是pd_op.split,另一种是pd_op.split_with_num,在pd_op.split 中axissections成为输入,num属性不存在,在pd_op.split_with_numaxis是输入,num是属性,而sections`不存在

  2. 在源文件中完成注册

    // paddle2onnx/mapper/tensor/split.cc
    REGISTER_PIR_MAPPER(split, SplitMapper)
    REGISTER_PIR_MAPPER(split_with_num, SplitMapper) // split_with_num算子可以复用split的mapper,因此在这同时注册了split_with_num
  3. 检查源文件中的转化逻辑,主要根据PIR下算子的输入、输出、属性的变化来调整 主要包括检查GetMinOpsetVersion方法和Opset7 方法等,如果PIR下算子的输入、输出、属性有变化,需要进行修改。需要注意的是,如果不是新增的算子,GetInputGetOutputGetAttr等方法中传入的变量或属性名使用旧IR下的即可,目前已经完成了自动映射的机制

    • 修改可参考paddle2onnx/mapper/tensor/split.cc 中的变化

单测完善

  1. paddle2onnx/tests/目录下找到算子对应的单测文件,一般命名为test_xxx.pytest_auto_scan_xxx.py,例如split算子的单测文件为tests/test_split.pytests/test_auto_scan_split.py
  2. 在相应的test函数前添加_test_with_pir进行测试
    # tests/test_split.py
    from onnxbase import _test_with_pir
    ....
    @_test_with_pir
    def test_split_v7_1():
    ....

4.7 结果验证

保证算子的单测已完善并通过本地测试,以算子conv2d为例:

python -m pytest test_nn_Conv2D.py
python -m pytest test_auto_scan_conv2d.py

4.8 PR提交格式要求

  1. PR标题需要以【P2O-PIR】开头,并写明适配的算子名称
  2. 在PR描述中列举本PR适配的算子名称,并说明该算子是否是新增算子以及其对应的单测文件
  3. 有一些特殊情况或者你认为重要的信息请在PR中一并描述
github-actions[bot] commented 3 days ago

This issue is stale because it has been open for 30 days with no activity.