Repository navigation
fix: 13 算子 register_a1 签名升级(counter + platform,#19) - #25
Conversation
按 templates/operator/register.py 与 ops/embedding 的 _BACKENDS + _DEVICE_PROBE 范式,升级 13 个算子的 A1 注册签名: - 签名统一为 register_a1(dispatch_key="AutogradPrivateUse1", counter: dict | None = None, platform=None) - 新增 _BACKENDS/_backend_for(platform 显式优先,dispatch_key 推断; 覆盖 Autograd/PrivateUse1/AutogradPrivateUse1 -> cambricon)与 _DEVICE_PROBE 注册守卫(MLU 可用性探测) - 10 个可注册算子:命中计数支持 counter["n"];test/op_level.py 同步 传入 counter 并断言 - 3 个不可注册算子(empty/detach_/result_type)同步签名,保持按设计 抛 NotImplementedError 验证(v26.08.0 容器,MLU): - 13/13 example 三层全绿;pytest tests/unit 24 passed - counter/platform/默认 key 实测通过 - 真实 vLLM A1 框架测试 tests/framework_level/test_a1_aten_ops.py 1 passed - 13 算子包态导入通过(ops.test_packaging.py 依赖 torch_npu,MLU 上未跑)
There was a problem hiding this comment.
感谢补充真机验证 🙏 先说明总体结论:signature / counter / platform 这条主线是对的,13 个算子的真机三层和 vLLM 注入结果也很有价值。我提 Request Changes 不是否定这批修复,而是包态调用链还有一个可复现的运行时缺口,需要补上后再合。
1. 已确认完成的部分
这几点我已经对过 PR 和说明,方向正确:
-
13 个算子都改成了新签名:
register_a1( dispatch_key="AutogradPrivateUse1", counter: dict | None = None, platform=None, )
-
10 个可注册算子接入了
counter["n"],op 层测试也断言了计数。 -
empty/detach_/result_type没有被强行注册,仍然保留NotImplementedError,符合原设计。 -
增加了 platform/dispatch key 校验和 MLU 设备探测。
-
CI 三门已经通过;你们 MLU 环境的 13/13 三层、
pytest tests/unit、真实 vLLM 注入结果也说明签名升级本身没有破坏现有脚本态用法。
下面的问题只针对 包态运行时路径。
2. 阻塞问题:包态不只是“能 import register_a1”,还要能执行到本算子 kernel
背景:仓库里现在有两种调用模式
这个仓库的算子需要同时支持两种模式。
模式 A:单算子脚本模式
例如 test/op_level.py 通常会先把算子目录插到 sys.path:
sys.path.insert(0, ops/clone)
import register
在这种模式下,下面这种裸导入可以工作:
from kernel.triton_level import clone_triton因为 ops/clone 就在 sys.path 里,顶层 kernel 能解析到 ops/clone/kernel。
模式 B:多算子包态模式
也是 #14 包化要支持的场景:
from ops.clone import register_a1这时 Python 的模块名是:
ops.clone.register
如果 register.py 内部仍然裸写:
from kernel.triton_level import clone_triton它找的是顶层 kernel,不是 ops.clone.kernel。在多算子同进程里,顶层 kernel 甚至可能已经被别的算子占用,这是 #13/#14 当初要根治的冲突来源。
可复现问题
在 PR 分支、仓库根目录下执行:
import torch
from ops.clone.register import clone_aten
clone_aten(torch.zeros(2))当前结果:
ModuleNotFoundError: No module named 'kernel'
这说明包态不仅能导出 register_a1,而且已经拿到了 clone_aten;但一执行就失败在实现内部的顶层 kernel 导入。
为什么现有验证没有发现?
因为现有检查分成了几层,每层都没有覆盖到这个位置:
-
ops-packagingCI 只验证:import ops.<op> assert hasattr(module, "register_a1")
它会触发
register.py导入,但不会调用clone_aten(),所以不会执行函数体里的:from kernel.triton_level import clone_triton
-
13 个算子的 op/framework 测试主要还是单算子脚本模式,
sys.path已经插入了各自目录,所以裸导入能工作。 -
真实 vLLM 注入大概率也是通过插件/脚本路径导入,这同样可能掩盖包态问题。
因此,这不是和你们验证结果矛盾,而是验证矩阵里还缺了一格:package mode + actual kernel execution。
建议的最小修复
10 个可注册算子的实现导入都改成“包态优先、脚本态 fallback”:
try:
from .kernel.triton_level import clone_triton
except ImportError:
from kernel.triton_level import clone_triton需要覆盖这 10 个文件:
ops/_local_scalar_dense/register.py
ops/clone/register.py
ops/contiguous/register.py
ops/copy_/register.py
ops/detach/register.py
ops/dropout/register.py
ops/empty_like/register.py
ops/empty_strided/register.py
ops/item/register.py
ops/type_as/register.py
empty / detach_ / result_type 不注册,没有这个问题。
建议补的验证
至少在 MLU 真机上选一个代表算子,直接走包态执行路径。最小验证可以是直接调用实现函数,不注册全局 aten op,避免测试进程污染:
import torch
from ops.clone.register import clone_aten
x = torch.zeros(2, device="mlu:0")
y = clone_aten(x)
assert y.shape == x.shape
assert y.data_ptr() != x.data_ptr()如果希望更接近消费方,也可以在独立子进程里做:
from ops.clone import register_a1
counter = {"n": 0}
lib = register_a1(
"PrivateUse1",
counter=counter,
platform="cambricon",
)
x = torch.zeros(2, device="mlu:0")
y = x.clone()
assert counter["n"] > 0
assert y.data_ptr() != x.data_ptr()这个测试的关键不是再证明 clone 数值正确,而是证明:从 ops.clone 包入口进来时,能找到并执行 ops.clone.kernel。
3. 关于 ops/test_packaging.py:MLU 环境应该怎么跑?
这里需要区分两个不同层级的“packaging test”。
层级 1:CPU 可跑的包入口扫描
CI 里的 ops-packaging job 做的是这一层:
import ops.<op>
assert hasattr(module, "register_a1")它不依赖 NPU/MLU 设备,可以在 Ubuntu CPU 环境跑。你们的 PR 里这项已经 PASS,所以对 issue #19 的“包化导出”要求是足够的。
层级 2:ops/test_packaging.py 的 NPU 真机 E2E
当前 ops/test_packaging.py 不是纯 import 测试,而是一个 NPU 场景集成测试,包含:
import torch_npunpu:0上的 embedding 消费- sdpa 大小 shape 路由
- NPU Triton/native 路径
- 多算子同进程真实数值验证
所以 MLU 机器跑不了它是预期行为,不需要强行改成 MLU 可跑。
建议的后续整理
以后可以把这个脚本拆成两个模式:
python3 ops/test_packaging.py --imports-only
python3 ops/test_packaging.py --npu-e2e
含义分别是:
--imports-only:CPU/MLU 都能跑,CI 使用;--npu-e2e:保留现在完整的 NPU 多算子消费验证。
这个拆分建议后续单独做,不必塞进本 PR。你们当前 PR 只需要引用已经通过的 ops-packaging CI 即可。
4. MLU A1 key:我的建议和理由
你们问到:ops/embedding 里现在是 Autograd -> mlu、AutogradPrivateUse1 -> ascend,而这批算子把三个 key 都映射到 cambricon;如果希望 MLU 严格使用某个 key,应该怎么对齐。
我的建议是:不要把 embedding 当前的 selector 作为这批算子的通用规则。embedding 是多平台算子,而且它的 Autograd -> mlu 是一条历史兼容/特殊映射;同一个 embedding 代码里的 kernel/platform.py、README、PLATFORM 报告又写的是 MLU 使用 AutogradPrivateUse1。这本身有不一致,我们会在 embedding 侧单独清理,但不建议把这条特殊映射继续泛化。
对这批当前只有 Cambricon 一个平台的算子,建议这样理解三个 key:
| key | 含义 | 建议 |
|---|---|---|
PrivateUse1 |
设备后端 key,也是旧 profile/旧测试常用值 | 可保留为兼容 key |
AutogradPrivateUse1 |
PrivateUse1 对应的 autograd key | 建议作为 canonical A1 key |
Autograd |
更泛的 autograd key,覆盖面更大 | 不建议默认映射,除非某个算子有真机证据说明必须使用 |
当前单平台环境下,三个 key 都可能命中;你们实测到这一点是合理的。风险主要出现在多后端同进程:generic Autograd 的覆盖范围更大,可能影响 NPU/CUDA 等其他后端的 autograd 分发。等到第二平台接入时,这个风险会更明显。
所以我的建议是:
canonical: AutogradPrivateUse1
compatibility: PrivateUse1
avoid by default: Autograd
如果某个算子确实因为 torch_mlu/functorch/dispatch 行为必须使用 generic Autograd,可以保留,但希望在 PR 里写清楚:
- 为什么要用 generic key;
- 哪个真机用例证明
AutogradPrivateUse1不满足; - 是否会影响多后端同进程。
这一点是设计建议,不是本次最主要的阻塞;阻塞点仍是第 2 节的包态执行 import。
5. 合并前 checklist
为了方便后续复审,建议按这个小清单收尾:
- 10 个可注册算子的实现导入改成包态优先、脚本态 fallback
- MLU 真机增加至少一个包态实际执行用例
- 保持 3 个不可注册算子的
NotImplementedError - key 映射建议收敛为
AutogradPrivateUse1+PrivateUse1;如保留Autograd,补充必要性说明 - CI 继续保持
ops-packaging/unit-tests/docs-and-syntax全绿
其余工作做得很好;补上包态执行这一块后,我应该可以直接复审通过。
- 10 个可注册算子的实现导入改为「包态优先、脚本态 fallback」: try: from .kernel.<mod> import <fn> / except ImportError: from kernel... 修复 ops.<op>.register 包态下顶层 kernel 遮蔽导致的 ModuleNotFoundError(FLAG-OP#25 review 可复现缺口) - _backend_for key 收敛为 canonical AutogradPrivateUse1 + 兼容 PrivateUse1, 移除 generic Autograd(多后端同进程覆盖过大,且无真机必要性证据) - clone/test/op_level.py 增加包态实际执行用例(子进程, 经 ops.clone.register -> ops.clone.kernel 执行并断言存储独立) 验证(v26.08.0 容器 / MLU): - review repro 通过: from ops.clone.register import clone_aten 可执行 - 13/13 example 三层全绿;pytest tests/unit 24 passed - 真实 vLLM A1 框架测试 1 passed
|
@TruNcat3 感谢 review,缺口已按建议补上(新 commit e283944):
本地(v26.08.0 容器 / MLU)复验:13/13 |
TruNcat3
left a comment
There was a problem hiding this comment.
感谢补齐,复查通过 ✅
确认点:
- 10 个可注册算子的实现导入都改为包态优先、脚本态 fallback;静态检查到 10 处
from .kernel...,顶层裸导入不再作为首选路径。 ops/clone/test/op_level.py新增子进程包态执行用例,从ops.clone.register调到clone_aten,并实际执行到ops.clone.kernel,同时断言输出 shape 和 storage independence。这个用例与脚本态 A1 测试、CI 包导出扫描互补,覆盖了此前缺口。- key 映射收敛为 canonical
AutogradPrivateUse1+ 兼容PrivateUse1,移除 genericAutograd,符合多后端同进程的保守边界。 - 3 个不可注册算子仍保持
NotImplementedError,没有为了统一签名强行注册。 - CI 三门全绿;你们 MLU 环境复验 13/13 三层、unit tests 和真实 vLLM 注入也都通过。
一个非阻塞 follow-up:后续可以再把包态用例增强为 from ops.clone import register_a1 → 注册 → x.clone() → counter 断言的一体化子进程用例;当前 ops.clone.register 直调实现已足够覆盖本次 review 指出的 kernel import 缺口。
LGTM。
摘要
按
templates/operator/register.py与ops/embedding的_BACKENDS+_DEVICE_PROBE范式,升级 13 个算子的 A1 注册签名(关联 #19 第 1 项):register_a1(dispatch_key="AutogradPrivateUse1", counter: dict | None = None, platform=None)_BACKENDS/_backend_for(platform显式优先,dispatch_key推断;覆盖Autograd/PrivateUse1/AutogradPrivateUse1→cambricon)与_DEVICE_PROBE注册守卫(MLU 可用性探测)counter["n"];test/op_level.py同步传入counter并断言empty/detach_/result_type)同步签名,保持按设计抛NotImplementedError自查
register.py/test/op_level.pyexample.py cambricon三层全绿;真实 vLLM 框架级tests/framework_level/test_a1_aten_ops.py1 passedexample.py内置 native 参照,无性能回归goldendata复用,script/check_accuracy.py通过ops/test_packaging.py顶部import torch_npu,本环境仅 MLU 无法运行;已做等价验证(13 算子包态导入 +register_a1可导入通过,见「说明」)PLATFORM.md/MERGE.md按 chore: PR#5 的 13 个算子按新库约定补两项——register 签名升级 + 多平台文档(平台扩展前) #19 约定暂欠Dashener2 2026-10-09-fix+# Dashener2 <dashen272@outlook.com>,与 commit 作者一致说明
问题:#19 指出 13 算子仍为旧式单参注册签名
register_a1(dispatch_key="PrivateUse1"),缺counter(op 层拦截计数)与platform(第二平台显式选择),未对齐模板 / embedding 范式。思路:
(dispatch_key="AutogradPrivateUse1", counter=None, platform=None)。_BACKENDS/_backend_for:platform显式优先,否则按dispatch_key推断;保留第二平台扩展位。_DEVICE_PROBE注册守卫:注册时探测torch.mlu可用性,跨平台误用即时报错,而非运行时静默错。counter["n"];不可注册算子保持NotImplementedError。怎么用: