已开启
docs: explain torch_npu PR validation with AscendForge #1
rmch创建于 8月3日
docs: explain torch_npu PR validation with AscendForge #1
已开启
共 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 的提交目标。** | ||