CANN ops-transformer 中 ChunkGatedDeltaRule 算子的 pytest 精度测试框架实战指南
【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-transformer
本指南以 attention/chunk_gated_delta_rule/tests/pytest/README.md 为骨架,系统讲解 CANN ops-transformer 项目中ChunkGatedDeltaRule算子 pytest 测试框架的架构、运行方式与复现手段。读完本文,你将掌握如何配置单用例参数、运行 single / rdv / random / random_npu 四种测试模式、理解随机用例生成与内存约束规则、通过 CSV 与随机种子定位并复现失败用例,以及利用 msprof 采集算子耗时。文中所有结论均可在仓库对应源码与测试脚本中得到验证。
一、框架概览:CPU Golden + NPU 直调 + 精度对比
ChunkGatedDeltaRule(chunk 化门控 Delta Rule,线性注意力的一种前向实现)算子的测试框架基于 pytest 构建,核心思路是"三段式验证":
- CPU 侧:复现算子功能,生成 golden 数据作为真值;
- NPU 侧:通过 TorchNPU 对算子进行直调(
torch_npu.npu_chunk_gated_delta_rule)获取实际结果; - 精度对比:将 CPU 与 NPU 结果按多项误差指标比对,验证算子功能正确性。
主调测逻辑位于 chunk_gated_delta_rule_main.py,其中run_chunk_gated_delta_rule_eager(L434 起)串起了整条链路:生成/加载输入 → 分别调用cgdr_golden(CPU 复现,L198)、cgdr_benchmark(优化版基准实现,L235)、cgdr_npu(NPU 直调,L259)→ 最后用compare_cv(L144)做精度判定。NPU 直调既支持 eager 模式(torch_npu.npu_chunk_gated_delta_rule),也支持 aclgraph 图模式(torch.compile(backend=npu_backend),见MyModelL50-69)。
二、当前实现范围与参数限制
框架当前覆盖的算子约束如下(与 test_chunk_gated_delta_rule_single.py 中随机生成器的注释一致):
| 约束项 | 限制 |
|---|---|
| batch_size | 支持大于 0(随机池:1/2/4/8/16/32/64/128) |
| seqlen | 支持任意序列长度,含非 chunk 对齐值 |
| NK、NV head 数 | NV 需为 NK 的倍数,且 Nv≥Nk |
| DK、DV | 均不超过 128 |
| data_type | 当前支持 BF16 |
| chunk_size | 固定 64(算子 tiling 硬编码,golden 须与 NPU 保持一致) |
在 test_chunk_gated_delta_rule_paramset.py 中可以看到默认的 single 用例即为 BF16:data_type=torch.bfloat16、state_data_type=torch.bfloat16,而 test_chunk_gated_delta_rule_paramset_rdv.py 的 RDV 参数集进一步通过_gen_fp32_cases与_gen_noncontiguous_cases扩展出state_data_type=float32和 state 非连续(is_contiguous=False)的变体,用于覆盖不同状态精度路径与内存布局路径。
三、环境配置与前置要求
运行测试前需要完成以下准备:
- TorchNPU 安装:安装与当前环境匹配的 TorchNPU 包(README 指向其官方安装教程,请以官方最新发布版本为准);
- ops-transformer 环境安装与环境变量配置:具体操作参见仓库根目录 README.md,完成算子 custom 包(custom 算子包)的编译与调用配置;
- custom 包调用:框架支持通过 custom 包方式调用算子,确保 NPU 侧算子已正确安装并可通过
torch_npu访问。
四、pytest 目录文件结构
测试代码集中在attention/chunk_gated_delta_rule/tests/pytest/目录下,各文件职责如下:
| 文件 | 职责 |
|---|---|
| test_run.sh | 执行脚本,封装各测试模式与可选标志 |
| conftest.py | pytest 钩子:逐用例记录参数/结果/随机种子,会话结束落 CSV |
| chunk_gated_delta_rule_golden.py | CPU 侧算子 golden 实现 |
| chunk_gated_delta_rule_main.py | CPU golden 与 NPU 结果精度对比及主调测逻辑 |
| chunk_gated_delta_rule_benchmark.py | 优化版基准实现(stage1/stage2/stage3 分阶段) |
| chunk_gated_delta_rule_operator_single.py | 单用例入口:解包参数并断言精度结果 |
| test_chunk_gated_delta_rule_single.py | 测试用例主程序:参数组合展开 +@pytest.mark.ci用例函数 |
| test_chunk_gated_delta_rule_paramset.py | single 模式入参配置 |
| test_chunk_gated_delta_rule_paramset_rdv.py | RDV 测试入参配置 |
README 中还提到 pytest.ini 用于创建 ci 单算子标记与 graph 图模式标记,与源码中@pytest.mark.ci装饰器以及-m ci筛选参数相互对应。
五、运行模式与命令速查
所有模式均在pytest目录下通过test_run.sh启动。脚本内部统一以TEST_MODE环境变量区分模式,并透传USE_GRAPH、SAVE_PT、LOAD_PT等开关(见 test_run.sh L121-168)。
5.1 单用例调测(single)
- 手动编辑 test_chunk_gated_delta_rule_paramset.py,在
ENABLED_PARAMS中启用需要的参数组(默认启用Testcase0与Testcase1,即 B=1/seqlen=64 与 B=1/seqlen=16384 两个基础用例); - 执行:
bash test_run.sh single5.2 RDV 测试(rdv)
- 手动编辑 test_chunk_gated_delta_rule_paramset_rdv.py,
ENABLED_PARAMS_RDV = GROUP_REDLINE + GROUP_STC默认启用全部 REDLINE(ARC-xxx,38 条)与 STC(ASC-xxx,34 条)用例; - 执行:
bash test_run.sh rdvRDV 参数集会自动经_expand扩展出-FP32(state 用 float32)与-NC(state 非连续)变体,单条 REDLINE/STC 用例会被拆成最多 3 条子用例。参数组内建议单组用例不超过 32 条,便于控制单次会话的时长与内存。
5.3 随机用例测试(random)
随机生成 N 条用例并执行(含 CPU golden 精度对比):
bash test_run.sh random 1005.4 随机用例测试·仅 NPU(random_npu)
设置SKIP_GOLDEN=1跳过 CPU golden 计算与精度对比,仅执行 NPU 算子,可显著加快执行速度,适合快速回归:
bash test_run.sh random_npu 1005.5 自定义单条用例(run)
除上述固定模式外,test_run.sh L171-274 还实现了run模式,支持两种方式指定单条用例:
方式一:指定 pt 文件加载执行(自动启用 load)
bash test_run.sh run --pt output/pt/xxx.pt方式二:命令行直接指定 shape 参数生成执行
bash test_run.sh run --B 1 --seqlen 64 --nk 4 --nv 4 --dk 128 --dv 128 bash test_run.sh run --B 1 --seqlen 64,128 --nk 4 --nv 4 --dk 128 --dv 128 # 逗号分隔变长序列run模式可用参数:--pt、--B、--seqlen(支持逗号分隔变长)、--nk、--nv、--dk、--dv、--chunk_size(默认 64)、--dtype(默认 bfloat16)、--state_dtype(默认 bfloat16)、--no_g(不使用门控 g)、--no_contig(state 非连续)。
5.6 可选标志
single / rdv / random / random_npu 四种模式均可追加以下标志:
| 标志 | 作用 | 对应环境变量 |
|---|---|---|
graph | 启用 aclgraph 图模式(torch.compile+ torchair 后端) | USE_GRAPH=true |
prof | 启用 msprof 性能采集,每用例跑 5 次算子并回填耗时 | ENABLE_PROF=true |
save | 将生成的输入数据保存为.pt(output/pt/下) | SAVE_PT=true |
load | 从output/pt/加载.pt数据执行 | LOAD_PT=true |
示例:
bash test_run.sh single save # single 模式并保存输入 pt bash test_run.sh single load # single 模式从 pt 加载执行 bash test_run.sh run --B 1 --seqlen 64 --nk 4 --nv 4 --dk 128 --dv 128 save bash test_run.sh rdv graph # rdv 模式 + aclgraph注意:save与load互斥,不可同时使用;save生成的文件名按input_B{B}_S{seqlen}_nk{nk}_nv{nv}_dk{dk}_dv{dv}_cs{chunk_size}_{dtype}_{state_dtype}_g{has_g}_contig{is_contiguous}.pt规则命名(见 chunk_gated_delta_rule_main.py L292-315),load时按同名规则自动查找。
六、随机用例生成规则深度解析
random与random_npu模式共用同一套随机参数生成器_generate_random_param_dict(见 test_chunk_gated_delta_rule_single.py L69-114),在算子约束内从 0 随机生成,不依赖 single / rdv 参数池。每条用例的入参生成规则如下:
| 接口入参 | 随机规则 | 约束/说明 |
|---|---|---|
| B | choice([1,2,4,8,16,32,64,128]) | batch size |
| seqlen | choice([1,3,7,32,64,100,128,200,256,300,512,1000,1024,2048,4096,5000,8192,10000,16384,32768,65535]) | 序列长度;含非 chunk 对齐值(如 100、300、5000、65535)测试 partial chunk 路径 |
| seqlen(变长) | B>1 时 30% 概率生成 list,每个 batch 独立随机 seqlen | 覆盖 actual_seq_lengths 变长路径 |
| nk | randint(1,64) | key 头数 |
| nv | nk × randint(1,64//nk) | Nv>=Nk 且 Nv%Nk==0 |
| dk | randint(1,min(128,budget)) | key 维度,受 state 元素上限约束 |
| dv | randint(1,min(128,budget//dk)) | value 维度,受 state 元素上限约束 |
| chunk_size | 固定 64 | 算子 tiling 硬编码,golden 须与 NPU 一致 |
| data_type | 固定 bfloat16 | 当前仅支持 BF16 |
| state_data_type | choice([bfloat16,float32]) | 状态数据类型 |
| has_g | choice([True,False]) | 50% 概率启用门控 |
| is_contiguous | choice([True,False]) | 50% 概率非连续 |
| query_datarange | 固定 [-1,1] | q 经 L2 归一化 |
| key_datarange | 固定 [-1,1] | k 经 L2 归一化 |
| value_datarange | choice([-10,10], [-1,1]) | 随机数据范围 |
| gamma_datarange | choice([-1,0], [-0.5,0], [-0.1,0], [-1,-0.5]) | 文档约束 [-1,0],g 经 exp 衰减 |
| beta_datarange | 固定 [0,1] | 门控因子 |
| state_datarange | 固定 [-10,10] | 初始状态范围 |
6.1 Shape 约束
B>0、seqlen>0、0<Nk<=64、0<Nv<=64 且 Nv>=Nk 且 Nv%Nk==0、0<Dk<=128、0<Dv<=128。
6.2 内存约束(防 OOM)
随机生成时通过两项元素上限共同防止单进程 OOM(对应源码中_STATE_ELEM_CAP = 2_000_000_000与_QKV_ELEM_CAP = 1_000_000_000,见 test_chunk_gated_delta_rule_single.py L65-66):
- Dk×Dv 受 state 元素数上限
_STATE_ELEM_CAP=2.0B约束(budget = STATE_ELEM_CAP // (B × Nv)); - T×max(Nk×Dk, Nv×Dv) 受 QKV 张量元素上限
_QKV_ELEM_CAP=1.0B约束(max_seqlen = QKV_ELEM_CAP // (B × qkv_per_token))。
生成时先按 batch 与 head 数分配 Dk/Dv 预算,再按qkv_per_token = max(nk*dk, nv*dv)反推允许的最大 seqlen,并仅从合法 seqlen 池中选择不超过该上限的值,从而保证任何随机组合都不会超出单进程内存预算。
6.3 随机种子机制
RANDOM_SEED控制 shape/参数序列(一个 seed 对应一组确定的 N 条用例参数);TORCH_SEED控制张量数值(每条用例独立,由 conftest 自动生成并记录进 CSV);- 不设
RANDOM_SEED时自动生成并回写os.environ,conftest 落 CSV; - 复现:
RANDOM_SEED=<seed> bash test_run.sh random N。
在 conftest.py 的_set_random_seedfixture(L32-44)中,设置了TORCH_SEED则固定该种子,否则用torch.seed()自动生成;torch.manual_seed与torch.npu.manual_seed同步设置,保证 CPU 与 NPU 侧张量数值完全一致。
七、结果输出、CSV 字段与失败复现
所有模式执行后均输出到output/目录(已 gitignore):
run_<时间戳>.log:完整执行日志(tee 屏显);result_<时间戳>.csv:逐用例结果表,每行一条用例。
CSV 写入由 conftest.py 的pytest_runtest_makereport(L53-104)与pytest_sessionfinish(L111-162)完成:每个用例执行完毕后收集参数与状态,会话结束时统一落盘,并打印total/passed/failed统计。字段说明如下:
| 列 | 说明 |
|---|---|
| random_seed | 随机 shape 序列种子(random 模式;single/rdv 为固定参数集无此值) |
| seed | 本条用例张量数值种子(每条独立记录) |
| test_name | 用例名称 |
| test_mode | single/rdv/random |
| check_type | precision=带 golden 精度对比 / execution_only=仅 NPU 执行 |
| model | 执行模式(torch 直调/aclgraph) |
| status | pytest 执行结果(PASSED/FAILED/SKIPPED) |
| B…is_continue | 本条用例全部入参 |
| errmsg | 失败详情(截断 2000 字符) |
| durations | 算子耗时(仅 prof 模式) |
失败用例复现:
# 整批复现(同 shape 序列):CSV 取 random_seed RANDOM_SEED=<random_seed> bash test_run.sh random N # 单条数值级复现(同 shape + 同张量数值):CSV 取入参与 seed TORCH_SEED=<tensor_seed> bash test_run.sh random 17.1 prof 模式与耗时回填
prof标志会触发 test_run.sh 的run_profile流程(L88-116):第一步正常跑一遍精度测试生成 CSV;第二步用msprof --summary-format=csv --export=on对全部用例做一次性能采集(每用例 1 次 warmup + 5 次计时);第三步由_backfill_durations(L28-86)从op_summary_*.csv中按OP Type == ChunkGatedDeltaRule提取Task Duration(us),丢弃每组前 1 条 warmup 数据,对其余 5 条取平均回填 CSV 的durations列。
八、精度对比原理(源码级)
8.1 多指标误差判定
精度对比实现于 chunk_gated_delta_rule_main.py 的compare_cv(L144-195),采用"实测误差 vs 高精度参考误差"的比率判定法:将 golden(FP32 复现)、benchmark(优化基准)与 NPU 结果两两对比,核心阈值定义在 L76-83:
CV_MAX_RE = 5:最大相对误差比率上限;CV_AVER_RE = 1.5:平均相对误差比率上限;CV_RMSE = 1.5:均方根误差比率上限;CV_SMALL_VAL = 2:小值域错误占比上限;CV_ERR_BALANCE = 2:误差均衡性上限;MIN_ERR = 1e-3:相对误差分母保护值,避免除零。
其中"小值域错误占比"(get_smra,L121-133)统计 golden 绝对值小于2^-10的位置中误差超过1e-16的比例,专门捕捉小数值区间的精度退化;"误差均衡性"(get_eb,L136-141)则考察平均相对偏差的方向性。最终判定还需满足:若max_re_npu < 2^-7,即使比率超标也视为通过(绝对误差极小兜底)。输出(o)与状态(state)两组结果分别判定,任一失败即整条用例失败。
8.2 Golden 与基准实现
- CPU golden:
chunk_gated_delta_rule_npu(chunk_gated_delta_rule_golden.py L15-70)按 batch 遍历、依据cu_seqlens切分序列,调用逐 chunk 递归的chunk_gated_delta_rule_native复现算子语义,支持use_qk_l2norm_in_kernel与output_final_state; - 优化基准:
chunk_gated_delta_rule_benchmark.py的chunk_gdn_benchmark_opt将算子拆为 stage1(chunk 内矩阵计算、门控累积衰减)、stage2(跨 chunk 状态递推)、stage3(输出计算)三阶段,并在注释中特别说明了 Vinner/Vprime 累加路径的精度对齐策略(v_inner_dtype与 state 数据类型保持一致)。
三路结果最终汇入run_chunk_gated_delta_rule_eager的对比环节(L604-622),失败时打印误差最大的元素索引及 golden/benchmark/NPU 三方数值,便于直接定位偏差来源。
九、环境变量汇总
| 变量 | 作用 | 适用模式 |
|---|---|---|
| RANDOM_SEED | 固定随机 shape 序列种子(不设则自动生成并记 CSV) | random/random_npu |
| TORCH_SEED | 固定张量数值种子(不设则每条自动生成并记 CSV) | 全部 |
| RANDOM_CASE_COUNT | 随机用例条数(test_run.sh 已透传) | random 系 |
| SKIP_GOLDEN | =1 跳过 CPU golden 与精度对比,仅 NPU 执行 | random_npu |
| CSV_FILE | 指定 CSV 输出路径(test_run.sh 已自动设置) | 全部 |
| CSV_APPEND | =1 时 CSV 追加写入 | 全部 |
| USE_GRAPH | =true 启用 aclgraph 模式 | 全部 |
除上表外,源码中还存在TEST_MODE(single/rdv/random,由 test_run.sh 注入)、ENABLE_PROF、SAVE_PT、LOAD_PT、LOAD_PT_FILE、CUSTOM_CASE(run 模式注入)等内部环境变量,均被 chunk_gated_delta_rule_main.py L26-31 与 test_chunk_gated_delta_rule_single.py L37/L117-131 解析。
十、实战建议
- 快速功能验证:用
random_npu模式做大范围 shape 冒烟(无 golden 开销,速度最快);发现异常后再用random模式带精度对比复现; - 问题定位:CSV 中
errmsg列已截断保留 2000 字符失败详情,配合RANDOM_SEED整批复现、TORCH_SEED单条数值级复现,可稳定回到失败现场;如需保存现场输入,用save标志落盘.pt后可用run --pt反复调试; - 性能观察:
prof标志结合 msprof 可直接在 CSVdurations列获得算子级耗时,无需另行写 profiling 脚本; - 环境约束:所有模式均要求 NPU 环境与 TorchNPU custom 包就绪,且 data_type 当前仅支持 BF16,随机生成的
state_data_type仅限 bfloat16/float32 二选一。
【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-transformer
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考