diff --git a/ops/README.md b/ops/README.md index f7072ed..8450929 100644 --- a/ops/README.md +++ b/ops/README.md @@ -62,6 +62,9 @@ grep -rl my_op . | xargs sed -i 's/my_op/<你的算子名>/g' ## 约定 - **目录名 = 算子名**(小写下划线,如 `gelu_and_mul`) +- **交付自查清单**: 见 templates/operator/README「交付自查清单」节 + (2026-10-07 审计后新增——13 算子曾缺包化入口已补齐,后续算子 + 合并前照单自查,勿再欠账) - **包化导入(多算子同进程必用)**: 目录含 `__init__.py`, `from ops.sdpa import register_a1` / `from ops.embedding import register_a1` / `from ops.sdpa_math import register_a1` 顶层名带包前缀, diff --git a/ops/_local_scalar_dense/__init__.py b/ops/_local_scalar_dense/__init__.py new file mode 100644 index 0000000..02acb1a --- /dev/null +++ b/ops/_local_scalar_dense/__init__.py @@ -0,0 +1,29 @@ +"""ops._local_scalar_dense — aten::_local_scalar_dense 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops._local_scalar_dense import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops._local_scalar_dense." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference")._local_scalar_dense_reference + raise AttributeError(f"ops._local_scalar_dense has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/clone/__init__.py b/ops/clone/__init__.py new file mode 100644 index 0000000..5b2dec8 --- /dev/null +++ b/ops/clone/__init__.py @@ -0,0 +1,29 @@ +"""ops.clone — aten::clone 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.clone import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.clone." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").clone_reference + raise AttributeError(f"ops.clone has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/contiguous/__init__.py b/ops/contiguous/__init__.py new file mode 100644 index 0000000..ecaca27 --- /dev/null +++ b/ops/contiguous/__init__.py @@ -0,0 +1,29 @@ +"""ops.contiguous — aten::contiguous 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.contiguous import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.contiguous." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").contiguous_reference + raise AttributeError(f"ops.contiguous has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/copy_/__init__.py b/ops/copy_/__init__.py new file mode 100644 index 0000000..08a708b --- /dev/null +++ b/ops/copy_/__init__.py @@ -0,0 +1,29 @@ +"""ops.copy_ — aten::copy_ 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.copy_ import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.copy_." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").copy_reference + raise AttributeError(f"ops.copy_ has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/detach/__init__.py b/ops/detach/__init__.py new file mode 100644 index 0000000..1de5a02 --- /dev/null +++ b/ops/detach/__init__.py @@ -0,0 +1,29 @@ +"""ops.detach — aten::detach 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.detach import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.detach." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").detach_reference + raise AttributeError(f"ops.detach has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/detach_/__init__.py b/ops/detach_/__init__.py new file mode 100644 index 0000000..3114be2 --- /dev/null +++ b/ops/detach_/__init__.py @@ -0,0 +1,29 @@ +"""ops.detach_ — aten::detach_ 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.detach_ import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.detach_." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").detach__reference + raise AttributeError(f"ops.detach_ has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/dropout/__init__.py b/ops/dropout/__init__.py new file mode 100644 index 0000000..025aae7 --- /dev/null +++ b/ops/dropout/__init__.py @@ -0,0 +1,29 @@ +"""ops.dropout — aten::dropout 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.dropout import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.dropout." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").dropout_reference + raise AttributeError(f"ops.dropout has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/embedding/MERGE.md b/ops/embedding/MERGE.md new file mode 100644 index 0000000..09e48d9 --- /dev/null +++ b/ops/embedding/MERGE.md @@ -0,0 +1,42 @@ +# 多平台合并流程(MERGE)— embedding + +> 新平台实现合入本目录的固定流程。范式实证:ascend910(PR#11)→ +> cambricon(PR#9 rebase 合入)。核心原则:**黄金/测试/注册链复用, +> 只写 kernel 本体**。 + +## 七步流程 + +1. **黄金复用**:`goldendata/` 平台无关(CPU 生成),新平台直接跑 + `script/check_accuracy.py`——不过黄金不谈合并 +2. **kernel 本体**:`kernel/.py` 四件套——`embedding` / + `embedding_backward` / `PLATFORM` / `_DEVICE_PROBE`(注册守卫 + 能力探测) +3. **facade 注册**:`kernel/platform.py` 三处——`_BACKENDS` 设备 + 映射、`DISPATCH_KEYS`、`synchronize` 分支 +4. **register 选择器**:`register.py` 的 `_BACKENDS` dict 加一行; + dispatch_key 冲突时(如 npu/mlu 同为 AutogradPrivateUse1)依赖 + `platform=` 显式参数 +5. **_profile 探测链**:`_profile.py` 加 try-import 段(顺序与 sdpa + 对齐:mlu → xmlir → npu → cpu) +6. **三层验证**:`EMBEDDING_PROFILE=` 跑 kernel/op/framework + 三层 + `example.py` 一键 +7. **文档同步**:README/REPORT 平台列、reports/ 增量、本文件与 + PLATFORM.md 绑定项、CHANGELOG + +## 合并冲突解决范式(PR#9 rebase 实证) + +- 文档冲突:双方内容**并列**(验证矩阵按平台列拆行),不删任何一方 +- 代码冲突:统一采 **platform facade** 新范式(旧 `_load_backend` / + 裸 `from kernel import` 全部迁移) +- rebase 后必须:本机全链回归 + `ops/test_packaging.py`(多算子 + 同进程)双绿才可合并 + +## 验证矩阵终态(三平台) + +| 层 | 命令 | 结果 | +|---|---|---| +| kernel(ascend910) | `EMBEDDING_PROFILE=ascend910 python3 test/kernel_level.py` | 20 前向+6 反向 err=0.0 | +| op(ascend910) | `test/op_level.py` | 拦截 5 次·逐位·梯度 err=0.0 | +| kernel/op/应用(p800) | 同上 | 20/20+6/6 err=0;A1 拦截 5 次 | +| kernel/op/应用(cambricon) | `EMBEDDING_PROFILE=cambricon ...` | 见 reports/cambricon.md | +| 包化共存 | `python3 ops/test_packaging.py` | 16 算子导入+双注册+消费 全绿 | diff --git a/ops/embedding/PLATFORM.md b/ops/embedding/PLATFORM.md new file mode 100644 index 0000000..6b1608c --- /dev/null +++ b/ops/embedding/PLATFORM.md @@ -0,0 +1,50 @@ +# 平台绑定清单(Platform Binding)— embedding + +> 当前交付包含三个平台:**ascend910**(厂商委托:index_select 同源 +> err=0 + dense_backward 委托)、**p800-kunlunxin**(厂商委托同构, +> gatherFIX 探针见 reports/)与 **cambricon**(MLU590,Autograd key +> 注册——见 reports/cambricon.md §4)。 +> 本文件记录不可凭直觉搬运的绑定结论;跨平台移植时逐项重验,不要把 +> 单平台实验结果当成普适行为。 + +## 1. 可直接复用(平台无关) + +| 内容 | 位置 | +|---|---| +| fp32 语义参考 | `reference.py` | +| 黄金规格与数据 | `goldendata/`(CPU 生成,天然跨平台) | +| 平台 facade(按张量设备路由) | `kernel/platform.py` | +| 三层测试、性能脚本 | `test/`、`script/`(`EMBEDDING_PROFILE` 切平台) | +| A1 autograd.Function 包装 | `register.py`(`_BACKENDS` 选择器 + `_DEVICE_PROBE` 守卫) | + +## 2. ascend910 绑定(厂商委托) + +| 绑定项 | 实测结论 | +|---|---| +| A1 拦截 key | **AutogradPrivateUse1**(PrivateUse1 永不命中——sdpa 开发报告 §3.1 dispatch 证据链同结论) | +| aten 签名坑 | `aten::embedding_dense_backward` **5 参无 sparse**(与 Python 层 6 参不同) | +| autograd.Function | staticmethod 读模块全局 → `register_a1` 里 `global` 全部三变量(PLATFORM/embedding/embedding_backward) | +| 同步 API | `torch.npu.synchronize`(非 cuda);`kernel/platform.py::synchronize` 已平台化 | +| 性能 | 委托=包装开销 0.62-0.99x native;Triton gather 探针 18-69x 慢(P800 结论在 Ascend 复现——embedding 是带宽型,自研 Triton 无优势) | + +## 3. p800-kunlunxin 绑定 + +- XMLIR 将 XPU 呈现为 **CUDA 张量**(device.type=="cuda"),dispatch + key 为 AutogradCUDA +- gatherFIX 探针结论见 `reports/`(正确性 0 error;特化比 native 慢 + 10.9-177.9x——与 ascend910 的 Triton 探针结论一致) + +## 4. cambricon(MLU590)绑定 + +- **Autograd key** 注册(与 configs/devices/cambricon.yaml 的 + PrivateUse1 不同):embedding 带 autograd 的 A1 交付须注册 Autograd + key 才能携带自带 backward;两个 key 实测都能命中,取 Autograd key + 以免覆盖 functorch 的 PrivateUse1 batch rule(reports/cambricon.md §4) +- 与 ascend910 同为 AutogradPrivateUse1 时:单机双 NPU+MLU 场景须 + `EMBEDDING_PROFILE` 显式指定平台(`_backend_for` 的 platform 参数 + 优先于 dispatch_key 推断) + +## 5. 新平台接入 + +按 `MERGE.md` 七步走;kernel 层实现 `embedding`/`embedding_backward` ++ `PLATFORM` + `_DEVICE_PROBE` 四件即可并入 `_BACKENDS`。 diff --git a/ops/empty/__init__.py b/ops/empty/__init__.py new file mode 100644 index 0000000..7b52659 --- /dev/null +++ b/ops/empty/__init__.py @@ -0,0 +1,29 @@ +"""ops.empty — aten::empty 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.empty import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.empty." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").empty_reference + raise AttributeError(f"ops.empty has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/empty_like/__init__.py b/ops/empty_like/__init__.py new file mode 100644 index 0000000..f643237 --- /dev/null +++ b/ops/empty_like/__init__.py @@ -0,0 +1,29 @@ +"""ops.empty_like — aten::empty_like 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.empty_like import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.empty_like." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").empty_like_reference + raise AttributeError(f"ops.empty_like has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/empty_strided/__init__.py b/ops/empty_strided/__init__.py new file mode 100644 index 0000000..c7c5694 --- /dev/null +++ b/ops/empty_strided/__init__.py @@ -0,0 +1,29 @@ +"""ops.empty_strided — aten::empty_strided 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.empty_strided import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.empty_strided." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").empty_strided_reference + raise AttributeError(f"ops.empty_strided has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/item/__init__.py b/ops/item/__init__.py new file mode 100644 index 0000000..8bbd65c --- /dev/null +++ b/ops/item/__init__.py @@ -0,0 +1,29 @@ +"""ops.item — aten::item 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.item import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.item." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").item_reference + raise AttributeError(f"ops.item has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/result_type/__init__.py b/ops/result_type/__init__.py new file mode 100644 index 0000000..2ce6a5d --- /dev/null +++ b/ops/result_type/__init__.py @@ -0,0 +1,29 @@ +"""ops.result_type — aten::result_type 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.result_type import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.result_type." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").result_type_reference + raise AttributeError(f"ops.result_type has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/ops/sdpa_math/PLATFORM.md b/ops/sdpa_math/PLATFORM.md new file mode 100644 index 0000000..cc13880 --- /dev/null +++ b/ops/sdpa_math/PLATFORM.md @@ -0,0 +1,36 @@ +# 平台绑定清单(Platform Binding)— sdpa_math + +> 当前交付包含两个平台:**ascend910**(自研 Triton:两段式 probs+PV, +> 小形状单 kernel 融合)与 **p800-kunlunxin**(vendor O/LSE + exact-P +> + A1)。cpu 为 ATen 组合对照。 +> 绑定结论移植时逐项重验;详细实验数据见 `reports/`。 + +## 1. 可直接复用(平台无关) + +| 内容 | 位置 | +|---|---| +| fp32 语义参考 | `reference.py` | +| 黄金规格与数据 | `goldendata/`(CPU 生成) | +| 三层测试、性能脚本 | `test/`、`script/`(位置参数传平台) | +| A1 注册(含平台分发) | `register.py` | + +## 2. ascend910 绑定(自研 Triton) + +- A1 拦截 key **AutogradPrivateUse1**(sdpa 同结论) +- Triton tile 上限 64×64(单核 192KB UB——见 sdpa + reports/perf_analysis.md,本算子同栈约束) +- 与 sdpa 全量版的关系:本算子是 `_scaled_dot_product_math` 的 + exact-P 分解路线;形状路由建议沿用 sdpa `kernel/auto_dispatch.py` + 的截流范式(大 S 走原生) + +## 3. p800-kunlunxin 绑定 + +- XMLIR 呈现 CUDA 张量(AutogradCUDA) +- vendor O/LSE 委托 + exact-P 补偿;`kernel/p800_fast_level.py` +- probes/ 归档(7 个探针)为该平台的证据链 + +## 4. 新平台接入 + +参照 `ops/sdpa/MERGE.md` 七步流程(本算子暂无独立 MERGE.md,结构 +对齐后可裁剪复用);kernel 本体 + register 平台分发 + 三层验证 + +包化 `__init__.py`(已有)四件套不可省。 diff --git a/ops/test_packaging.py b/ops/test_packaging.py index 4b34894..0e76a0b 100644 --- a/ops/test_packaging.py +++ b/ops/test_packaging.py @@ -60,6 +60,16 @@ print(f" sdpa 路由: native={stats['routed_native']} " f"triton={stats['routed_triton']}") +# ── 3.5 全算子包态导入扫描(审计回归: __init__.py 逐个可导)── +import importlib as _il +_ops_dir = ROOT / "ops" +for _d in sorted(_ops_dir.iterdir()): + if not _d.is_dir() or _d.name.startswith("__"): + continue + _m = _il.import_module(f"ops.{_d.name}") + assert hasattr(_m, "register_a1"), f"ops.{_d.name} 缺 register_a1 导出" +print(f"[3.5] 全算子包态导入 OK({sum(1 for _d in _ops_dir.iterdir() if _d.is_dir() and not _d.name.startswith('__'))} 目录)") + # ── 4. 单算子旧用法兼容(脚本模式 sys.path 注入)── import subprocess r = subprocess.run( diff --git a/ops/type_as/__init__.py b/ops/type_as/__init__.py new file mode 100644 index 0000000..89351ce --- /dev/null +++ b/ops/type_as/__init__.py @@ -0,0 +1,29 @@ +"""ops.type_as — aten::type_as 算子包。 + +包化约定(多算子同进程必用, 见 ops/README「包化导入」与 +sdpa/reports/e2e_mini_llm.md 的同名冲突实证): + - 包态: from ops.type_as import register_a1 ← 顶层名带包前缀 + - 脚本态: sys.path.insert(0, 算子目录) 后 from register import ... + (单算子目录内运行不变) + +wt 2026-10-07-fix 补包化入口(审计发现 13 算子缺失, #14 范式补齐) +# wt +""" +from __future__ import annotations + +import importlib + + +def _pkg_import(name: str): + return importlib.import_module("ops.type_as." + name) + + +def __getattr__(name: str): + if name == "register_a1": + return _pkg_import("register").register_a1 + if name == "reference": + return _pkg_import("reference").type_as_reference + raise AttributeError(f"ops.type_as has no attribute {name!r}") + + +__all__ = ["register_a1", "reference"] diff --git a/templates/operator/README.md b/templates/operator/README.md index 593d40b..80dca84 100644 --- a/templates/operator/README.md +++ b/templates/operator/README.md @@ -106,4 +106,18 @@ grep -rl my_op . | xargs sed -i 's/my_op/<你的算子名>/g' 转发原生会无限递归, 用函数层 patch(sdpa 教训) 参考样例: [ops/sdpa](../../ops/sdpa/)(三平台 + 路由 + e2e)· -[ops/embedding](../../ops/embedding/)(双平台 + 委托模式)。 +[ops/embedding](../../ops/embedding/)(三平台 + 委托模式 + facade)。 + +## 交付自查清单(合并前逐项打勾) + +> 2026-10-07 全库审计后新增——审计发现 13 算子缺包化入口、多平台 +> 算子缺 PLATFORM/MERGE 文档。后续作者请勿再欠账: + +- [ ] 核心八件: README / REPORT / / reference / + register / example / kernel/ / test/ +- [ ] 三层测试: test/{kernel,op,framework}_level.py 全绿 +- [ ] 性能对照: script/bench_perf.py(native 参照必备)+ reports/ 四件套 +- [ ] 黄金: goldendata/ + script/check_accuracy.py 全过 +- [ ] 包化回归: `ops/test_packaging.py` 全算子导入扫描通过 +- [ ] 多平台时: PLATFORM.md(绑定清单)+ MERGE.md(七步流程) +- [ ] 署名: 改动处 `wt-YYYY-MM-DD-fix` + `# wt <邮箱>`,commit 作者一致