已合并
[test] ShapeEnv APIs NPU兼容性验证与资料更新 #36139
[test] ShapeEnv APIs NPU兼容性验证与资料更新 #36139
已合并
Yhw050920创建于 5月19日
Yhw050920
Yhw050920
5月19日

【合入来源】

https://gitcode.com/Ascend/pytorch/issues/1627
请勿携带内部流程信息(需求链接、问题单、内部issue等)

【修改方案】

本 PR 在仓库已有 test/fx/test_symbolic_shapes.pytorch.fx.experimental.symbolic_shapes 模块测试)中增补 TestShapeEnvNPU,对 issue #1627 要求的 ShapeEnv 守卫与符号表 APIAscend NPU(v2.7.1) 上做单元验证,写法与文件内现有 TestSymbolicShapes 一致(TestCase + run_tests())。

合入目标分支:v2.7.1(MR 36139)

1. 上游社区与仓库现有测试情况

测试位置 覆盖侧重点 与本次 API 的关系
test/fx/test_symbolic_shapes.py is_accessor_nodeis_concrete_*is_symbolic;已使用 ShapeEnv 本 PR 在此文件扩展 ShapeEnv 守卫类 API 用例,模块定位清晰
test/fx/test_symbolic_shapes_api.py definitely_trueDimConstraints 等其它 symbolic_shapes API 不同 API 类别,不混放
test/dynamo/test_export.pytest/dynamo/test_misc.py 导出等集成路径中间接使用 ShapeEnv 缺少下列公开方法的独立、可回归 NPU 用例
test/fx/test_fx_passes.py FX Pass / Graph 变换 不涉及 ShapeEnv 守卫字符串与 sympy 简化

结论:需在 test_symbolic_shapes.py 中补齐 ShapeEnv 守卫类 API 在 NPU 上的直接单测;不新增 test_cases.py(文件名无法体现测试模块)。

2. 目标 API 功能说明(全称,v2.7.1 测试范围)

