Skip to main content

cpp-sink

负责《Paddle API 对齐 PyTorch 项目》中 Step2 代码修改,实施『C++下沉』方案。通过将 Python API 下沉至 C++层,可以减少 Python 装饰器带来的性能开销,提升 API 调度效率。

Source facts

Repository
PaddlePaddle/docs
Last source activity
July 7, 2026 at 10:18
Detected SKILL.md language
Chinese
Stars
284
Forks
904

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
cpp-sink
description
负责《Paddle API 对齐 PyTorch 项目》中 Step2 代码修改,实施『C++下沉』方案。通过将 Python API 下沉至 C++层,可以减少 Python 装饰器带来的性能开销,提升 API 调度效率。
context
fork
disable-model-invocation
false
# 一、标准工作流程 根据 API 的复杂度,将下沉场景分为三类: ## 场景一: 仅参数名不一致(最简单) **适用条件(需全部满足):** - Paddle Python API 与`ops.yaml`中参数**类型或数量一致** - Paddle API 和 PyTorch API 仅参数名称不一致 - Python 端调用`_C_ops`前**无任何前处理逻辑** **典型示例:** `paddle.log2` ### Step 1:配置 `python_api_info.yaml` 添加参数别名映射(按 op name 的字典序添加): ```yaml - op : log2 name : [paddle.log2, paddle.Tensor.log2] args_alias : use_default_mapping : True # 启用默认映射:x->input ``` **说明:** - `name`:指定对应的 Python API 名称(函数 API 和 Tensor 方法) - `use_default_mapping : True`:自动配置常用字段映射(x→input, y→other, axis→dim, keepdims→keepdim) - 不在默认映射范围时,可配置自定义映射:`y: [exponent]`(Paddle 参数名为 key,PyTorch 参数名为 value) ### Step 2:迁移文档到 `_paddle_docs.py` 使用 `add_doc_and_signature` 装饰器迁移文档,关键要点: 1. **Alias 说明格式**:在 Args 部分为有别名的参数添加 `Alias: ``alias_name``` 2. **out 参数处理**:keyword-only 参数放在 `Keyword Args:` 部分,位置参数放在 `Args:` 部分,如下: ```python # out 为 keyword-only 参数 """ Args: ... Keyword Args: out (Tensor|optional): The output tensor. Default: None. """ # out 为位置参数 """ Args: out (Tensor, optional): The output Tensor. Default: None. """ ``` **示例**: ```python @add_doc_and_signature def log2( x: Tensor, name: str | None = None, *, out: Tensor | None = None, ) -> Tensor: r""" Calculates the log to the base 2 of the given input tensor, element-wise. .. math:: Out = \log_2x Args: x (Tensor): Input tensor must be one of the following types: int32, int64, float16, bfloat16, float32, float64, complex64, complex128. name (str|None, optional): Name for the operation (optional, default is None). For more information, please refer to :ref:`api_guide_Name`. out (Tensor, optional): The output Tensor. If set, the result will be stored in this Tensor. Default: None. Returns: Tensor: The log to the base 2 of the input Tensor computed element-wise. Examples: .. code-block:: pycon >>> import paddle >>> # example 1: x is a float >>> x_i = paddle.to_tensor([[1.0], [2.0]]) >>> res = paddle.log2(x_i) >>> res Tensor(shape=[2, 1], dtype=float32, place=Place(cpu), stop_gradient=True, [[0.], [1.]]) """ ... ``` **注意**: - Tensor 类方法(如 paddle.Tensor.abs)没有文档,无需处理,请勿与普通方法(如 paddle.abs)混淆 - Inplace 方法(如 paddle.abs_等下划线 API),只需要更新 API 签名,不需要修改文档 - 注意文档格式规范,需与 `_paddle_docs.py` 现有文档格式保持一致 ### Step 3:替换 Python 实现 找到 API 的 Python 实现位置(如 `python/paddle/tensor/math.py`,注意不要误检索到稀疏 API 位置): 1. 在文件上方合适位置**导入**C++实现 2. 直接**删除**原有的 Python 函数实现 ```python # 在文件最上方合适位置导入 from paddle._C_ops import log2 # noqa: F401 # 以下内容全部删除 # def log2(x: Tensor, name: str | None = None) -> Tensor: # ... ``` ## 场景二: 具有前处理逻辑(中等复杂度) **适用条件(全部满足):** - Paddle Python API 与`ops.yaml`中参数**类型或数量一致** - Paddle API 和 PyTorch API 仅参数名称不一致 - Python 端在调用`_C_ops`前**有其他前处理逻辑** **典型示例:** `paddle.logsumexp` ### Step 1:配置 `python_api_info.yaml` ```yaml - op : logsumexp name : [paddle.logsumexp, paddle.Tensor.logsumexp] args_alias: use_default_mapping : True # x->input, axis->dim pre_process: func : LogsumexpPreProcess(x, axis, reduce_all) # 前处理函数 ``` **关键点:** - `name`:指定对应的 Python API 名称 - `args_alias.use_default_mapping`:启用默认参数映射 - `pre_process.func`:指定前处理函数名称及其参数列表 ### Step 2:实现前处理函数 将 Python 端在调用`_C_ops`前的**其他前处理逻辑**,修改为 C++的实现。在 `paddle/fluid/pybind/arg_pre_process.h` 声明,在 `arg_pre_process.cc` 实现。 **关键要点:** - 必须同时实现**动态图版本**(参数类型为 `Tensor*`)和**静态图版本**(参数类型为 `pir::Value*`) - 函数通过指针修改参数值 - 参考 `arg_pre_process.cc` 中已有实现,保持风格一致 **声明示例**: ```cpp void LogsumexpPreProcess(Tensor *x, std::vector<int> *axis, bool *reduce_all); // 动态图 void LogsumexpPreProcess(pir::Value *x, std::vector<int> *axis, bool *reduce_all); // 静态图 ``` ### Step 3:迁移文档到 `_paddle_docs.py` 参考场景一的 Step 2 执行相同操作。 ### Step 4:替换 Python 实现 参考场景一的 Step 3 执行相同操作。 ## 场景三: 复杂参数映射(最复杂) **适用条件(全部满足):** - Paddle Python API 与`ops.yaml`中参数**类型或数量不一致** - 需要复杂的自定义参数解析逻辑,来匹配 Paddle Python API 与`ops.yaml`的参数差异 **典型示例:** `paddle.argmax`/`paddle.argmin` ### Step 1:配置 `python_api_info.yaml` ```yaml - op : argmax name : [paddle.argmax, paddle.Tensor.argmax] args_mapper : func : ArgMaxMinMapper # 自定义参数映射函数 ``` **关键点:** - `name`:指定对应的 Python API 名称 - `args_mapper.func`:指定自定义 Mapper 函数名称 - 当使用`args_mapper`时,**不会生成默认参数解析代码** - Mapper 需要手动解析所有参数,包括参数别名支持 ### Step 2:实现自定义 Mapper 将 Python API 与`ops.yaml`中参数**类型或数量不一致**的差异,通过 C++自定义 Mapper 来进行匹配与转换。在 `paddle/fluid/pybind/args_mapper.h` 声明,在 `args_mapper.cc` 实现。 **关键要点:** - 必须同时实现**动态图版本**和**静态图版本** - 使用 `args_mapper` 时不会生成默认参数解析代码,需手动解析所有参数 - 参考 `args_mapper.cc` 中已有实现,保持风格一致 **核心工具函数:** | 函数 | 用途 | |------|------| | `GetTensorFromArgsOrKWArgs` | 解析 Tensor 参数,支持别名列表 | | `GetItemFromArgsOrKWArgs` | 获取通用 Python 对象 | | `CastPyArg2Scalar/Boolean/DataType` | 类型转换 | | `CheckParamsCount` / `CheckRemainingParamsValidity` | 参数校验 | **静态图特殊处理:** 使用 `pir::Value` 代替 `Tensor`,常量需通过 `paddle::dialect::full` 转换为 Value 类型。 **声明示例**: ```cpp void ArgMaxMinMapper(PyObject* args, PyObject* kwargs, Tensor* x, Scalar* axis, bool* keepdims, bool* flatten, DataType* dtype); // 动态图 void ArgMaxMinMapper(PyObject* args, PyObject* kwargs, pir::Value* x, pir::Value* axis, ...); // 静态图 ``` ### Step 3: 迁移文档到 `_paddle_docs.py` 除了完成场景一的文档迁移操作之外,场景三文档迁移还需要额外注意: 如果使用了自定义 Mapper,则 API 有可能支持了签名重载,需要分别描述两种签名,如下: > 注:只需在文档正文中阐述两种签名(Paddle 在前,Pytorch 在后),文档其他位置如 Args/Returns 仍以 Paddle 风格签名为准 ```python """ This API has two signatures: 1. ``paddle.sum(x, axis=None, dtype=None, keepdim=False, name=None, *, out=None)`` (Paddle-style) 2. ``paddle.sum(input, dim=None, keepdim=False, dtype=None, *, out=None)`` (PyTorch-style) Args: ... Returns: ... """ ``` ### Step 4:替换 Python 实现 参考场景一的 Step 3 执行相同操作。 # 二、注意事项 1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 2. 若 Python API 参数顺序与`_C_ops` API 不同,属于特殊情况,Cpp 下沉方案无法实现,需要使用 Python 装饰器方案 3. 代码中不允许提交中文,代码注释采用英文 4. 若 API 需支持`out`参数,必须在 API 签名中 out 参数 5. 不要修改`generated_tensor_methods_patch.py`,该文件是自动生成的,修改没有意义,如无法对齐可考虑放弃 C++下沉方案而不是改动该文件 6. 示例代码若涉及多种数据类型,可能触发类型检查误报,添加注释忽略: ```python .. code-block:: pycon >>> # type: ignore >>> import paddle >>> x = paddle.to_tensor([1.0, 2.0]) ``` # 三、常见问题处理 ## Q1:静态图报错"must be Value, but got Variable" **错误现象**: ```python TypeError: (InvalidType) all(): argument (position 1) must be Value, but got Variable ``` **解决方法**: 1. 删除过时的测试文件: ```bash rm -rf test/deprecated/test_xxx.py ``` 2. 删除`CMakeLists.txt`中涉及的单测配置 3. 检查并更新所有引用这些测试的代码 --- ## Q2:参数解析报错"got an unexpected keyword argument" **错误现象**: ```python TypeError: argmax() got an unexpected keyword argument 'invalid_param' ``` **解决方法**: 1. 检查参数名称拼写 2. 确认是否支持该参数
View on GitHub