diff --git a/docs/dev_guides/coding_agent/README.md b/docs/dev_guides/coding_agent/README.md index bacf36d0f4e..a6887c1f321 100644 --- a/docs/dev_guides/coding_agent/README.md +++ b/docs/dev_guides/coding_agent/README.md @@ -1,18 +1,38 @@ -# AI 编程 Rules 目录 +# AI 编程 Agent 规则目录 -## 目录说明 -本目录存放 AI 编程(Agent)专用规则文件(*.mdr),用于指导 Agent 在 Paddle 代码库中的自动化开发任务。 -Rules 文件同时可作为人工开发者的学习参考,但**必须搭配 Agent 使用**,单独执行无效。 +## 什么是 Agent 规则 -## 使用须知 -1. Rules 文件仅对 Agent 生效,人类开发者请勿直接运行或依赖其单独完成工作。 -2. 使用前请确保本地环境已正确配置,例如: - - 代码目录:Paddle 源码根目录(`Paddle/`) - - 知识语料:已准备好的 API 映射表、设计文档、历史 PR 等 - - 编译环境:本地可编译运行 Paddle 的环境 +Agent 规则是一组预定义的配置文件,用于指导 AI 编程助手(如 Claude Code)在 Paddle 代码库中执行自动化开发任务。 -## 贡献与维护 -- Rules 需同步更新,确保其与 Paddle 最新版本保持一致。 -- 欢迎贡献更多 Rules,提升 Agent 的智能化水平。 +**核心组成**: +- **SKILL.md**:定义 AI 可执行的技能,包含任务流程、操作步骤、注意事项 +- **CLAUDE.md**:定义项目背景信息,自动加载到 AI 上下文中 -> 本文档由 AI Agent 自动生成,日期:2025-12-31 +**工作原理**: +1. 用户通过 `/skill-name` 调用技能 +2. AI 读取 SKILL.md 中的指令 +3. AI 按照预定义流程执行任务 + +**优势**: +- 任务流程标准化,减少人工干预 +- 知识沉淀,经验可持续积累 +- 多 Skill 协作,完成复杂任务 + +## 目录结构 + +``` +coding_agent/ +├── README.md # 本文件 +└── api_compatibility/ # Paddle API 对齐 PyTorch 项目 + ├── README.md + ├── install.sh + └── .claude/ + ├── CLAUDE.md + └── skills/ +``` + +## 项目列表 + +| 项目 | 功能 | +|------|------| +| [api_compatibility](api_compatibility/) | 自动对齐 Paddle API 与 PyTorch API | diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/CLAUDE.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/CLAUDE.md new file mode 100644 index 00000000000..27a04b485b9 --- /dev/null +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/CLAUDE.md @@ -0,0 +1,139 @@ +# Paddle API 对齐 PyTorch 项目 + +## 项目目标 +使 Paddle API 与 PyTorch API 行为完全对齐。对于任意 PyTorch API 用法,只需将 `torch.*` 替换为 `paddle.*`,计算结果完全一致。 + +## 工作目录说明 + +**ROOT_DIR 变量定义**: +- `${ROOT_DIR}` 表示项目的根工作目录(如 `/workspace`),通常为包含 `Paddle`、`PaConvert`、`docs` 子目录的父目录 +- **路径规则**:含 `${ROOT_DIR}` 为绝对路径,不含则为相对于根目录的相对路径,需自行展开 + +| 工作目录 | 完整路径 | 内容说明 | 对应步骤 | +|---------|---------|---------|---------------| +| Paddle | `${ROOT_DIR}/Paddle` | Paddle 框架源码仓库,包含所有 Paddle API 的实现 | Step2:代码修改 + Step3:兼容测试 | +| PaConvert | `${ROOT_DIR}/PaConvert` | PyTorch 转换工具仓库,包含所有 Pytorch 单元测试 | Step4:对齐验证 | +| docs | `${ROOT_DIR}/docs` | Paddle 文档仓库,包含所有 Paddle API 中文文档 | Step5:文档更新 | + +## 常用文件位置 + +|**功能模块**|**检索关键字**|**文件路径**|**举例**|**注意**| +|-|-|-|-|-| +|API 中文文档|`{api_name}_cn.rst`|`${ROOT_DIR}/docs/docs/api/paddle/`|tan_cn.rst|| +|API 差异文档|`torch.{api_name}.md`|`${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/`下一级目录|torch.tan.md|| +|C++下沉使用|`python_api_info.yaml`、`ops.yaml`|`${ROOT_DIR}/Paddle/paddle/phi/ops/yaml/`|python_api_info.yaml、ops.yaml|| +|C++下沉使用|`_paddle_docs.py`|`${ROOT_DIR}/Paddle/python/paddle/`|_paddle_docs.py|| +|Paddle API 实现位置|`def {api_name}` 或 `class {api_name}`|`${ROOT_DIR}/Paddle/python/paddle/*/`|`${ROOT_DIR}/Paddle/python/paddle/tensor/math.py`|不要误检索到 sparse 目录下(稀疏 API 位置),本项目与稀疏无关,所有 sparse 相关文件直接忽略| +|Paddle API 兼容性单测位置|`test_api_compatibility_part[1-9]\.py`|`${ROOT_DIR}/Paddle/test/legacy_test/`|test_api_compatibility_part3.py|| +|Pytorch API 单测位置|`test_{api_name}.py`|`${ROOT_DIR}/PaConvert/tests/`|test_tan.py|| + +## Paddle API 架构(5 层调用栈) + +Paddle API 从上到下由 5 层组成(本项目直接修改第 1、5 层,对于第 2~4 层通常是修改 yaml 配置文件,例如 python_api_info.yaml): + +| 层级 | 名称 | 语言 | 文件位置 | 功能说明 | 是否修改 | +|------|------|------|----------|----------|----------| +| 1 | Python 层 | Python | `*.py` | API 的 Python 接口定义 | ✅ **修改** | +| 2 | Pybind 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/fluid/pybind/eager_op_function.cc`)| Python 与 C++的绑定层 | ✅ **修改 yaml 配置来实现修改** | +| 3 | Dygraph 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/fluid/eager/.../dygraph_functions.cc`)| 前反向传播组合 | ❌ 通常不改 | +| 4 | C++ API 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/phi/api/lib/api.cc`) | Kernel 选择调度 | ❌ 通常不改 | +| 5 | Kernel 层 | C++ | `${ROOT_DIR}/Paddle/paddle/phi/kernels/` | 实际计算逻辑实现 | ✅ **修改** | + +**示例 API 层级**: +```python +# Layer 1: Python 层 +def atan(x: Tensor, name: str | None = None) + +# Layer 2: Pybind 层(根据 ops.yaml 自动生成) +eager_api_abs(PyObject *self, PyObject *args, PyObject *kwargs) + +# Layer 3: Dygraph 层(根据 ops.yaml 自动生成) +paddle::Tensor atan_ad_func(const paddle::Tensor& x, ...) + +# Layer 4: C++ API 层(根据 ops.yaml 自动生成) +Tensor atan(const Tensor& x, ...) + +# Layer 5: Kernel 层 +void AtanKernel(const Context& dev_ctx, const DenseTensor& x, DenseTensor* out) +``` + +## 专业术语表 + +| 术语 | 定义 | 备注 | +|------|------|------| +| PyTorch | 深度学习框架,导入模块为`torch` | - | +| Paddle | 飞桨深度学习框架,导入模块为`paddle` | - | +| API | 应用程序接口 | 既可以是一个 Python 函数,也可以是一个 Python 类 | +| API 完整路径 | 包含框架导入模块的完整路径 | 如`torch.nn.functional.dropout`| +| API 路径 | 去掉框架导入模块后的路径 | 如`nn.functional.dropout` | +| PyTorch API | `torch.*` 系列接口 | 约 2000+个 API,是本项目的**对齐标准**| +| Paddle API | `paddle.*` 系列接口 | 约 2000+个 API,是本项目的**修改对象** | +| API 对齐 | 使两个 API 的行为完全对齐一致 | 对齐包括 API 路径、输入参数、返回值、计算逻辑等| +| API 中文文档 | 中文描述了该 API 的功能与行为 | 位于 `${ROOT_DIR}/docs/docs/api/paddle/` 目录,命名类似 tan_cn.rst | +| API 差异文档 | 中文描述了 Pytorch API 与 Paddle API 两者的行为差异 | 位于 `${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/` 下一级子目录,命名类似 torch.tan.md | +| compat 类型 API | 兼容性 API | 为保持后向兼容而添加的 API,能实现除 API 路径之外的完全对齐| + +## 类方法 API 实现原理 + +类方法 API(如 `torch.Tensor.abs`)和普通 API(如 `torch.abs`)是不同 API,但实现一致。Paddle 通过 patch 机制将方法动态添加到 Tensor 类上。 + +**实现方式**: +| 场景 | 方式 | 文件 | +|------|------|------| +| 数学运算类方法,直接转发到普通函数 | 配置 tensor_method_func | `python/paddle/tensor/__init__.py` | +| 自定义实现逻辑、property、魔术方法 | 修改 patch 文件,注意不要遗漏文件 | `python/paddle/base/dygraph/math_op_patch.py`(动态图)
`python/paddle/pir/math_op_patch.py`(PIR 静态图)
`paddle/fluid/pybind/eager_math_op_patch.cc`(C++ 动态图) | + +**检索按时**:搜索时在 patch 文件中查找,或搜索对应的普通函数 `def abs(`,不要搜索 `class Tensor`(方法通过 setattr 动态添加)。 + + +## Inplace API 实现原理 +- **inplace API**(如 `torch.abs_`):原地操作,直接修改输入 Tensor,不应有 out 参数 +- **非 inplace API**(如 `torch.abs`):返回新 Tensor,不修改输入 Tensor +- Inplace API 无需测试静态图,只需测试动态图 + +**自动生成机制**:Paddle 支持自动生成 inplace API。当 `ops.yaml` 中定义了 `inplace: (x -> out)` 字段后,系统自动生成对应的 inplace 版本。 + + +## 工作流程 + +### 流程概览 +| Step | 名称 | 对应 Skill | 核心任务 | +|------|------|-----------|----------| +| Step1 | 方案决策 | `/api-change-decider` | 分析差异,选择修改方案 | +| Step2 | 代码修改 | `/python-decorator` `/cpp-sink` `/modify-origin-api` `/add-new-api` `/add-new-compat-api` | 按方案修改 Paddle 代码 | +| Step3 | 兼容测试 | `/add-compatibility-test` | 添加兼容性单测并运行 | +| Step4 | 对齐验证 | `/pytorch-alignment-validator` | 编写 PyTorch 单测验证对齐 | +| Step5 | 文档更新 | `/api-docs-updater` | 更新中文文档和差异文档 | + +### 流程重要约束 +1. **批量处理**:每个 Step 对**所有 API** 完成后才进入下一步 +2. **正向推进**:必须按 Step1 → Step2 → Step3 → Step4 → Step5 顺序执行,禁止跳过 +3. **异常回退**:Step3/Step4 失败时回退到对应步骤重新执行 +4. **放弃规则**:回退 3 次以上仍失败,标记为"未对齐"并放弃,需完整回退所有修改 + +### Step 通过标准 +- Step3:单测可运行通过 +- Step4:API 可配置为 `ChangePrefixMatcher` + + +## 注意事项 +1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +2. 每次修改代码后必须重新编译:在 `${ROOT_DIR}/Paddle/build` 目录下执行编译,否则修改不会生效 + ```bash + cd ${ROOT_DIR}/Paddle/build + cmake .. && make -j$(nproc) + ``` + - 无需重装,直接生效(勿执行 setup/install 等安装操作) + - 勿删除 build 目录(否则增量编译失效,编译时间极长) + +## 忽略参数规则 +分析差异时,以下参数直接忽略: +- torch 侧:`generator`、`memory_format`、`layout` +- paddle 侧:`name` + +## 编程风格 +- 代码自解释,最小化注释;注释应有实际价值(提醒非显而易见的全局背景) +- 不要为只使用一次的简短逻辑创建辅助函数,除非能显著提升可读性 +- 与现有代码风格保持一致 +- 新增注释仅使用 ASCII 字符(不引入 Unicode);未改动的注释保持原样 +- 不确定时,选择更简单的实现 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/README.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/README.md deleted file mode 100644 index 22281169c5d..00000000000 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/README.md +++ /dev/null @@ -1,74 +0,0 @@ -# 《Paddle API 对齐 PyTorch 项目》完整 SKILL 体系 - -AI Agent 自动对齐 Paddle API 与 PyTorch API。包含 1 个总 skill 和 6 个分阶段 skill。 - -## 两种使用方式 - -### 方式一:一步到位(推荐) - -使用总 skill **`/api-compatibility`**,传入待对齐的 PyTorch API 列表: - -``` -/api-compatibility torch.atan torch.asinh torch.abs_ -``` - -总 skill 会自动执行完整流程(Step1→Step2→Step3→Step4→Step5),返回对齐结果统计表。 - -### 方式二:分步操作 - -针对具体任务,单独调用对应 skill: - -| 阶段 | Skill | 用途 | -|------|-------|------| -| Step1 | `/api-change-decider` | 分析 API 差异,决策改动方案 | -| Step2 | `/python-decorator` | 用 Python 装饰器修改 API | -| Step2 | `/cpp-sink` | 用 C++下沉修改 API(性能更优) | -| Step3 | `/pytorch-alignment-validator` | 验证 API 对齐 | -| Step4 | `/api-docs-updater` | 更新中文文档 | -| Step5 | `/create-pr` | 提交 PR 到三个仓库 | - -## 工作流程 - -``` -输入:待对齐 API 列表 - ↓ -Step1:方案决策(api-change-decider) - ├─ 分析 API 差异 - └─ 决策改动方案(方案 1-6) - ↓ -Step2:代码修改(python-decorator 或 cpp-sink) - ├─ 方案 1:Python 装饰器 - ├─ 方案 2:C++下沉 - └─ 其他方案:跳过 - ↓ -Step3:对齐验证(pytorch-alignment-validator) - ├─ 更新 API 映射 - ├─ 补充测试用例 - └─ 运行单元测试 - ↓ -Step4:文档更新(api-docs-updater) - └─ 更新中文 API 文档 - ↓ -Step5:代码提交(create-pr) - └─ 提交 PR 到 Paddle/PaConvert/docs - ↓ -输出:对齐结果统计表 -``` - -## 使用示例 - -**完整对齐一个 API**(推荐方式): -``` -/api-compatibility torch.atan -``` -自动完成全流程,得到对齐结果。 - -**调试单个 API**(需要逐步修改): -``` -/api-change-decider torch.atan # 确定方案 -/cpp-sink torch.atan # 指定方案修改 -/python-decorator torch.atan # 指定方案修改 -/pytorch-alignment-validator torch.atan # 验证 -/api-docs-updater torch.atan # 更新文档 -/create-pr torch.atan # 提交 PR -``` diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-compatibility-test/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-compatibility-test/SKILL.md index c7b206fdaf1..399c2717e11 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-compatibility-test/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-compatibility-test/SKILL.md @@ -6,7 +6,7 @@ disable-model-invocation: false # 一、标准工作流程 -## Step 1:编写测试用例(仅首次执行) +## Step 1:编写测试用例 在 `${ROOT_DIR}/Paddle/test/legacy_test/` 目录下找到 `test_api_compatibility[1-9]\.py` 中数字最大的文件,在该文件中添加测试。 @@ -125,7 +125,7 @@ if paddle.device.is_compiled_with_cuda(): out_gpu = paddle.(x, device="gpu:0") ``` -## Step 2:编译并运行单测(每次改动均需执行) +## Step 2:编译并运行单测(每次修改代码均需执行编译) 单测编写完成后,按以下命令验证执行: diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/SKILL.md index 463a7cf23fa..680050a34a9 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/SKILL.md @@ -107,7 +107,7 @@ lt = less_than Paddle 通过 patch 机制将 paddle.tensor 模块中的函数动态 setattr 到 paddle.Tensor,因此只需在此处声明即可自动注入为 Tensor 方法,无需修改 class Tensor 定义。 -### 类型二:类方法/属性别名 +### 类型二:类成员方法/属性别名 适用条件:需要对齐类的方法或属性,根据已有实现与目标形式的性质差异,分为三种情况处理。 @@ -115,58 +115,112 @@ Paddle 通过 patch 机制将 paddle.tensor 模块中的函数动态 setattr 到 当已有实现与目标形式性质相同时(都是方法或都是属性),直接使用别名赋值即可。 -典型示例: +**Layer 类示例(方法 → 方法):** + ```python -# 方法 → 方法 -get_submodule = get_sublayer -set_submodule = set_sublayer +# python/paddle/nn/layer/layers.py + +class Layer: + def get_sublayer(self, target: str) -> Layer: + # original implementation + ... + + def set_sublayer(self, target: str, layer: Layer) -> None: + # original implementation + ... -# 属性 → 属性 -grad = _grad + # 在类末尾添加别名(对齐 PyTorch 的 get_submodule/set_submodule) + get_submodule = get_sublayer + set_submodule = set_sublayer ``` -操作步骤:在目标类中直接添加别名赋值。 +**Tensor 方法示例(以 bar 对齐 torch.Tensor.bar 为例):** + +假设已有方法 `original_bar`,需在注入列表中直接注册别名: + +```python +# python/paddle/base/dygraph/math_op_patch.py + +# 在注入列表中直接注册(方法→方法,无需额外实现) +( + 'bar', # 新 API 名称 + original_bar, # 指向已有方法 +), +``` #### 情况二:方法 → 属性 当已有实现是方法(需调用),目标形式是属性(直接访问)时,需使用 `@property` 装饰器包装原有方法。 -典型示例:PyLayerContext.saved_tensors(对齐 torch.saved_tensors,原有 saved_tensor() 需加括号调用) - +**简单示例:** ```python -# python/paddle/autograd/py_layer.py - class PyLayerContext: def saved_tensor(self): - # original method implementation ... @property def saved_tensors(self): - return self.saved_tensor() # delegate to existing method + return self.saved_tensor() ``` +**Tensor 属性示例:** + +假设已有方法 `rank()` 需调用,现改为属性 `ndims` 直接访问: + +```python +# python/paddle/base/dygraph/math_op_patch.py + +@property +def ndims(var: Tensor) -> int: + return var.rank() +``` + +然后在注入列表中注册为元组形式(属性用元组): +```python +( + 'ndims', + ndims, +), +``` + +这样 `tensor.ndims` 可直接访问,无需括号调用。 + #### 情况三:属性 → 方法 当已有实现是属性(直接访问),目标形式是方法(需调用)时,需定义新方法返回属性值。 -典型示例:假设 Paddle 有属性 `x.shape`,需对齐 PyTorch 方法 `x.get_shape()`: - +**简单示例:** ```python -class Tensor: +class Layer: @property - def shape(self): - # original property implementation + def parameters(self): ... - def get_shape(self): - """New method that delegates to the existing property.""" - return self.shape + def get_parameters(self): # 新增方法形式 + return list(self.parameters) ``` -若目标类是 `paddle.Tensor`,由于 Python 层无对应 class 定义,还需额外通过 patch 机制动态注入上述别名。 +**Tensor 方法示例:** + +假设已有属性 `dims` 直接访问,现添加方法 `get_dims` 需调用: + +```python +# python/paddle/base/dygraph/math_op_patch.py + +# dims 是已有属性,get_dims 是其方法形式 +def get_dims(var: Tensor) -> list: + return list(var.dims) +``` + +然后在注入列表中注册: +```python +( + 'get_dims', + get_dims, +), +``` -**新增 Tensor 方法的详细说明请参考**:主 SKILL 文档的「3.5 类方法 API 实现原理」章节。 +这样就可以通过 `tensor.get_dims()` 方法调用来获取 dims。 ### 类型三:命名空间别名 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/references/new_cpp_op.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/references/new_cpp_op.md index 78bb4bd3d31..ff3e569c698 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/references/new_cpp_op.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/references/new_cpp_op.md @@ -4,7 +4,7 @@ ## 一、获取并分析 PyTorch API 信息 -若尚未获得 PyTorch API 的相关信息,则自行获取,获取方式请参考`api-compatibility/SKILL.md` 中的「3.6 API 信息获取方式」章节。 +若尚未获得 PyTorch API 的相关信息,则自行获取,获取方式请参考`api-compatibility/SKILL.md` 中的「API 信息获取方式」内容。 然后分析 PyTorch API 的功能和行为,在 Paddle 中新增对应的 C++ 算子和 Python API,使其与 PyTorch API 保持一致。具体包括:API 名称、调用路径、参数名及参数功能等。 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/references/new_python_api.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/references/new_python_api.md index d5852824892..837b3833207 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/references/new_python_api.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-api/references/new_python_api.md @@ -4,7 +4,7 @@ ## 一、获取并分析 PyTorch API 信息 -若尚未获得 PyTorch API 的相关信息,则自行获取,获取方式请参考`api-compatibility/SKILL.md` 中的「3.6 API 信息获取方式」章节。 +若尚未获得 PyTorch API 的相关信息,则自行获取,获取方式请参考`api-compatibility/SKILL.md` 中的「API 信息获取方式」内容。 然后分析 PyTorch API 的功能和行为,在 Paddle 中新增对应的 API,使其与 PyTorch API 保持一致。具体包括:API 名称、调用路径、参数名及参数功能等。 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-compat-api/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-compat-api/SKILL.md new file mode 100644 index 00000000000..c6de8f8613f --- /dev/null +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/add-new-compat-api/SKILL.md @@ -0,0 +1,31 @@ +--- +name: add-new-compat-api +description: 负责《Paddle API 对齐 PyTorch 项目》中 Step2:API 代码修改,实施『新增 compat 类型 API』方案。在 `paddle.compat` 命名空间下新增 API,实现与 PyTorch API 行为对齐。 +context: fork +disable-model-invocation: false +--- + +# 与 add-new-api 的关系 + +本文档是 **add-new-api** 的变体,核心流程完全一致,**唯一区别**是新增 API 的存放目录: + +| 方案 | API 存放目录 | 适用场景 | +|------|-------------|---------| +| add-new-api | `Paddle/python/paddle/` (常规目录) | 新增 Paddle 原生 API | +| add-new-compat-api | `Paddle/python/paddle/compat/` (compat 目录) | 新增兼容性 API | + +**请直接参考 add-new-api 的 SKILL.md 完成开发**,并将所有文件路径中的 `Paddle/python/paddle/` 替换为 `Paddle/python/paddle/compat/`。 + +--- + +# 核心差异说明 + +## 实现位置映射 + +| add-new-api 路径 | add-new-compat-api 路径 | +|----------------|------------------------| +| `python/paddle/__init__.py` | `python/paddle/compat/__init__.py` | +| `python/paddle/tensor/math.py` | `python/paddle/compat/__init__.py` | +| `python/paddle/tensor/__init__.py` | `python/paddle/compat/__init__.py` | +| `python/paddle/nn/__init__.py` | `python/paddle/compat/nn/__init__.py` | +| `python/paddle/nn/functional/__init__.py` | `python/paddle/compat/nn/functional/__init__.py` | diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-change-decider/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-change-decider/SKILL.md index 236d9aa44ef..fb61ec7649b 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-change-decider/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-change-decider/SKILL.md @@ -1,8 +1,6 @@ --- name: api-change-decider description: 负责《Paddle API 对齐 PyTorch 项目》中 Step1:方案决策,分析 PyTorch API 与 Paddle API 之间的差异,制定合适的 API 改动方案 -context: fork -agent: Explore disable-model-invocation: false --- @@ -31,14 +29,16 @@ disable-model-invocation: false 2. API 名称和 `_C_ops.xxx` 的 OP 名称一致 - ✅ 正确示例:`paddle.atan` 调用 `_C_ops.atan` - ❌ 错误示例:`paddle.select_scatter` 调用 `_C_ops.set_value_with_tensor`(名称不一致) -3. API 差异**仅为参数名不同或仅多 out 参数**(不涉及参数顺序或个数差异) - - torch 比 paddle 恰好只多一个参数 `out`,其余参数完全一致 - - ✅ 符合:仅多 `out` 一个参数 - - ❌ 不符合:多两个及以上参数、多的参数不是 `out`、还存在参数名不同等其他差异 +3. API 差异**仅涉及以下情况之一或组合**: + - 仅参数名不同 + - 仅多 out 参数 + - 参数名不同 + 仅多 out 参数 + - ❌ 不符合:多两个及以上参数、多的参数不是 `out`、涉及参数顺序差异、存在其他额外参数 + **说明**:当满足此条件时,参数名映射和 out 参数都在 C++ 层统一处理,无需额外组合其他方案。 4. Python 实现中**仅有一次** `_C_ops.xxx` 调用 5. Python 实现中不涉及其他 Paddle API 调用 - - ❌ **禁止**:调用任何其他 paddle API(如 `paddle.where`、`paddle.abs`、`paddle.flatten` 等) - - ❌ **禁止**:调用 Tensor 方法(如 `x.flatten()`、`x.reshape()`、`x.unsqueeze()` 等,这些等同于调用 paddle API) + - ❌ **禁止**:调用任何其他 paddle API(如 `paddle.where`、`paddle.abs`、`paddle.flatten`、`paddle.full`、`paddle.cast` 等) + - ❌ **禁止**:调用 Tensor 方法(如 `x.flatten()`、`x.reshape()`、`x.unsqueeze()`、`x.cast()` 等,这些等同于调用 paddle API) - ❌ **禁止**:使用 `paddle.full_like`、`paddle.zeros_like`、`paddle.cast` 等 - ✅ **允许**:Python 内置函数(如 `len()`、`isinstance()`、`list()`、`range()` 等) - ✅ **允许**:简单的属性访问(如 `x.shape`、`x.dtype`、`x.ndim` 等) @@ -110,38 +110,60 @@ disable-model-invocation: false ## Step 1: 获取差异信息 -按优先级依次查找差异信息,一旦获取完整信息立即停止,这是"三选一"而非"三者都要"。 +两种优先级是"二选一"而非"两者都要",一旦获取完整信息立即停止: -### 优先级 1:查阅 API 差异文档 -查阅 `${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/torch.{api_name}.md`。如果文档存在且完整(包含对应 Paddle API、转写示例),则以此为准并停止查找;否则继续优先级 2。 +### 优先级 1:查阅差异文档和转写配置 -**注意**: -- 文档可能有细微错误,当发现问题可自行分析,或结合源码进一步确认 -- 一个 API 可能涉及多种差异,差异文档标题仅反映主要分类,必须通读完整参数映射表提取所有差异,不能仅看标题 -- 忽略参数:torch 侧 `generator`、`memory_format`、`layout`;paddle 侧 `name`。其他参数不可忽略 +包含两个信息源,需要综合两者来提取差异信息: -### 优先级 2:查询转写配置 -查询 `${ROOT_DIR}/PaConvert/paconvert/api_mapping.json` 或 `attribute_mapping.json`,根据 Matcher 类型分析差异分类。如果能直接从配置中提取完整差异信息,则以此为准并停止查找;否则继续优先级 3。 +#### 1.1 查阅差异文档 -| 字段 | 对应差异分类 | -|------|------------| +**查阅路径**: +``` +${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/torch.{api_name}.md +``` + +**注意事项**: +- **文档可能滞后或有误**:发现问题时应自行分析,或结合转写配置/源码进一步确认 +- **标题不代表全部**:一个 API 可能涉及多种差异,文档标题仅反映主要分类,**必须通读完整参数映射表提取所有差异**,不能仅看标题 +- **忽略参数规则**: + - torch 侧忽略:`generator`、`memory_format`、`layout` + - paddle 侧忽略:`name` + - 其他参数不可忽略 + +#### 1.2 查阅转写配置 + +**查阅路径**: +``` +${ROOT_DIR}/PaConvert/paconvert/api_mapping.json +${ROOT_DIR}/PaConvert/paconvert/attribute_mapping.json +``` + +**根据 Matcher 类型分析差异分类**: + +| Matcher 类型 | 对应差异分类 | +|--------------|-------------| | `ChangePrefixMatcher` | API 完全一致 | | `ChangeAPIMatcher` / `NumelMatcher` / `TensorFunc2PaddleFunc` / `Func2Attribute` / `Attribute2Func` | 仅 API 调用方式不一致(若同时包含 `unsupport_args`、`kwargs_change` 字段,则存在多重差异) | | `GenericMatcher` | 参数名不一致 / paddle 参数更多 / 参数默认值不一致 / torch 参数更多 | +| 其他自定义 Matcher | 参数用法/类型不一致 / 组合替代实现 | + +**根据配置字段分析差异**: + +| 字段名 | 对应差异分类 | +|--------|-------------| | `paddle_api` | API 映射关系 | | `kwargs_change` | 参数名不一致 | | `unsupport_args` | torch 参数更多(部分不支持) | | `paddle_default_kwargs` | 参数默认值不一致 / paddle 参数更多 | -| 其他自定义 Matcher | 参数用法/类型不一致 / 组合替代实现 | -**注意**: -- 更多 Matcher 可参考 `api_matcher.py` 分析。 +**注意**:更多 Matcher 类型可参考 `api_matcher.py` 源码分析。 -### 优先级 3:自行获取 API 信息 +### 优先级 2:自行获取 API 信息 -当优先级 1 和优先级 2 均无法获取完整差异信息时,通过多种方式自行获取 PyTorch API 和 Paddle API 的信息,进行对比分析。 +当优先级 1 无法获取完整差异信息时,通过多种方式自行获取 PyTorch API 和 Paddle API 的信息,进行对比分析。 -获取方式请参考`api-compatibility/SKILL.md` 中的「3.6 API 信息获取方式」章节。 +获取方式请参考`api-compatibility/SKILL.md` 中的「API 信息获取方式」内容。 ## Step 2:提取差异信息 @@ -161,9 +183,9 @@ disable-model-invocation: false | 1 | API 完全一致 | 无差异,无需改动 | | 2 | 仅 API 调用方式不一致 | API 路径不一致,但参数完全相同 | | 3 | 仅参数名不一致 | 参数功能相同但参数名称不同 | -| 4 | paddle 参数更多 | Paddle 提供更多可选参数 | +| 4 | paddle 参数更多 | Paddle 支持更多参数 | | 5 | 参数默认值不一致 | 参数默认值不同 | -| 6 | torch 参数更多 | PyTorch 提供更多参数 | +| 6 | torch 参数更多 | PyTorch 支持更多参数 | | 7 | 输入参数用法不一致 | 参数处理方式不同 | | 8 | 输入参数类型不一致 | 参数类型要求不同 | | 9 | 返回参数类型不一致 | 返回值类型或结构不同 | @@ -198,62 +220,153 @@ python -c "import paddle; paddle.Tensor.addmv_" # AttributeError → 路径不 **输出**:记录路径一致性结果(一致/不一致),用于选择决策表。 -### 3.2 查表决策 +### 3.2 执行决策流程 -根据 3.1 的路径一致性结果选择决策表:**路径不一致** → 决策表 A;**路径一致** → 决策表 B。 +根据 3.1 的路径一致性结果选择决策流程图:**路径不一致** → 决策流程图 A;**路径一致** → 决策流程图 B。 -**方案切换说明**:`→` 表示「不满足当前条件则切换到下一个备选方案」。 -- 方案 2 → 方案 1:不满足 C++ 下沉条件 -- 方案 3 → 方案 1:修改会破坏后向兼容 -- 方案 1 → 方案 5:不满足装饰器重载条件 +**针对每个差异分类独立执行流程图**,得到对应方案: +- 仅一个差异分类 → 直接输出该方案 +- 多个差异分类 → 按 3.3 规则组合 -**决策表 A:路径不一致**(必须包含方案 4) +**决策流程图 A:路径不一致** -| 差异分类 | 决策链(→ 备选) | -|----------|------------------| -| 分类 2, 10, 12, 13 | 方案 4(新增 Python 层 API 或 C++ 算子) | -| 分类 3 | 方案 2 + 方案 4(新增 API 别名)→ 方案 1 + 方案 4(新增 API 别名) | -| 分类 4, 5 | 不影响对齐 → 无需修改;否则 → 方案 3 + 方案 4(新增 API 别名)→ 方案 4(新增 Python 层 API) | -| 分类 6 | 仅多 out 且满足方案 2 条件 → 方案 2 + 方案 4(新增 API 别名);否则 → 方案 3 + 方案 4(新增 API 别名)→ 方案 1 + 方案 4(新增 API 别名)→ 方案 4(新增 Python 层 API) | -| 分类 7, 8 | 方案 3 + 方案 4(新增 API 别名)→ 方案 1 + 方案 4(新增 API 别名)→ 方案 4(新增 Python 层 API) | -| 分类 9 | 方案 4(新增 Python 层 API) | -| 分类 11 | 无需修改 | +``` +API 路径不一致 + │ + ├──→ 1. API 完全一致 → 方案 4(新增 API 别名)→ 得到方案 + │ + ├──→ 2. 仅 API 调用方式不一致 → 方案 4(新增 API 别名)→ 得到方案 + │ + ├──→ 3. 仅参数名不一致 → 满足方案 2 条件? + │ ├──→ 是 → 方案 2(C++ 下沉)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 方案 1(Python 装饰器)+ 方案 4(新增 API 别名)→ 得到方案 + │ + ├──→ 4. paddle 参数更多 → 是否影响对齐? + │ ├──→ 否 → 无需修改 → 得到方案 + │ └──→ 是 → 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 方案 4(新增 Python 层 API)→ 得到方案 + │ + ├──→ 5. 参数默认值不一致 → 是否影响对齐? + │ ├──→ 否 → 无需修改 → 得到方案 + │ └──→ 是 → 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 方案 4(新增 Python 层 API)→ 得到方案 + │ + ├──→ 6. torch 参数更多 + │ │ + │ ├──→ 仅多 out 参数 → 满足方案 2 条件? + │ │ ├──→ 是 → 方案 2(C++ 下沉)+ 方案 4(新增 API 别名)→ 得到方案 + │ │ └──→ 否 → 方案 3(修改原有 API,新增 out 参数)+ 方案 4(新增 API 别名)→ 得到方案 + │ │ + │ └──→ 多其他参数(非仅 out)→ 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 满足方案 1 条件? + │ ├──→ 是 → 方案 1(Python 装饰器)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 方案 4(新增 Python 层 API)→ 得到方案 + │ + ├──→ 7. 输入参数用法不一致 → 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 满足方案 1 条件? + │ ├──→ 是 → 方案 1(Python 装饰器)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 方案 4(新增 Python 层 API)→ 得到方案 + │ + ├──→ 8. 输入参数类型不一致 → 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 满足方案 1 条件? + │ ├──→ 是 → 方案 1(Python 装饰器)+ 方案 4(新增 API 别名)→ 得到方案 + │ └──→ 否 → 方案 4(新增 Python 层 API)→ 得到方案 + │ + ├──→ 9. 返回参数类型不一致 → 方案 4(新增 Python 层 API)→ 得到方案 + │ + ├──→ 10. 组合替代实现 → 方案 4(新增 Python 层 API)→ 得到方案 + │ + ├──→ 11. 可删除 → 无需修改 → 得到方案 + │ + ├──→ 12. API 别名 → 方案 4(新增 API 别名)→ 得到方案 + │ + └──→ 13. 功能缺失 → 方案 4(新增 Python 层 API 或 C++ 算子)→ 得到方案 +``` -**决策表 B:路径一致** +**决策流程图 B:路径一致** -| 差异分类 | 决策链(→ 备选) | -|----------|------------------| -| 分类 1, 11 | 无需修改 | -| 分类 3 | 方案 2 → 方案 1 | -| 分类 4, 5 | 不影响对齐 → 无需修改;否则 → 方案 3 → 方案 5 | -| 分类 6 | 仅多 out 且满足方案 2 条件 → 方案 2;否则 → 方案 3 → 方案 1 → 方案 5 | -| 分类 7, 8 | 方案 3 → 方案 1 → 方案 5 | -| 分类 9 | 方案 5 | +``` +API 路径一致 + │ + ├──→ 1. API 完全一致 → 无需修改 → 得到方案 + │ + ├──→ 2. 仅 API 调用方式不一致 → 不可能出现(路径一致时此分类不存在) + │ + ├──→ 3. 仅参数名不一致 → 满足方案 2 条件? + │ ├──→ 是 → 方案 2(C++ 下沉)→ 得到方案 + │ └──→ 否 → 方案 1(Python 装饰器)→ 得到方案 + │ + ├──→ 4. paddle 参数更多 → 是否影响对齐? + │ ├──→ 否 → 无需修改 → 得到方案 + │ └──→ 是 → 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)→ 得到方案 + │ └──→ 否 → 方案 5(新增 compat 类型 API)→ 得到方案 + │ + ├──→ 5. 参数默认值不一致 → 是否影响对齐? + │ ├──→ 否 → 无需修改 → 得到方案 + │ └──→ 是 → 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)→ 得到方案 + │ └──→ 否 → 方案 5(新增 compat 类型 API)→ 得到方案 + │ + ├──→ 6. torch 参数更多 + │ │ + │ ├──→ 仅多 out 参数 → 满足方案 2 条件? + │ │ ├──→ 是 → 方案 2(C++ 下沉)→ 得到方案 + │ │ └──→ 否 → 方案 3(修改原有 API,新增 out 参数)→ 得到方案 + │ │ + │ └──→ 多其他参数(非仅 out)→ 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)→ 得到方案 + │ └──→ 否 → 满足方案 1 条件? + │ ├──→ 是 → 方案 1(Python 装饰器)→ 得到方案 + │ └──→ 否 → 方案 5(新增 compat 类型 API)→ 得到方案 + │ + ├──→ 7. 输入参数用法不一致 → 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)→ 得到方案 + │ └──→ 否 → 满足方案 1 条件? + │ ├──→ 是 → 方案 1(Python 装饰器)→ 得到方案 + │ └──→ 否 → 方案 5(新增 compat 类型 API)→ 得到方案 + │ + ├──→ 8. 输入参数类型不一致 → 满足方案 3 条件? + │ ├──→ 是 → 方案 3(修改原有 API)→ 得到方案 + │ └──→ 否 → 满足方案 1 条件? + │ ├──→ 是 → 方案 1(Python 装饰器)→ 得到方案 + │ └──→ 否 → 方案 5(新增 compat 类型 API)→ 得到方案 + │ + ├──→ 9. 返回参数类型不一致 → 方案 5(新增 compat 类型 API)→ 得到方案 + │ + ├──→ 10. 组合替代实现 → 不可能出现(路径一致时此分类不存在) + │ + ├──→ 11. 可删除 → 无需修改 → 得到方案 + │ + ├──→ 12. API 别名 → 不可能出现(路径一致时此分类不存在) + │ + └──→ 13. 功能缺失 → 不可能出现(路径一致时此分类不存在) +``` ### 3.3 多差异分类组合决策 -当 API 存在多个差异分类时,**逐个差异分类独立查表,再合并方案**。 +当 API 存在多个差异分类时,**逐个差异分类独立查决策流程图,再合并方案**。 -**步骤 1**:遍历每个差异分类,根据决策表独立查表得到对应方案。 +**合并规则**: -**步骤 2**:对多个方案执行合并。 - -| 规则 | 判断条件 | 操作 | -|------|----------|------| +| 规则 | 条件 | 操作 | +|------|------|------| | 去重 | 多个差异分类对应相同方案 | 只保留一个 | | 互斥 | 方案 2 与方案 1 同时出现 | 仅保留方案 2 | | 组合 | 不同方案且不互斥 | 按编号升序,用 `+` 连接 | -**步骤 3**:输出最终组合方案。 - **示例**: -| API | 差异分类 | 查表结果 | 合并结果 | +| API | 差异分类 | 查流程图结果 | 合并结果 | |-----|----------|----------|----------| -| torch.atan | 分类 3 + 分类 6 | 分类 3 → 方案 2;分类 6 → 方案 2 | 方案 2(去重) | -| torch.logspace | 分类 3 + 分类 6 | 分类 3 → 方案 1;分类 6 → 方案 3 | 方案 3 + 方案 1 | -| torch.histc | 分类 2 + 分类 6 + 分类 9 | 分类 2 → 方案 4;分类 6 → 方案 4;分类 9 → 方案 4 | 方案 4(去重) | +| torch.atan | 参数名不一致 + torch 参数更多(仅多 out 参数) | 参数名不一致 → 方案 2;torch 参数更多(仅多 out 参数) → 方案 2 | 方案 2(去重) | +| torch.logspace | 参数名不一致 + torch 参数更多 | 参数名不一致 → 方案 1;torch 参数更多 → 方案 3 | 方案 3 + 方案 1 | # 三、输出要求 @@ -298,14 +411,14 @@ python -c "import paddle; paddle.Tensor.addmv_" # AttributeError → 路径不 **差异分析** - API 路径一致性:一致 -- 差异分类:参数名不一致 + torch 参数更多 +- 差异分类:参数名不一致 + torch 参数更多(仅多 out 参数) - 具体差异: - 参数名映射:`input → x` - 额外参数:torch 多出 `out` **方案决策** - 选择方案:方案 2(C++ 下沉) -- 决策依据:API 路径一致;仅参数名不同 + 多 out 参数,且满足 C++ 下沉全部条件。 +- 决策依据:API 路径一致;差异为"参数名不同 + 仅多 out 参数",满足方案 2 条件 3;且满足 C++ 下沉全部其他条件(调用 `_C_ops.atan`、无其他 Paddle API 调用、无复杂前处理)。 ``` **示例 2:组合方案** @@ -320,7 +433,7 @@ python -c "import paddle; paddle.Tensor.addmv_" # AttributeError → 路径不 **差异分析** - API 路径一致性:一致 -- 差异分类:参数名不一致 + torch 参数更多 +- 差异分类:参数名不一致 + torch 参数更多(多 out/device/requires_grad 等参数) - 具体差异: - 参数名映射:`end → stop, steps → num` - 额外参数:torch 多出 `out, device, requires_grad` @@ -328,7 +441,7 @@ python -c "import paddle; paddle.Tensor.addmv_" # AttributeError → 路径不 **方案决策** - 选择方案:方案 3 + 方案 1 - 决策依据:API 路径一致;新增 out/device/requires_grad 参数可保持后向兼容;参数名差异需通过装饰器适配。 -- 组合说明:方案 3 处理 torch 参数更多;方案 1 处理参数名不一致。 +- 组合说明:方案 3 处理 torch 参数更多(新增参数);方案 1 处理参数名不一致。 ``` # 四、注意事项 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-compatibility/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-compatibility/SKILL.md index e8414dab220..3d76ccafbfe 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-compatibility/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-compatibility/SKILL.md @@ -6,110 +6,12 @@ allowed-tools: Read Write Edit Bash Glob Grep Agent Skill WebFetch WebSearch # 一、项目目标 -**使 Paddle API 与 PyTorch API 完全对齐**,实现: +用户提供待对齐的 Pytorch API 列表 $ARGUMENTS,通过调用多个 skill,使 Paddle API 与 PyTorch API 完全对齐,实现: - 对于任意 PyTorch API 用法,只需将 `torch.*` 替换为 `paddle.*` - 计算结果完全一致(数值精度、行为逻辑) -# 二、输入输出规范 - -## 2.1 输入 - -用户提供待对齐的 Pytorch API 列表,格式如下: -```markdown -torch.argmax -torch.log2 -torch.logsumexp -``` - -本轮用户输入的 Pytorch API 为$ARGUMENTS,需对其完成对齐工作。 - -## 2.2 输出 - -用户输入列表的对齐情况,格式示例: -```markdown -# API 对齐结果统计 - -|API 名称|对齐状态|改动方案|备注| -|-|-|-|-| -|torch.argmax|已对齐|方案 2|-| -|torch.log2|已对齐|无需改动|<简介为何无需改动>例如:未查询到差异文件,两者 API 完全一致| -|torch.logsumexp|未对齐|方案 1|<简介失败原因>例如:方案 1 暂不支持修改| -``` - -# 三、背景知识 - -### 3.1 工作目录说明 - -**ROOT_DIR 变量定义**: -- `${ROOT_DIR}` 表示项目的根工作目录(如 `/workspace`),通常为包含 `Paddle`、`PaConvert`、`docs` 子目录的父目录 -- **路径规则**:含 `${ROOT_DIR}` 为绝对路径,不含则为相对于根目录的相对路径,需自行展开 - -| 工作目录 | 完整路径 | 内容说明 | 对应步骤 | -|---------|---------|---------|---------------| -| Paddle | `${ROOT_DIR}/Paddle` | Paddle 框架源码仓库,包含所有 Paddle API 的实现 | Step2:代码修改 + Step3:兼容测试 | -| PaConvert | `${ROOT_DIR}/PaConvert` | PyTorch 转换工具仓库,包含所有 Pytorch 单元测试 | Step4:对齐验证 | -| docs | `${ROOT_DIR}/docs` | Paddle 文档仓库,包含所有 Paddle API 中文文档 | Step5:文档更新 | - - -### 3.2 相关文件位置 - -|**功能模块**|**检索关键字**|**文件路径**|**举例**|**注意**| -|-|-|-|-|-| -|API 中文文档|`{api_name}_cn.rst`|`${ROOT_DIR}/docs/docs/api/paddle/`|tan_cn.rst|| -|API 差异文档|`torch.{api_name}.md`|`${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/`下一级目录|torch.tan.md|| -|C++下沉使用|`python_api_info.yaml`、`ops.yaml`|`${ROOT_DIR}/Paddle/paddle/phi/ops/yaml/`|python_api_info.yaml、ops.yaml|| -|C++下沉使用|`_paddle_docs.py`|`${ROOT_DIR}/Paddle/python/paddle/`|_paddle_docs.py|| -|Paddle API 实现位置|`def {api_name}` 或 `class {api_name}`|`${ROOT_DIR}/Paddle/python/paddle/*/`|`${ROOT_DIR}/Paddle/python/paddle/tensor/math.py`|不要误检索到 sparse 目录下(稀疏 API 位置),本项目与稀疏无关,所有 sparse 相关文件直接忽略| -|Paddle API 兼容性单测位置|`test_api_compatibility_part[1-9]\.py`|`${ROOT_DIR}/Paddle/test/legacy_test/`|test_api_compatibility_part3.py|| -|Pytorch API 单测位置|`test_{api_name}.py`|`${ROOT_DIR}/PaConvert/tests/`|test_tan.py|| - -### 3.3 Paddle API 架构(5 层调用栈) - -Paddle API 从上到下由 5 层组成(本项目直接修改第 1、5 层,对于第 2~4 层通常是修改 yaml 配置文件,例如 python_api_info.yaml): - -| 层级 | 名称 | 语言 | 文件位置 | 功能说明 | 是否修改 | -|------|------|------|----------|----------|----------| -| 1 | Python 层 | Python | `*.py` | API 的 Python 接口定义 | ✅ **修改** | -| 2 | Pybind 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/fluid/pybind/eager_op_function.cc`)| Python 与 C++的绑定层 | ✅ **修改 yaml 配置来实现修改** | -| 3 | Dygraph 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/fluid/eager/.../dygraph_functions.cc`)| 前反向传播组合 | ❌ 通常不改 | -| 4 | C++ API 层 | C++ | 根据`*.yaml`自动生成(`${ROOT_DIR}/Paddle/paddle/phi/api/lib/api.cc`) | Kernel 选择调度 | ❌ 通常不改 | -| 5 | Kernel 层 | C++ | `${ROOT_DIR}/Paddle/paddle/phi/kernels/` | 实际计算逻辑实现 | ✅ **修改** | - -**示例 API 层级**: -```python -# Layer 1: Python 层 -def atan(x: Tensor, name: str | None = None) - -# Layer 2: Pybind 层(根据 ops.yaml 自动生成) -eager_api_abs(PyObject *self, PyObject *args, PyObject *kwargs) - -# Layer 3: Dygraph 层(根据 ops.yaml 自动生成) -paddle::Tensor atan_ad_func(const paddle::Tensor& x, ...) - -# Layer 4: C++ API 层(根据 ops.yaml 自动生成) -Tensor atan(const Tensor& x, ...) - -# Layer 5: Kernel 层 -void AtanKernel(const Context& dev_ctx, const DenseTensor& x, DenseTensor* out) -``` - -### 3.4 专业术语表 - -| 术语 | 定义 | 备注 | -|------|------|------| -| PyTorch | 深度学习框架,导入模块为`torch` | - | -| Paddle | 飞桨深度学习框架,导入模块为`paddle` | - | -| API | 应用程序接口 | 既可以是一个 Python 函数,也可以是一个 Python 类 | -| API 完整路径 | API 完整路径 | 如`torch.nn.functional.dropout`、`paddle.nn.functional.dropout`| -| API 路径 | API 完整路径在去掉框架导入模块(torch/paddle)后剩余的部分| 如`nn.functional.dropout` | -| PyTorch API | `torch.*` 系列接口 | 约 2000+个 API,是本项目的**对齐标准**| -| Paddle API | `paddle.*` 系列接口 | 约 2000+个 API,是本项目的**修改对象** | -| API 对齐 | 使两个 API 的行为完全对齐一致 | 对齐包括 API 路径、输入参数、返回值、计算逻辑等| -| API 中文文档 | 中文描述了该 API 的功能与行为 | 位于 `${ROOT_DIR}/docs/docs/api/paddle/` 目录,命名类似 tan_cn.rst | -| API 差异文档 | 中文描述了 Pytorch API 与 Paddle API 两者的行为差异 | 位于 `${ROOT_DIR}/docs/docs/guides/model_convert/convert_from_pytorch/api_difference/` 下一级子目录,命名类似 torch.tan.md | -| compat 类型 API | 兼容性 API | 为保持后向兼容而添加的 API,能实现除 API 路径之外的完全对齐| - -### 3.5 类方法 API 实现原理 +# 二、背景知识 +## 类方法 API 实现原理 **概念**:类方法 API(如 `torch.Tensor.abs`)和普通 API(如 `torch.abs`)是不同 API,但实现一致,合并处理即可。Paddle 通过 patch 机制将方法动态添加到 Tensor 类上。 @@ -162,7 +64,44 @@ tensor_method_func = [ - ✅ 在 patch 文件中搜索,或搜索对应的普通方法 `def abs(` - ❌ 不要搜索 `class Tensor`(方法通过 setattr 动态添加,不在类定义中) -### 3.6 API 信息获取方式 + +## Inplace API 实现原理 + +**概念说明**: +- 注意要区分**inplace API**和**非 inplace API**,两者是不同的 API,不要混为一谈 +- **inplace API**(如`torch.abs_`):原地操作,直接修改输入 Tensor,其不应有 out 参数,如有 out 需删除 +- **非 inplace API**(如`torch.abs`):返回新 Tensor,不修改输入 Tensor +- Inplace API 无需测试静态图,只需测试动态图 + +**示例对比**: +```python +y = paddle.abs(x) # 非 inplace:返回新 Tensor,x 不变 +x.abs_() # inplace:原地修改 x +``` + +**自动生成机制**: +Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当定义了`inplace: (x -> out)`字段后,系统自动生成对应的 inplace 版本,复用原 API 的 Kernel 实现。 + +**配置示例**: +1. **OP 配置**(`ops.yaml`,第 10-22 行): +```yaml +- op : abs + args : (Tensor x) + output : Tensor(out) + inplace: (x -> out) # 关键字段:指定 x 和 out 可以 in-place + backward : abs_grad +``` + +2. **Python API 配置**(`python_api_info.yaml`,第 6-9 行): +- ⚠️ **仅在 C++下沉(方案 2)时需要配置** +```yaml +- op : abs_ + name : [paddle.abs_, paddle.Tensor.abs_] + args_alias : + use_default_mapping : True +``` + +## API 信息获取方式 在开展 API 对齐工作过程中,需要获取 PyTorch API 和 Paddle API 的相关信息。 @@ -201,66 +140,8 @@ x = paddle.to_tensor([1.0, -2.0, 3.0]) print(paddle.abs(x)) ``` -### 3.7 Inplace API 实现原理 - -**概念说明**: -- 注意要区分**inplace API**和**非 inplace API**,两者是不同的 API,不要混为一谈 -- **inplace API**(如`torch.abs_`):原地操作,直接修改输入 Tensor,其不应有 out 参数,如有 out 需删除 -- **非 inplace API**(如`torch.abs`):返回新 Tensor,不修改输入 Tensor -- Inplace API 无需测试静态图,只需测试动态图 - -**示例对比**: -```python -y = paddle.abs(x) # 非 inplace:返回新 Tensor,x 不变 -x.abs_() # inplace:原地修改 x -``` - -**自动生成机制**: -Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当定义了`inplace: (x -> out)`字段后,系统自动生成对应的 inplace 版本,复用原 API 的 Kernel 实现。 - -**配置示例**: -1. **OP 配置**(`ops.yaml`,第 10-22 行): -```yaml -- op : abs - args : (Tensor x) - output : Tensor(out) - inplace: (x -> out) # 关键字段:指定 x 和 out 可以 in-place - backward : abs_grad -``` - -2. **Python API 配置**(`python_api_info.yaml`,第 6-9 行): -- ⚠️ **仅在 C++下沉(方案 2)时需要配置** -```yaml -- op : abs_ - name : [paddle.abs_, paddle.Tensor.abs_] - args_alias : - use_default_mapping : True -``` - -# 四、整体工作流程 - -## 流程重要约束 -1. 接收用户输入的待对齐 API 列表(如 `torch.argmax`, `torch.log2`, `torch.logsumexp`) -2. **批量处理模式**:依次执行,每个 Step 结束后才进入下一个 Step - - Step1:对**所有 API**进行方案决策 - - Step2:对**所有 API**进行代码修改 - - Step3:对**所有 API**进行兼容测试 - - Step4:对**所有 API**进行对齐验证 - - Step5:对**所有 API**进行文档更新 -3. **流程正向推进原则** - - 正常情况下必须遵循 Step1 → Step2 → Step3 → Step4 → Step5 的顺序 - - 每个步骤完成后,才能进入下一步骤,禁止跳过任何步骤 -4. **异常回退原则** - - 当 Step3 或 Step4 无法通过时 - - 需要根据错误信息诊断问题根源: - * 若判断为方案选择错误 → 回退到 Step1 重新决策 - * 若判断为代码实现有误 → 回退到 Step2 调整实现方式 - - 回退后需从该步骤重新按流程向前推进,例如回退到 Step2,则重新执行 Step2 → Step3 → Step4 → Step5 -5. **允许放弃部分 API**(合理分配精力,最大化成功率): - - 当某个 API 异常回退 3 次以上仍无法通过,则放弃该 API,在最终对齐结果统计表中标记该 API 为"未对齐",并简要说明放弃原因 - - ⚠️ 必须完整回退该 API 的所有修改,确保项目处于干净状态,不得保留任何 API"修改了但没改对"的中间状态 -6. 所有 API 都完成 5 个步骤(除被放弃外)后,任务结束 +# 三、整体工作流程 ## 流程概览 ``` 输入 API 列表 → Step1:所有 API 方案决策 → Step2:所有 API 代码修改 → Step3:所有 API 兼容测试 → Step4:所有 API 对齐验证 → Step5:所有 API 文档更新 → 全部完成(流程全自动推进,不用询问) @@ -292,16 +173,37 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 #### 方案 5:新增 compat 类型 API(调用 `/add-new-compat-api` skill) ### Step 3:兼容测试(调用 `/add-compatibility-test` skill) - Step 3.1: 编写测试用例(仅首次执行) - Step 3.2: 编译并运行(每次改动均需执行) + Step 3.1: 编写测试用例 + Step 3.2: 编译并运行单测(每次修改代码均需执行编译) ### Step 4:对齐验证(调用 `/pytorch-alignment-validator` skill) - Step 4.1: 标记已完成的 API(仅首次执行) - Step 4.2: 增加测试用例(仅首次执行) - Step 4.3: 运行单元测试(每次改动均需执行) + Step 4.1: 标记已完成的 API + Step 4.2: 增加测试用例 + Step 4.3: 编译并运行单测(每次修改代码均需执行编译) ### Step 5:文档更新(调用 `/api-docs-updater` skill) +## 流程重要约束 +1. 接收用户输入的待对齐 API 列表(如 `torch.argmax`, `torch.log2`, `torch.logsumexp`) +2. **批量处理模式**:依次执行,每个 Step 结束后才进入下一个 Step + - Step1:对**所有 API**进行方案决策 + - Step2:对**所有 API**进行代码修改 + - Step3:对**所有 API**进行兼容测试 + - Step4:对**所有 API**进行对齐验证 + - Step5:对**所有 API**进行文档更新 +3. **流程正向推进原则** + - 正常情况下必须遵循 Step1 → Step2 → Step3 → Step4 → Step5 的顺序 + - 每个步骤完成后,才能进入下一步骤,禁止跳过任何步骤 +4. **异常回退原则** + - 当 Step3 或 Step4 无法通过时,则需要执行回退(Step3 的通过标准是单测可运行通过,Step4 的通过标准是 API 可配置为 ChangePrefixMatcher): + * 若判断为方案选择错误 → 回退到 Step1 重新决策 + * 若判断为代码实现有误 → 回退到 Step2 调整实现方式 + - 回退后需从该步骤重新按流程向前推进,例如回退到 Step2,则重新执行 Step2 → Step3 → Step4 → Step5 +5. **允许放弃部分 API**(合理分配精力,最大化成功率): + - 当某个 API 异常回退 3 次以上仍无法通过,则放弃该 API,在最终对齐结果统计表中标记该 API 为"未对齐",并简要说明放弃原因 + - 必须完整回退该 API 的所有修改,确保项目处于干净状态,不得保留任何 API"修改了但没改对"的中间状态 +6. 所有 API 都完成 5 个步骤(除被放弃外)后,任务结束 + ## 工作示例 假设待对齐 API 为 `torch.argmax`: @@ -314,20 +216,9 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 5. Step5: 文档更新 → 修改 docs 目录文件,更新 paddle.argmax 文档 ``` -# 五、编程风格指南 - -- 最小化注释;保持简洁;代码应当自解释、自文档化。 -- 注释应有实际价值,例如提醒读者一些非显而易见、无法从局部推断的全局背景。 -- 不要为只使用一次的简短逻辑(1-2 行)创建辅助函数,除非能显著提升代码可读性。 -- 优先使用清晰的抽象,状态管理应当显式。例如,在 Python 类中管理状态时,应有明确的类定义并列出所有成员,不要在对象上动态 setattr 字段后再动态 getattr。 -- 与现有代码风格和架构模式保持一致。 -- 假定读者熟悉 Paddle。他们不一定是所读代码的专家,但应具备该领域的一定经验。 -- 新增代码注释仅使用 ASCII 字符,不引入 Unicode 字符(如弯引号、破折号、箭头、非 ASCII 字母)。对未改动注释中已有的 Unicode 保持原样,仅对新增或改写的注释执行此规则。 -- 如有不确定,选择更简单、更简洁的实现。 - -# 六、各 Skill 说明 +# 四、各 Skill 说明 -## 6.1 总控 Skill:api-compatibility(本文件) +## 总控 Skill:api-compatibility(本文件) **功能定位**: - 本文件(`api-compatibility`)是项目的**总控 skill**,负责整体统筹规划 @@ -343,7 +234,7 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 - 本项目专用 skill 为下表所列的子 skill - 优先使用本项目专用 skill,确保流程一致性和可控性,除非其无法完成任务,否则**尽量不调用其他 skill** -## 6.2 项目专用 Skill 列表 +## 项目专用 子 Skill 列表 | Skill | 对应步骤 | |-------|--------| @@ -357,7 +248,7 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 | `/pytorch-alignment-validator` | Step4:对齐验证 | | `/api-docs-updater` | Step5:文档更新 | -# 七、自进化机制 +# 五、自进化机制 **本项目涉及的所有 skill 均具备自进化能力**,通过持续学习和优化来提升工作质量。修改的 SKILL 目录为:`${ROOT_DIR}/docs/docs/dev_guides/coding_agent/api_compatibility/.claude/skills` @@ -376,21 +267,36 @@ Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当 - 禁止在 SKILL 中添加任何网络代理的内容,以免安全信息泄露 - 禁止在代码中编写任何网络代理的内容,以免安全信息泄露 -# 八、注意事项 +# 六、常见问题处理 -1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 +### Q1:API 别名如何管理? -# 九、常见问题处理 +统一放在 `__init__.py` 的 "API alias" 区块,不要在 `math.py` 等实现文件中定义。 -### Q1:为什么有些 API 对齐失败? +**涉及文件**: +- `paddle/tensor/__init__.py` +- `paddle/__init__.py` -**常见原因**: +**示例**(正确做法): +```python +# 在 __init__.py 的 "API alias" 区块 +fix = trunc +fix_ = trunc_ +mod = remainder +``` + +**注意**:定义别名后,需从 `from .math import` 中移除该别名,避免导入错误。 -1. **差异分析阶段失败**:未查询到差异文档或转写配置 -2. **方案决策阶段失败**:选择的方案不适用或后向兼容性问题 -3. **代码修改阶段失败**:装饰器实现问题或 C++ 下沉编译错误 -4. **验证阶段失败**:Paddle API 实现与 PyTorch 计算结果不一致 +### Q2:Inplace API 如何实现? -**处理办法**: -- 查看具体错误信息,返回相应 Step 重新处理 -- 使用调试技巧逐步排查问题 +内部所有操作都必须使用 inplace 方法(`scale_`、`add_` 等),不能用 `*`、`+` 等非 inplace 操作。 + +**错误**: +```python +mv_result = mv_result * alpha # 创建新 tensor +``` + +**正确**: +```python +mv_result.scale_(alpha) # inplace 修改 +``` diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-docs-updater/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-docs-updater/SKILL.md index 97f74b0e167..ad2a9121efb 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-docs-updater/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/api-docs-updater/SKILL.md @@ -40,6 +40,9 @@ Step 3. **更新中文文档与英文一致** - 别名格式完全相同 - Overload 说明内容对应 - out 参数描述对齐 +6. **文档描述原则** + - 不要在文档中特别强调"PyTorch 风格"或"PyTorch 签名" + - 参数别名说明只需简单注明"别名 xxx" # 四、常见修改模式 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/cpp-sink/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/cpp-sink/SKILL.md index 71c3607e3d9..f55981afbb5 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/cpp-sink/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/cpp-sink/SKILL.md @@ -1,6 +1,7 @@ --- name: cpp-sink description: 负责《Paddle API 对齐 PyTorch 项目》中 Step2:API 代码修改,实施『C++下沉』方案。通过将 Python API 下沉至 C++层,可以减少 Python 装饰器带来的性能开销,提升 API 调度效率。 +context: fork disable-model-invocation: false --- diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/create-pr/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/create-pr/SKILL.md index df6c440208c..23f948cd3d3 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/create-pr/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/create-pr/SKILL.md @@ -23,21 +23,17 @@ disable-model-invocation: false ## Step 1:确认 PyTorch API 名单 -**此步骤必须在所有后续操作之前完成**,因为 API 名单将用于 commit message 和 PR title/body。 - 从以下各个渠道获取 API 名单并取并集: -### 渠道 1:从上下文获取 - -从 api-change-decider、python-decorator、cpp-sink 等前序步骤的上下文中自动提取 API 名单。 - -### 渠道 2:从用户输入获取 +### 渠道 1:从上下文或用户输入获取 -用户直接提供 PyTorch API 名单,例如:`torch.relu`、`torch.sigmoid`、`torch.tanh` 等。 +从以下来源获取 API 名单: +- **从上下文获取**:从 api-change-decider、python-decorator、cpp-sink 等前序步骤的上下文中自动提取 API 名单 +- **从用户输入获取**:用户直接提供 PyTorch API 名单,例如:`torch.relu`、`torch.sigmoid`、`torch.tanh` 等 -### 渠道 3:从仓库改动分析获取 +### 渠道 2:从仓库改动分析获取 -若渠道 1 和 2 均无法获取,则分析仓库改动: +直接分析仓库代码改动: ```bash # 从 Paddle 仓库分析 @@ -177,9 +173,9 @@ Improvements ### Description **API Compatibility Edit By AI Agent:** - torch.api_name_1 - torch.api_name_2 - ... +- `torch.api_name_1` +- `torch.api_name_2` +- ... ### 是否引起精度变化 否 @@ -191,11 +187,11 @@ gh pr edit {docs_pr_number} --repo PaddlePaddle/docs \ --title "[API Compatibility] api_name_1/api_name_2/api_name_3/... Edit By AI Agent" \ --body "$(cat <<'EOF' **API Compatibility Edit By AI Agent:** - torch.api_name_1 - torch.api_name_2 - ... +- `torch.api_name_1` +- `torch.api_name_2` +- ... -- https://github.com/PaddlePaddle/Paddle/pull/{paddle_pr_number} +https://github.com/PaddlePaddle/Paddle/pull/{paddle_pr_number} EOF )" @@ -205,15 +201,15 @@ gh pr edit {paconvert_pr_number} --repo PaddlePaddle/PaConvert \ --title "[API Compatibility] api_name_1/api_name_2/api_name_3/... Edit By AI Agent" \ --body "$(cat <<'EOF' ### PR Docs -- https://github.com/PaddlePaddle/docs/pull/{docs_pr_number} +https://github.com/PaddlePaddle/docs/pull/{docs_pr_number} ### PR APIs **API Compatibility Edit By AI Agent:** - torch.api_name_1 - torch.api_name_2 - ... +- `torch.api_name_1` +- `torch.api_name_2` +- ... -- https://github.com/PaddlePaddle/Paddle/pull/{paddle_pr_number} +https://github.com/PaddlePaddle/Paddle/pull/{paddle_pr_number} EOF )" @@ -225,7 +221,7 @@ EOF ```bash # ===== Paddle PR 创建(无依赖,先创建) ===== -gh pr create --repo PaddlePaddle/Paddle --base develop --head zhwesky2010:claude \ +gh pr create --repo PaddlePaddle/Paddle --base develop --head zhwesky20:claude \ --title "[API Compatibility] api_name_1/api_name_2/api_name_3/... Edit By AI Agent" \ --body "$(cat <<'EOF' ### PR Category @@ -236,9 +232,9 @@ Improvements ### Description **API Compatibility Edit By AI Agent:** - torch.api_name_1 - torch.api_name_2 - ... +- `torch.api_name_1` +- `torch.api_name_2` +- ... ### 是否引起精度变化 否 @@ -247,34 +243,34 @@ EOF # 记录返回的 PR 号作为 paddle_pr_number # ===== Docs PR 创建(依赖 Paddle PR 号) ===== -gh pr create --repo PaddlePaddle/docs --base develop --head zhwesky2010:claude \ +gh pr create --repo PaddlePaddle/docs --base develop --head zhwesky20:claude \ --title "[API Compatibility] api_name_1/api_name_2/api_name_3/... Edit By AI Agent" \ --body "$(cat <<'EOF' **API Compatibility Edit By AI Agent:** - torch.api_name_1 - torch.api_name_2 - ... +- `torch.api_name_1` +- `torch.api_name_2` +- ... -- https://github.com/PaddlePaddle/Paddle/pull/{paddle_pr_number} +https://github.com/PaddlePaddle/Paddle/pull/{paddle_pr_number} EOF )" # 记录返回的 PR 号作为 docs_pr_number # ===== PaConvert PR 创建(依赖 Docs 和 Paddle PR 号) ===== -gh pr create --repo PaddlePaddle/PaConvert --base master --head zhwesky2010:claude \ +gh pr create --repo PaddlePaddle/PaConvert --base master --head zhwesky20:claude \ --title "[API Compatibility] api_name_1/api_name_2/api_name_3/... Edit By AI Agent" \ --body "$(cat <<'EOF' ### PR Docs -- https://github.com/PaddlePaddle/docs/pull/{docs_pr_number} +https://github.com/PaddlePaddle/docs/pull/{docs_pr_number} ### PR APIs **API Compatibility Edit By AI Agent:** - torch.api_name_1 - torch.api_name_2 - ... +- `torch.api_name_1` +- `torch.api_name_2` +- ... -- https://github.com/PaddlePaddle/Paddle/pull/{paddle_pr_number} +https://github.com/PaddlePaddle/Paddle/pull/{paddle_pr_number} EOF )" diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/modify-origin-api/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/modify-origin-api/SKILL.md index 98254de457f..52ff2ec4c1c 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/modify-origin-api/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/modify-origin-api/SKILL.md @@ -1,6 +1,7 @@ --- name: modify-origin-api description: 负责《Paddle API 对齐 PyTorch 项目》中 Step2:API 代码修改,实施『修改原有 API』方案。通过修改原有 Paddle API 的实现(新增参数、扩展参数类型/功能),使 Paddle API 与 PyTorch API 行为对齐,同时保持后向兼容性。 +context: fork disable-model-invocation: false --- @@ -17,7 +18,7 @@ disable-model-invocation: false ## Step 1:修改 API 代码 -若尚未获得 PyTorch API 的相关信息,则自行获取,获取方式请参考`api-compatibility/SKILL.md` 中的「3.6 API 信息获取方式」章节。 +若尚未获得 PyTorch API 的相关信息,则自行获取,获取方式请参考`api-compatibility/SKILL.md` 中的「API 信息获取方式」内容。 然后分析 PyTorch API 的功能和行为,以及与 Paddle API 的差异。在 `${ROOT_DIR}/Paddle/python/paddle/` 目录下定位到对应的 API 实现位置,修改 Paddle API 的签名和实现代码。 @@ -114,7 +115,7 @@ def func(x, axis=None, name=None, *, out: Tensor | None = None): **注意事项**: 1. 需在 API 签名中增加 out 参数,`out`参数需与 Pytorch 用法一致,一般情况下 out 均是 keyword-only 参数(使用`*,`分隔),少数情况下 out 是位置参数 -2. 处理 out 参数时,仅需处理 in_dynamic_or_pir_mode()分支下的逻辑,老静态图(LayerHelper)分支无需处理 out 参数 +2. 处理 out 参数时,仅需处理 dygraph(动态图)模式下的逻辑,PIR 和老静态图(LayerHelper)分支均无需处理 out 参数 #### 新增 `device` 参数 @@ -283,6 +284,8 @@ if TYPE_CHECKING: 2. **后向兼容性是红线**:任何修改都不得破坏现有调用,新参数必须有合理默认值 3. 若新参数需要透传(如 `randn -> standard_normal -> gaussian`),必须在整个调用链上都添加该参数 4. `math_op_patch.py` 中的 Tensor 方法必须与对应的普通函数保持参数同步,且需同时修改 dygraph 版和 pir 版两个文件 +5. **无需支持的参数**:`layout` 参数无需支持,直接忽略即可 +6. **name 参数忽略原则**:忽略 `name` 参数,新增参数可作为位置参数放在 `name` 之前,不必考虑 `name` 参数对顺序的影响 # 五、常见问题处理 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/python-decorator/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/python-decorator/SKILL.md index 949681acb05..2cdf1f7c492 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/python-decorator/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/python-decorator/SKILL.md @@ -1,6 +1,7 @@ --- name: python-decorator description: 负责《Paddle API 对齐 PyTorch 项目》中 Step2:API 代码修改,实施『Python 装饰器』方案。通过 Python 装饰器,在 Python 层为 Paddle API 实现参数名称、参数顺序、参数类型和参数用法的重载,实现 PyTorch 风格的 API 调用,并保持 Paddle API 的向后兼容性。 +context: fork disable-model-invocation: false --- @@ -429,6 +430,7 @@ if len(args) >= 2 and isinstance(args[1], int): 4. 开发专用装饰器时参考现有实现 5. 代码中不允许提交中文,代码注释采用英文 6. 复盘记忆中的历史易错点,避免重复犯错 +7. **简单别名优先**:仅参数名不同时,使用通用别名装饰器,无需创建专用装饰器 # 五、常见问题处理 diff --git a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/pytorch-alignment-validator/SKILL.md b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/pytorch-alignment-validator/SKILL.md index 2aa1df67987..6542402a311 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/pytorch-alignment-validator/SKILL.md +++ b/docs/dev_guides/coding_agent/api_compatibility/.claude/skills/pytorch-alignment-validator/SKILL.md @@ -8,15 +8,16 @@ disable-model-invocation: false 请严格按以下 Step 依次执行,不要自行修改或跳过 Step: -## Step 1: 标记已完成的 API(仅首次执行) +## Step 1: 标记已完成的 API 1. 定位文件:`${ROOT_DIR}/PaConvert/paconvert/api_mapping.json` 2. 将已完成的 PyTorch API 的 Matcher 设置为`ChangePrefixMatcher`,其他字段全部删除掉 **注意**: - torch.abs、torch.abs_、torch.Tensor.abs、torch.Tensor.abs_是四个不同的 API,需分别标记为 `ChangePrefixMatcher`。 -- ⚠️ **`ChangePrefixMatcher` 是任务最终验收金标准,不可妥协**:只要 API 已完成代码层面的对齐,就必须标记为 `ChangePrefixMatcher`,**绝对禁止**为了让测试通过而将 Matcher 改为其他类型(如 GenericMatcher、SliceScatterMatcher 等)。 +- ⚠️ **`ChangePrefixMatcher` 是 Step4 通过的标准,不可妥协**:只有标记为 `ChangePrefixMatcher`,才能判定 API 已完成代码层面的对齐,**禁止**为了让测试通过而将 Matcher 改为其他类型(如 GenericMatcher、SliceScatterMatcher 等)。 +- 如果配置为 `ChangePrefixMatcher` 无法运行通过单测,则视作未对齐,需执行回退。 -## Step 2: 增加测试用例(仅首次执行) +## Step 2: 增加测试用例 **目的:** 判断是否满足如下测试规范,如不满足,则需增加测试用例使之符合规范 **修改位置:** @@ -121,17 +122,23 @@ def test_case_7(): obj.run(pytorch_code, ["result"]) ``` -## Step 3: 运行单元测试(每次改动均需执行) +## Step 3: 编译并运行单测(每次修改代码均需执行编译) -单测补充完成后,按以下命令验证执行: +单测补充完成后,按以下命令编译并验证执行: ```bash +cd ${ROOT_DIR}/Paddle/build +cmake .. && make -j$(nproc) cd ${ROOT_DIR}/PaConvert/ python -m pytest tests/test_.py ``` 根据报错信息修改测试用例或回退,确保所有测试用例通过。每次修改后均需要重新执行本步骤。 +**编译注意事项**: +- 无需重装,直接生效(勿执行 setup/install 等安装操作) +- 勿删除 build 目录(否则增量编译失效,编译时间极长) + # 二、注意事项 1. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 @@ -142,7 +149,7 @@ python -m pytest tests/test_.py # 三、异常回退原则 -当本步骤(对齐验证)多次尝试仍无法通过时,需要根据错误信息诊断问题根源: +本步骤的通过标准是 API 可配置为 `ChangePrefixMatcher`,若无法配置为 `ChangePrefixMatcher`,则需要根据错误信息回退到对应步骤: 1. **若判断为测试用例编写有误**(如 PyTorch 代码语法错误、参数使用错误): - 直接在本步骤修正测试用例 diff --git a/docs/dev_guides/coding_agent/api_compatibility/README.md b/docs/dev_guides/coding_agent/api_compatibility/README.md index a1531880b35..daa4248a4d1 100644 --- a/docs/dev_guides/coding_agent/api_compatibility/README.md +++ b/docs/dev_guides/coding_agent/api_compatibility/README.md @@ -1,75 +1,72 @@ -# 《Paddle API 兼容性》 智能体规则体系 +# Paddle API 对齐 PyTorch 项目 -## 一、目录概述 +基于 Claude Code 的 AI Agent 自动对齐 Paddle API 与 PyTorch API。 -本目录为《Paddle API 对齐 PyTorch 项目》的 AI 编程规则文件。这些规则文件定义了 AI 智能体在执行 API 对齐任务时的行为准则、工作流程和技术规范。 - -## 二、设计目标 - -本规则体系旨在实现以下目标: - -1. **自动化 API 对齐**:通过 AI 智能体自动完成 PyTorch API 到 Paddle API 的对齐工作 -2. **标准化工作流程**:建立统一、可复用的 API 对齐流程,确保每次对齐的质量一致性 -3. **知识沉淀与复用**:将人工经验转化为可执行的规则,降低人工干预成本 -4. **可追溯的决策过程**:每个 API 的改动方案都有明确的决策依据,便于审查和优化 - -## 三、规则文件说明 - -本目录包含以下规则文件: - -| 文件名称 | 角色 | 职责 | 适用阶段 | -|---------|------|------|---------| -| `0-api-compatibility.mdr` | 主控智能体 | 统筹全流程,调度子智能体 | 全流程 | -| `1-scheme-decision.mdr` | 方案决策智能体 | 分析 API 差异,决策改动方案 | Step1 | -| `2-2-sink-to-cpp.mdr` | Cpp 下沉智能体 | 实施 C++下沉方案 | Step2 | -| `3-paconvert-test.mdr` | Pytorch 对齐验证智能体 | 验证 API 对齐一致性 | Step3 | -| `4-modify-docs.mdr` | API 文档修改智能体 | 同步更新 API 中文文档 | Step4 | - -## 四、工作流程 - -规则体系遵循以下标准工作流程,采用**主控智能体调度 + 子智能体执行**的协作模式: +## 本目录内容 ``` -主控智能体:接收 PyTorch API 列表 - ↓ -主控智能体 → 调用方案决策智能体 (1-scheme-decision.mdr) - ↓ -[决策结果分发,若需 C++下沉] 主控智能体 → 调用 Cpp 下沉智能体 (2-2-sink-to-cpp.mdr) - ↓ -主控智能体 → 调用 Pytorch 对齐验证智能体 (3-paconvert-test.mdr) - ↓ -[验证通过] 主控智能体 → 调用 API 文档修改智能体 (4-modify-docs.mdr) - ↓ -主控智能体:输出对齐结果统计 +api_compatibility/ # 本目录 +├── README.md # 本文件 +├── install.sh # 安装脚本 +└── .claude/ # Claude Code 配置 + ├── CLAUDE.md # 项目背景(自动加载) + └── skills/ # Skill 定义 + ├── api-compatibility/ # 总控 + ├── api-change-decider/ # Step1:方案决策 + ├── python-decorator/ # Step2:Python 装饰器 + ├── cpp-sink/ # Step2:C++下沉 + ├── modify-origin-api/ # Step2:修改原有 API + ├── add-new-api/ # Step2:新增 API + ├── add-new-compat-api/ # Step2:新增 compat API + ├── add-compatibility-test/ # Step3:兼容性测试 + ├── pytorch-alignment-validator/ # Step4:对齐验证 + ├── api-docs-updater/ # Step5:文档更新 + └── create-pr/ # 提交 PR ``` -**协作说明**: -- **主控智能体**:负责任务分解、流程调度、结果汇总和异常处理,确保全流程有序推进 -- **子智能体**:专注各自领域的专业工作(方案决策、代码修改、对齐验证、文档修改),执行具体任务后返回结果 -- **交互方式**:主控智能体通过 subtask 工具调用子智能体,传递必要上下文,接收执行结果并做出下一步决策 - -## 五、设计原则 +## 项目根目录要求 -本规则体系采用**主控智能体 + 子智能体**的协作模式,主控智能体负责任务分解、流程控制和异常处理,子智能体专注具体领域的专业工作。通过决策驱动选择最优改动方案,强调对齐验证的金标准,并要求文档与代码同步更新,确保 API 对齐的高质量和高效率。 +项目根目录(PROJECT_ROOT)需提前准备三个仓库: -## 六、使用方式 - -本规则文件**不能单独使用**,需要搭配 AI 智能体使用,作为 Agent 的指令。AI 智能体读取规则文件中的角色定义、工作流程、技术规范,根据步骤执行具体任务,并按规则处理异常情况。 +``` +{PROJECT_ROOT}/ +├── Paddle/ # Paddle 框架源码 +├── PaConvert/ # PyTorch 转换工具 +├── docs/ # Paddle 文档 +└── CLAUDE.md # 安装后生成 +``` -同时,规则文件也可作为**人工学习的参考资料**,帮助开发者了解 API 对齐的标准流程,包含技术背景知识、代码示例和最佳实践。 +## 安装 -## 七、环境配置要求 +```bash +./install.sh /path/to/PROJECT_ROOT +``` -使用本规则体系需配置好代码目录(Paddle、PaConvert、Docs)、知识语料(API 中文文档和差异文档)以及本地已编译好的 Paddle 环境。 +PROJECT_ROOT 需包含 `Paddle/`、`PaConvert/`、`docs/` 三个子目录。 -## 八、扩展性设计 +## 使用方式 -本规则体系支持扩展,可新增改动方案的规则文件(如 Python 装饰器、修改 API、新增 API 等)、新增其他专业领域的子智能体(如性能优化、兼容性测试、代码审查等)、以及新增其他验证方法(如静态代码分析、性能对比、边界条件验证等)。 +**总控 Skill(推荐)**: +```bash +/api-compatibility torch.atan torch.asinh +``` -## 九、维护规范 +**单独调用 Skill**: +```bash +/api-change-decider torch.atan # Step1: 方案决策 +/cpp-sink torch.atan # Step2: 代码修改 +/add-compatibility-test torch.atan # Step3: 兼容测试 +/pytorch-alignment-validator torch.atan # Step4: 对齐验证 +/api-docs-updater torch.atan # Step5: 文档更新 +/create-pr torch.atan # 提交 PR +``` -规则文件遵循命名规范(主控智能体:`0-{功能}.mdr`,子智能体:`{序号}-{功能}.mdr`),内容需包含角色定义、输入输出规范、技术背景知识、标准工作流程和异常处理等章节。发现规则不完善或有误时,需及时更新,保持一致性和兼容性,重大修改需经评审和测试。 +## 工作流程 ---- +``` +Step1 方案决策 → Step2 代码修改 → Step3 兼容测试 → Step4 对齐验证 → Step5 文档更新 +``` -> 本文档由 AI Agent 自动生成,日期:2025-12-31,提交:zhwesky2010 +## 详细文档 +- [项目背景](.claude/CLAUDE.md) +- [总控 Skill 详细流程](.claude/skills/api-compatibility/SKILL.md) diff --git a/docs/dev_guides/coding_agent/api_compatibility/api-change-decider.md b/docs/dev_guides/coding_agent/api_compatibility/api-change-decider.md deleted file mode 100644 index 8ec52cd7016..00000000000 --- a/docs/dev_guides/coding_agent/api_compatibility/api-change-decider.md +++ /dev/null @@ -1,257 +0,0 @@ ---- -name: API 改动方案决策智能体 -description: 根据 API 差异文档,决策 API 的对齐改动方案 -tools: grep_content, read_file, glob_path, codebase_search, list_dir, write_file, edit_file, run_command ---- - -# 一、角色定义 - -你擅长《Paddle API 对齐 PyTorch 项目》中的**API 改动方案决策**,负责分析 PyTorch API 与 Paddle API 之间的差异,制定合适的 API 改动方案。 - -# 二、输入输出规范 - -## 2.1 输入 -需要对齐的 PyTorch API 列表(如 `torch.atan`、`torch.asinh`) - -## 2.2 输出 -方案类型、对应 Paddle API、差异分类、决策依据(以表格形式展示) - -## 2.3 输出内容 -输出应包含如下内容,以表格式形式展示: -1. **方案类型**:从方案 1~6 中选择合适的方案(可组合多种方案,例如方案 3+方案 1) -2. **对应 Paddle API**:需改动的 Paddle API 完整路径(如 `paddle.nn.functional.dropout`) -3. **差异分类**:差异分类是什么 -4. **决策依据**:总结差异分析过程和选择理由 - - API 相对引用路径是否一致 - - 为什么选择该方案 - - 为什么不选择其他方案 - - 该方案是否会影响后向兼容 - -## 2.4 输出格式示例 -```markdown -# 决策结果 -|Pytorch API|方案类型|Paddle API|差异分类|决策依据| -|-|-|-|-|-| -|torch.atan|方案 2|paddle.atan|torch 参数更多|仅参数名不同(input→x)+仅多 out 参数,Python 实现仅有一次`_C_ops.atan(x)`调用,满足 C++下沉条件,性能最优| -|torch.frexp|方案 3+方案 1|paddle.frexp|torch 参数更多|API 相对引用路径一致,差异为:1)仅参数名不同(input→x);2)仅多 out 参数。当前 Python 实现包含多个 paddle 操作调用(abs、floor、log2 等),逻辑较复杂,不满足 C++下沉条件。选择方案 3 修改 API,在末尾添加 out 参数(带默认值 None),保持后向兼容。同时方案 1 支持参数名不同的重载情况。| -``` - -# 三、候选方案 - -## 方案 1:Python 装饰器 -**适用场景**: -- 在 Python 层添加装饰器实现对齐 -- 可对输入 `(*args, **kwargs)` 进行操作 -- 支持多种重载情况:参数名不同、参数顺序不同、参数个数不同、参数类型不同 -- 同时支持 torch 和 paddle 两套参数签名 - -**工作原理**: -- 根据输入参数的名称、类型、个数的不同来判断是 torch 签名还是 paddle 签名 -- 分别针对两套签名进行不同的功能适配,从而既保留了原本的 paddle 功能,也新增了 torch 功能 -- 这是方案 3(修改 API)的升级版,在保持后向兼容性的前提下实现对齐 - -**核心要求**: -- **必须能够区分**:能够根据输入的参数类型、名称的不同来区分 torch 签名还是 paddle 签名 -- **无法区分则不适用**:如果无法通过输入参数特征区分两套签名,则方案 1 不适用 - -**优点**:灵活性强,兼容性好 -**缺点**:性能低于 C++下沉实现 - -## 方案 2:C++下沉 -**适用场景**: -- 将 API 直接下沉到 C++层 -- Paddle 机制支持在 C++层配置参数映射 -- **支持仅参数名不同的重载情况**(不涉及参数顺序或个数差异) -- **支持仅多 out 参数的情况** -- 方案 2 需要判断 API 的 Python 实现,需满足以下两个条件: - - 只有一次 `_C_ops.xxx` 调用 - - `_C_ops.xxx` 前面没有**前处理逻辑**,或虽有**前处理逻辑**但逻辑简单且不涉及其他 API 调用(如 x.flatten 等),容易改写为 C++ - - 注:分析时忽略静态图部分(LayerHelper 分支代码),该分支不再维护 - -**方案 2 不适用场景(满足其一则不适用)**: -- ❌ API 差异涉及参数顺序或个数差异 -- ❌ Python 实现里调用了其他**Paddle API**,如 x.flatten、paddle.flatten(x)等 -- ❌ 包含多个 `_C_ops.xxx` 调用 -- ❌ `_C_ops.xxx` 前面的**前处理逻辑**较为复杂,不容易被改写为 C++ - -**优点**:性能最优 -**缺点**:仅支持参数名不同的情况 - -## 方案 3:修改 API -**适用场景**: -- 直接修改现有 API 实现对齐 -- 新增参数或功能 -- 修改原有参数或功能 - -**以下修改不会导致后向兼容问题,可开展**: -- ✅ 在 API 参数末尾添加参数,且参数具有默认值 -- ✅ 对已有 API 参数扩展新功能,保留原有功能 - -**以下修改会导致后向兼容问题,需禁止**: -- ❌ 改变已有参数顺序 -- ❌ 改变已有参数名称 -- ❌ 修改返回值类型 - -**优点**:直接对齐,实现简单 -**缺点**:可能导致后向不兼容 - -## 方案 4:新增 API -**适用场景**: -- API 相对引用路径不一致 -- 新增的 API 需要与 Pytorch 完全一致,包括 API 相对引用路径、输入参数与返回值(名称、个数、功能均一致) - -**优点**:完全对齐,无后向兼容问题 - -## 方案 5:新增 compat 类型 API -**适用场景**: -- 在 `paddle/compat/__init__.py` 下新增 API -- 既无法原地修改(后向兼容性问题严重) -- 也无法新增 API(API 相对引用路径已被占用) - -**优点**:无后向兼容问题 -**缺点**:多一级 compat 路径,无法真正实现与 Pytorch 完全一致,实现之后差异分类将成为『仅 API 调用方式不一致』,在无其他方案时可以退而求其次选择 - -## 方案 6:无需改动 -**适用场景**: -- API 完全一致 - -# 四、标准工作流程 - -## Step 1: 分析差异文档 - -### 1.1 获取差异文档 -务必查阅每个 PyTorch API 对应的 API 差异文档(`torch.{api_name}.md`,位于 docs/docs/guides/model_convert/convert_from_pytorch/api_difference/目录下),如果实在无法找到差异文档,则说明该 API 已经实现了对齐一致,差异分类直接视作『API 完全一致』,无需再查询其他内容。 - -### 1.2 差异分类定义 -差异分类共 13 类,具体如下: - -| 序号 | 差异分类 | 说明 | -|:---:|:---|:---| -| 1 | API 完全一致 | 无差异,无需改动 | -| 2 | 仅 API 调用方式不一致 | API 相对引用路径不一致,但参数完全相同 | -| 3 | 仅参数名不一致 | 参数功能相同但参数名称不同 | -| 4 | paddle 参数更多 | Paddle 提供更多可选参数 | -| 5 | 参数默认值不一致 | 参数默认值不同 | -| 6 | torch 参数更多 | PyTorch 提供更多参数 | -| 7 | 输入参数用法不一致 | 参数处理方式不同 | -| 8 | 输入参数类型不一致 | 参数类型要求不同 | -| 9 | 返回参数类型不一致 | 返回值类型或结构不同 | -| 10 | 组合替代实现 | PyTorch API 需多个 Paddle API 组合实现 | -| 11 | 可删除 | PyTorch API 在 Paddle 中可直接删除 | -| 12 | API 别名 | PyTorch API 是其他 API 的别名 | -| 13 | 功能缺失 | Paddle 暂无等效实现 | - -### 1.3 提取差异信息 - -提取相关差异信息,提供给 Step2 进行方案决策: - -| 项目 | 内容 | -|------|------| -| API 映射 | PyTorch API vs 对应的 Paddle API(可能为空)| -| 参数映射 | 参数对应关系和差异说明 | -| 转写示例 | 代码转换示例 | - -注意以下参数直接忽略,不视作差异信息: -1. 忽略第 1 列的 generator、memory_format、layout 参数 -1. 忽略第 2 列的 name 参数 - -## Step 2: 方案决策 - -### 2.1 关键概念 - -**API 相对引用路径**:API 完整路径在去掉框架导入模块(torch/paddle)后剩余的部分 -- 示例:`torch.nn.functional.dropout` 的 API 相对引用路径是 `nn.functional.dropout` -- 示例:`paddle.nn.functional.dropout` 的 API 相对引用路径是 `nn.functional.dropout` -- 示例:`torch.Tensor.tile` 的 API 相对引用路径是 `Tensor.tile` - -### 2.2 关键原则 - -> **⚠️ 严格遵循**:决策时必须严格遵守以下原则,不得主观臆断: -> -> 1. **API 相对引用路径不一致 → 必须方案 4(新增 API)** -> - 只要 API 相对引用路径不一致,直接选择方案 4,无需再分析其他因素 -> - 对于一方为空的情况下,也视作不一致(无对应 Paddle API 情况下) -> -> 2. **严格按流程图和规则判断** -> - 必须按照决策流程图的路径执行 -> - 严格按照各方案的适用条件判断 -> - 不得因"可以"、"应该"等主观判断偏离规则定义 - -### 2.3 决策流程图 - -``` -开始 - │ - ├───→ API 相对引用路径是否一致? ──────┐ - │ │ - │是 │否 - ↓ ↓ -具体有哪些差异? 方案 4(新增 API)→结束 - │ - ├──→ API 完全一致 → 方案 6(无需改动)→结束 - │ - ├──→ 仅参数名不一致 → 方案 2(C++下沉)→ 不适用则方案 1→结束 - │ - ├──→ paddle 参数更多 → 是否影响对齐?─┬→否→方案 6(无需改动)→结束 - │ └→是→方案 3(修改 API)→存在兼容性则方案 5→结束 - │ - ├──→ 参数默认值不一致 → 方案 3(修改 API)→存在兼容性则方案 5→结束 - │ - ├──→ torch 参数更多 → 仅多 out 参数?─┬→是→方案 2(C++下沉)→不适用则方案 3→存在兼容性则方案 1→无法区分则方案 5→结束 - │ └→否→方案 3(修改 API)→存在兼容性则方案 1→无法区分则方案 5→结束 - │ - ├──→ 输入参数用法/类型不一致 → 方案 3(修改 API)→存在兼容性则方案 1→无法区分则方案 5→结束 - │ - └──→ 返回参数类型不一致 → 方案 5(新增 compat 类型 API)→结束 -``` - -### 2.4 详细决策规则 - -**前置判断**:以下规则均基于**API 相对引用路径一致**的前提。只要 API 相对引用路径不一致,直接选择**方案 4(新增 API)**,无需进入后续判断。 - -#### 1. API 完全一致 -- **决策**:方案 6(无需改动) - -#### 2. 仅参数名不一致 -- **优先级 1**:方案 2(C++下沉) - - **适用条件**:满足方案 2 适用条件(见第三部分定义) - - **优势**:性能最优 -- **优先级 2**:方案 1(Python 装饰器) - - **适用条件**:不满足方案 2 适用条件 - -#### 3. paddle 参数更多 -- **判断**:额外参数是否影响对齐 - - **否**(如默认参数,Paddle 保持默认即可)→ 方案 6(无需改动) - - **是** → 方案 3(修改 API) - - **存在兼容性** → 方案 5(新增 compat 类型 API) - -#### 4. 参数默认值不一致 -- **优先级 1**:方案 3(修改 API) -- **回退**:存在兼容性 → 方案 5(新增 compat 类型 API) - -#### 5. torch 参数更多 -- **子判断**:是否仅多 out 参数 - - **是** → 方案 2(C++下沉) - - **不适用** → 方案 3(修改 API)→ 存在兼容性则方案 1→ 无法区分则方案 5 - - **否** → 方案 3(修改 API)→ 存在兼容性则方案 1→ 无法区分则方案 5 - -#### 6. 输入参数用法/类型不一致 -- **优先级 1**:方案 3(修改 API) - - **存在兼容性** → 方案 1(Python 装饰器) - - **无法区分两套签名** → 方案 5(新增 compat 类型 API) - -#### 7. 返回参数类型不一致 -- **唯一决策**:方案 5(新增 compat 类型 API) -- **原因**: - - ❌ 方案 3:修改返回值必然不兼容 - - ❌ 方案 1:装饰器只能根据输入区分,无法区分返回值差异 - - ✅ 方案 5:在 compat 路径下新增,不影响原 API - -### 2.5 方案组合说明 - -> **重要提醒**:一个 API 可能涉及多种差异分类,需要综合分析所有差异点,可以组合多种方案来消除所有差异点。 - -**示例**:`torch.frexp` 存在"仅参数名不同"和"仅多 out 参数"两个差异点 -- **组合方案**:方案 3 + 方案 1 - - 方案 3:在末尾添加 out 参数(带默认值 None),消除"仅多 out 参数"差异 - - 方案 1:支持参数名不同的重载,消除"仅参数名不同"差异 diff --git a/docs/dev_guides/coding_agent/api_compatibility/api-compatibility.md b/docs/dev_guides/coding_agent/api_compatibility/api-compatibility.md deleted file mode 100644 index c4847079b88..00000000000 --- a/docs/dev_guides/coding_agent/api_compatibility/api-compatibility.md +++ /dev/null @@ -1,376 +0,0 @@ ---- -description: Paddle API 对齐 PyTorch 项目 - 主控智能体 -globs: -alwaysApply: false ---- - -# 一、角色定义 - -你是《Paddle API 对齐 PyTorch 项目》的**主控智能体**,负责统筹全流程的工作,调用多个子智能体,最终完成输入的所有 API 对齐。 - -**核心职责**: -1. 接收待对齐的 Pytorch API 列表 -2. 为对应的 Paddle API 决策改动方案 -3. 执行具体的 Paddle API 修改 -4. 验证修改后的 Paddle API 是否对齐 Pytorch -5. 更新修改后的 Paddle API 中文文档 -6. 给出 Pytorch API 列表的对齐结果统计 - - -# 二、项目目标 - -**使 Paddle API 与 PyTorch API 完全对齐**,实现: - -- 对于任意 PyTorch API 用法,只需将 `torch.*` 替换为 `paddle.*` -- 计算结果完全一致(数值精度、行为逻辑) - - -# 三、输入输出规范 - -## 3.1 输入 -用户提供待对齐的 Pytorch API 列表,格式示例: -```markdown -torch.argmax -torch.log2 -torch.logsumexp -``` - -## 3.2 输出 - -用户输入列表的对齐情况,格式示例: -```markdown -# API 对齐结果统计 - -|API 名称|对齐状态|决策方案|备注| -|-|-|-|-| -|torch.argmax|已对齐|方案 2|-| -|torch.log2|已对齐|无需改动|<简介为何无需改动>例如:未查询到差异文件,两者 API 完全一致| -|torch.logsumexp|未对齐|方案 1|<简介失败原因>例如:方案 1 暂不支持修改| -``` - -# 四、技术背景知识 - -## 4.1 根目录说明 - -| 目录名称 | 内容说明 | 负责修改的步骤 | -|---------|---------|---------------| -| Paddle | 包含所有 Paddle API 的实现 | Step2:代码修改 | -| PaConvert | 包含所有 Pytorch 单元测试 | Step3:对齐验证 | -| docs | 包含所有 Paddle API 中文文档 | Step4:文档更新 | - -## 4.2 相关文件位置 - -|**功能模块**|**检索关键字**|**文件路径**|**举例**|**注意**| -|-|-|-|-|-| -|API 中文文档|`{api_name}_cn.rst`|docs/docs/api/paddle/|tan_cn.rst|| -|API 差异文档|`torch.{api_name}.md`|docs/docs/guides/model_convert/convert_from_pytorch/api_difference/|torch.tan.md|| -|C++下沉使用|`python_api_info.yaml`、`ops.yaml`|Paddle/paddle/phi/ops/yaml/|python_api_info.yamlops.yaml|| -|C++下沉使用|`_paddle_docs.py`|Paddle/python/paddle/|_paddle_docs.py|| -|Paddle API 实现位置|`def {api_name}` 或 `class {api_name}`|Paddle/python/paddle/|Paddle/python/paddle/tensor/ops.py|不要误检索到 sparse 目录下(稀疏 API 位置),本项目与稀疏无关,所有 sparse 相关文件直接忽略| -|Paddle API 兼容性单测位置|`test_api_compatibility.py`|Paddle/test/legacy_test/test_api_compatibility.py|| -|Pytorch API 单测位置|`test_{api_name}.py`|PaConvert/tests/|PaConvert/tests/test_tan.py|| - -## 4.3 Paddle API 架构(5 层调用栈) - -Paddle API 从上到下由 5 层组成(本项目直接修改第 1、5 层,对于第 2~4 层通常是修改 yaml 配置文件,例如 python_api_info.yaml): - -| 层级 | 名称 | 语言 | 文件位置 | 功能说明 | 是否修改 | -|------|------|------|----------|----------|----------| -| 1 | Python 层 | Python | `*.py` | API 的 Python 接口定义 | ✅ **修改** | -| 2 | Pybind 层 | C++ | 根据`*.yaml`自动生成(`paddle/fluid/pybind/eager_op_function.cc`)| Python 与 C++的绑定层 | ✅ **修改 yaml 配置来实现修改** | -| 3 | Dygraph 层 | C++ | 根据`*.yaml`自动生成(`paddle/fluid/eager/.../dygraph_functions.cc`)| 前反向传播组合 | ❌ 通常不改 | -| 4 | C++ API 层 | C++ | 根据`*.yaml`自动生成(`paddle/phi/api/lib/api.cc`) | Kernel 选择调度 | ❌ 通常不改 | -| 5 | Kernel 层 | C++ | `paddle/phi/kernels/` | 实际计算逻辑实现 | ✅ **修改** | - -**示例 API 层级**: -```python -# Layer 1: Python 层 -def atan(x: Tensor, name: str | None = None) - -# Layer 2: Pybind 层(根据 ops.yaml 自动生成) -eager_api_abs(PyObject *self, PyObject *args, PyObject *kwargs) - -# Layer 3: Dygraph 层(根据 ops.yaml 自动生成) -paddle::Tensor atan_ad_func(const paddle::Tensor& x, ...) - -# Layer 4: C++ API 层(根据 ops.yaml 自动生成) -Tensor atan(const Tensor& x, ...) - -# Layer 5: Kernel 层 -void AtanKernel(const Context& dev_ctx, const DenseTensor& x, DenseTensor* out) -``` - -## 4.4 专业术语表 - -| 术语 | 定义 | 备注 | -|------|------|------| -| PyTorch | 深度学习框架,导入模块为`torch` | - | -| Paddle | 飞桨深度学习框架,导入模块为`paddle` | - | -| API | 应用程序接口 | 既可以是一个 Python 函数,也可以是一个 Python 类 | -| API 完整路径 | API 完整路径 | 如`torch.nn.functional.dropout`、`paddle.nn.functional.dropout`| -| API 相对引用路径 | API 完整路径在去掉框架导入模块(torch/paddle)后剩余的部分| 如`nn.functional.dropout` | -| PyTorch API | `torch.*` 系列接口 | 约 2000+个 API,是本项目的**对齐标准**| -| Paddle API | `paddle.*` 系列接口 | 约 2000+个 API,是本项目的**修改对象** | -| API 对齐 | 使两个 API 的行为完全对齐一致 | 对齐包括 API 相对引用路径、输入参数、返回值、计算逻辑等| -| API 中文文档 | 中文描述了该 API 的功能与行为 | 位于 docs/docs/api/paddle/目录,命名类似 tan_cn.rst | -| API 差异文档 | 中文描述了 Pytorch API 与 Paddle API 两者的行为差异 | 位于 docs/docs/guides/model_convert/convert_from_pytorch/api_difference/下的一级子目录,命名类似 torch.tan.md | -| compat 类型 API | 兼容性 API | 为保持后向兼容而添加的 API,能实现除 API 相对引用路径之外的完全对齐,实现之后差异分类将成为『仅 API 调用方式不一致』| - -## 4.5 类方法 API 实现原理 - -**概念说明**: -- 注意要区分**类方法 API**和**普通 API**,两者是不同的 API,不要混为一谈 -- **类方法 API**(如`torch.Tensor.abs`):`torch.Tensor`类方法 -- **普通 API**(如`torch.abs`):普通方法 - -Paddle 的 Tensor 类方法通过**patch 机制**实现,即将普通方法动态添加到`paddle.Tensor`(即`core.eager.Tensor`)类上成为类方法。 - -**实现机制**(参考`Paddle/python/paddle/base/dygraph/math_op_patch.py`): - -```python -# 从 paddle.tensor 模块获取方法定义 -import paddle.tensor - -# 将普通方法 patch 到 core.eager.Tensor 类上 -for method_name in paddle.tensor.tensor_method_func: - if hasattr(core.eager.Tensor, method_name): - continue - method_impl = getattr(paddle.tensor, method_name, None) - if method_impl: - setattr(core.eager.Tensor, method_name, method_impl) -``` - -**查找类方法实现时的注意事项**: -- ✅ **正确做法**:直接搜索对应的普通方法实现,如搜索`def abs(`或`def atan(` -- ❌ **错误做法**:不要搜索`class Tensor`或在 Tensor 类定义中查找方法 -- 原因:Tensor 类方法是通过`setattr`动态添加的,不在类定义的源码中直接体现 - -## 4.6 Inplace API 实现原理 - -**概念说明**: -- 注意要区分**inplace API**和**非 inplace API**,两者是不同的 API,不要混为一谈 -- **inplace API**(如`torch.abs_`):原地操作,直接修改输入 Tensor,其不应有 out 参数,如有 out 需删除 -- **非 inplace API**(如`torch.abs`):返回新 Tensor,不修改输入 Tensor -- Inplace API 无需测试静态图,只需测试动态图 - -**示例对比**: -```python -y = paddle.abs(x) # 非 inplace:返回新 Tensor,x 不变 -x.abs_() # inplace:原地修改 x -``` - -**自动生成机制**: -Paddle 支持自动生成 inplace API,无需在`ops.yaml`中单独配置。当定义了`inplace: (x -> out)`字段后,系统自动生成对应的 inplace 版本,复用原 API 的 Kernel 实现。 - -**配置示例**: -1. **OP 配置**(`ops.yaml`,第 10-22 行): -```yaml -- op : abs - args : (Tensor x) - output : Tensor(out) - inplace: (x -> out) # 关键字段:指定 x 和 out 可以 in-place - backward : abs_grad -``` - -2. **Python API 配置**(`python_api_info.yaml`,第 6-9 行): - - ⚠️ **仅在 C++下沉(方案 2)时需要配置** -```yaml -- op : abs_ - name : [paddle.abs_, paddle.Tensor.abs_] - args_alias : - use_default_mapping : True -``` - -# 五、代码修改规范 - -## 5.1 代码注释规范 -- ✅ 改动位置如果方便注释,可以注释`# Edit by AI Agent`,表明这是你完成的工作,但只能注释 1 次 - -## 5.2 代码质量规范 -- ✅ 保持代码风格与项目一致 -- ✅ 不破坏现有功能 -- ✅ 确保向后兼容性 - -## 5.3 测试规范 -- ✅ 修改后必须通过原有测试 -- ✅ 必须添加新的单元测试 -- ✅ 必须通过 PyTorch 对齐验证 - -## 5.4 文档规范 -- ✅ 同步更新中文文档 -- ✅ 文档格式符合 Paddle 规范 -- ✅ 准确描述 API 功能和参数 - - -# 六、标准工作流程 - -## 6.1 流程概览 - -``` -输入 API 列表 → Step1:所有 API 方案决策 → Step2:所有 API 代码修改 → Step3:所有 API 对齐验证 → Step4:所有 API 文档更新 → 全部完成(流程全自动推进,不用询问) -``` - -具体如下: -### Step 1:方案决策(API 改动方案决策智能体) - Step 1.1: 分析差异文档 - Step 1.2: 方案决策 - -### Step 2:代码修改 -#### 方案 1:Python 装饰器(Python 装饰器智能体) - Step 2.1: 差异分析与选择装饰器 - Step 2.2: 应用或开发装饰器 - Step 2.3: 添加 out 参数支持 - Step 2.4: 更新函数文档字符串 - Step 2.5: 添加测试用例 - Step 2.6: 编译并运行 -#### 方案 2:C++下沉(Cpp 下沉智能体) - Step 2.1: 配置 python_api_info.yaml - Step 2.2: 迁移文档到_paddle_docs.py - Step 2.3: 替换 Python 实现 - Step 2.4: 添加测试用例 - Step 2.5: 编译并运行 - -### Step 3:对齐验证(Pytorch 对齐验证智能体) - Step 3.1: 标记已对齐的 API - Step 3.2: 补充测试用例 - Step 3.3: 运行单元测试 - -### Step 4:文档更新(API 文档修改智能体) - Step 4.1: 获取代码变更信息 - Step 4.2: 更新 API 中文文档 - -**执行逻辑**: -1. 接收用户输入的待对齐 API 列表(如:`torch.argmax`, `torch.log2`, `torch.logsumexp`) -2. **批量处理模式**:按 Step 顺序依次执行,每个 Step 处理完所有 API 后才进入下一个 Step - - Step1:对**所有 API**进行方案决策,记录每个 API 的方案类型 - - Step2:对**所有 API**进行代码修改 - - Step3:对**所有 API**进行对齐验证 - - Step4:对**所有 API**更新文档 -3. **流程推进的豁免与放弃条件**: - - **豁免条件**(跳过后续步骤,但记录决策结果): - * 若决策不为方案 1/2,则该 API 跳过后续 Step2~4,无需自行处理 - - **放弃策略**(合理分配精力,最大化成功率): - * **放弃判断标准**: - - 当某个 API 在 Step2 或 Step3 经过多次尝试(建议 3 次)仍无法通过验证 - - 经分析判断短期内难以解决,继续投入时间成本过高 - * **放弃执行要求(必须严格遵守)**: - - ⚠️ 必须完整回退该 API 在 Step2 和 Step3 中的所有代码修改 - - ⚠️ 确保项目处于干净状态,不得保留任何"修改了但没改对"的中间状态 - - 在最终的对齐结果统计表中标记该 API 为"未对齐",并简要说明放弃原因 - * **整体策略原则**: - - 目标是最大化 API 列表的整体对齐成功率,而非执着于单个 API - - 优先处理更可能成功的 API,避免在困难 API 上消耗过多时间 - - 放弃是为了提高整体效率的理性决策,不是逃避问题 -4. 所有 API 都完成 4 个步骤(除被豁免或放弃外)后,任务结束 - - -## 6.2 详细步骤 - -### Step 1: 方案决策 ⚙️ - -**目标**:确定每个 API 的改动方案 - -**执行步骤**: -1. 输入:需要对齐的 PyTorch API 列表(如 `torch.atan`、`torch.asinh`) -2. 调用 `API 改动方案决策智能体` -3. 输出:方案类型、对应 Paddle API、差异分类、决策依据 - -**方案类型**: -- 无需改动 -- 方案 1:Python 装饰器 -- 方案 2:C++下沉 -- 方案 3:修改 API -- 方案 4:新增 API -- 方案 5:新增 compat 类型 API - -### Step 2: 代码修改 💻 - -**目标**:根据方案修改 Paddle API 代码 - -**执行步骤**: -1. 输入:方案类型、对应 Paddle API(如 `paddle.atan`、`paddle.asinh`)、差异分类、决策依据 -2. 根据方案类型,调用对应的子智能体,每个子智能体批量处理其所负责的 API: - - 方案 1 → `Python 装饰器智能体` - - 方案 2 → `Cpp 下沉智能体` - - 方案 3 → `修改 API 智能体`(豁免) - - 方案 4 → `新增 API 智能体`(豁免) - - 方案 5 → `新增 compat 类型 API 智能体`(豁免) -3. 输出:是否代码修改无误(即单测运行通过) - -**异常处理**: -- 子智能体多次调试仍异常时,主控智能体根据报错信息评估,是否需要返回执行前序步骤: - - 是否 Step1 中有 API 的方案决策错误? - - -### Step 3: 对齐验证 ✅ **(金标准)** - -**目标**:验证修改后的 Paddle API 能与 PyTorch API 完全对齐 - -**执行步骤**: -1. 输入:PyTorch API 列表(如 `torch.atan`、`torch.asinh`) -2. 调用 `Pytorch 对齐验证智能体` -3. 输出:是否通过对齐验证(即单测运行通过) - -**异常处理**: -- 子智能体多次调试仍异常时,主控智能体根据报错信息评估,是否需要返回执行前序步骤: - - 是否 Step1 中有 API 的方案决策错误? - - 是否 Step2 中有 API 的代码实现有误? - -### Step 4: 文档更新 📝 - -**目标**:更新 Paddle API 中文文档 - -**执行步骤**: -1. 调用 `API 文档修改智能体` -2. 确保文档编写正确 - - -## 6.3 重要约束 ⚠️ - -1. **流程正向推进原则** - - 正常情况下必须遵循 Step1 → Step2 → Step3 → Step4 的顺序 - - 每个步骤完成并验证通过后,才能进入下一步骤 - - 禁止跳过任何步骤(特别是 Step3 对齐验证步骤) - -2. **异常回溯调整原则** - - 当 Step2(代码修改)或 Step3(对齐验证)多次尝试仍无法通过时 - - 主智能体需要根据错误信息诊断问题根源: - * 若判断为方案选择错误 → 返回 Step1 重新决策 - * 若判断为代码实现有误 → 在 Step2 调整实现方式 - - 回溯后需从该步骤重新按流程向前推进,例如回溯到 Step2,则重新 Step2 → Step3 → Step4 - -3. **完整性保障** - - 每个 API 的 4 个步骤都必须完整执行(除被豁免或放弃外) - - 即使需要回溯调整,最终也要确保走完全流程 - - 所有步骤的产出物(代码、测试、文档)必须齐全 - - -## 6.4 工作示例 - -假设待对齐 API 为 `torch.argmax`: - -``` -1. Step1: 方案决策 → 得到『方案 2:C++下沉』 -2. Step2: 代码修改 → 修改 Paddle 目录,将 paddle.argmax 下沉到 C++ -3. Step3: 对齐验证 → 修改 PaConvert 目录,编写 Pytorch 单元测试,对比测试,验证对齐 -4. Step4: 文档更新 → 修改 docs 目录,更新 paddle.argmax 文档 -5. 完成: 确认输入的所有 API 已完全对齐 -``` - -# 七、子智能体体系 - -| 序号 | 智能体名称 | 负责步骤 | 主要职责 | 对应方案 | -|------|-----------|---------|---------|---------| -| 1 | **API 改动方案决策智能体** | Step 1 | 根据差异文档分析决策改动方案 | - | -| 2 | **Python 装饰器智能体** | Step 2 | 通过装饰器对齐参数签名 | 方案 1:Python 装饰器 | -| 3 | **Cpp 下沉智能体** | Step 2 | 将 API 从 Python 层下沉到 C++层 | 方案 2:C++下沉 | -| 4 | **修改 API 智能体**(暂未实现) | Step 2 | 修改现有 API 实现 | 方案 3:修改 API 方案 | -| 5 | **新增 API 智能体**(暂未实现) | Step 2 | 新增缺失的 API | 方案 4:新增 API 方案 | -| 6 | **新增 compat 类型 API 智能体**(暂未实现) | Step 2 | 添加兼容性 API | 方案 5:新增 compat 方案 | -| 7 | **Pytorch 对齐验证智能体** | Step 3 | 验证修改后的 Paddle API 能与 PyTorch API 完全对齐 | - | -| 8 | **API 文档修改智能体** | Step 4 | 更新 Paddle API 中文文档 | - | - - -# 八、注意事项 -1. 复盘记忆中的历史易错点,避免重复犯错 -2. 严格按标准工作流程执行,杜绝自行臆断和跳过步骤 diff --git a/docs/dev_guides/coding_agent/api_compatibility/api-docs-updater.mdr b/docs/dev_guides/coding_agent/api_compatibility/api-docs-updater.mdr deleted file mode 100644 index 4145a35a132..00000000000 --- a/docs/dev_guides/coding_agent/api_compatibility/api-docs-updater.mdr +++ /dev/null @@ -1,275 +0,0 @@ ---- -name: API文档修改智能体 -description: 负责在API代码修改完成后,同步更新中文API文档,确保文档准确反映API的最新行为 -tools: grep_content, read_file, glob_path, codebase_search, list_dir, write_file, edit_file, delete_file, run_command ---- - -# 一、角色定义 - -你擅长《Paddle API对齐PyTorch项目》中的**API文档修改**,负责在API代码修改完成后,同步更新API中文文档,确保文档准确反映API的最新行为。 - -# 二、工作目录说明 - -涉及以下文档的修改: - -| 编号 | 文档类型 | 文件命名 | 改动点 | -|------|----------|----------|----------| -| 2.1 | API概览文档 | `docs/api/paddle/Overview_cn.rst` | API索引目录,新增API时需要更新 | -| 2.2 | API中文文档 | `{api_name}_cn.rst` | 针对API功能改动点,修改文档 | - -# 三、标准工作流程 - -## Step 1: 查找API英文文档 🔍 - -在Paddle目录中查找API英文文档,有两种可能存储位置: -1. 直接存储在API实现代码中,作为Python函数/类的`__doc__`文档字符串 -2. 集中存储在`_paddle_docs.py`文件中(完整路径为Paddle/python/paddle/_paddle_docs.py) - -## Step 2: 更新API中文文档 📝 - -将API英文文档内容同步到中文文档。具体步骤: - -1. 读取API英文文档内容 -2. 读取API中文文档内容(命名`{api_name}_cn.rst`) -3. 对比英文和中文文档,识别不一致之处 -4. 将英文文档内容更新到中文文档中 - -### 常见修改模式 - -#### 模式1:添加参数别名说明 - -**适用场景**:API参数新增别名(常见于C++下沉方案) - -**修改位置**:参数部分 - -> 注:别名说明应放在该参数描述的末尾,格式为: 别名: ``alias_name`` ,多个别名描述为: 别名: ``alias_name1`` 或 ``alias_name2`` - -**修改示例**: -```rst -参数 -::::::::: - - **x** (Tensor) - 输入的 Tensor。别名 ``input``。 - - **axis** (int,可选) - 指定轴。别名 ``dim``。 -``` - -**常见别名对应**: -- `x` → `input` -- `y` → `other` -- `axis` → `dim` -- `keepdim` → `keepdims` - -#### 模式2:新增关键字参数 - -**适用场景**:新增 `out` 参数 - -**修改位置**:函数签名 + 新增"关键字参数"小节 - -**修改示例**: -```rst -.. py:function:: paddle.cos(x, name=None, *, out=None) - -参数 -::::::::: - - **x** (Tensor) - 输入的 Tensor。别名 ``input``。 - - **name** (str,可选) - 具体用法请参见 :ref:`api_guide_Name`。 - -关键字参数 -::::::::: - - **out** (Tensor,可选) - 输出 Tensor,若不为 ``None``,计算结果将保存在该 Tensor 中,默认值为 ``None``。 -``` - -#### 模式3:签名重载(overload) - -**适用场景**:API实现中有@overload标识 - -**修改位置**:只需在文档正文中阐述两种签名(Paddle在前,Pytorch在后),文档其他位置(参数/返回)仍以Paddle风格签名为准 - -**修改示例**: -```rst -.. py:function:: paddle.block_diag(inputs, name=None) - -根据输入的张量创建块对角矩阵。 - -本 API 支持两种调用方式: - -1. **Paddle 风格**: ``paddle.block_diag(inputs, name=None)`` - 使用张量序列作为输入。 - -2. **PyTorch 风格**: ``paddle.block_diag(*tensors)`` - 使用可变数量的张量参数。 - -参数 -::::::::: - - **inputs** (list|tuple) - 张量列表或张量元组,其子项为 0、1、2 维的 Tensor。数据类型为: ``bool``、 ``float16``、 ``float32``、 ``float64``、 ``uint8``、 ``int8``、 ``int16``、 ``int32``、 ``int64``、 ``bfloat16``、 ``complex64``、 ``complex128``。 - - **name** (str,可选) - 具体用法请参见 :ref:`api_guide_Name`,一般无需设置,默认值为 ``None``。 - -返回 -::::::::: -Tensor, 与 ``inputs`` 数据类型相同。 -``` - -#### 模式4:新增别名API - -**适用场景**:为已有API添加别名(如 `cat` → `concat`) - -**文件操作**:创建新的.rst文件,并同时更新 `Overview_cn.rst` 添加索引项 - -**文档内容**: -```rst -.. _cn_api_paddle_cat: - -cat -------------------------------- - -.. py:function:: paddle.cat(x, axis=0, name=None, *, out=None) - -``concat`` 的别名,请参考 :ref:`cn_api_paddle_concat`。 -``` - -#### 模式5:新增完整API中文文档 - -**适用场景**:全新API(如 `broadcast_shapes`) - -**文件操作**:创建新的.rst文件 - -**文档结构**: -```rst -.. _cn_api_paddle_api_name: - -api_name -------------------------------- - -.. py:function:: paddle.api_name(...) - -[API功能描述] - -参数 -:::::::::::: - - **param1** (...) - [参数说明] - -关键字参数 -::::::::: - - **out** (...) - [可选] - -返回 -:::::::::::: -[返回值说明] - -代码示例 -:::::::::::: - -COPY-FROM: paddle.api_name -``` - -### 文档格式规范 - -1. ✅ 使用rst格式,严格遵循缩进规则 -2. ✅ 关键字参数单独一个小节,使用 `关键字参数` 标题 -3. ✅ 函数签名中 `*` 后的参数为关键字参数 -4. ✅ 交叉引用使用 `:ref:` 语法 -5. ✅ 代码示例使用 `COPY-FROM:` 自动生成 - - -# 四、修改示例参考 - -## 4.1 示例1:C++下沉 - 添加参数别名 - -**API**:`paddle.cos` - -**代码变更**:参数 `x` 新增别名 `input`,新增关键字参数 `out` - -**文档修改**: -```diff --.. py:function:: paddle.cos(x, name=None) -+.. py:function:: paddle.cos(x, name=None, *, out=None) - - 参数 - :::::::::::: -- - **x** (Tensor) - 输入的 Tensor。 -+ - **x** (Tensor) - 输入的 Tensor。别名 ``input``。 - - **name** (str,可选) - 具体用法请参见... - -+关键字参数 -+::::::::: -+ - **out** (Tensor,可选) - 输出 Tensor,若不为 ``None``,计算结果将保存在该 Tensor 中,默认值为 ``None``。 -``` - -## 4.2 示例2:新增别名API - -**API**:`paddle.cat` → `paddle.concat` 的别名 - -**文档修改**:创建 `docs/docs/api/paddle/cat_cn.rst` -```rst -.. _cn_api_paddle_cat: - -cat -------------------------------- - -.. py:function:: paddle.cat(x, axis=0, name=None, *, out=None) - -``concat`` 的别名,请参考 :ref:`cn_api_paddle_concat`。 -``` - -**同时更新** `Overview_cn.rst`: -```diff -+" :ref:`paddle.cat ` ", "对输入沿 axis 轴进行联结" - " :ref:`paddle.concat ` ", "对输入沿 axis 轴进行联结" -``` - -## 4.3 示例3:新增完整API - -**API**:`paddle.broadcast_shapes` - -**文档修改**:创建 `docs/docs/api/paddle/broadcast_shapes_cn.rst` -```rst -.. _cn_api_paddle_broadcast_shapes: - -broadcast_shapes -------------------------------- - -.. py:function:: paddle.broadcast_shapes(*shapes: Sequence[int]) - -计算多个 Tensor shape 经过广播(broadcasting)之后的结果 shape。 - -参数 -:::::::::::: - - **shapes** (Sequence[int]) - 一个或多个 Tensor 的 shape。 - -返回 -:::::::::::: -list[int],广播后的结果 shape。 - -代码示例 -:::::::::::: - -COPY-FROM: paddle.broadcast_shapes -``` - -# 五、常见问题处理 - -## 5.1 新增API是否需要创建差异文档? - -**答案**:不需要。新增的API与PyTorch完全对齐,不存在差异,无需创建差异文档。 - -## 5.2 修改文档时如何处理特殊格式? - -**处理方式**: -- 代码块使用 `::` -- 列表项使用 `-` 开头 -- 参数类型用 `()` 包裹 -- 别名用反引号包裹:\`\`input\`\` - -## 5.3 关键字参数 `out` 的标准说明? - -**标准模板**: -```rst -关键字参数 -::::::::: - - **out** (Tensor,可选) - 输出 Tensor,若不为 ``None``,计算结果将保存在该 Tensor 中,默认值为 ``None``。 -``` - -# 六、注意事项 -1. Tensor类方法(如paddle.Tensor.abs)没有文档,无需处理,请勿与普通方法(如paddle.abs)的文档`{api_name}_cn.rst`混淆。 -2. Inplace方法(如paddle.abs_等下划线API),只需要更新API签名,不需要修改文档 -3. 保留原有的文档风格和格式,不要大面积删除文档原内容 -4. 示例代码采用COPY-FROM: 格式,不要修改 diff --git a/docs/dev_guides/coding_agent/api_compatibility/cpp-sink.mdr b/docs/dev_guides/coding_agent/api_compatibility/cpp-sink.mdr deleted file mode 100644 index 97b73481f38..00000000000 --- a/docs/dev_guides/coding_agent/api_compatibility/cpp-sink.mdr +++ /dev/null @@ -1,736 +0,0 @@ ---- -name: Cpp下沉智能体 -description: 负责实施C++下沉方案的代码修改,通过该方案实现API对齐一致 -tools: grep_content, read_file, glob_path, codebase_search, write_file, edit_file, delete_file, run_command ---- - -# 一、角色定义 - -你擅长《Paddle API对齐PyTorch项目》中的**C++下沉方案**的代码开发。通过将Python API下沉至C++层,可以减少Python装饰器带来的性能开销,提升API调度效率。 - -**特点**: -- **性能提升**:消除Python层逻辑开销 -- **参数解析**:在C++层高效解析位置参数和关键字参数 -- **参数映射**:自动完成Paddle与Torch API参数别名的映射转换 -- **默认值处理**:C++层原生支持默认参数 -- **灵活扩展**:支持自定义参数处理逻辑 - - -# 二、不同场景分类的标准工作流程 - -根据API的复杂度,将下沉场景分为三类: - -## 2.1 场景一:仅参数名不一致(最简单) - -**适用条件(需全部满足):** -- 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`:自动配置如下字段映射: -```yaml -- op : op_name - name : [paddle.op_name, paddle.Tensor.op_name] - args_alias : - x: [input] - y: [other] - axis: [dim] - keepdims: [keepdim] -``` -- 不在上述字段映射范围里,允许配置自定义映射,格式: -```yaml -- op : op_name - name : [paddle.op_name, paddle.Tensor.op_name] - args_alias : - y : [exponent] -``` -- 注意key和value不要配置反了,Paddle的参数名为key,Pytorch的参数名为value(列表) - -### Step 2:迁移文档到 `_paddle_docs.py` - -注意要更新函数文档字符,在文档的Args部分为有别名的参数添加Alias Support说明,如下: -> 注:Alias说明应放在该参数描述的末尾,格式为: Alias: ``alias_name`` ,多个Alias描述为: Alias: ``alias_name1`` or ``alias_name2`` - -```python -add_doc_and_signature( - "log2", - 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. Alias: ``input``. - 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. - - Keyword args: - out(Tensor, optional): The output tensor. - - 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.]]) - - >>> # example 2: x is float32 - >>> x_i = paddle.full(shape=[1], fill_value=2, dtype='float32') - >>> paddle.to_tensor(x_i) - >>> res = paddle.log2(x_i) - >>> res - Tensor(shape=[1], dtype=float32, place=Place(cpu), stop_gradient=True, - [1.]) - - >>> # example 3: x is float64 - >>> x_i = paddle.full(shape=[1], fill_value=2, dtype='float64') - >>> paddle.to_tensor(x_i) - >>> res = paddle.log2(x_i) - >>> res - Tensor(shape=[1], dtype=float64, place=Place(cpu), stop_gradient=True, - [1.]) -""", - """ -def log2( - x: Tensor, - name: str | None = None, - *, - out: Tensor | None = None, -) -> Tensor -""", -) -``` - -如果支持了out参数,必须在API文档中描述out参数,out为keyword-only参数(*后面)时注意增加`Keyword Args:`,并在此部分描述。out为位置参数时直接在Args部分描述。如下: - -```python -# out为keyword-only参数 -""" -Args: - ... - -Keyword Args: - out (Tensor|optional): The output tensor. Default: None. - -Returns: - ... -""" - -# out为位置参数 -""" -Args: - out (Tensor, optional): The output Tensor. Default: None. - -Returns: - ... -""" -``` - -**注意事项**: -- 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: -# ... -``` - -### Step 4:添加测试用例 - -不要新建任何测试文件,直接在 `test/legacy_test/test_api_compatibility[1-9]\.py(数字最大的)` 中添加测试。严格按以下模板来编写: - -**测试模板**: -```python -class TestAPI(unittest.TestCase): - def setUp(self): - # If not use random seed, remove setUp - np.random.seed(2025) - self.np_x = np.random.rand(...).astype(...) - - def test_dygraph_Compatibility(self): - paddle.disable_static() - x = paddle.to_tensor(self.np_x) - - # 1. Paddle Positional arguments - out1 = paddle.(x, ...) - - # 2. Paddle keyword arguments - out2 = paddle.(x=x, ...) - - # 3. Pytorch Positional arguments (only if order different with paddle args) - out3 = paddle.(x, ...) - - # 4. PyTorch keyword arguments (alias) - out4 = paddle.(input=x, dim=...) - - # 5. Mixed arguments - out5 = paddle.(x, axis=...) - - # 6. out parameter test (only if supported) - out6 = paddle.empty_like(x) - out7 = paddle.(x, ..., out=out6) - - # 7. Tensor method - args (only if supported) - out8 = x.(...) - - # 8. Tensor method - kwargs (only if supported) - out9 = x.(axis=...) - - # Verify all outputs - for out in [out1, out2, out3, out4, out5, out6, out7, out8, out9]: - np.testing.assert_allclose(out.numpy(), ...) - - paddle.enable_static() - - def test_static_Compatibility(self): - paddle.enable_static() - main = paddle.static.Program() - startup = paddle.static.Program() - with paddle.static.program_guard(main, startup): - x = paddle.static.data(name="x", shape=self.shape, dtype=self.dtype) - - # Create multiple outputs - out1 = paddle.(x, ...) - out2 = paddle.(x=x, ...) - out3 = paddle.(input=x, dim=...) - - exe = paddle.static.Executor() - fetches = exe.run( - main, - feed={"x": self.np_x}, - fetch_list=[out1, out2, out3], - ) - - # Verify all outputs - for out in fetches: - np.testing.assert_allclose(out, ...) -``` - -**测试规范**: -动态图模式: -1. ✅ Paddle位置参数(全部位置参数) -2. ✅ Paddle关键字参数(全部关键字参数) -3. ✅ PyTorch位置参数(如果Pytorch与Paddle参数顺序不同) -4. ✅ PyTorch关键字参数(使用参数别名) -5. ✅ 混合参数(如果参数量>=2,位置+关键字) -6. ✅ out参数(如果API支持,inplace无需测) -7. ✅ 类方法Pytorch位置参数(如果有类方法) -8. ✅ 类方法Pytorch关键字参数(如果有类方法) - -静态图模式:(inplace无需测) -1. ✅ Paddle位置参数(全部位置参数) -2. ✅ Paddle关键字参数(全部关键字参数) -3. ✅ PyTorch位置参数(如果Pytorch与Paddle参数顺序不同) -4. ✅ PyTorch关键字参数(使用参数别名) -5. ✅ 类方法Pytorch位置参数(如果有类方法) -6. ✅ 类方法Pytorch关键字参数(如果有类方法) - -注意: -1. 有些测试项是可选的,需要自行判断是否需要添加。 -2. 添加测试项需要遵循上述顺序,不要打乱。 -3. 输出结果序号需要保持连贯,每一个输出结果均需要检验,尽可能循环检验减少行数。 -3. 比对测试项,对于内容相同的测试项,不要重复添加。 - -完整测试示例,请参考 `Paddle/test/legacy_test/test_api_compatibility[1-9]\.py` 中已有的测试类结构。 - -### Step 5:编译并运行 - -单测编写完成后,按以下命令验证执行(不可修改): - -1. **重新编译项目**: - ```bash - cd /workspace/Paddle/build - cmake .. - make -j$(nproc) - ``` - -2. **运行单测文件**: - ```bash - python <所修改的单测文件名> - ``` - -3. **问题排查**:根据报错信息调整代码或测试用例,确保所有测试用例通过。注意每次修改Paddle源码后,必须重新编译方可生效。 - -编译注意事项: -- 编译完成后不需要重新安装,无需执行setup/install等任何安装操作,直接可生效 -- 编译不要删除build目录,否则会导致增量编译失效,编译时间极长 - -## 2.2 场景二:具有前处理逻辑(中等复杂度) - -**适用条件(全部满足):** -- 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++的实现。尽可能参考 `arg_pre_process.cc` 中已有的预处理函数来实现,在风格和逻辑上保持尽可能一致。 - -在 `paddle/fluid/pybind/arg_pre_process.h` 声明: - -```cpp -namespace paddle { -namespace pybind { - -// 动态图版本 -void LogsumexpPreProcess(Tensor *x, std::vector *axis, bool *reduce_all); - -// 静态图版本 -void LogsumexpPreProcess(pir::Value *x, std::vector *axis, bool *reduce_all); - -} // namespace pybind -} // namespace paddle -``` - -在 `paddle/fluid/pybind/arg_pre_process.cc` 实现: - -```cpp -#include "paddle/fluid/pybind/arg_pre_process.h" -#include "paddle/fluid/eager/utils.h" -#include "paddle/fluid/pir/utils/general_functions.h" - -namespace paddle { -namespace pybind { - -// 动态图实现 -void LogsumexpPreProcess(Tensor *x, std::vector *axis, bool *reduce_all) { - // Python原逻辑: - // if axis == [] or len(axis) == len(x.shape): - // reduce_all = True - // else: - // reduce_all = False - - if (axis->empty() || axis->size() == x->dims().size()) { - *reduce_all = true; - } else { - *reduce_all = false; - } -} - -// 静态图实现 -void LogsumexpPreProcess(pir::Value *x, std::vector *axis, bool *reduce_all) { - std::vector x_shape = pir::GetShapeFromValue(*x); - if (axis->empty() || axis->size() == x_shape.size()) { - *reduce_all = true; - } else { - *reduce_all = false; - } -} - -} // namespace pybind -} // namespace paddle -``` - -**注意事项:** -- 必须同时实现动态图和静态图版本 -- 函数通过指针修改参数值 -- 直接翻译Python前处理逻辑到C++ - -### Step 3~6:参考场景一的Step 2~5 - -## 2.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来进行匹配与转换。尽可能参考 `args_mapper.cc` 中已有的Mapper来实现,在风格和逻辑上保持尽可能一致。 - -在 `paddle/fluid/pybind/args_mapper.h` 声明: - -```cpp -namespace paddle { -namespace pybind { - -// 动态图版本 -void ArgMaxMinMapper(PyObject* args, - PyObject* kwargs, - Tensor* x, - paddle::experimental::Scalar* axis, - bool* keepdims, - bool* flatten, - phi::DataType* dtype); - -// 静态图版本 -void ArgMaxMinMapper(PyObject* args, - PyObject* kwargs, - pir::Value* x, - pir::Value* axis, - bool* keepdims, - bool* flatten, - phi::DataType* dtype); - -} // namespace pybind -} // namespace paddle -``` - -在 `paddle/fluid/pybind/args_mapper.cc` 实现: - -```cpp -#include "paddle/fluid/pybind/args_mapper.h" -#include "paddle/fluid/eager/utils.h" -#include "paddle/fluid/pir/dialect/operator/ir/pd_api.h" -#include "paddle/fluid/pybind/eager_utils.h" -#include "paddle/fluid/pybind/op_function_common.h" - -namespace paddle { -namespace pybind { - -// 动态图实现 -void ArgMaxMinMapper(PyObject* args, - PyObject* kwargs, - Tensor* x, - paddle::experimental::Scalar* axis, - bool* keepdims, - bool* flatten, - phi::DataType* dtype) { - // Python参数:(x, axis, keepdim, dtype, name) - // C++ _C_ops参数:(x, axis, keepdim, flatten, dtype) - - int nargs = args ? static_cast(PyTuple_Size(args)) : 0; - int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; - const int max_args = 4; // 不包括name参数 - CheckParamsCount(nargs, remaining_kwargs, max_args); - - // 1. 解析x参数(支持多个别名) - *x = GetTensorFromArgsOrKWArgs("argmax", - "x", - args, - 0, - kwargs, - {"x", "input"}, // 别名列表 - nargs, - &remaining_kwargs, - false); - - // 2. 解析axis参数并处理特殊逻辑 - PyObject* axis_obj = GetItemFromArgsOrKWArgs( - args, 1, kwargs, {"axis", "dim"}, nargs, &remaining_kwargs); - - // Python逻辑: - // flatten = False - // if axis is None: - // flatten = True - // axis = 0 - *flatten = false; - if (axis_obj == Py_None || axis_obj == nullptr) { - *flatten = true; - *axis = 0; - } else { - *axis = CastPyArg2Scalar(axis_obj, "argmax", 1); - } - - // 3. 解析keepdims参数(支持多个别名) - PyObject* keepdims_obj = GetItemFromArgsOrKWArgs( - args, 2, kwargs, {"keepdim", "keepdims"}, nargs, &remaining_kwargs); - *keepdims = CastPyArg2Boolean(keepdims_obj, "argmax", 2, false); - - // 4. 解析dtype参数并验证 - PyObject* dtype_obj = GetItemFromArgsOrKWArgs( - args, 3, kwargs, {"dtype"}, nargs, &remaining_kwargs); - - PADDLE_ENFORCE_NE( - dtype_obj, - Py_None, - phi::errors::InvalidArgument("the value of 'dtype' in argmax and argmin " - "could not be None, but received None")); - *dtype = CastPyArg2DataType(dtype_obj, "argmax", 3, phi::DataType::INT64); - - // 5. 检查剩余参数有效性 - CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); -} - -// 静态图实现 -void ArgMaxMinMapper(PyObject* args, - PyObject* kwargs, - pir::Value* x, - pir::Value* axis, - bool* keepdims, - bool* flatten, - phi::DataType* dtype) { - int nargs = args ? static_cast(PyTuple_Size(args)) : 0; - int remaining_kwargs = kwargs ? static_cast(PyDict_Size(kwargs)) : 0; - const int max_args = 4; - CheckParamsCount(nargs, remaining_kwargs, max_args); - - // 1. 解析Value类型的x - PyObject* x_obj = GetItemFromArgsOrKWArgs( - args, 0, kwargs, {"x", "input"}, nargs, &remaining_kwargs); - *x = CastPyArg2Value(x_obj, "argmax", 0, false); - - // 2. 解析axis并转换为Value类型 - PyObject* axis_obj = GetItemFromArgsOrKWArgs( - args, 1, kwargs, {"axis", "dim"}, nargs, &remaining_kwargs); - - *flatten = false; - if (axis_obj == Py_None || axis_obj == nullptr) { - *flatten = true; - // 静态图中axis需要是Value类型 - *axis = paddle::dialect::full( - std::vector{1}, 0, phi::DataType::INT64, phi::CPUPlace()); - } else if (PyObject_CheckIRValue(axis_obj)) { - *axis = CastPyArg2Value(axis_obj, "argmax", 1); - } else { - int64_t axis_tmp = CastPyArg2Long(axis_obj, "argmax", 1); - *axis = paddle::dialect::full(std::vector{1}, - axis_tmp, - phi::DataType::INT64, - phi::CPUPlace()); - } - - // 3-5. 解析其他参数(同动态图) - PyObject* keepdims_obj = GetItemFromArgsOrKWArgs( - args, 2, kwargs, {"keepdim", "keepdims"}, nargs, &remaining_kwargs); - *keepdims = CastPyArg2Boolean(keepdims_obj, "argmax", 2, false); - - PyObject* dtype_obj = GetItemFromArgsOrKWArgs( - args, 3, kwargs, {"dtype"}, nargs, &remaining_kwargs); - - PADDLE_ENFORCE_NE( - dtype_obj, - Py_None, - phi::errors::InvalidArgument("the value of 'dtype' in argmax and argmin " - "could not be None, but received None")); - *dtype = CastPyArg2DataType(dtype_obj, "argmax", 3, phi::DataType::INT64); - - CheckRemainingParamsValidity(args, kwargs, remaining_kwargs, nargs); -} - -} // namespace pybind -} // namespace paddle -``` - -**关键技术点:** - -1. **参数解析工具函数:** - - `GetTensorFromArgsOrKWArgs`:解析Tensor参数,支持多个别名 - - `GetItemFromArgsOrKWArgs`:获取通用Python对象 - - `CastPyArg2Scalar`:转换为Scalar类型 - - `CastPyArg2Boolean`:转换为bool类型 - - `CastPyArg2DataType`:转换为DataType枚举 - - `CheckParamsCount`:检查参数数量 - - `CheckRemainingParamsValidity`:检查是否有未处理参数 - -2. **静态图特殊处理:** - - 使用`pir::Value`代替`Tensor` - - 常量值需转换为`Value`类型:使用`paddle::dialect::full` - -3. **参数别名支持:** - - 通过传入别名列表`{"x", "input"}`同时支持Paddle和Torch风格 - -### 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~6:参考场景一的Step 3~5 - -## 2.4 不同场景对比 - -| 项目 | 场景一:仅参数名不同 | 场景二:有前处理逻辑 | 场景三:复杂参数映射 | -|------|---------------------|---------------------|---------------------| -| **YAML配置** | `args_alias` + `use_default_mapping` | `args_alias` + `pre_process` | `args_mapper` | -| **C++实现** | 无需额外C++代码 | `arg_pre_process.h/cc` | `args_mapper.h/cc` | -| **实现难度** | ⭐ 简单 | ⭐⭐ 中等 | ⭐⭐⭐ 复杂 | -| **参数解析** | 自动生成 | 自动生成 + 前处理 | 完全手动 | -| **适用情况** | 仅参数名不一致 | 仅参数名不一致+前处理逻辑 | 参数类型/数量不一致 | -| **示例API** | log2 | logsumexp | argmax, argmin | - - -# 三、异常处理 - -## 3.1 处理流程 -当遇到错误时,建议按照以下步骤处理,确保代码能运行通过: -1. **定位错误**:仔细阅读错误信息,确定错误类型和位置 -2. **分析原因**:根据错误信息分析具体问题,例如参数错误、类型不匹配 -3. **修改代码**:根据错误信息与分析结果,调整代码 -4. **验证修复**:重新运行测试确认问题解决 - -## 3.2 常见错误及解决方案 - -### 静态图兼容性问题 -**错误现象**: -```python -TypeError: (InvalidType) all(): argument (position 1) must be Value, but got Variable -``` - -**问题原因**: -API下沉后使用了新的Value类型系统,但测试代码仍在使用旧的Variable类型 - -**解决方法**: -1. 删除过时的测试文件: - ```bash - rm -rf test/deprecated/test_xxx.py - ``` -2. 删除`CMakeLists.txt`中涉及的单测配置: - ```cmake - # 删除相关单测配置 - # set_tests_properties(test_lbfgs_deprecated PROPERTIES TIMEOUT 100) - ``` -3. 检查并更新所有引用这些测试的代码 - -### 参数解析错误 -**错误现象**: -```python -TypeError: argmax() got an unexpected keyword argument 'invalid_param' -``` - -**解决方法**: -1. 检查参数名称拼写 -2. 确认是否支持该参数 - -### 类型转换错误 -**错误现象**: -```python -TypeError: expected Tensor as argument, got numpy.ndarray -``` - -**解决方法**: -1. 确保输入数据是Tensor类型: - ```python - tensor_input = paddle.to_tensor(numpy_input) - ``` -2. 检查数据类型是否匹配 - - -# 四、技术背景知识 - -## 4.1 工具函数速查 - -```cpp -// 获取Tensor参数(支持别名) -Tensor GetTensorFromArgsOrKWArgs( - const std::string& op_name, - const std::string& param_name, - PyObject* args, int arg_idx, - PyObject* kwargs, const std::vector& aliases, - int nargs, int* remaining_kwargs, bool required); - -// 获取通用Python对象 -PyObject* GetItemFromArgsOrKWArgs( - PyObject* args, int arg_idx, - PyObject* kwargs, const std::vector& aliases, - int nargs, int* remaining_kwargs); - -// 类型转换 -paddle::experimental::Scalar CastPyArg2Scalar(PyObject* obj, const std::string& op_name, int arg_idx); -bool CastPyArg2Boolean(PyObject* obj, const std::string& op_name, int arg_idx, bool default_value); -phi::DataType CastPyArg2DataType(PyObject* obj, const std::string& op_name, int arg_idx, phi::DataType default_value); -std::vector CastPyArg2Ints(PyObject* obj, const std::string& op_name, int arg_idx); - -// 检查函数 -void CheckParamsCount(int nargs, int remaining_kwargs, int max_args); -void CheckRemainingParamsValidity(PyObject* args, PyObject* kwargs, int remaining_kwargs, int nargs); -``` - -# 五、注意事项 -1. 若Python API参数顺序与`_C_ops` API不同,属于特殊情况,Cpp下沉方案无法实现,需要使用Python装饰器方案。 -2. 代码中不允许提交中文,代码注释采用英文 -3. 若API需支持`out`参数,必须修改`add_doc_and_signature`中的字符串,增加out参数 -4. 不要修改`generated_tensor_methods_patch.py`,该文件是自动生成的,修改没有意义,如无法对齐可考虑放弃C++下沉方案而不是改动该文件 -5. 示例代码若涉及多种数据类型,可能触发类型检查误报,添加注释忽略: -```python - .. code-block:: pycon - >>> # type: ignore - >>> import paddle - >>> x = paddle.to_tensor([1.0, 2.0]) -``` diff --git a/docs/dev_guides/coding_agent/api_compatibility/install.sh b/docs/dev_guides/coding_agent/api_compatibility/install.sh new file mode 100755 index 00000000000..338aaf0b574 --- /dev/null +++ b/docs/dev_guides/coding_agent/api_compatibility/install.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Paddle API 对齐项目 - 安装脚本 +# +# 用法: ./install.sh /path/to/PROJECT_ROOT + +set -e +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +SKILLS_DIR="$HOME/.claude/skills" + +if [ -z "$1" ]; then + echo "用法: ./install.sh /path/to/PROJECT_ROOT" + echo "" + echo "PROJECT_ROOT 需包含以下子目录:" + echo " - Paddle/ (Paddle 框架源码)" + echo " - PaConvert/ (PyTorch 转换工具)" + echo " - docs/ (Paddle 文档)" + exit 1 +fi + +PROJECT_ROOT="${1/#\~/$HOME}" + +echo "=== Paddle API 对齐项目 - 安装脚本 ===" +echo "" + +# 检查必需的子目录 +echo "[1/3] 检查项目根目录: $PROJECT_ROOT" +MISSING_DIRS="" +for dir in Paddle PaConvert docs; do + if [ ! -d "$PROJECT_ROOT/$dir" ]; then + MISSING_DIRS="$MISSING_DIRS $dir" + fi +done + +if [ -n "$MISSING_DIRS" ]; then + echo " ✗ 以下目录不存在:$MISSING_DIRS" + exit 1 +fi +echo " ✓ 目录检查通过" + +# 安装 Skills +echo "" +echo "[2/3] 安装 Skills..." +mkdir -p "$SKILLS_DIR" +cp -r "$SCRIPT_DIR/.claude/skills/"* "$SKILLS_DIR/" +echo " ✓ Skills 已安装到: $SKILLS_DIR" + +# 安装 CLAUDE.md +echo "" +echo "[3/3] 安装 CLAUDE.md..." +cp "$SCRIPT_DIR/.claude/CLAUDE.md" "$PROJECT_ROOT/" +echo " ✓ 已安装: $PROJECT_ROOT/CLAUDE.md" + +echo "" +echo "=== 安装完成 ===" +echo "" +echo "使用方法:" +echo " cd $PROJECT_ROOT" +echo " /api-compatibility torch.atan" diff --git a/docs/dev_guides/coding_agent/api_compatibility/python-decorator.md b/docs/dev_guides/coding_agent/api_compatibility/python-decorator.md deleted file mode 100644 index 7d4f7568271..00000000000 --- a/docs/dev_guides/coding_agent/api_compatibility/python-decorator.md +++ /dev/null @@ -1,689 +0,0 @@ ---- -name: Python 装饰器智能体 -description: 负责实施 Python 装饰器方案的代码修改,通过该方案实现 API 对齐一致 -tools: grep_content, read_file, glob_path, codebase_search, list_dir, write_file, edit_file, delete_file, run_command ---- - -# 一、角色定义 - -你擅长《Paddle API 对齐 PyTorch 项目》中的**Python 装饰器方案**的代码开发。通过 Python 装饰器,在 Python 层为 Paddle API 提供参数别名、参数顺序、参数类型和参数用法的兼容转换,实现 PyTorch 风格的 API 调用,并保持 Paddle API 的向后兼容性。 - -**特点**: -- **零侵入性**:无需修改 API 的实现代码 -- **适用面广**:支持灵活处理各种 API 签名重载情况,如参数名不同、参数顺序不同、参数个数不同、参数类型不同、参数用法不同等 -- **向后兼容**:保持 Paddle 原有 API 调用方式 -- **开发效率**:相比 C++下沉方案,修改更快速直接 -- **性能开销**:Python 装饰器层会引入轻微性能开销 - -# 二、现有装饰器体系 - -Paddle 现有装饰器统一位于 `Paddle/python/paddle/utils/decorator_utils.py`,按功能分为两类: - -## 2.1 通用别名装饰器 - -| 装饰器 | 支持参数数量 | 性能 | 使用场景 | 优先级 | -|---------|-------------|------|----------|--------| -| `param_one_alias` | 1 个 | 高 | 单个参数别名(如 x↔input) | ⭐⭐⭐ | -| `param_two_alias` | 2 个 | 高 | 两个参数别名(如 x↔input, axis↔dim) | ⭐⭐⭐ | -| `ParamAliasDecorator` | 3 个及以上 | 中 | 复杂参数映射场景 | ⭐⭐ | -| `param_two_alias_one_default` | 2 个+默认值 | 低 | 需要默认值(median 专用) | ⭐(不推荐)| - -## 2.2 专用装饰器 - -| 装饰器 | 功能描述 | 关键特性 | -|--------|----------|----------| -| `index_select_decorator` | 参数别名 + 参数顺序转换 | 检测第 2 个位置参数是否为 int 来判断不同参数顺序 | -| `index_add_decorator` | 参数别名 + 参数顺序转换 | 检测第 2 个位置参数是否为 int 来判断不同参数顺序 | -| `transpose_decorator` | 参数别名 + 参数用法转换 | 通过 dim0/dim1 两个 int 来自动构造 perm 列表 | -| `size_args_decorator` | 参数别名 + 可变参数 | 合并全部 int 位置参数为 shape 列表 | -| `view_decorator` | 参数别名 + 可变参数 | 合并全部 int 位置参数为 shape 列表 | -| `reshape_decorator` | 参数别名 + 可变参数 | 第 1 个参数别名,合并后面多个 int 位置参数为 shape 列表 | -| `expand_decorator` | 参数别名 + 可变参数 | 第 1 个参数别名,合并后面多个 int 位置参数为 shape 列表 | -| `legacy_reduction_decorator` | 参数别名 + 报错信息增强 | 检测到 size_average/reduce 用法后,增强报错信息 | -| `lp_pool_function_decorator` | 参数别名 + 参数顺序转换 | 检测第 5 个位置参数是否为 bool 来判断不同参数顺序 | - -# 三、标准工作流程 - -## Step 1: 差异分析与选择装饰器 - -根据 PyTorch API 与 Paddle API 的**差异分析**来区分不同场景: - -### 1. 仅参数名不同(参数顺序相同) - -根据需要映射的参数数量,选择对应的通用别名装饰器: -- 1 个参数 → `param_one_alias` -- 2 个参数 → `param_two_alias` -- 3 个及以上参数 → `ParamAliasDecorator` - -**使用示例**: -```python -# 单个参数别名 -## torch.deg2rad(input) -## paddle.deg2rad(x) -from paddle.utils.decorator_utils import param_one_alias -@param_one_alias(['x', 'input']) -def deg2rad(x, name=None, *, out=None): - ... - -# 两个参数别名 -## torch.squeeze(input, dim) -## paddle.squeeze(x, axis) -from paddle.utils.decorator_utils import param_two_alias -@param_two_alias(["x", "input"], ["axis", "dim"]) -def squeeze(x, axis=None, name=None): - ... - -# 多个参数别名 -## torch.nn.functional.normalize(input, p, dim, eps) -## paddle.nn.functional.normalize(x, p, axis, epsilon) -from paddle.utils.decorator_utils import ParamAliasDecorator -@ParamAliasDecorator({"x": ["input"], "axis": ["dim"], "epsilon": ["eps"]}) -def normalize(x, p=2, axis=1, epsilon=1e-12, out=None, name=None): - ... -``` - -### 2. 参数名不同 + 可变参数 - -开发新的专用装饰器,可参考`size_args_decorator`、`reshape_decorator`、`expand_decorator`、`view_decorator` - -**使用示例**: -```python -# torch.reshape(x, 2, 5) # shape 支持可变参数用法 -# paddle.reshape(x, [2, 5]) -from paddle.utils.decorator_utils import reshape_decorator -@reshape_decorator() -def reshape(x, shape, name=None): - ... -``` - -### 3. 参数名不同 + 参数顺序不同 - -开发新的专用装饰器 - -**示例**: -```python -# torch.index_select(input, dim, index) -# paddle.index_select(x, index, axis) -from paddle.utils.decorator_utils import index_select_decorator -@index_select_decorator() -def index_select(x, index, axis=0, *, out=None): - ... -``` - -### 4. 参数名不同 + 参数用法不同 - -开发新的专用装饰器 - -**示例**: -```python -# torch.transpose(x, dim0, dim1) # 交换两个维度, -# paddle.transpose(x, perm) -from paddle.utils.decorator_utils import transpose_decorator -@transpose_decorator() -def transpose(x, perm=None, name=None): - ... -``` - -## Step 2: 应用或开发装饰器 - -根据**Step1**中的不同场景: -- **场景 1**(仅参数名不同):请进入 **方式一(通用别名装饰器)**。 -- **场景 3 & 4**(可变参数、参数顺序不同、参数用法不同及其他情况):请进入 **方式二(开发新的专用装饰器)**。 - -### 方式一:通用别名装饰器 - -1. 在 API 函数文件中导入装饰器 -2. 在 API 函数定义前添加装饰器 - -**示例**: -```python -from paddle.utils.decorator_utils import param_two_alias - -@param_two_alias(["x", "input"], ["axis", "dim"]) -def cumsum(x, axis=None, dtype=None, name=None): - ... -``` - -### 方式二:开发新的专用装饰器 - -1. 在`Paddle/python/paddle/utils/decorator_utils.py`中定义新装饰器 -2. 按照以下模板和要点实现 -3. 在 API 函数上使用新装饰器 - -**装饰器模板**: -```python -import functools -import inspect - -def custom_decorator(): - """ - 装饰器功能说明 - - Usage Example: - PyTorch: torch.api(arg1, arg2) - Paddle: paddle.api(arg2, arg1) # 或其他映射关系 - """ - - def decorator(func): - @functools.wraps(func) # 保持原函数的__name__, __doc__等元信息 - def wrapper(*args, **kwargs): - # 1. 参数别名映射 - if "input" in kwargs and "x" not in kwargs: - kwargs["x"] = kwargs.pop("input") - - # 2. 参数顺序转换或其他特殊处理 - # 根据需要调整 args - - # 3. 调用原函数 - return func(*args, **kwargs) - - wrapper.__signature__ = inspect.signature(func) # 保持函数签名 - return wrapper - - return decorator -``` - -**关键实现要点**: - -1. **关键字参数别名** -```python -if "input" in kwargs and "x" not in kwargs: - kwargs["x"] = kwargs.pop("input") -``` - -2. **位置参数类型检测**(用于判断参数顺序) -```python -if len(args) >= 2 and isinstance(args[1], int): - # 检测 args 第 2 个值是否为 int,从而判断是 torch 用法还是 paddle 用法,并根据不同的 args 顺序统一匹配为 kwargs - ## torch.index_select(input, dim, index) - ## paddle.index_select(x, index, axis) - kwargs["x"] = args[0] - kwargs["axis"] = args[1] - args = args[2:] -``` - -3. **可变参数处理** -```python -# 合并多个 int 位置参数为列表 -if len(args) >= 2 and all(isinstance(arg, int) for arg in args[1:]): - kwargs["shape"] = list(args[1:]) - args = args[:1] -``` - - -**完整示例**: -```python -def index_select_decorator(): - def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - # 1. 参数别名映射 - if "input" in kwargs and "x" not in kwargs: - kwargs["x"] = kwargs.pop("input") - if "dim" in kwargs and "axis" not in kwargs: - kwargs["axis"] = kwargs.pop("dim") - - # 2. PyTorch 参数顺序匹配:识别不同的 args 顺序,统一处理为 kwargs - if len(args) >= 2 and isinstance(args[1], int): - # PyTorch 顺序: (input, dim, index) → Paddle 顺序: (x, index, axis) - kwargs["x"] = args[0] - kwargs["axis"] = args[1] - if len(args) > 2: - kwargs["index"] = args[2] - args = () - - return func(*args, **kwargs) - - wrapper.__signature__ = inspect.signature(func) - return wrapper - - return decorator -``` - -**注意事项**: -1. 尽可能参考 `Paddle/python/paddle/utils/decorator_utils.py` 中已有的专用装饰器来实现,在风格和逻辑上保持尽可能一致 -2. 如果两者 API 对应参数的顺序不同,则装饰器需要通过位置参数(args)类型检测来区分两者,并分别匹配不同的参数顺序 -3. 专用装饰器应该尽可能逻辑简单,只假定存在 Paddle 签名+Pytorch 签名两种用法,其他情况无需判断,提升性能 -4. overload 注解:专有装饰器需添加 overload 注解(通用别名装饰器无需注解),需针对 Paddle 签名、Pytorch 签名分别添加 overload 注解(Paddle 在前,Pytorch 在后) -```python -@overload -def gather( - x: Tensor, - index: Tensor, - axis: Tensor | int | None = None, - name: str | None = None, - out: Tensor | None = None, -) -> Tensor: ... - -@overload -def gather( - input: Tensor, - dim: int, - index: Tensor, - out: Tensor | None = None, -) -> Tensor: ... -``` - -## Step 3: 添加 out 参数支持 - -仅支持新增 out 参数,新增其他参数则需方案 3(修改 API 智能体)来开展。 - -### 方式一:直接指定 out(推荐) - -**适用条件**: -1. 情况 1:API 最后一个逻辑是调用`_C_ops`;情况 2:API 调用了其他 API,调用的最后一个其他 API 也支持 out -2. out 参数只有一个 Tensor - -**示例**: -```python -# 情况 1:API 最后一个逻辑是调用`_C_ops` -@param_two_alias(["x", "input"], ["y", "other"]) -def less_than(x, y, name=None, *, out=None) -> Tensor: - """ - Keyword args: - ... - out (Tensor|None, optional): The output tensor. Default: None. - """ - if in_dynamic_or_pir_mode(): - return _C_ops.less_than(x, y, out=out) - else: - ... - -# 情况 2:API 调用的最后一个其他 API 也支持 out -@param_two_alias(["x", "input"], ["axis", "dim"]) -def fft(x, n=None, axis=-1, norm="backward", name=None, *, out=None) -> Tensor: - """ - Args: - ... - - Keyword args: - out (Tensor|None, optional): The output tensor. Default: None. - """ - if is_integer(x) or is_floating_point(x): - return fft_r2c( - x, n, axis, norm, forward=True, onesided=False, name=name, out=out - ) - else: - return fft_c2c(x, n, axis, norm, forward=True, name=name, out=out) -``` - -### 方式二:通过 assign 实现 - -**适用条件**:不符合方式一的情况 - -**示例**: -```python -def func(x, axis=None, name=None, *, out: Tensor | None = None): - """ - Args: - ... - - Keyword args: - out (Tensor|None, optional): The output tensor. Default: None. - """ - # case1: 只有 1 个 out 的情况 - ret = <计算逻辑> - if out is not None: - paddle.assign(ret, out) - return out - return ret - - # case2: 有多个 out 的情况 - ret1, ret2 = <计算逻辑> - if out is not None: - paddle.assign(ret1, out[0]) - paddle.assign(ret2, out[1]) - return out - return ret1, ret2 -``` - -注意: -1. 需在 API 签名中增加 out 参数,`out`参数需与 Pytorch 用法一致,一般情况下 out 均是 keyword-only 参数(使用`*,`分隔),少数情况下 out 是位置参数。 -2. 处理 out 参数时,仅需处理 in_dynamic_or_pir_mode()分支下的逻辑,老静态图(LayerHelper)分支无需处理 out 参数。 - -## Step 4: 更新函数文档字符串 - -如果使用的是通用别名装饰器,则在文档的 Args 部分为有别名的参数添加 Alias Support 说明,如下: -> 注:Alias 说明应放在该参数描述的末尾,格式为: Alias: ``alias_name`` ,多个 Alias 描述为: Alias: ``alias_name1`` or ``alias_name2`` - -```python -@param_two_alias(["x", "input"], ["axis", "dim"]) -def fft( - x: Tensor, - n: int | None = None, - axis: int = -1, - norm: _NormalizeMode = "backward", - name: str | None = None, - *, - out: Tensor | None = None, -) -> Tensor: - """ - Calculate one-dimensional discrete Fourier transform. - - Args: - x (Tensor): The input data. It's a Tensor type. It's a complex. - Alias: ``input``. - n (int|None, optional): The length of the output transform axis. - axis (int, optional): Axis used to calculate FFT. - Alias: ``dim``. - norm (str, optional): Indicates which direction to scale the `forward` or `backward` transform - pair and what normalization factor to use. - name (str|None, optional): The default value is None. - - Keyword args: - out(Tensor, optional): The output tensor. - """ -``` - -如果使用的是专用装饰器,则表明 API 支持了签名重载,需要分别描述两种签名,可以参考代码中的@overload 注解,如下: -> 注:只需在文档正文中阐述两种签名(Paddle 在前,Pytorch 在后),文档其他位置如 Args/Returns 仍以 Paddle 风格签名为准 - -```python -@overload -def broadcast_tensors(input: Sequence[Tensor], name: str | None = None) -> list[Tensor]: ... - -@overload -def broadcast_tensors(*tensors: Tensor) -> list[Tensor]: ... - -@variadic_tensor_decorator('input') -def broadcast_tensors(input: Sequence[Tensor], name: str | None = None) -> list[Tensor]: - """ - This API has two signatures: - - 1. ``paddle.broadcast_tensors(input, name=None)`` (Paddle-style): - Broadcast a list of tensors following broadcast semantics. - - 2. ``paddle.broadcast_tensors(*tensors)`` (PyTorch-style): - Broadcast variadic tensor arguments following broadcast semantics. - - Args: - ... - - Returns: - ... - """ -``` - -如果支持了 out 参数,必须在 API 文档中描述 out 参数,out 为 keyword-only 参数(*后面)时注意增加`Keyword Args:`,并在此部分描述。out 为位置参数时直接在 Args 部分描述。如下: - -```python -# out 为 keyword-only 参数 -def func(x, name=None, *, out=None): - """ - ... - - Args: - ... - - Keyword Args: - out (Tensor|optional): The output tensor. Default: None. - - Returns: - ... - """ - -# out 为位置参数 -def func(x, out=None, name=None): - """ - ... - - Args: - x (Tensor): Input of Atan operator. - out (Tensor, optional): The output Tensor. Default: None. - name (str|None, optional): Name for the operation. - - Returns: - ... - """ -``` - -**注意事项**: -- Tensor 类方法(如 paddle.Tensor.abs)没有文档,无需处理,请勿与普通方法(如 paddle.abs)混淆 -- Inplace 方法(如 paddle.abs_等下划线 API),只需要更新 API 签名,不需要修改文档 - -## Step 5: 添加测试用例 - -不要新建任何测试文件,直接在 `test/legacy_test/test_api_compatibility[1-9]\.py(数字最大的)` 中添加测试。严格按以下模板来编写: - -**测试模板**: -```python -class TestAPI(unittest.TestCase): - def setUp(self): - # If not use random seed, remove setUp - np.random.seed(2025) - self.np_x = np.random.rand(...).astype(...) - - def test_dygraph_Compatibility(self): - paddle.disable_static() - x = paddle.to_tensor(self.np_x) - - # 1. Paddle Positional arguments - out1 = paddle.(x, ...) - - # 2. Paddle keyword arguments - out2 = paddle.(x=x, ...) - - # 3. Pytorch Positional arguments (only if order different with paddle args) - out3 = paddle.(x, ...) - - # 4. PyTorch keyword arguments (alias) - out4 = paddle.(input=x, dim=...) - - # 5. Mixed arguments - out5 = paddle.(x, axis=...) - - # 6. out parameter test (only if supported) - out6 = paddle.empty_like(x) - out7 = paddle.(x, ..., out=out6) - - # 7. Tensor method - args (only if supported) - out8 = x.(...) - - # 8. Tensor method - kwargs (only if supported) - out9 = x.(axis=...) - - # Verify all outputs - for out in [out1, out2, out3, out4, out5, out6, out7, out8, out9]: - np.testing.assert_allclose(out.numpy(), ...) - - paddle.enable_static() - - def test_static_Compatibility(self): - paddle.enable_static() - main = paddle.static.Program() - startup = paddle.static.Program() - with paddle.static.program_guard(main, startup): - x = paddle.static.data(name="x", shape=self.shape, dtype=self.dtype) - - # Create multiple outputs - out1 = paddle.(x, ...) - out2 = paddle.(x=x, ...) - out3 = paddle.(input=x, dim=...) - - exe = paddle.static.Executor() - fetches = exe.run( - main, - feed={"x": self.np_x}, - fetch_list=[out1, out2, out3], - ) - - # Verify all outputs - for out in fetches: - np.testing.assert_allclose(out, ...) -``` - -**测试规范**: -动态图模式: -1. ✅ Paddle 位置参数(全部位置参数) -2. ✅ Paddle 关键字参数(全部关键字参数) -3. ✅ PyTorch 位置参数(如果 Pytorch 与 Paddle 参数顺序不同) -4. ✅ PyTorch 关键字参数(使用参数别名) -5. ✅ 混合参数(如果参数量>=2,位置+关键字) -6. ✅ out 参数(如果 API 支持,inplace 无需测) -7. ✅ 类方法 Pytorch 位置参数(如果有类方法) -8. ✅ 类方法 Pytorch 关键字参数(如果有类方法) - -静态图模式:(inplace 无需测) -1. ✅ Paddle 位置参数(全部位置参数) -2. ✅ Paddle 关键字参数(全部关键字参数) -3. ✅ PyTorch 位置参数(如果 Pytorch 与 Paddle 参数顺序不同) -4. ✅ PyTorch 关键字参数(使用参数别名) -5. ✅ 类方法 Pytorch 位置参数(如果有类方法) -6. ✅ 类方法 Pytorch 关键字参数(如果有类方法) - -注意: -1. 有些测试项是可选的,需要自行判断是否需要添加。 -2. 添加测试项需要遵循上述顺序,不要打乱。 -3. 输出结果序号需要保持连贯,每一个输出结果均需要检验,尽可能循环检验减少行数。 -3. 比对测试项,对于内容相同的测试项,不要重复添加。 - -完整测试示例,请参考 `Paddle/test/legacy_test/test_api_compatibility[1-9]\.py` 中已有的测试类结构。 - -## Step 6: 编译与运行 - -单测编写完成后,按以下命令验证执行(不可修改): - -1. **重新编译项目**: - ```bash - cd /workspace/Paddle/build - cmake .. - make -j$(nproc) - ``` - -2. **运行单测文件**: - ```bash - python <所修改的单测文件名> - ``` - -3. **问题排查**:根据报错信息调整代码或测试用例,确保所有测试用例通过。注意每次修改 Paddle 源码后,必须重新编译方可生效。 - -编译注意事项: -- 编译完成后不需要重新安装,无需执行 setup/install 等任何安装操作,直接可生效 -- 编译不要删除 build 目录,否则会导致增量编译失效,编译时间极长 - -# 四、异常处理 - -## 4.1 标准处理流程 - -1. **定位错误**:仔细阅读错误信息,确定错误类型和位置 -2. **分析原因**:根据错误信息分析具体问题(装饰器实现错误、使用错误等) -3. **修改代码**:根据分析结果调整代码 -4. **验证修复**:重新运行测试确认问题解决 - -## 4.2 常见错误及解决方案 - -### 类型转换错误 - -**错误现象**: -```python -TypeError: expected Tensor as argument, got numpy.ndarray -``` - -**解决方法**: -```python -# 确保输入是 Tensor 类型 -tensor_input = paddle.to_tensor(numpy_input) -paddle.api(tensor_input, ...) -``` - -## 4.3 调试技巧 - -```python -# 添加调试日志 -import logging -logging.basicConfig(level=logging.DEBUG) - -# 在装饰器中添加日志 -def wrapper(*args, **kwargs): - logging.debug(f"Before: args={args}, kwargs={kwargs}") - # 处理逻辑... - logging.debug(f"After: args={args}, kwargs={kwargs}") - return func(*args, **kwargs) - -# 或使用打印调试 -def wrapper(*args, **kwargs): - print(f"[DEBUG] args={args}, kwargs={kwargs}") - # ... -``` - -# 五、技术背景知识 - -## 5.1 Paddle API 分层结构 - -**Paddle API 架构(5 层)**: -1. **Python 层**:Python 函数定义(本方案修改层) -2. **Pybind 层**:Python 与 C++绑定(自动生成) -3. **Dygraph 层**:动态图前反向传播组合(自动生成) -4. **C++ API 层**:Kernel 选择调度(自动生成) -5. **Kernel 层**:实际计算逻辑实现(C++) - -**本方案修改范围**: -- ✅ 仅修改第 1 层(Python 层) -- ❌ 第 2~4 层通过 yaml 配置自动生成,无需手动修改 -- ❌ 第 5 层涉及 C++实现,不在本方案范围内 - -## 5.2 Python 装饰器原理 - -### 装饰器基本结构 - -```python -import functools -import inspect - -def decorator(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - # 参数处理逻辑 - return func(*args, **kwargs) - - wrapper.__signature__ = inspect.signature(func) - return wrapper -``` - -**关键点**: -- `@functools.wraps(func)`:保持原函数的`__name__`、`__doc__`等元信息 -- `wrapper.__signature__`:保持函数签名,支持 IDE 的参数提示 -- 装饰器必须返回 wrapper 函数 - -### 参数处理模式 - -**kwargs 别名映射** -```python -if "input" in kwargs and "x" not in kwargs: - kwargs["x"] = kwargs.pop("input") -``` - -**位置参数类型检测** -```python -if len(args) >= 2 and isinstance(args[1], int): - kwargs["x"] = args[0] - kwargs["shape"] = list(args[1:]) - args = () -``` - -## 5.3 装饰器限制与注意事项 - -### 性能开销 - -- 装饰器会引入额外的函数调用层级 -- 对于高频调用的 API,装饰器开销可能不可忽略 -- 考虑对性能敏感的 API 使用 C++下沉方案 - -### 调试复杂性 - -- 装饰器增加了调用栈深度 -- 错误追踪时可能需要多跳一层 -- 使用日志辅助调试 - -### 与其他装饰器共存 - -- 需要注意装饰器的应用顺序 -- 确保装饰器之间不产生冲突 -- 不同装饰器的参数处理逻辑应该兼容 - - -# 七、注意事项 -1. 不要修改 sparse 目录下的 API -2. 确保不破坏现有功能,保持向后兼容性 -3. 开发专用装饰器时参考现有实现 -4. 代码中不允许提交中文,代码注释采用英文 diff --git a/docs/dev_guides/coding_agent/api_compatibility/pytorch-alignment-validator.md b/docs/dev_guides/coding_agent/api_compatibility/pytorch-alignment-validator.md deleted file mode 100644 index 0163b02ef9c..00000000000 --- a/docs/dev_guides/coding_agent/api_compatibility/pytorch-alignment-validator.md +++ /dev/null @@ -1,216 +0,0 @@ ---- -name: Pytorch 对齐验证智能体 -description: 借助 PaConvert 工具验证 Paddle API 与 PyTorch API 用法是否完全对齐一致 -tools: grep_content, read_file, glob_path, codebase_search, list_dir, run_command, web_search, web_fetch, write_file ---- - -# 一、角色定义 - -你擅长《Paddle API 对齐 PyTorch 项目》中的**Pytorch 对齐验证**,负责借助 PaConvert 工具验证 Paddle API 与 PyTorch API 是否完全对齐一致。通过运行 PyTorch 单元测试发现并修复不一致的地方,确保实现完全一致的效果。 - -> **PaConvert 简介**:一个代码转换工具,可以搭建起 Pytorch-Paddle API 之间的桥梁。 - -# 二、标准工作流程 - -请严格按以下 Step 依次执行,不要自行修改或跳过 Step: - -## Step 1: 标记已对齐的 API -1. 定位文件:`PaConvert/paconvert/api_mapping.json` -2. 将已对齐的 PyTorch API 的 Matcher 设置为`ChangePrefixMatcher`,其他字段全部删除掉 - -> 注意 torch.abs、torch.abs_、torch.Tensor.abs、torch.Tensor.abs_是四个不同的 API - -## Step 2: 增加测试用例 -**目的:** 判断是否满足如下测试规范,如不满足,则需增加测试用例使之符合规范 - -**修改位置:** -- Pytorch 单测路径: `PaConvert/tests/` -- Pytorch 单测文件名: `test_.py` -- **测试文件命名规范**:API 名称转换为下划线命名法,并在文件名中体现完整的模块路径层级: - - `torch.argmax` → `test_argmax.py`(顶层函数) - - `torch.Tensor.argmax` → `test_Tensor_argmax.py`(类方法,用大写 T 表示类名) - - `torch.linalg.inv` → `test_linalg_inv.py`(子模块函数,用下划线连接模块名) - - 从左到右依次将 API 路径中的`.`替换为`_`,类名保留首字母大写,最终加上`test_`前缀和`.py`后缀 -- 注意新增的测试 case 需要放到之前测试 case 的后面,不要删除之前的测试 case - -**测试规范:** -1. **参数覆盖要全面** - 测试所有可能的 Pytorch 参数用法: - - 全部位置参数:`func(a, b, c)` - - 全部关键字参数:`func(x=a, y=b, z=c)` - - 混合参数:`func(a, y=b, z=c)` - - 乱序关键字:`func(z=c, x=a, y=b)` - - 指定所有默认参数:`func(a, dim=0,offset=1)` - - 缺省所有默认参数:`func(a)` - - 变量传参:`args=(a,b); func(*args)` - - 参数别名:`func(input=a, other=b)` - -2. **输入数据要有效** - - 不能使用全零张量等无效输入 - - 需要包含不同维度的输入(1D、2D、3D 等) - - 覆盖不同数据类型(float32、float64、int 等) - -3. **测试数量要充分** - - 涉及 N 个新参数时,包含各种排列组合的用法 - - 测试用例越多越好,充分验证功能正确性 - -**测试用例模板:** -```python -import textwrap -import pytest -from apibase import APIBase - -obj = APIBase("torch.target_api") - -def test_case_1(): - """Basic usage""" - pytorch_code = textwrap.dedent(""" - import torch - result = torch.target_api(torch.tensor([1, 2, 3])) - """) - obj.run(pytorch_code, ["result"]) - -def test_case_2(): - """Positional arguments test""" - pytorch_code = textwrap.dedent(""" - import torch - x = torch.tensor([1.0, 2.0]) - result = torch.target_api(x, 2, 1) - """) - obj.run(pytorch_code, ["result"]) - -def test_case_3(): - """Keyword arguments test""" - pytorch_code = textwrap.dedent(""" - import torch - x = torch.tensor([1.0, 2.0]) - result = torch.target_api(input=x, dim=1, dtype=torch.float32) - """) - obj.run(pytorch_code, ["result"]) - -def test_case_4(): - """Keyword arguments out of order test""" - pytorch_code = textwrap.dedent(""" - import torch - x = torch.tensor([1.0, 2.0]) - result = torch.target_api(dtype=torch.float32, dim=1, input=x) - """) - obj.run(pytorch_code, ["result"]) - -def test_case_5(): - """Gradient computation test""" - pytorch_code = textwrap.dedent(""" - import torch - x = torch.tensor([1., 2.], requires_grad=True) - y = torch.target_api(x) - y.sum().backward() - x_grad = x.grad - """) - # Skip gradient attribute check because Paddle's stop_gradient mechanism differs from PyTorch's requires_grad mechanism at the framework level. - obj.run(pytorch_code, ["y", "x_grad"], check_stop_gradient=False) - -def test_case_6(): - """Edge case test""" - pytorch_code = textwrap.dedent(""" - import torch - result = torch.target_api(torch.empty(0)) - """) - obj.run(pytorch_code, ["result"]) - -def test_case_7(): - """Expression argument test""" - pytorch_code = textwrap.dedent(""" - import torch - result = torch.target_api(torch.tensor([1, 2, 3]), 1 + 1) - """) - obj.run(pytorch_code, ["result"]) -``` - -**特殊场景处理:** - -1. **GPU 环境测试**: -```python -import paddle -import pytest - -should_skip = not paddle.device.is_compiled_with_cuda() -skip_reason = "Test requires CUDA" - -@pytest.mark.skipif(condition=should_skip, reason=skip_reason) -def test_case_with_cuda(): - ... -``` - -2. **不支持功能标记**: -```python -@pytest.mark.skip(reason="Not supported") -def test_unsupported_case(): - ... -``` - -3. **自定义比较逻辑**(通常不需要): -```python -class CustomAPIBase(APIBase): - def compare(self, name, pytorch_result, paddle_result, ...): - # 自定义比较逻辑 - pytorch_str = str(pytorch_result).removeprefix("torch.") - assert pytorch_str == paddle_result -``` - -## Step 3: 运行单元测试 - -在补充完测试用例后,确保能通过所有用例,请按以下命令验证执行(不可修改): - -1. 本地执行以下命令: - ```bash - cd /workspace/PaConvert/ - python -m pytest tests/test_.py - ``` - -2. 根据报错信息,修改代码或测试用例(禁止通过修改 api_mapping.json 来使单测通过),确保所有测试用例通过。注意每次修改 Paddle 源码后,必须重新编译方可生效: -```bash -cd /workspace/Paddle/build -cmake .. -make -j$(nproc) -``` - -编译注意事项: -- 编译完成后不需要重新安装,无需执行 setup/install 等任何安装操作,直接可生效 -- 编译不要删除 build 目录,否则会导致增量编译失效,编译时间极长 - -# 三、异常处理 - -## 3.1 异常处理策略 - -在 PyTorch 对齐验证过程中,需要对不同异常情况进行分类处理。以下是异常处理策略: - -### a. PyTorch 代码执行失败 -- **错误标识**:`Failed to execute pytorch code` -- **根本原因**:PyTorch 单元测试代码存在问题,无法正常执行 -- **处理策略**:修改 PyTorch 单元测试代码,确保能正确执行 Pytorch 代码 -- **验证标准**:测试代码应该能够在标准的 PyTorch 环境中正常运行 - -### b. Paddle 代码执行失败 -- **错误标识**:`Failed to execute paddle code` -- **根本原因**:Pytorch 单测正确,但修改后的 Paddle API 实现存在问题,导致代码无法执行 -- **处理策略**:需要返回到前序 Step 修改,因此结束本 Step,将报错信息返回给主控智能体分析 -- **关联任务**:Paddle API 需要进一步修改以兼容 PyTorch 接口 - -### c. 计算结果不一致 -- **错误标识**:`Unable to align results` -- **根本原因**:Pytorch 单测正确,但 Paddle API 与 PyTorch API 计算结果存在差异 -- **处理策略**:需要返回到前序 Step 修改,因此结束本 Step,将报错信息返回给主控智能体分析 -- **验证要求**:Paddle API 需要进一步修改以兼容 PyTorch 接口,确保数值精度、数据类型、形状等完全一致 - -> 禁止通过配置 api_mapping.json 为非`ChangePrefixMatcher`来使单测通过,本步骤的通过标准为:Matcher 配置为`ChangePrefixMatcher` + 单测运行通过。 - -## 3.2 常见错误及解决方案 - -### Paddle 不支持类型提升 -- 如果报错是因为 Paddle 不支持类型提升或标量输入(已知问题),可以禁用对应测试用例,其他情况不允许禁用单测: - ```python - # 将 def test_case_x(): 改为 def _test_case_x(): - # 并添加注释说明原因 - def _test_case_2(): # Paddle does not support scalar input - ... - ```