API 全称 功能简述 本 PR 是否编写用例
torch.fx.experimental.symbolic_shapes.ShapeEnv.produce_guards_expression 根据占位 FakeTensor 等输入,生成用于运行时检查的守卫表达式字符串
torch.fx.experimental.symbolic_shapes.ShapeEnv.produce_guards_verbose 在表达式基础上结合 Source 生成更详细的守卫信息 是(_produce_guards_verbose_works() 端到端探测,不可用时 skip
torch.fx.experimental.symbolic_shapes.ShapeEnv.replace 在 ShapeEnv 符号表上下文中替换 sympy 表达式
torch.fx.experimental.symbolic_shapes.ShapeEnv.set_unbacked_var_to_val unbacked 符号绑定具体值 是(_shape_env_set_unbacked_var_to_val_works() 探测,不可用时 skip
torch.fx.experimental.symbolic_shapes.ShapeEnv.simplify 在 ShapeEnv 环境下对 sympy 表达式做化简

未纳入本 PR 测试:

API 原因
ShapeEnv.add_backed_var_to_val PyTorch 2.11.0+ 才引入,v2.7.1 无此方法,非本分支可测范围;文档由 MR 36144 按版本标注,2.11.0+ 测试由对应版本 MR 单独提交

3. 用例设计与开发思路

3.1 总体原则

  1. 模块归属:ShapeEnv 属于 torch.fx.experimental.symbolic_shapes,仓库中 test/fx/test_symbolic_shapes.py 已是该模块的 NPU 测试入口(现有 TestSymbolicShapes 测谓词与 accessor)。本 PR 在同一文件新增 TestShapeEnvNPU,与现有类并列,避免另起 test_cases.py 导致模块不可见。
  2. 一 API 一用例:每个目标 API 对应一个独立 test 方法,方法名采用 test_torch_fx_experimental_symbolic_shapes_ShapeEnv_<api>,与 API 全称一一对应,便于 CI 报告、issue 追溯与后续扩展。
  3. 设备约束:所有 ShapeEnv 用例均加 @unittest.skipUnless(torch.npu.is_available(), "requires npu"),与仓库内其它 FX NPU 测试一致,确保仅在 Ascend 环境执行。
  4. 断言驱动:测试体只做「构造 → 调用 → 断言」,不在用例内捕获异常掩盖失败;版本/能力不满足时由 @unittest.skipUnless + 模块级探测函数 在收集阶段决定 SKIP。

3.2 公共辅助逻辑

辅助项 作用
_shape_env_with_fake_placeholders(shape=(3, 4)) 创建 ShapeEnv(),绑定 FakeTensorMode(shape_env=env),在 NPUfrom_tensor 得到占位 FakeTensor,返回 (env, [fake_tensor])。模拟 dynamo/FX 导出中最常见的「带符号形状的 NPU 占位输入」路径。
_shape_env_has(name) 判断 ShapeEnv 是否导出可调用方法,用于能力探测的前置检查。
_produce_guards_verbose_works() 端到端探测:在 CPU 上用最小 FakeTensor + 裸 Source() 试调 produce_guards_verbose;若抛 NotImplementedError / TypeError(2.7.1 CI wheel 实测 bare Source() 无法满足 name),则整用例 SKIP,避免误报 FAIL。
_shape_env_set_unbacked_var_to_val_works() 端到端探测:试调 set_unbacked_var_to_val(create_unbacked_symint(), 4);若 2.7.1 上触发 TypeError: non-nested SymInt(SymInt 不能作 dict key),则 SKIP。

为何用端到端探测而非仅 hasattr
2.7.1 上部分 API「存在但不可用」(方法在类上可见,调用仍失败)。仅 hasattr 会导致 CI ERROR;探测逻辑与 CI 预装 wheel 行为一致,保证 PASS / SKIP 语义正确

3.3 分 API 用例设计

(1)produce_guards_expression

  • 目的:验证在 NPU FakeTensor 占位场景下,ShapeEnv 能生成守卫表达式字符串(dynamo 导出、符号形状推断的核心路径)。
  • 步骤
    1. env, placeholders = _shape_env_with_fake_placeholders()(NPU 上 (3,4) 随机张量);
    2. guards = env.produce_guards_expression(placeholders)
    3. assertIsInstance(guards, str) —— 返回值类型正确即可证明 API 在 NPU 路径下可调用、可完成守卫生成。
  • 设计说明:不校验 guards 具体字符串内容(随上游 sympy/符号状态变化),只验证接口可达性与基本语义,降低用例脆弱性。

(2)produce_guards_verbose

  • 目的:验证在提供 Source 列表时,ShapeEnv 能否生成更详细的守卫信息。
  • 步骤
    1. 同(1)构造 NPU placeholders;
    2. sources = [Source()] * len(placeholders)
    3. guards = env.produce_guards_verbose(placeholders, sources)
    4. assertIsNotNone(guards)
  • SKIP 条件_produce_guards_verbose_works() 为 False。
    原因:2.7.1 预装 PyTorch 中,裸 Source() 未实现完整 name 链,调用会 NotImplementedError;属上游/测试桩限制,不代表 NPU 后端缺陷,故 SKIP 而非 FAIL。

(3)replace

  • 目的:验证 ShapeEnv 在 sympy 表达式替换路径下行为正确(符号表上下文中的表达式改写)。
  • 步骤
    1. env = ShapeEnv()a, b = sympy.symbols("a b")expr = a + b
    2. assertEqual(env.replace(expr), expr) —— 无替换规则时恒等,验证 API 可调用且代数语义一致。
  • 设计说明:不依赖 FakeTensor/NPU 张量内容,但仍放在 NPU 门禁下,与 issue 要求的「NPU 环境验证」一致。

(4)set_unbacked_var_to_val

  • 目的:验证为 unbacked 符号绑定具体整型值的路径在 NPU 测试环境中可触发。
  • 步骤
    1. env = ShapeEnv()sym = env.create_unbacked_symint()
    2. env.set_unbacked_var_to_val(sym, 4) —— 无异常即通过。
  • SKIP 条件_shape_env_set_unbacked_var_to_val_works() 为 False。
    原因:2.7.1 上 create_unbacked_symint() 返回的 SymInt 在 unbacked_var_to_val 内部作 dict key 时触发 non-nested SymInt,为上游已知限制;用例保留以便高版本 wheel 探测通过后自动变为 PASS。

(5)simplify

  • 目的:验证 ShapeEnv 环境下 sympy 表达式化简。
  • 步骤
    1. env = ShapeEnv()a, b = sympy.symbols("a b")
    2. assertEqual(env.simplify((a + b) - b), a) —— 验证典型化简 (a+b)-b → a

3.4 未覆盖 API 的说明

API 本 PR 不测的原因
add_backed_var_to_val v2.7.1 无此成员,非 issue 在本分支的可测范围;由 2.11.0+ 对应 MR 在方法存在时再补测;文档侧由 MR 36144 标注版本差异。

3.5 与现有 TestSymbolicShapes 的关系

  • TestSymbolicShapes:覆盖 is_accessor_nodeis_concrete_*is_symbolic谓词/图节点行为,仅少量 ShapeEnv().create_unbacked_* 用于构造符号值。
  • TestShapeEnvNPU(本 PR):覆盖 ShapeEnv 实例方法(守卫生成、符号绑定、sympy 改写),补齐同一模块下另一类 API。
  • 二者同文件、同 run_tests() 入口,不互相依赖,可单独跑 TestShapeEnvNPU 或全文件。

3.6 运行与 CI 对接

  • 文件末尾保留 if __name__ == "__main__": run_tests(),与 test/nn/test_nn_api.py 等仓库惯例一致。
  • Ascend CI 对 MR diff 文件执行 UT;本 MR 仅改 test/fx/test_symbolic_shapes.py,流水线会跑:
    cd test && python fx/test_symbolic_shapes.py -v
    
  • 本地可按类过滤:
    python fx/test_symbolic_shapes.py -v TestShapeEnvNPU
    

4. 变更范围

  • 仅修改 test/fx/test_symbolic_shapes.py(单文件),不修改业务代码与用户可见接口。
  • 其它 PyTorch 版本(2.9.0 ~ 2.12.0 / master)由对应 MR 单独提交;资料(torch-fx.md)由 MR 36144 单独提交

【资料变更】

不涉及。API 支持度表格更新由配套资料 PR 单独合入,本 PR 仅负责 v2.7.1 测试补齐。

【接口变更】

不涉及。未修改跨仓或用户可见接口行为。

【功能验证】

测试环境

  • 硬件:Ascend 910B 系列(以 CI ascend-pytorch-* 流水线为准)
  • 软件:PyTorch 2.7.1 + 对应 torch_npu + CANN(由 CI 预装)

测试命令

在仓库 test 目录下执行(与 CI 一致):

cd test
python fx/test_symbolic_shapes.py -v TestShapeEnvNPU

或运行该文件全部用例:

cd test
python fx/test_symbolic_shapes.py -v

预期结果(PyTorch 2.7.1 目标分支)

API 全称 预期
ShapeEnv.produce_guards_expression PASS
ShapeEnv.produce_guards_verbose SKIP(bare Source() 无法满足 name,2.7.1 CI 实测)
ShapeEnv.replace PASS
ShapeEnv.set_unbacked_var_to_val SKIP(2.7.1 上 API 存在但 non-nested SymInt 报错)
ShapeEnv.simplify PASS

合计:5 个用例,3 PASS + 2 SKIP

自验证

  • 本地/CI 执行上述命令,unittest 输出中可见各 test_torch_fx_experimental_symbolic_shapes_ShapeEnv_* 的 PASS/SKIP 状态。
  • image.png

【CheckList】

likedislike
Pull Request已成功合入, 合并人@ascend-robot
(感谢 Yhw050920 的贡献)
Yhw050920Yhw050920
5月19日 创建了 pull request,commit b3e9de79
Yhw050920Yhw050920
5月19日 关联了issue:【开源实习】Torch-NPU API一致性对齐:补齐测试用例、API功能对齐、补齐文档(21)
ascend-robot
ascend-robot成员
5月19日 评论:

Thanks for your pull-request.
The full list of commands accepted by me can be found at here
You can get sig-info at here


PR Approval Progress

Congratulations! All modules have met the lgtm and approve requirements.

Module Approval Details

module lgtm status approve status
test sunyu-xuan, 李伟 (2/2) 李伟 (1/1)

💡 Tip:

  • Committer can comment /approve or /lgtm
  • Commenting /approve implies both code review (lgtm) and intent to merge (approve)

CLA Signature Pass

hongwei-2026, thanks for your pull request. All authors of the commits have signed the CLA. 👍

likedislike
ascend-robotascend-robot成员
5月19日 添加了label:ascend-cla/no
此处折叠了277条消息 查看更多
sunyu-xuan成员
5月30日 评论:

/lgtm

likedislike
liwei386成员
6月1日 评论:

/approve

likedislike
ascend-robotascend-robot成员
6月1日 添加了label:approvedlgtm
ascend-robotascend-robot成员
6月1日 合入了pull request
ascend-robot
ascend-robot成员
6月1日 评论:
流水线 pytorch_gitcode_PR_multiVersion#9773 [ commitID:16ebb22d ] 运行失败
likedislike