|
| 1 | +--- |
| 2 | +name: api-change-decider |
| 3 | +description: 仅用于《Paddle API 对齐 PyTorch 项目》,负责 Step1:方案决策,分析 PyTorch API 与 Paddle API 之间的差异,制定合适的 API 改动方案 |
| 4 | +allowed-tools: Read Grep Glob WebSearch |
| 5 | +disable-model-invocation: false |
| 6 | +--- |
| 7 | + |
| 8 | +# 一、输入输出规范 |
| 9 | + |
| 10 | +## 1.1 输入 |
| 11 | +需要对齐的 PyTorch API 列表(如 `torch.atan`、`torch.asinh`) |
| 12 | + |
| 13 | +## 1.2 输出 |
| 14 | +方案类型、对应 Paddle API、差异分类、决策依据(以表格形式展示) |
| 15 | + |
| 16 | +## 1.3 输出内容 |
| 17 | +输出应包含如下内容,以表格式形式展示: |
| 18 | +1. **方案类型**:从方案 1~6 中选择合适的方案(可组合多种方案,例如方案 3+方案 1) |
| 19 | +2. **对应 Paddle API**:需改动的 Paddle API 完整路径(如 `paddle.nn.functional.dropout`) |
| 20 | +3. **差异分类**:差异分类是什么 |
| 21 | +4. **决策依据**:总结差异分析过程和选择理由 |
| 22 | + - API 相对引用路径是否一致 |
| 23 | + - 为什么选择该方案 |
| 24 | + - 为什么不选择其他方案 |
| 25 | + - 该方案是否会影响后向兼容 |
| 26 | + |
| 27 | +## 1.4 输出格式示例 |
| 28 | +```markdown |
| 29 | +# 决策结果 |
| 30 | +|Pytorch API|方案类型|Paddle API|差异分类|决策依据| |
| 31 | +|-|-|-|-|-| |
| 32 | +|torch.atan|方案 2|paddle.atan|torch 参数更多|仅参数名不同(input→x)+仅多 out 参数,Python 实现仅有一次`_C_ops.atan(x)`调用,满足 C++下沉条件,性能最优| |
| 33 | +|torch.frexp|方案 3+方案 1|paddle.frexp|torch 参数更多|API 相对引用路径一致,差异为:1)仅参数名不同(input→x);2)仅多 out 参数。当前 Python 实现包含多个 paddle 操作调用(abs、floor、log2 等),逻辑较复杂,不满足 C++下沉条件。选择方案 3 修改 API,在末尾添加 out 参数(带默认值 None),保持后向兼容。同时方案 1 支持参数名不同的重载情况。| |
| 34 | +``` |
| 35 | + |
| 36 | +# 二、候选方案 |
| 37 | + |
| 38 | +## 方案 1:Python 装饰器 |
| 39 | +**适用场景**: |
| 40 | +- 在 Python 层添加装饰器实现对齐 |
| 41 | +- 可对输入 `(*args, **kwargs)` 进行操作 |
| 42 | +- 支持多种重载情况:参数名不同、参数顺序不同、参数个数不同、参数类型不同 |
| 43 | +- 同时支持 torch 和 paddle 两套参数签名 |
| 44 | + |
| 45 | +**工作原理**: |
| 46 | +- 根据输入参数的名称、类型、个数的不同来判断是 torch 签名还是 paddle 签名 |
| 47 | +- 分别针对两套签名进行不同的功能适配,从而既保留了原本的 paddle 功能,也新增了 torch 功能 |
| 48 | +- 这是方案 3(修改 API)的升级版,在保持后向兼容性的前提下实现对齐 |
| 49 | + |
| 50 | +**核心要求**: |
| 51 | +- **必须能够区分**:能够根据输入的参数类型、名称的不同来区分 torch 签名还是 paddle 签名 |
| 52 | +- **无法区分则不适用**:如果无法通过输入参数特征区分两套签名,则方案 1 不适用 |
| 53 | + |
| 54 | +**优点**:灵活性强,兼容性好 |
| 55 | +**缺点**:性能低于 C++下沉实现 |
| 56 | + |
| 57 | +## 方案 2:C++下沉 |
| 58 | +**适用场景**: |
| 59 | +- 将 API 直接下沉到 C++层 |
| 60 | +- Paddle 机制支持在 C++层配置参数映射 |
| 61 | +- **支持仅参数名不同的重载情况**(不涉及参数顺序或个数差异) |
| 62 | +- **支持仅多 out 参数的情况** |
| 63 | +- 方案 2 需要判断 API 的 Python 实现,需满足以下两个条件: |
| 64 | + - 只有一次 `_C_ops.xxx` 调用 |
| 65 | + - `_C_ops.xxx` 前面没有**前处理逻辑**,或虽有**前处理逻辑**但逻辑简单且不涉及其他 API 调用(如 x.flatten 等),容易改写为 C++ |
| 66 | + - 注:分析时忽略静态图部分(LayerHelper 分支代码),该分支不再维护 |
| 67 | + |
| 68 | +**方案 2 不适用场景(满足其一则不适用)**: |
| 69 | +- ❌ API 差异涉及参数顺序或个数差异 |
| 70 | +- ❌ Python 实现里调用了其他**Paddle API**,如 x.flatten、paddle.flatten(x)等 |
| 71 | +- ❌ 包含多个 `_C_ops.xxx` 调用 |
| 72 | +- ❌ `_C_ops.xxx` 前面的**前处理逻辑**较为复杂,不容易被改写为 C++ |
| 73 | + |
| 74 | +**优点**:性能最优 |
| 75 | +**缺点**:仅支持参数名不同的情况 |
| 76 | + |
| 77 | +## 方案 3:修改 API |
| 78 | +**适用场景**: |
| 79 | +- 直接修改现有 API 实现对齐 |
| 80 | +- 新增参数或功能 |
| 81 | +- 修改原有参数或功能 |
| 82 | + |
| 83 | +**以下修改不会导致后向兼容问题,可开展**: |
| 84 | +- ✅ 在 API 参数末尾添加参数,且参数具有默认值 |
| 85 | +- ✅ 对已有 API 参数扩展新功能,保留原有功能 |
| 86 | + |
| 87 | +**以下修改会导致后向兼容问题,需禁止**: |
| 88 | +- ❌ 改变已有参数顺序 |
| 89 | +- ❌ 改变已有参数名称 |
| 90 | +- ❌ 修改返回值类型 |
| 91 | + |
| 92 | +**优点**:直接对齐,实现简单 |
| 93 | +**缺点**:可能导致后向不兼容 |
| 94 | + |
| 95 | +## 方案 4:新增 API |
| 96 | +**适用场景**: |
| 97 | +- API 相对引用路径不一致 |
| 98 | +- 新增的 API 需要与 Pytorch 完全一致,包括 API 相对引用路径、输入参数与返回值(名称、个数、功能均一致) |
| 99 | + |
| 100 | +**优点**:完全对齐,无后向兼容问题 |
| 101 | + |
| 102 | +## 方案 5:新增 compat 类型 API |
| 103 | +**适用场景**: |
| 104 | +- 在 `paddle/compat/__init__.py` 下新增 API |
| 105 | +- 既无法原地修改(后向兼容性问题严重) |
| 106 | +- 也无法新增 API(API 相对引用路径已被占用) |
| 107 | + |
| 108 | +**优点**:无后向兼容问题 |
| 109 | +**缺点**:多一级 compat 路径,无法真正实现与 Pytorch 完全一致,实现之后差异分类将成为『仅 API 调用方式不一致』,在无其他方案时可以退而求其次选择 |
| 110 | + |
| 111 | +## 方案 6:无需改动 |
| 112 | +**适用场景**: |
| 113 | +- API 完全一致 |
| 114 | + |
| 115 | +# 三、标准工作流程 |
| 116 | + |
| 117 | +## Step 1: 分析差异文档 |
| 118 | + |
| 119 | +### 1.1 获取差异文档 |
| 120 | +务必查阅每个 PyTorch API 对应的 API 差异文档(`torch.{api_name}.md`,位于 docs/docs/guides/model_convert/convert_from_pytorch/api_difference/目录下),如果实在无法找到差异文档,则说明该 API 已经实现了对齐一致,差异分类直接视作『API 完全一致』,无需再查询其他内容。 |
| 121 | + |
| 122 | +### 1.2 差异分类定义 |
| 123 | +差异分类共 13 类,具体如下: |
| 124 | + |
| 125 | +| 序号 | 差异分类 | 说明 | |
| 126 | +|:---:|:---|:---| |
| 127 | +| 1 | API 完全一致 | 无差异,无需改动 | |
| 128 | +| 2 | 仅 API 调用方式不一致 | API 相对引用路径不一致,但参数完全相同 | |
| 129 | +| 3 | 仅参数名不一致 | 参数功能相同但参数名称不同 | |
| 130 | +| 4 | paddle 参数更多 | Paddle 提供更多可选参数 | |
| 131 | +| 5 | 参数默认值不一致 | 参数默认值不同 | |
| 132 | +| 6 | torch 参数更多 | PyTorch 提供更多参数 | |
| 133 | +| 7 | 输入参数用法不一致 | 参数处理方式不同 | |
| 134 | +| 8 | 输入参数类型不一致 | 参数类型要求不同 | |
| 135 | +| 9 | 返回参数类型不一致 | 返回值类型或结构不同 | |
| 136 | +| 10 | 组合替代实现 | PyTorch API 需多个 Paddle API 组合实现 | |
| 137 | +| 11 | 可删除 | PyTorch API 在 Paddle 中可直接删除 | |
| 138 | +| 12 | API 别名 | PyTorch API 是其他 API 的别名 | |
| 139 | +| 13 | 功能缺失 | Paddle 暂无等效实现 | |
| 140 | + |
| 141 | +### 1.3 提取差异信息 |
| 142 | + |
| 143 | +提取相关差异信息,提供给 Step2 进行方案决策: |
| 144 | + |
| 145 | +| 项目 | 内容 | |
| 146 | +|------|------| |
| 147 | +| API 映射 | PyTorch API vs 对应的 Paddle API(可能为空)| |
| 148 | +| 参数映射 | 参数对应关系和差异说明 | |
| 149 | +| 转写示例 | 代码转换示例 | |
| 150 | + |
| 151 | +注意以下参数直接忽略,不视作差异信息: |
| 152 | +1. 忽略第 1 列的 generator、memory_format、layout 参数 |
| 153 | +1. 忽略第 2 列的 name 参数 |
| 154 | + |
| 155 | +## Step 2: 方案决策 |
| 156 | + |
| 157 | +### 2.1 关键概念 |
| 158 | + |
| 159 | +**API 相对引用路径**:API 完整路径在去掉框架导入模块(torch/paddle)后剩余的部分 |
| 160 | +- 示例:`torch.nn.functional.dropout` 的 API 相对引用路径是 `nn.functional.dropout` |
| 161 | +- 示例:`paddle.nn.functional.dropout` 的 API 相对引用路径是 `nn.functional.dropout` |
| 162 | +- 示例:`torch.Tensor.tile` 的 API 相对引用路径是 `Tensor.tile` |
| 163 | + |
| 164 | +### 2.2 关键原则 |
| 165 | + |
| 166 | +> **⚠️ 严格遵循**:决策时必须严格遵守以下原则,不得主观臆断: |
| 167 | +> |
| 168 | +> 1. **API 相对引用路径不一致 → 必须方案 4(新增 API)** |
| 169 | +> - 只要 API 相对引用路径不一致,直接选择方案 4,无需再分析其他因素 |
| 170 | +> - 对于一方为空的情况下,也视作不一致(无对应 Paddle API 情况下) |
| 171 | +> |
| 172 | +> 2. **严格按流程图和规则判断** |
| 173 | +> - 必须按照决策流程图的路径执行 |
| 174 | +> - 严格按照各方案的适用条件判断 |
| 175 | +> - 不得因"可以"、"应该"等主观判断偏离规则定义 |
| 176 | +
|
| 177 | +### 2.3 决策流程图 |
| 178 | + |
| 179 | +``` |
| 180 | +开始 |
| 181 | + │ |
| 182 | + ├───→ API 相对引用路径是否一致? ──────┐ |
| 183 | + │ │ |
| 184 | + │是 │否 |
| 185 | + ↓ ↓ |
| 186 | +具体有哪些差异? 方案 4(新增 API)→结束 |
| 187 | + │ |
| 188 | + ├──→ API 完全一致 → 方案 6(无需改动)→结束 |
| 189 | + │ |
| 190 | + ├──→ 仅参数名不一致 → 方案 2(C++下沉)→ 不适用则方案 1→结束 |
| 191 | + │ |
| 192 | + ├──→ paddle 参数更多 → 是否影响对齐?─┬→否→方案 6(无需改动)→结束 |
| 193 | + │ └→是→方案 3(修改 API)→存在兼容性则方案 5→结束 |
| 194 | + │ |
| 195 | + ├──→ 参数默认值不一致 → 方案 3(修改 API)→存在兼容性则方案 5→结束 |
| 196 | + │ |
| 197 | + ├──→ torch 参数更多 → 仅多 out 参数?─┬→是→方案 2(C++下沉)→不适用则方案 3→存在兼容性则方案 1→无法区分则方案 5→结束 |
| 198 | + │ └→否→方案 3(修改 API)→存在兼容性则方案 1→无法区分则方案 5→结束 |
| 199 | + │ |
| 200 | + ├──→ 输入参数用法/类型不一致 → 方案 3(修改 API)→存在兼容性则方案 1→无法区分则方案 5→结束 |
| 201 | + │ |
| 202 | + └──→ 返回参数类型不一致 → 方案 5(新增 compat 类型 API)→结束 |
| 203 | +``` |
| 204 | + |
| 205 | +### 2.4 详细决策规则 |
| 206 | + |
| 207 | +**前置判断**:以下规则均基于**API 相对引用路径一致**的前提。只要 API 相对引用路径不一致,直接选择**方案 4(新增 API)**,无需进入后续判断。 |
| 208 | + |
| 209 | +#### 1. API 完全一致 |
| 210 | +- **决策**:方案 6(无需改动) |
| 211 | + |
| 212 | +#### 2. 仅参数名不一致 |
| 213 | +- **优先级 1**:方案 2(C++下沉) |
| 214 | + - **适用条件**:满足方案 2 适用条件(见第三部分定义) |
| 215 | + - **优势**:性能最优 |
| 216 | +- **优先级 2**:方案 1(Python 装饰器) |
| 217 | + - **适用条件**:不满足方案 2 适用条件 |
| 218 | + |
| 219 | +#### 3. paddle 参数更多 |
| 220 | +- **判断**:额外参数是否影响对齐 |
| 221 | + - **否**(如默认参数,Paddle 保持默认即可)→ 方案 6(无需改动) |
| 222 | + - **是** → 方案 3(修改 API) |
| 223 | + - **存在兼容性** → 方案 5(新增 compat 类型 API) |
| 224 | + |
| 225 | +#### 4. 参数默认值不一致 |
| 226 | +- **优先级 1**:方案 3(修改 API) |
| 227 | +- **回退**:存在兼容性 → 方案 5(新增 compat 类型 API) |
| 228 | + |
| 229 | +#### 5. torch 参数更多 |
| 230 | +- **子判断**:是否仅多 out 参数 |
| 231 | + - **是** → 方案 2(C++下沉) |
| 232 | + - **不适用** → 方案 3(修改 API)→ 存在兼容性则方案 1→ 无法区分则方案 5 |
| 233 | + - **否** → 方案 3(修改 API)→ 存在兼容性则方案 1→ 无法区分则方案 5 |
| 234 | + |
| 235 | +#### 6. 输入参数用法/类型不一致 |
| 236 | +- **优先级 1**:方案 3(修改 API) |
| 237 | + - **存在兼容性** → 方案 1(Python 装饰器) |
| 238 | + - **无法区分两套签名** → 方案 5(新增 compat 类型 API) |
| 239 | + |
| 240 | +#### 7. 返回参数类型不一致 |
| 241 | +- **唯一决策**:方案 5(新增 compat 类型 API) |
| 242 | +- **原因**: |
| 243 | + - ❌ 方案 3:修改返回值必然不兼容 |
| 244 | + - ❌ 方案 1:装饰器只能根据输入区分,无法区分返回值差异 |
| 245 | + - ✅ 方案 5:在 compat 路径下新增,不影响原 API |
| 246 | + |
| 247 | +### 2.5 方案组合说明 |
| 248 | + |
| 249 | +> **重要提醒**:一个 API 可能涉及多种差异分类,需要综合分析所有差异点,可以组合多种方案来消除所有差异点。 |
| 250 | +
|
| 251 | +**示例**:`torch.frexp` 存在"仅参数名不同"和"仅多 out 参数"两个差异点 |
| 252 | +- **组合方案**:方案 3 + 方案 1 |
| 253 | + - 方案 3:在末尾添加 out 参数(带默认值 None),消除"仅多 out 参数"差异 |
| 254 | + - 方案 1:支持参数名不同的重载,消除"仅参数名不同"差异 |
0 commit comments