Skip to content

【快乐开源】Paddle2Torch API 转换功能开发 #72643

@cangtianhuang

Description

@cangtianhuang

【快乐开源】Paddle2Torch API 转换功能开发

一、任务背景

PaddleAPITest 项目致力于确保 PaddlePaddle API 的正确性,这对 PaddlePaddle 框架的训练、推理和可靠性至关重要。该项目主要解决三个方面的正确性问题:API 精度、大张量计算和零尺寸张量支持。目前已经采集到 732 个 API 的 300 余万条配置,并进行了广泛的测试与适配,项目已初步建成,但仍有 100 多个 API 尚未支持精度对比测试。

Paddle2Torch 模块作为 PaddleAPITest 的关键组件,能够自动将 PaddlePaddle API 调用转换为对应的 PyTorch 实现,用于精度对比测试。

Paddle2Torch 模块是一个轻量级、解耦的工具,包含三个核心组件:

  • converter.py:转换引擎,响应 Paddle API 调用并生成 PyTorch 代码
  • mapping.json:转换配置文件,定义 Paddle 到 PyTorch 的 API 映射关系
  • rules.py:转换规则文件,用于处理复杂的 API 转换

本任务的目标是修复未支持精度对比测试的 API,通过开发和扩展 API 转换能力来增强 Paddle2Torch 模块,以支持更广泛的 PaddlePaddle API 精度对比测试,确保语义一致性、实现强大的跨框架验证。现已释放 76+11+25 个 API 的转换功能开发任务!

这是开源贡献者们参与深度学习关键工具开发的绝佳机会,可促进学习模型迁移、跨框架验证和混合编程!!过程中参与者将会对 PaddlePaddle、PyTorch 的 API 更加熟悉!

二、任务清单

