CANN ops-transformer 中 RecurrentGatedDeltaRule 算子的 TTK 测试资产设计与精度验证实践

发布时间:2026/9/19 23:51:46
CANN ops-transformer 中 RecurrentGatedDeltaRule 算子的 TTK 测试资产设计与精度验证实践 CANN ops-transformer 中 RecurrentGatedDeltaRule 算子的 TTK 测试资产设计与精度验证实践【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-transformer本篇技术指南以 CANN ops-transformer 仓库中 attention/recurrent_gated_delta_rule/tests/assets/README.md 为核心脉络系统讲解 RecurrentGatedDeltaRule循环门控 Delta 规则RGDR算子如何基于 ops-test-kitTTK测试框架搭建 E2E 与 ACLNN 双模式的精度验证资产。读完本文你将掌握测试资产的文件结构、TestSpec 适配器机制、RDV 用例到 TTK CSV 的转换方法以及 eager、静态图、离线 prepare/replay 等多种 TTK 执行方式的完整命令行操作。一、背景RGDR 算子与 TTK 测试框架Recurrent Gated Delta Rule循环门控 Delta 规则RGDR是一种应用于循环神经网络与线性注意力机制的算子。在每个时间步 $t$网络根据当前输入 $q_t$、$k_t$、$v_t$ 与上一个隐藏状态 $S_{t-1}$ 计算当前注意力输出 $o_t$ 与新的隐藏状态 $S_t$其中门控单元决定有多少新信息写入隐藏状态、多少旧信息被遗忘。其核心计算见 aclnnRecurrentGatedDeltaRule.md为$$ S_t : S_{t-1}(\alpha_t Diag(\alpha_{kt})(I - \beta_t k_t k_t^T)) \beta_t v_t k_t^T \alpha_t Diag(\alpha_{kt})S_{t-1} \beta_t (v_t - \alpha_t Diag(\alpha_{kt})S_{t-1}k_t)k_t^T $$$$ o : \frac{S_t q_t}{\sqrt{d_k}} $$其中 $S_{t-1}, S_t \in R^{d_v \times d_k}$$q_t, k_t \in R^{d_k}$$v_t \in R^{d_v}$$\alpha_t \in R$$\alpha_{kt} \in R^{d_k}$$\beta_t \in R$$o \in R^{d_v}$。算子内部通过torch_npu.npu_recurrent_gated_delta_ruleTorchNPU Python API与aclnnRecurrentGatedDeltaRuleaclnn C API声明见 aclnn_recurrent_gated_delta_rule.h对外暴露。TTKops-test-kit是 CANN 生态的算子测试框架本文所介绍的测试资产位于 attention/recurrent_gated_delta_rule/tests/assets/其核心目标是通过统一的 CSV 用例描述驱动 TTK 在 E2ETorchNPU与 ACLNNaclnn C API两条调用链路上获得 NPU 实际输出再与 CPU golden 做数值精度对比从而验证算子实现的功能正确性。二、测试资产总体设计双模式 双输出精度对比2.1 支持的三种测试方式模式API说明E2E eagertorch_npu.npu_recurrent_gated_delta_ruletorch 直调含 profilingE2E const graph同上torch.compile 静态 shape 编译执行ACLNNaclnnRecurrentGatedDeltaRuleaclnn C API 调用E2E 模式通过 TorchNPU Python API 直调或 torch.compile 图模式获取 NPU 实际数据与 CPU golden 对比ACLNN 模式通过 aclnn C APIaclnnRecurrentGatedDeltaRule调用算子与 CPU golden 对比精度对比支持 eager、静态图const graph多种执行方式对 CPU 与 NPU 结果进行精度对比。RGDR 算子的一个显著特点是state 张量同时承担输入与输出职责in-place 修改因此精度对比必须覆盖 output 与 state 两个输出详见impl/compare.py的双输出设计与output_tensor_indexes/inplace_input_indexes的 CSV 声明。2.2 精度标准与判定规则tolerance 声明社区标准stat_rel_errbfloat16在 spec.py 中通过tolerance {bfloat16: {standard: stat_rel_err}}声明compare 判定条件实现见 impl/compare.pynp.isclose(rtol0.0078125, atol0.0001)通过率 ≥ 99.5% 且最大相对误差 10.0 方为 Pass。对应到源码常量_RTOL 0.0078125即 $2^{-7}1/128$、_ATOL 0.0001、_DIFF_THD 0.005换算为pct_thd (1 - 0.005) * 100% 99.5%、_MAX_DIFF_HD 10.0。对比流程细节as_numpy()先将 NPU 张量 detach 到 CPUbfloat16/float16 统一转 float32 后再比较逐元素执行np.isclose(..., equal_nanTrue)统计不满足 isclose 的元素为err_count得到真实达标率fulfill_percent (总数 - err_count) / 总数 × 100%通过条件fulfill_percent 99.5%且max_rel_err 10.0否则 FAIL失败时输出详细诊断差异索引前 1000 个、相对误差最大的前几条、error_info汇总如fulfill_percentxx%, max_rel_errxx, err_countxx/total返回结构为 dictpass / precision / diff_indices / error_info / metricsmetrics 中携带rtol、atol、pct_thd、fulfill_percent、max_rel_err、max_diff_hd。值得注意compare()对多输出做了通用化处理接收NPU 输出在前、golden 输出在后、数量相等的参数序列按一半切分后逐对调用numerical_compare单输出返回单个 dict多输出返回 dict 列表——这正是 RGDR output state 双输出对比的实现基础。2.3 环境配置前置要求TorchNPU 安装包下载路径需及时更换为最新版本TorchNPU 安装教程请从 Ascend/pytorch 官方仓库获取最新安装包完成环境安装和环境变量配置具体操作请参考 ops-transformer 仓库根 README获取并安装 ops-test-kit 测试框架TTK。三、文件结构每个文件的职责拆解attention/recurrent_gated_delta_rule/tests/ └── assets/ ├── convert_rdv_to_csv.py # RDV全量用例转TTK CSV脚本E2E ACLNN ├── spec.py # TestSpec注册API golden/inputs/tolerance/compare/torch_graphe2e aclnn └── impl/ ├── golden.py # golden适配器e2e aclnn复用pytest的CPU golden ├── inputs.py # inputs适配器e2e aclnn填充index/length类张量 ├── compare.py # 数值精度对比output state双输出 └── graph.py # 自定义torch.nn.Moduletorch.compile图模式专用3.1 spec.pyTestSpec 注册中心spec.py 是 TTK 插件与测试资产之间的契约层要点如下定义RecurrentGatedDeltaRuleSpec类e2e声明golden、customize_inputs、torch_graph、tolerance、compare定义AclnnRgdrSpec类aclnn声明golden、customize_inputs、tolerance、compare通过__spec__dict 注册两条 APItorch_npu.npu_recurrent_gated_delta_rule→RecurrentGatedDeltaRuleSpecaclnnRecurrentGatedDeltaRule→AclnnRgdrSpectorch_graph指向 impl/graph.py 的RgdrGraphModule供 torch.compile 图模式使用动态加载impl/下四个模块load_impl_module()基于importlib.util.spec_from_file_location从impl/目录按文件名加载golden/inputs/compare/graph避免硬编码模块路径也便于后续扩展。3.2 impl/golden.pyCPU golden 适配器复用而非重写impl/golden.py 的设计哲学是复用 pytest 的 CPU golden不重复实现通过load_pytest_golden_module()动态加载 tests/pytest/recurrent_gated_delta_rule_golden.py 中的 CPU golden 实现模块级缓存避免重复加载e2e 适配器cpu_recurrent_gated_delta_rule(query, key, value, state, *args, **kwargs)使用*args, **kwargs兼容签名按_PARAM_ORDER [beta, scale, actual_seq_lengths, ssm_state_indices, num_accepted_tokens, g, gk]将位置参数与关键字参数归一化再映射到 CPU golden 的命名参数返回(output, state)与 NPU 侧输出对齐NPU 侧为返回的npu_out 经inplace_input_indexes采集的 in-place 修改后 stateaclnn 适配器aclnn_cpu_recurrent_gated_delta_rule参数顺序完全对齐aclnnRecurrentGatedDeltaRuleGetWorkspaceSize的函数签名query, key, value, beta, stateRef, actualSeqLengths, ssmStateIndices, g, gk, numAcceptedTokens, scaleValue, out返回[output, state_out]列表与 CSV 中的output_tensor_indexes顺序一致内部约定CPU golden 会 clone state因此不会修改调用方张量返回前将 output/state 分别 cast 回 query/state 的原始 dtype。3.3 impl/inputs.pyindex/length 类张量的确定性填充impl/inputs.py 解决的是随机生成无法满足语义一致性的 int32 张量填充问题。actual_seq_lengths、ssm_state_indices、num_accepted_tokens这类索引/长度张量必须与张量 shape 强一致否则算子执行或 golden 计算会直接出错actual_seq_lengths将 $T$query.shape[0]均分到 $B$ 个 batchbase T // B余数T % B依次加 1 分配给前几个 batch保证 $\sum L_i T$ssm_state_indices填充arange(T)即第 i 个 token 映射到第 i 个状态块num_accepted_tokens可选每 batch 取min(i 1, act_vals[i])保证取值在[1, seq_len]范围内fill_tensor()同时兼容 torch Tensortensor.copy_与 numpy 数组两种宿主类型e2e 与 aclnn 各有一份同名生成函数generate_rgdr_inputs/aclnn_generate_rgdr_inputs后者参数顺序同样对齐 aclnn GetWorkspaceSize 签名返回值被 ACLNN input pipeline 忽略原地修改即可。3.4 impl/compare.py双输出数值精度对比如前文 2.2 节所述impl/compare.py 实现 NPU 输出与 golden 的数值对比核心特征是支持 output state 双输出打印格式与 pass/fail 标准与 pytest 侧check_result()保持一致保证两条测试链路结论可对齐。3.5 impl/graph.pytorch.compile 图模式专用 Moduleimpl/graph.py 定义了RgdrGraphModule(torch.nn.Module)其forward()显式返回(output, state)二元组。这样做的原因是RGDR 算子会in-place 修改 state若图模式 Module 只返回 outputtorchair 后端无法在计算图中把输入 state与in-place 修改后的 state连接起来产生错误结果。显式返回 state 让 torch.compile 能够完整追踪这条 in-place 数据流。四、convert_rdv_to_csv.pyRDV 全量用例到 TTK CSV 的转换convert_rdv_to_csv.py 将 tests/pytest/test_recurrent_gated_delta_rule_paramset_rdv.py 中的全量 RDV 用例148 条转换为 TTK CSV一次生成两份E2E 模式recurrent_gated_delta_rule_rdv.csvACLNN 模式aclnn_recurrent_gated_delta_rule_rdv.csv。覆盖维度连续/非连续 state、bf16/fp32 state dtype 的组合。从 test_recurrent_gated_delta_rule_paramset_rdv.py 的ENABLED_PARAMS_RDV定义可见用例矩阵 全部 BF16 用例GROUP_1~GROUP_6L0_L1_CASES× 4 种变体fp32 state、非连续 state、fp32 非连续 state 组合。其中L0_L1_CASES系统覆盖了 $N_k/N_v$ 组合如 (1,1)、(4,8)、(32,256) 等 18 种与 $D_k/D_v$ 组合32~512边界 case 还包含N_k65, D_k1等非常规 shape。非连续 state 的 CSV 描述通过tensor_storage_shapes/tensor_view_strides/tensor_view_offsets三列描述。脚本以pad1方式构造state 张量 storage 为(BlockNum, Nv, Dv1, Dk)dv 维 1 填充stride 按 row-major 计算offset 为 0与 pytest 侧 pad1 的方式保持一致其余张量填连续值storage view shapestride 连续offset 0。两份 CSV 的列差异体现 E2E 与 ACLNN 语义差异列E2E CSVACLNN CSVattributes{scale: ...}{scaleValue: ...}in-place 声明inplace_input_indexes(3,)state 是第 4 个输入下标 3output_inplace_indexes(4,)输出声明无由 golden 返回对齐output_tensor_indexes(10,4)out 下标 10stateRef 下标 4此外 ACLNN 的可选输入g/gk/numAcceptedTokens未启用时以None填充 shape/dtype/ranges 占位。脚本还支持--rdv-file与--output-dir两个可选参数定制输入输出路径默认读取 pytest 目录下的 RDV 文件、输出到 assets 目录。执行转换cd attention/recurrent_gated_delta_rule/tests/assets python3 convert_rdv_to_csv.py五、使用方法TTK 命令行全解使用时需准备 E2E 与 ACLNN 的 CSV 用例文件可由上一节脚本生成并定义路径变量TTK_DIRops-test-kit路径 ASSETSattention/recurrent_gated_delta_rule/tests/assets CSV_E2EE2E CSV用例路径 CSV_ACLNNACLNN CSV用例路径5.1 E2E torch 直调eagercd $TTK_DIR python3 -m ttk e2e \ -i $CSV_E2E \ --plugin $ASSETS \ --warmup false --run 1 \ --pc 15.2 E2E 静态图const graphcd $TTK_DIR python3 -m ttk e2e \ -i $CSV_E2E \ --plugin $ASSETS \ --warmup false --run 1 \ -c \ --pc 1 \ -o /tmp/rgdr_perf.csv-c选项开启 E2E 静态图模式耗时测量执行时经 impl/graph.py 的RgdrGraphModule驱动 torch.compile 编译执行。5.3 ACLNN 模式cd $TTK_DIR python3 -m ttk aclnn \ -i $CSV_ACLNN \ --plugin $ASSETS \ --pc 1 \ -o /tmp/rgdr_aclnn_result.csv5.4 离线数据存 bin 与指定 bin 回放两阶段执行该能力将输入生成/CPU golden 生成与设备执行拆为两步prepare 阶段只生成并保存 input/golden 到 bin 文件不跑设备replay 阶段从 bin 恢复数据后跑设备 compare。适用于准备机与执行机分离、或需复用固定输入复跑的场景。MANUAL_DIR/tmp/rgdr_manual # bin 数据存放根目录 OUT结果输出CSV路径1. prepare存 bin完整数据input golden# E2E cd $TTK_DIR python3 -m ttk e2e \ -i $CSV_E2E --plugin $ASSETS \ --no-prof --dump in,golden --dump-format bin \ --manual-data-dirs $MANUAL_DIR --pc 1 \ -o $OUT # ACLNN python3 -m ttk aclnn \ -i $CSV_ACLNN --plugin $ASSETS \ --no-prof --dump in,golden --dump-format bin \ --manual-data-dirs $MANUAL_DIR --pc 1 \ -o $OUT仅准备 inputreplay 时再现算 goldenpython3 -m ttk e2e \ -i $CSV_E2E --plugin $ASSETS \ --no-prof --dump in --dump-format bin \ --manual-data-dirs $MANUAL_DIR --pc 1 \ -o $OUT2. replay指定 bin 跑# E2E python3 -m ttk e2e \ -i $CSV_E2E --plugin $ASSETS \ --manual-data-dirs $MANUAL_DIR --pc 1 \ -o $OUT # ACLNN python3 -m ttk aclnn \ -i $CSV_ACLNN --plugin $ASSETS \ --manual-data-dirs $MANUAL_DIR --pc 1 \ -o $OUT两阶段执行的注意事项prepare 成功状态为MANUAL_DATA_PREPAREDreplay 命中后跳过随机输入生成从 bin 恢复 input及 golden日志可见OnLoadManualData: loaded prepared input/scalar data from $MANUAL_DIR/...--pc 1单进程串行执行in-place state 用例建议单进程两个阶段须使用同一份 CSV 与 assets修改 input shape/view 或 attributes 后需重新 prepare--plugin必传两阶段都依赖 spec.py 提供 golden/inputs 适配器漏传会报cannot save golden[0] sentinel UNSUPPORTEDGolden Shapes: ()为空--no-prof是双横杠写成-no-prof会报unrecognized arguments: -no-prof。5.5 关键参数速查参数作用本算子取值--run N执行次数取平均E2E必须1in-place约束ACLNN默认3--warmupprofiling前warmupE2E必须falsein-place约束ACLNN默认true-o FILE输出结果CSV含耗时列profiling时建议带上-cE2E额外测静态图模式耗时可选--pc N并发进程数本算子建议--pc 1in-place state 用例--no-prof --dump in[,golden]prepare 阶段存 bin不跑设备详见离线数据存bin小节--manual-data-dirs DIRreplay 从 DIR 恢复 bin 数据与 prepare 的 DIR 保持一致5.6 仅校验 CSV 格式# E2E python3 -m ttk e2e -i $CSV_E2E --validate # ACLNN python3 -m ttk aclnn -i $CSV_ACLNN --plugin $ASSETS --validate注意E2E 的--validate可不带--plugin而 ACLNN 模式需要--plugin $ASSETS因为其用例依赖 spec 解析output_tensor_indexes等字段。六、源码级深化算子约束与测试参数的对应关系为了理解测试资产为何如此构造需要回到算子本身的约束。依据 aclnnRecurrentGatedDeltaRule.md 与 tests/pytest/README.mdshape 约束$0 L_i \le 8$每序列长度、$0 N_k \le 256$、$N_k \le N_v \le 256$ 且 $N_v % N_k 0$、$0 D_k \le 512$、$0 D_v \le 512$、$0 T$、$0 B$、$T \le BlockNum$。这也是 test_recurrent_gated_delta_rule_paramset_rdv.py 中 mtp 取值 1~8、$N_k/N_v$ 与 $D_k/D_v$ 上限的直接依据。数值约束算子无法校验需用户保证ssmStateIndices[i] BlockNum$0 actualSeqLengths[i] \le 8$且累加和等于 $T$$1 \le numAcceptedTokens[i] \le actualSeqLengths[i]$$-1 \le query[i][j][k] \le 1$、$-1 \le key[i][j][k] \le 1$$g[i][j] 0$、$gk[i][j][k] 0$$0 beta[i][j] 1$。测试资产正是围绕这些约束构造inputs.py保证 index/length 类张量的语义一致性RDV 参数池test_recurrent_gated_delta_rule_paramset_rdv.py 的BASE_CONFIG将 query/key datarange 固定为[-1,1]、beta 固定[0,1]、gamma 系列固定负区间[-1,0]或[-10,0]、value/state 取[-10,10]。同时该算子支持 BF16 主输入 BF16/FP32 的 state dtype 组合且 stateRef 支持 0 轴、1 轴非连续——这正是 CSV 中state_data_type与tensor_storage_shapes系列字段需要覆盖的维度。此外从 test_aclnn_recurrent_gated_delta_rule.cpp 示例可见典型入参规模batchSize2, mtp2, headKNum4, headVNum8, dimVdimK32state shape 为(B×mtp, Nv, Dv, Dk)与测试资产中 E2E/ACLNN 两份 CSV 的tensor_view_shapes构造完全同构可作为理解 CSV 各列含义的对照。七、常见问题与排错速查cannot save golden[0] sentinel UNSUPPORTEDprepare/replay 阶段漏传--plugin $ASSETS导致 TTK 无法从 spec.py 获取 golden/inputs 适配器unrecognized arguments: -no-prof--no-prof是双横杠选项误写成单横杠会报参数解析错误E2E profiling 报错RGDR 存在 in-place state 修改--run必须为 1、--warmup必须为 false且建议--pc 1单进程执行避免多次执行/in-place 写入带来的数据竞争静态图结果错误图模式必须使用 impl/graph.py 的RgdrGraphModule显式返回(output, state)否则 torchair 无法追踪 in-place state 数据流修改用例后未更新 bin离线两阶段执行时任何 input shape/view 或 attributes 变更后都必须重新执行 prepare非连续 state 用例CSV 必须同时提供tensor_storage_shapes/tensor_view_strides/tensor_view_offsets三列且 storage 采用Dv1pad 方案与 pytest 一致否则无法正确构造 view。八、小结RecurrentGatedDeltaRule 的 TTK 测试资产以 spec.py 为注册中心通过golden / inputs / compare / graph四个适配器模块实现了CPU golden 复用、index 张量确定性填充、双输出精度对比、图模式数据流追踪四大能力配合 convert_rdv_to_csv.py 将 RDV 参数池一键转换为 E2E/ACLNN 两份 CSV并借助 TTK 的 eager、const graph、ACLNN 及 prepare/replay 两阶段能力构成了覆盖 BF16/FP32 state、连续/非连续 state、多种 shape 组合的完整精度验证闭环。对于其他同样具有 in-place 输出、多输出或 index 类张量输入的算子本套资产的组织方式与适配器分层同样具有直接的参考价值。【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-transformer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考