CANN ops-math 算子验收指南:用 AscendOpTest 官方工具完成 Polar 算子精度/性能测试
【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-math
Polar 算子是 CANN ops-math 仓库中由极坐标(模长 input 与幅角 angle)构造复数张量的数学基础算子,本指南围绕 experimental/math/polar/tests/aot/README.md 展开,完整讲解如何基于官方 AscendOpTest 工具在 NPU 上对自定义 Polar 算子做精度与性能验收。读完本文,你将掌握测试资产(算子描述文件、用例 JSON、CPU 基准)的组织方式、complex64 精度阈值的显式配置方法,以及从算子部署、官方工具拉取到result.csv结果判读的完整可复现流程。
为什么精度验收必须用官方 AscendOpTest 工具
在 ops-math 的算子开发流程中,Polar 算子同时存在两套测试手段:仓库内自带的 pybind 测试框架(基于 torch_npu + pybind 复刻)与官方 AscendOpTest 工具。任务要求的精度判据是"满足 AscendOpTest 工具默认阈值",因此验收必须以官方工具实测结果为准,pybind 复刻只能作为开发期的快速冒烟手段。
本目录(tests/aot/)即为验收提前离线准备好的资产集合,确保在 NPU notebook 上可以一键复现官方验收:
| 文件 | 作用 |
|---|---|
| Polar.json | 算子描述文件(IR/原型),通过-i参数传入官方工具 |
| polar_cases.json | 测试用例(6 例),通过-c参数传入 |
| polar_golden.py | expect_funcCPU 基准(numpy 广播实现 polar),被 case json 引用 |
算子描述文件:Polar.json
Polar.json 是 AscendOpTest 识别自定义算子的原型描述,声明了两个 float 类型 ND 格式的输入与一个 complex64 输出:
[ { "op": "Polar", "language": "cpp", "input_desc": [ { "name": "input", "param_type": "required", "format": ["ND"], "type": ["float"] }, { "name": "angle", "param_type": "required", "format": ["ND"], "type": ["float"] } ], "output_desc": [ { "name": "out", "param_type": "required", "format": ["ND"], "type": ["complex64"] } ] } ]该描述与仓库中算子原型的实际注册完全一致。查看 polar_def.cpp 可以看到input/angle均为DT_FLOAT+FORMAT_ND,out恒为DT_COMPLEX64,且通过AICore().AddConfig("ascend910b")与AddConfig("ascend910_93")同时注册了 Atlas A2(910B)与 Atlas A3(910_93)两套平台配置——这正是官方工具跑--op-type custom时依赖的原型来源。
CPU 基准:polar_golden.py
polar_golden.py 是被 case json 中"expect_func"引用的 CPU 基准函数,完整实现了 Polar 的数学语义:
def polar(input, angle): a = np.asarray(input).astype(np.float32) th = np.asarray(angle).astype(np.float32) # numpy 广播(input.dim 与 angle.dim 可不一致,与算子 InferShape 对齐) a, th = np.broadcast_arrays(a, th) out = (a * (np.cos(th) + 1j * np.sin(th))).astype(np.complex64) return [np.ascontiguousarray(out)]其约束与官方工具约定保持一致:参数名/顺序须与算子描述文件及 case 文件input_desc一致(input, angle);返回值必须是 list,元素为 numpy.ndarray,输出 dtype 必须是 complex64。公式polar(abs, angle) = abs * (cos(angle) + i*sin(angle))与仓库中 polar_infershape.cpp 的 numpy 右对齐广播推导、以及 kernel 侧Cos(angle)/Sin(angle)再乘 abs 的实现一一对应,构成"CPU 基准 ↔ NPU 实现"的可比对闭环。
关键点:complex64 无内置默认阈值,必须显式配置
这是整个验收中最容易踩坑的一步。AscendOpTest 的accuracy_config对常见 dtype 内置了默认误差阈值,但complex64 没有内置默认——若不显式配置,运行时会直接抛KeyError。
解决方案在 polar_cases.json 中已落地:每个用例的output_desc都显式写入了"err_threshold":[0.0001,0.0001],其中第一个分量是绝对偏差(fp32 分量默认值),第二个分量是错误率。对应的判定逻辑(见 design.md 中"精度细化与实测"):compare_complex对实部、虚部各自做纯绝对误差判定,要求实/虚部分量误差 ≤ 1e-4,且错误元素数不超过size × 1e-4,否则判失败。
在 NPU notebook 上运行官方验收
以下步骤在 Atlas A2/A3(910B4 等)的 ModelArts notebook / Developer Space 环境中操作,本地无 NPU 无法运行。
0) 安装前置依赖
pip install ml_dtypes1) 部署自定义 Polar 算子
构建并安装算子.run安装包(与仓库内S8/Polar的构建流程相同;在 ops-math 仓内则使用 build.sh 风格的--experimental构建,详见 测试步骤指导.md):
cd ~/work/S8/Polar && bash build.sh && ./build_out/*.run --quiet2) 使部署算子生效(README 红字强调的关键步骤)
source $ASCEND_HOME_PATH/opp/vendors/customize/bin/set_env.bash export LD_LIBRARY_PATH=$ASCEND_HOME_PATH/opp/vendors/customize/op_api/lib:$LD_LIBRARY_PATH注:ops-math 仓内构建会强制 vendor 名为
customize_math(与--vendor_name无关),此时上述路径中的customize需替换为customize_math,并配合--op-path $ASCEND_HOME_PATH/opp/vendors/customize_math/op_api参数使用。此步若跳过,工具将解析不到自定义实现。
3) 获取官方工具
git clone https://gitcode.com/HIT1920/AscendOpTest.git && cd AscendOpTest4) 跑精度验收
python run_test.py \ -i /home/ma-user/work/S8/Polar.json \ -c /home/ma-user/work/case_910b/Polar/aot/polar_cases.json \ --op-type custom --build--build:首次运行或改动用例后必须加,用于重新构建/编译;--op-type custom:声明被测对象为自定义算子(非内置算子)。
若在 ops-math 仓内复现,
-i与-c直接指向仓内路径,并追加--op-path指定自定义 op_api 库目录。同时注意:polar_cases.json中的expect_func路径按/home/ma-user/work/case_910b/Polar/aot/polar_golden.py:polar写死,若上传路径不同,需同步修改polar_cases.json(仓内复现可用sed批量替换为$POLAR/tests/aot/polar_golden.py:polar)。
5) 跑性能验收(msprof 形式)
python run_test.py -i .../Polar.json -c .../polar_cases.json --op-type custom --msprof性能模式以 msprof application 形式采集,聚合每个用例op_summary*.csv的 Task Duration 作为每调用设备时,与自测报告口径一致。
用例设计解析:6 个用例覆盖的核心矩阵
polar_cases.json 中的 6 个用例并非随机生成,而是围绕 Polar 算子的两大特性——逐元素极坐标构造与NumPy 广播——刻意设计的覆盖矩阵:
| 用例名 | input shape | angle shape | 覆盖意图 |
|---|---|---|---|
Test_same_small | [2, 6, 10] | [2, 6, 10] | 同 shape 小规模基础正确性 |
Test_same_16M | [4096, 4096] | [4096, 4096] | 同 shape 16M 大规模(满核场景 + 非确定性复核) |
Test_bcast_lowhigh | [4, 1, 8] | [4, 5, 8] | 广播 低维→高维(input 低维广播到 angle 高维) |
Test_bcast_scalar | [1] | [3, 4, 5] | 标量×高维广播 |
Test_bcast_2way | [8, 1] | [1, 7] | 双向多轴广播(两输入各有一维为 1) |
Test_highdim_unalign | [3, 5, 17, 269] | [3, 5, 17, 269] | 高维 + 非 32B 对齐内维(269 非对齐) |
所有用例统一约定:
- 角度
angle取值[-3.14, 3.14](单周期,干净地验证正确性); - 模长
abs取值[-10, 10](含负值,验证负 abs 翻号在数学上合法:(-a)·(cosθ+i·sinθ)等价于a·(cos(θ+π)+i·sin(θ+π))); - 输出 shape 为两输入广播后的 shape,与 polar_infershape.cpp 中右对齐逐轴取 max 的推导逻辑完全一致。
16M 用例的特殊使命
Test_same_16M用例专门用于让官方工具独立复核此前 standalone 测试中测出的 16M 规模非确定性问题(对应设计文档中的 ⚠️ 未决风险)。16M 是"所有核参与"的核心验收场景,design.md 中的实测数据也验证了这一规模的价值:16M 场景下本算子 937.98 µs 对 l0 参考 1665 µs,加速约 1.78×,是证明融合单 kernel 性能优势的关键证据。
运行约束与结果判读
运行前需核对以下一致性约束(当前资产已对齐):
input/angle/out的name 与顺序必须与Polar.json、OpDef 一致,即(input, angle, out)——三者不一致会导致工具无法正确绑定输入输出;- 每个
output_desc必须显式携带err_threshold(complex64 无内置默认,见上文关键点)。
运行结束后结果写入result.csv,每个用例一行 pass/fail。官方 AscendOpTest 实跑记录(见 测试步骤指导.md):6 个用例(Test_same_small、Test_same_16M、Test_bcast_lowhigh、Test_bcast_scalar、Test_bcast_2way、Test_highdim_unalign)在 Atlas A2(910B4)上全部 PASS,与 msopgen 产物精度一致、重构零回归。该结论与 design.md "可维可测分析"章节中"官方 AscendOpTest 实跑 6 用例全 PASS(含 16M [4096,4096])"的描述互相印证。
如需深入了解 Polar 算子的整体设计(融合 kernel 的 UB 布局、Gather+静态偏移表的复数交织选型、广播的矢量化 unravel 实现)与性能基线对比方法,可继续阅读 docs/design.md、docs/性能优化_inner_broadcast.md 以及 op_kernel/polar.h 的源码注释。
【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-math
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考