序号 API 名称 认领人/状态/PR号 难度
1 paddle.assign @Cutelemon6 #165
@HangFu7
2 paddle.autograd.hessian @cangtianhuang #135
⭐⭐⭐⭐
3 paddle.autograd.jacobian @cangtianhuang #135
⭐⭐⭐⭐
4 paddle.binomial @Cutelemon6 #141
⭐⭐⭐
5 paddle.cartesian_prod @yuwu46 #160
⭐⭐⭐
6 paddle.geometric.segment_mean @yuwu46 #136
⭐⭐⭐
7 paddle.geometric.segment_min @yuwu46 #136
⭐⭐⭐
8 paddle.geometric.segment_sum @yuwu46 #136
⭐⭐
9 paddle.geometric.send_u_recv @cszdrg #159
⭐⭐⭐⭐⭐
10 paddle.geometric.send_ue_recv @cszdrg #159
⭐⭐⭐⭐⭐
11 paddle.geometric.send_uv @yuwu46 #160
⭐⭐⭐⭐⭐
12 paddle.histogram_bin_edges @cszdrg #131
⭐⭐⭐
13 paddle.incubate.nn.functional.blha_get_max_len @yuwu46 #136
⭐⭐⭐⭐⭐⭐
14 paddle.incubate.nn.functional.block_multihead_attention @cangtianhuang #135
@Cutelemon6
⭐⭐⭐⭐⭐
15 paddle.incubate.nn.functional.fused_bias_act @cangtianhuang #140
⭐⭐⭐⭐⭐
16 paddle.incubate.nn.functional.fused_bias_dropout_residual_layer_norm @Cutelemon6 #134
⭐⭐⭐⭐⭐
17 paddle.incubate.nn.functional.fused_dropout_add @Cutelemon6 #134
⭐⭐⭐⭐⭐
18 paddle.incubate.nn.functional.fused_feedforward @Cutelemon6 #163
⭐⭐⭐⭐⭐
19 paddle.incubate.nn.functional.fused_layer_norm @Cutelemon6 #163
⭐⭐⭐⭐⭐
20 paddle.incubate.nn.functional.fused_linear @Cutelemon6 #134
⭐⭐⭐⭐⭐
21 paddle.incubate.nn.functional.fused_linear_activation @Cutelemon6 #134
⭐⭐⭐⭐⭐
22 paddle.incubate.nn.functional.fused_matmul_bias @cangtianhuang #140
⭐⭐⭐⭐⭐
23 paddle.incubate.nn.functional.fused_multi_head_attention @cangtianhuang #140
⭐⭐⭐⭐⭐
24 paddle.incubate.nn.functional.fused_rms_norm @cangtianhuang #140
⭐⭐⭐⭐⭐
25 paddle.incubate.nn.functional.fused_rotary_position_embedding @cangtianhuang #140
⭐⭐⭐⭐⭐
26 paddle.incubate.nn.functional.masked_multihead_attention @cangtianhuang #135
⭐⭐⭐⭐⭐
27 paddle.incubate.nn.functional.swiglu @Cutelemon6 #134
⭐⭐⭐⭐⭐
28 paddle.incubate.nn.functional.variable_length_memory_efficient_attention @cangtianhuang #135
⭐⭐⭐⭐⭐⭐
29 paddle.incubate.segment_max @cangtianhuang #127
⭐⭐⭐
30 paddle.incubate.segment_mean @cangtianhuang #127
⭐⭐⭐
31 paddle.incubate.segment_min @cangtianhuang #127
⭐⭐⭐
32 paddle.incubate.segment_sum @cangtianhuang #127
⭐⭐⭐
33 paddle.incubate.softmax_mask_fuse @cangtianhuang #129
⭐⭐⭐⭐
34 paddle.incubate.softmax_mask_fuse_upper_triangle @cangtianhuang #129
⭐⭐⭐⭐
35 paddle.index_add @mzj104 #132
⭐⭐
36 paddle.index_put @mzj104 #132
⭐⭐⭐
37 paddle.index_sample @mzj104 #132
⭐⭐
38 paddle.log_normal @mzj104 #132
⭐⭐
39 paddle.masked_scatter @mzj104 #132
⭐⭐⭐
40 paddle.matmul @ccsuzzh #156
41 paddle.multinomial @ccsuzzh #142 #156
42 paddle.nn.functional.adaptive_avg_pool2d @cangtianhuang #125
⭐⭐
43 paddle.nn.functional.adaptive_avg_pool3d @cangtianhuang #125
⭐⭐
44 paddle.nn.functional.pixel_shuffle @yuwu46 #144
⭐⭐⭐
45 paddle.nn.functional.pixel_unshuffle @yuwu46 #144
⭐⭐⭐
46 paddle.nn.functional.prelu @yuwu46 #144
47 paddle.nn.functional.selu @yuwu46 #144
48 paddle.nn.quant.weight_only_linear @cszdrg #159
⭐⭐⭐⭐
49 paddle.nn.quant.weight_quantize @cszdrg #159
⭐⭐⭐⭐
50 paddle.signal.stft @yuwu46 #136
⭐⭐
51 paddle.slice_scatter @mzj104 #126
⭐⭐⭐
52 paddle.standard_gamma @mzj104 #126
⭐⭐
53 paddle.standard_normal @mzj104 #126
⭐⭐
54 paddle.stanh @mzj104 #126
⭐⭐
55 paddle.strided_slice @mzj104 #126
⭐⭐
56 paddle.subtract @mzj104 #123
57 paddle.take @mzj104 #132
⭐⭐
58 paddle.Tensor.__len__ @HangFu7 #138
59 paddle.Tensor.__lshift__ @Cutelemon6 #141
⭐⭐
60 paddle.Tensor.__neg__ @Cutelemon6 #141
61 paddle.Tensor.__nonzero__ @Cutelemon6 #141
62 paddle.Tensor.__or__ @Cutelemon6 #141
63 paddle.Tensor.__rlshift__ @mzj104 #137
⭐⭐
64 paddle.Tensor.__ror__ @mzj104 #137
65 paddle.Tensor.__rrshift__ @mzj104 #137
⭐⭐
66 paddle.Tensor.__rxor__ @mzj104 #137
67 paddle.Tensor.__xor__ @mzj104 #137
68 paddle.Tensor.bernoulli_ @yuwu46 #124
69 paddle.Tensor.cast @yuwu46 #130
70 paddle.Tensor.cauchy_ @yuwu46 #124
⭐⭐
71 paddle.Tensor.fill_diagonal_tensor @yuwu46 #160
⭐⭐
72 paddle.Tensor.slice_scatter @yuwu46 #124
⭐⭐⭐
73 paddle.unstack @yuwu46 #124
74 paddle.vander @yuwu46 #160
⭐⭐
75 paddle.vecdot @yuwu46 #130
⭐⭐
76 paddle.view_as @yuwu46 #124
77 paddle.Tensor.argmax @inaomIIsfarell
@Cutelemon6 #122
78 paddle.argmax @inaomIIsfarell
@Cutelemon6 #122
79 paddle.full @Cutelemon6 #122
80 paddle.full_like @Cutelemon6 #122
81 paddle.linspace @Cutelemon6 #122
82 paddle.logcumsumexp @Cutelemon6 #122
⭐⭐
83 paddle.logspace @Cutelemon6 #165
84 paddle.nn.functional.sequence_mask @cszdrg #159
⭐⭐⭐
85 paddle.ones_like @yuwu46 #130
86 paddle.sum @cangtianhuang #128
87 paddle.zeros_like @yuwu46 #130
88 paddle.argmin @mzj104 #146
89 paddle.chunk @mzj104 #146
90 paddle.clip @cszdrg #159
91 paddle.cumsum @mzj104 #146
92 paddle.diag @mzj104 #146
93 paddle.eye @mzj104 #146
94 paddle.linalg.cov @yuwu46 #149
@superdonkey007
⭐⭐⭐
95 paddle.linalg.lstsq @superdonkey007 #153
⭐⭐
96 paddle.linalg.norm @superdonkey007 #153
97 paddle.mm @mzj104 #146
98 paddle.nn.functional.affine_grid @yuwu46 #149
99 paddle.nn.functional.grid_sample @yuwu46 #149
100 paddle.outer @mzj104 #146
101 paddle.quantile @mzj104 #146
⭐⭐
102 paddle.reshape @cszdrg #159
103 paddle.roll @yuwu46 #147
104 paddle.sign @yuwu46 #147
105 paddle.squeeze @yuwu46 #147
106 paddle.take_along_axis @yuwu46 #147
107 paddle.Tensor.clip @cszdrg #159
108 paddle.Tensor.matmul @mzj104 #146
109 paddle.tensordot @mzj104 #146
110 paddle.tile @yuwu46 #147
111 paddle.unflatten @cszdrg #159
⭐⭐
112 paddle.unsqueeze @yuwu46 #147

