已开启
docs: explain torch_npu PR validation with AscendForge #1
rmch创建于 8月3日
docs: explain torch_npu PR validation with AscendForge #1
已开启
rmch创建于 8月3日
共 1 个文件变更+380-0
@@ -0,0 +1,380 @@
1+# 使用 AscendForge 验证 torch_npu 主仓 PR
2+ 
3+本文说明如何使用 [AscendForge](https://gitcode.com/liuyutong_bury/AscendForge) 测试框架验证 torch_npu 主仓(包括 triton_experimental backend)中的代码变更。
4+ 
5+AscendForge 是测试框架,不是被测代码仓库:
6+ 
7+- unit_test/:基于 torch.inductor 的 UT,覆盖静态 shape、dynamic shapes 和可选的 opinfo;
8+- op_test/:单算子正确性、compiled/eager 精度对比、性能和 profiler 测试;
9+- 被测对象是当前安装到 Python 环境中的 torch_npu 主仓 PR 构建。
10+ 
11+## 1. 验证门禁
12+ 
13+一个 torch_npu PR 在提交或合入前,必须完成以下验证:
14+ 
15+1. AscendForge UT 通过,且相对父提交没有新增失败、超时、异常跳过或收集错误;
16+2. AscendForge OP correctness 全部通过,没有 FAIL、编译错误、runtime 错误或精度校验错误;
17+3. 受影响 OP 的 compiled 结果与 eager 结果一致,使用 case 内定义的 torch.testing.assert_close 判定;
18+4. OP 性能相对父提交不劣化;性能比较使用相同硬件、软件、输入、backend、warmup 和迭代次数;
19+5. 测试结果能够追溯到 torch_npu 父提交、PR 提交、AscendForge 提交和完整环境信息。
20+ 
21+失败用例可以重跑用于定位,但“重跑通过”不能替代完整测试,也不能用 blacklist、跳过 case 或放宽精度阈值掩盖回归。
22+ 
23+## 2. 目录和版本关系
24+ 
25+建议固定两个仓库的提交:
26+ 
27+~~~text
28+torch_npu/ # 被测主仓 PR 分支或 PR 构建
29+AscendForge/ # 测试框架,固定到用于验收的 commit
30+~~~
31+ 
32+记录两个仓库的提交:
33+ 
34+~~~bash
35+git -C /path/to/torch_npu rev-parse HEAD
36+git -C /path/to/AscendForge rev-parse HEAD
37+~~~
38+ 
39+测试过程中不要修改 AscendForge 的测试用例来适配某个 PR。若确实需要修改测试框架,应先单独提交并固定新的 AscendForge commit,再重新对父提交和 PR 提交各跑一遍。
40+ 
41+## 3. 环境准备
42+ 
43+### 3.1 安装被测 torch_npu
44+ 
45+先按照 torch_npu 主仓的构建方式编译并安装目标 PR。确认 Python 实际加载的是 PR 构建,而不是旧 wheel、源码目录或其他环境中的版本:
46+ 
47+~~~bash
48+python - <<'PY'
49+import torch
50+import torch_npu
51+ 
52+print("torch:", torch.__version__, torch.__file__)
53+print("torch_npu:", torch_npu.__version__, torch_npu.__file__)
54+print("npu available:", torch.npu.is_available())
55+print("npu count:", torch.npu.device_count())
56+PY
57+~~~
58+ 
59+torch、torch_npu、CANN、驱动和 Triton 版本必须匹配。当前 backend 由环境变量选择:
60+ 
61+~~~bash
62+export TORCHINDUCTOR_NPU_BACKEND=triton_experimental
63+~~~
64+ 
65+该变量必须在导入 torch_npu 或启动测试前设置。若 backend 已合入 torch_npu 主仓,不需要额外安装旧的独立 npu_inductor 包。
66+ 
67+### 3.2 准备 NPU 和 CANN
68+ 
69+~~~bash
70+npu-smi info
71+source /usr/local/Ascend/cann/set_env.sh # 按机器实际路径调整
72+export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 # 只使用空闲卡
73+~~~
74+ 
75+建议为父提交和 PR 提交分别设置独立缓存目录:
76+ 
77+~~~bash
78+export TEST_TAG=parent_abcdef123456 # 示例;PR 测试时换成 pr_<短提交号>
79+export TORCHINDUCTOR_CACHE_DIR="/tmp/torchinductor_$TEST_TAG"
80+export TRITON_CACHE_DIR="/tmp/triton_$TEST_TAG"
81+export TMPDIR="/tmp/ascendforge_tmp_$TEST_TAG"
82+mkdir -p "$TORCHINDUCTOR_CACHE_DIR" "$TRITON_CACHE_DIR" "$TMPDIR"
83+~~~
84+ 
85+### 3.3 配置 AscendForge
86+ 
87+~~~bash
88+cd /path/to/AscendForge
89+cp config/env.sh.example config/env.sh
90+# 按本机修改 config/env.sh;不要提交 config/env.sh
91+source config/env.sh
92+~~~
93+ 
94+AscendForge 的 UT runner 会在子进程中设置 backend;运行前确认 unit_test/run_inductor_comparison.py 的 triton 映射到 triton_experimental。
95+ 
96+> 当前 unit_test/run_three_cases.sh 的部分版本包含硬编码的 ASCEND_RT_VISIBLE_DEVICES。如果当前版本仍有此行,必须先改为使用外部配置,例如 export ASCEND_RT_VISIBLE_DEVICES="${ASCEND_RT_VISIBLE_DEVICES:?}",否则命令行指定的卡号会被覆盖。
97+ 
98+## 4. 建立 torch_npu 父提交基线
99+ 
100+性能和回归判断必须以 torch_npu PR 的父提交为基线。AscendForge 测试框架 commit、Python 环境、CANN、卡号和测试参数保持不变,只替换被测 torch_npu:
101+ 
102+~~~bash
103+export PARENT_COMMIT=abcdef1234567890 # 替换成真实父提交
104+git -C /path/to/torch_npu checkout "$PARENT_COMMIT"
105+# 按 torch_npu 主仓流程重新编译并安装
106+~~~
107+ 
108+保存基线信息和产物:
109+ 
110+~~~bash
111+export TEST_TAG="parent_${PARENT_COMMIT:0:12}"
112+export ARTIFACT_DIR="/path/to/AscendForge/artifacts/$TEST_TAG"
113+mkdir -p "$ARTIFACT_DIR"
114+{
115+ echo "torch_npu commit: $(git -C /path/to/torch_npu rev-parse HEAD)"
116+ echo "AscendForge commit: $(git -C /path/to/AscendForge rev-parse HEAD)"
117+ python --version
118+ python -c 'import torch, torch_npu; print(torch.__version__); print(torch_npu.__version__)'
119+ env | grep -E 'ASCEND|TORCHINDUCTOR|TRITON|WORKERS|TIMEOUT|BACKEND'
120+ npu-smi info
121+} | tee "$ARTIFACT_DIR/env.txt"
122+~~~
123+ 
124+父提交至少运行一次完整 UT、一次 OP correctness 和一次 OP performance。只运行受影响 case 的结果不能作为完整基线。
125+ 
126+## 5. 运行 UT
127+ 
128+### 5.1 完整 UT
129+ 
130+~~~bash
131+cd /path/to/AscendForge
132+export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3
133+export WORKERS=4
134+export TIMEOUT=600
135+export BACKEND=triton
136+bash unit_test/run_three_cases.sh
137+~~~
138+ 
139+默认运行:
140+ 
141+- inductor_tests:静态 shape UT;
142+- dynamic_shapes:动态 shape UT。
143+ 
144+涉及算子注册、dtype、shape 推导、codegen、动态 shape 或公共 Inductor 逻辑的 torch_npu PR,必须追加 opinfo:
145+ 
146+~~~bash
147+RUN_OPINFO=1 bash unit_test/run_three_cases.sh
148+~~~
149+ 
150+### 5.2 UT 结果和通过标准
151+ 
152+结果位于:
153+ 
154+~~~text
155+test_results/<YYYYMMDD_HHMM>/
156+├── inductor_tests/comparison_report.txt
157+├── dynamic_shapes/comparison_report.txt
158+├── opinfo/comparison_report.txt # RUN_OPINFO=1 时
159+└── */failures/ # pytest 原始失败日志
160+~~~
161+ 
162+验收要求:
163+ 
164+- 新增 failed = 0;
165+- 新增 timeout = 0;
166+- 不得出现新的异常 skipped;
167+- 不得有 collection error、编译失败、NPU runtime error 或进程崩溃;
168+- 父提交已有失败可以作为已知基线保留,但 PR 不能增加失败集合;
169+- 新增或修改的 UT 必须实际执行,不能被 blacklist 静默排除。
170+ 
171+检查报告和原始日志:
172+ 
173+~~~bash
174+export UT_RUN_DIR=test_results/20260803_1200 # 替换为本次实际目录
175+rg -n '\b(failed|timeout)\b|ERROR|INTERNALERROR|Traceback' "$UT_RUN_DIR"
176+~~~
177+ 
178+不要只根据 shell 返回码判断通过;必须检查每个 comparison_report.txt 和 failures/。
179+ 
180+### 5.3 失败用例重跑
181+ 
182+将失败用例写入 rerun_list.txt,每行一个完整 pytest node ID:
183+ 
184+~~~text
185+test_torchinductor.py::NPUTests::test_xxx_npu
186+test_torchinductor_dynamic_shapes.py::DynamicShapesNPUTests::test_xxx_dynamic_shapes_npu
187+~~~
188+ 
189+执行重跑:
190+ 
191+~~~bash
192+python unit_test/rerun_failed.py rerun_list.txt \
193+ --backend triton --workers 4 --timeout 600
194+~~~
195+ 
196+重跑结果只能用于区分代码问题、环境问题和偶发问题。修复后必须重新运行完整 UT,并在 PR 中保留原始失败和最终结果。
197+ 
198+## 6. 运行 OP Test
199+ 
200+### 6.1 全量正确性
201+ 
202+op_test/test_all.py 默认使用 triton_experimental,每个 case 会执行 compiled/eager 对比;部分 case 还覆盖 backward、dynamic shape、inplace 或有限值检查。
203+ 
204+~~~bash
205+cd /path/to/AscendForge
206+set -o pipefail
207+python op_test/test_all.py --continue-on-fail 2>&1 | tee "$ARTIFACT_DIR/op_correctness.log"
208+~~~
209+ 
210+验收要求:
211+ 
212+- 全部 case 输出 PASS;
213+- 日志无 FAIL、Traceback、编译错误或 NPU runtime error;
214+- compiled 与 eager 通过 case 内定义的 torch.testing.assert_close;
215+- 反向 case 的梯度存在且为有限值;
216+- 不允许通过跳过 case 或临时修改 rtol/atol 让结果通过。
217+ 
218+查看 case 或先跑受影响的 case:
219+ 
220+~~~bash
221+python op_test/test_all.py --list
222+python op_test/test_all.py test_add test_layernorm --continue-on-fail
223+~~~
224+ 
225+受影响 case 通过后仍要运行全量 correctness,不能只提交定向测试结果。
226+ 
227+### 6.2 性能对比
228+ 
229+正确性全量通过后,父提交和 PR 提交使用完全相同的参数采集性能:
230+ 
231+~~~bash
232+set -o pipefail
233+python op_test/test_all.py \
234+ --perf --perf-warmup 5 --perf-iters 20 \
235+ --continue-on-fail 2>&1 | tee "$ARTIFACT_DIR/op_perf.log"
236+~~~
237+ 
238+建议父提交和 PR 提交各重复至少 3 次,使用中位数比较,避免单次调度抖动影响结论。必须保持一致:
239+ 
240+- NPU 型号、卡号、可见设备和系统负载;
241+- CANN、驱动、Python、PyTorch、torch_npu、Triton 和 backend;
242+- 输入 shape、dtype、warmup、测量迭代次数和 case 集合;
243+- cache 策略和 profiler 开关。
244+ 
245+PR 的性能结论至少包含:
246+ 
247+| case | 父提交 compiled | PR compiled | 父提交 speedup | PR speedup | correctness |
248+|---|---:|---:|---:|---:|---|
249+| test_xxx | … ms | … ms | …x | …x | PASS |
250+ 
251+门禁为:PR compiled latency 不高于父提交,且 speedup 不低于父提交。出现回归或明显抖动时,增加重复次数并用 profiler 定位后再决定是否提交;不能把未解释的性能下降标记为通过。
252+ 
253+### 6.3 Profiler
254+ 
255+Profiler 用于解释性能变化,不替代 correctness 或 --perf:
256+ 
257+~~~bash
258+python op_test/test_all.py \
259+ --profile --profile-dir "$ARTIFACT_DIR/profile" \
260+ --continue-on-fail 2>&1 | tee "$ARTIFACT_DIR/op_profile.log"
261+~~~
262+ 
263+## 7. 验证 torch_npu PR 提交
264+ 
265+对 PR 提交重复第 3~6 节,只替换 torch_npu 安装,不改变 AscendForge commit 和测试参数:
266+ 
267+~~~bash
268+export PR_COMMIT=1234567890abcdef # 替换成真实 PR 提交
269+git -C /path/to/torch_npu checkout "$PR_COMMIT"
270+# 按主仓流程重新构建并安装
271+export TORCHINDUCTOR_NPU_BACKEND=triton_experimental
272+export TEST_TAG="pr_${PR_COMMIT:0:12}"
273+export ARTIFACT_DIR="/path/to/AscendForge/artifacts/$TEST_TAG"
274+mkdir -p "$ARTIFACT_DIR"
275+ 
276+cd /path/to/AscendForge
277+RUN_OPINFO=1 bash unit_test/run_three_cases.sh
278+python op_test/test_all.py --continue-on-fail \
279+ 2>&1 | tee "$ARTIFACT_DIR/op_correctness.log"
280+python op_test/test_all.py --perf --perf-warmup 5 --perf-iters 20 \
281+ --continue-on-fail 2>&1 | tee "$ARTIFACT_DIR/op_perf.log"
282+~~~
283+ 
284+将父提交和 PR 提交的以下集合做差集:
285+ 
286+- UT failed、timeout、skipped;
287+- OP FAIL 和错误日志;
288+- compiled/eager 精度结果;
289+- compiled latency、speedup 和 profiler kernel 统计。
290+ 
291+只有“无新增 UT 问题、OP correctness 全通过、精度无新增误差、性能无劣化”时,才可以在 torch_npu 主仓 PR 中填写通过。
292+ 
293+## 8. 结果归档
294+ 
295+建议按被测提交归档,避免父提交和 PR 结果混淆:
296+ 
297+~~~text
298+artifacts/
299+├── <parent-commit>/
300+│ ├── env.txt
301+│ ├── ut/
302+│ ├── op_correctness.log
303+│ ├── op_perf.log
304+│ └── profile/
305+└── <pr-commit>/
306+ ├── env.txt
307+ ├── ut/
308+ ├── op_correctness.log
309+ ├── op_perf.log
310+ └── profile/
311+~~~
312+ 
313+不要把大型 profiler 原始目录直接提交到代码仓;将其作为 CI artifact 或外部存储附件,并在 PR 中提供链接。
314+ 
315+## 9. torch_npu PR 描述模板
316+ 
317+~~~markdown
318+## AscendForge 验证
319+ 
320+- torch_npu 父提交:
321+- torch_npu PR 提交:
322+- AscendForge 提交:
323+- 芯片/卡号:
324+- CANN/驱动:
325+- Python/PyTorch/torch_npu/Triton:
326+- TORCHINDUCTOR_NPU_BACKEND:triton_experimental
327+ 
328+### UT
329+- [ ] inductor_tests:无新增 failed/timeout/skipped
330+- [ ] dynamic_shapes:无新增 failed/timeout/skipped
331+- [ ] opinfo:通过或已说明不适用
332+- 结果目录:
333+- 父提交已知失败:
334+- PR 新增失败:无
335+ 
336+### OP correctness
337+- [ ] 全量 case PASS
338+- [ ] compiled/eager 精度通过
339+- [ ] backward/dynamic/inplace 相关 case 通过
340+- 日志:
341+ 
342+### OP performance
343+- [ ] warmup/iters/设备/输入与父提交一致
344+- [ ] compiled latency 不高于父提交
345+- [ ] speedup 不低于父提交
346+- [ ] 性能重复测量并使用中位数
347+- 对比表:
348+- profiler:
349+ 
350+### 结论
351+- [ ] 无新增 UT 问题
352+- [ ] OP correctness 通过
353+- [ ] 精度无劣化
354+- [ ] 性能无劣化
355+~~~
356+ 
357+## 10. 常见问题
358+ 
359+### backend 不是 triton_experimental
360+ 
361+~~~bash
362+echo "$TORCHINDUCTOR_NPU_BACKEND"
363+python -c 'import torch_npu; import torch_npu._inductor; print(torch_npu.__file__)'
364+~~~
365+ 
366+确认变量在 Python 启动前设置,并确认加载路径属于 PR 构建。不要让旧的 torch_npu wheel 或未安装的源码目录覆盖 PR 构建。
367+ 
368+### UT 仍使用错误卡号
369+ 
370+检查 unit_test/run_three_cases.sh 是否覆盖了外部 ASCEND_RT_VISIBLE_DEVICES。优先修正本地测试框架脚本或直接调用 runner,不要在结果中假设命令行卡号已经生效。
371+ 
372+### 失败重跑通过但完整测试失败
373+ 
374+以完整测试为准。检查并行 worker、NPU 卡冲突、缓存污染和单用例超时;确认失败是否与 PR 代码相关后,清理独立缓存并重新跑完整门禁。
375+ 
376+### 性能下降但 correctness 通过
377+ 
378+保留父提交和 PR 的 profiler 结果,比较 kernel 数量、单 kernel duration、编译 fallback、内存拷贝和同步点。未定位原因或未恢复性能前,不应将 PR 标记为通过。
379+ 
380+**AscendForge 的作用是为 torch_npu 主仓 PR 提供可重复的 UT、OP correctness、精度和性能证据;它本身不是被测 PR 的提交目标。**