【腾讯文档】Paddle2Torch API 转换功能开发(此处为总统计表,已有多位同学完成 API 转换功能开发,上次更新:6/8)

同学们可查看该文档中的已贡献 PR,学习了解本活动~

三、任务详情

Paddle2Torch 模块通过解析 PaddlePaddle API 调用,使用预定义的转换规则与动态代码生成,实现从 PaddlePaddle 到 PyTorch 的自动转换,转换过程需确保代码的语义一致性。

Paddle2Torch 模块的工作原理是:

  1. 读取 mapping.json 配置,加载 rules.py 中所有 Rule 类,形成 API 与 Rule 的映射字典(默认为 GenericRule 类)
  2. 根据输入的 API 信息执行相应 Rule 的 apply 方法,获取转换结果和需要执行的代码行列表(字符串形式的代码)
  3. 传入测试配置的具体参数,使用 exec() 执行对应代码,返回最终结果

经过归纳总结,PaddlePaddle 到 PyTorch 的 API 转换情况可分为 8 类:

  • 第1类为 API 可直接映射,最简单的情况,包括:无参数、参数完全一致、仅参数名不一致
  • 第2类为 参数默认值不一致,一般可直接映射,但需注意设置 torch 参数默认值
  • 第3类为 仅 torch 参数更多,如果使用 torch 的部分参数可以完整表达,就直接映射,但需注意设置 torch 参数默认值
  • 第4类为 仅 paddle 参数更多,一般无法直接映射(会丢失信息)
  • 第5类为 torch 和 paddle 都支持更多参数,情形与 仅 paddle 参数更多 类似(不考虑 torch 多的参数)
  • 第6类为 参数用法不一致,无法直接映射,如:参数类型不一致、参数含义不一致、返回参数类型不同
  • 第7类为 没有对应 API,无法直接映射,但可通过 组合替代实现(通过多个 API 组合实现)、自定义规则(撰写 torch 代码)方法解决
  • 第8类为 功能缺失,完全无法或很难使用 torch 表达当前 API 的功能,不进行转换

需要说明的是,我们仅关心能否使用 Torch API 完整地模拟出 Paddle API 的表现,在非常功利的视角下,我们仅需关注 Torch 的执行结果!

Paddle2Torch 模块的内核机制提供以下的转换方案:

  1. 读取 mapping.json,直接进行 API 映射,解决第1类与部分第2、3类 API
  2. 读取 mapping.json,直接进行 API 映射的同时,手动设置 torch 的部分 args 与 kwargs,解决部分第2-7类问题
  3. 读取 mapping.json 的 Rule 注册,加载 rules.py 中相应的 Rule 规则,将 API 分配给指定的 Rule 类执行,解决剩余的第2-7类问题

在任务开发过程中,需要完成以下步骤。更详细的开发指南请参考 Paddle2Torch README#贡献指南

1. 在 mapping.json 中编写转换配置

如果 PaddlePaddle API 有直接对应的 PyTorch API,可采用 直接映射 的方法。需在 mapping.json 的相应条目(去掉 paddle. 后的字典序)下编写转换配置,编写规则为:

    "<api_name>": {
        "torch_api": "torch api 名称",
        "set_defaults":{
            "_description1": "默认值设置字典,键为参数名,值为默认值",
            "_description2": "建议参考官方文档设置默认值,不会覆盖已有参数值,功能等效于 var = locals().get('var', value)"
        },
        "paddle_torch_args_map": {
            "_description": "参数名映射字典,键对应 paddle,值对应 torch",
        },
        "torch_args": [
            "torch api 位置参数列表, 变量名可使用 {} 环绕,字符串的引号请使用 \\ 转义,可以直接设为常值"
        ],
        "torch_kwargs": {
            "_description": "torch api 关键字参数字典,与 torch_args 类似"
        }
    }

如果 PaddlePaddle API 没有直接对应的 PyTorch API,或者无法直接映射(Paddle 参数更多、参数用法不同等),应采用 规则映射 的方法,编写转换规则。既需要在 mapping.json 中注册,也需要在 rules.py 中定义类。注册规则为:

    "<api_name>": {
        "Rule": "自定义 Rule 类的类名"
    }

此外,也可以添加更多的常规配置,以减少 Rule 类代码的编写量(需要在 Rule 类中主动调用 apply_generic() 方法,返回 defaults_code 与 map_code ):

    "<api_name>": {
        "Rule": "自定义 Rule 类的类名",
        "torch_api": "torch api 名称",
        "set_defaults":{
            "_description1": "默认值设置字典,键为参数名,值为默认值",
            "_description2": "建议参考官方文档设置默认值,不会覆盖已有参数值,功能等效于 var = locals().get('var', value)"
        },
        "paddle_torch_args_map": {
            "_description": "参数名映射字典,键对应 paddle,值对应 torch"
        }
    }

paddle.nn.functional.conv1d 的转换配置为例:

    "paddle.nn.functional.conv1d": {
        "Rule": "Conv1dRule",
        "torch_api": "torch.nn.functional.conv1d",
        "set_defaults": {
            "bias": "None",
            "stride": 1,
            "padding": 0,
            "dilation": 1,
            "groups": 1,
            "data_format": "'NCL'"
        },
        "paddle_torch_args_map": {
            "x": "input",
            "weight": "weight",
            "bias": "bias",
            "stride": "stride",
            "padding": "padding",
            "dilation": "dilation",
            "groups": "groups"
        }
    },

2. 在 rules.py 中编写转换规则代码

Rule 类的定义需要继承自抽象基类 BaseRule,并实现 apply() 方法,否则无法执行转换。基类定义为:

class BaseRule(ABC):
"""转换规则的抽象基类"""

    @abstractmethod
    def apply(self, paddle_api: str) -> ConvertResult:
        pass

paddle.nn.functional.conv1d 的转换规则为例:

class Conv1dRule(BaseRule):
    def apply(self, paddle_api: str) -> ConvertResult:
        defaults_code, map_code = self.apply_generic()
        pre = """
if data_format == "NLC":
    x = x.permute(0, 2, 1)
stride = tuple(stride) if isinstance(stride, list) else stride
dilation = tuple(dilation) if isinstance(dilation, list) else dilation
if isinstance(padding, str):
    if padding.lower() == "same":
        padding = "same"
    elif padding.lower() == "valid":
        padding = "valid"
elif isinstance(padding, list):
    if len(padding) == 2:
        pad_left, pad_right = padding
        x = torch.nn.functional.pad(x, (pad_left, pad_right))
        padding = 0
    else:
        padding = tuple(padding)
"""
        core = f"result = {self.torch_api}(**_kwargs)"
        post = """
if data_format == "NLC":
    result = result.permute(0, 2, 1)
"""
        code = Code(
            preprocess=defaults_code + pre.splitlines() + map_code,
            core=[core],
            postprocess=post.splitlines(),
        )
        return ConvertResult.success(paddle_api, code)

更详细的 Rule 编写指南可参考 Paddle2Torch README#高级Rule指南

3. 测试转换结果

在 PaddleAPITest 项目 tester/api_config 路径下搜索 API 名称,将所有 api_config_merged_*.txt 文件内的相关测试配置移至临时文件中,然后运行 accuracy 测试命令:

python engineV2.py --accuracy=True --api_config_file="tester/api_config/temp.txt" >> "tester/api_config/test_log/log.log" 2>&1

测试结果将位于 tester/api_config/test_log 文件夹中。若全部 pass,请将配置合并至通过 accuracy 测试的 tester/api_config/api_config_support2torch_*.txt 中(递增认领一个文件);如果有 torch_error、paddle_error 或 accuracy_error,请进一步定位是否是转换出错,亦或是 PaddleAPITest 引擎问题、PaddlePaddle 问题 或 PyTorch 问题,前者请尝试仔细阅读文档,或寻求项目开发者帮助。

如果确认是引擎问题,请 @cangtianhuang 进行反馈;其他情况请在 report/fresh_report/accuracy 中记录错误配置、报错信息,并将配置合并至未通过精度测试的 tester/api_config/api_config_accuracy_error_*.txt 中(递增认领一个文件)

四、如何开始

1. 克隆仓库

访问 https://github.com/PFCCLab/PaddleAPITest ,点击右上角的 “Fork” 按钮,将仓库 fork 到你自己的 GitHub 账号下,进行本地分支开发

git clone https://github.com/YOUR_USERNAME/PaddleAPITest.git
cd PaddleAPITest
git remote add upstream https://github.com/PFCCLab/PaddleAPITest.git
git checkout -b develop main

2. 配置环境

建议在虚拟环境或 docker 中开发(需先安装 paddlepaddle-gpu 再安装 torch,否则会报错,重新安装请添加 --force-reinstall )

pip install --pre paddlepaddle-gpu -i https://www.paddlepaddle.org.cn/packages/nightly/cu118/
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118
pip install func_timeout pebble pynvml

3. 任务认领

Important

请务必严格按照格式填写,否则快乐开源小助手无法自动更新信息

请大家在 issue 下以 comment 的形式认领任务,否则不会正确报名,格式如下:

【报名】: 1、2、3-5

多个任务之间使用中文顿号分隔,多个连续任务可用横线表示

4. 提交 PR

// ------- PR 标题 --------

[P2T support No.xxx]+API名称

// ------- PR 内容 --------

## 转换能力补齐

### [API 名称]

[描述转换所属情况,具体转换方案]

## 测试结果

[描述配置测试结果,处理与截图]

- https://github.com/PaddlePaddle/Paddle/issues/72643

@cangtianhuang 和 @wanghuancoder 

五、参考文档 和 PR 示例

请务必查阅 API 文档:

README:

百度同学可查阅:

PR 示例:

看板信息

任务方向 任务数量 提交作品 / 任务认领 提交率 完成 完成率
转换功能开发 112 112 / 112 100.0% 112 100.0%

统计信息

排名不分先后 @Cutelemon6 (20) @cangtianhuang (19) @yuwu46 (31) @cszdrg (10) @mzj104 (27) @ccsuzzh (2) @HangFu7 (1) @superdonkey007 (2)

Metadata

Metadata

Labels

Type

No type

Projects

Status

Done

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions