已合并
test(fx): add NPU tests for torch.fx graph APIs #35514
test(fx): add NPU tests for torch.fx graph APIs #35514
已合并
zhouzirui1234创建于 5月13日
1 个文件变更+109-0
Atest/fx/test_fx_graph_api.py+109-0
@@ -0,0 +1,109 @@
1+"""
2+Add validation cases for torch.fx Graph APIs on NPU:
3+ 
4+1. This file adds lightweight direct validations for torch.fx Graph APIs on NPU.
5+2. This file validates torch.fx.Graph.inserting_after,
6+ torch.fx.Graph.inserting_before, torch.fx.graph.magic_methods.format,
7+ and torch.fx.graph.inplace_methods.format.
8+"""
9+ 
10+import operator
11+ 
12+import torch
13+from torch.testing._internal.common_utils import run_tests, TestCase
14+from torch.fx import GraphModule, symbolic_trace
15+ 
16+device_type = acc.type if (acc := torch.accelerator.current_accelerator()) else "cpu"
17+ 
18+ 
19+class TestFxGraphApiNPU(TestCase):
20+ def test_graph_inserting_after(self):
21+ graph = torch.fx.Graph()
22+ x = graph.placeholder("x")
23+ neg = graph.call_function(torch.neg, (x,))
24+ with graph.inserting_after(neg):
25+ relu = graph.call_function(torch.relu, (neg,))
26+ graph.output(relu)
27+ graph.lint()
28+ 
29+ nodes = list(graph.nodes)
30+ # Validate both insertion order and data dependency.
31+ self.assertEqual(nodes.index(relu), nodes.index(neg) + 1)
32+ self.assertEqual(neg.args, (x,))
33+ self.assertEqual(relu.args, (neg,))
34+ self.assertEqual(relu.target, torch.relu)
35+ 
36+ gm = GraphModule(torch.nn.Module(), graph)
37+ input_tensor = torch.randn(2, 3).to(device_type)
38+ self.assertEqual(gm(input_tensor), torch.relu(torch.neg(input_tensor)))
39+ 
40+ def test_graph_inserting_before(self):
41+ graph = torch.fx.Graph()
42+ x = graph.placeholder("x")
43+ relu = graph.call_function(torch.relu, (x,))
44+ graph.output(relu)
45+ with graph.inserting_before(relu):
46+ neg = graph.call_function(torch.neg, (x,))
47+ relu.args = (neg,)
48+ graph.lint()
49+ 
50+ nodes = list(graph.nodes)
51+ # Validate both insertion order and rewritten input dependency.
52+ self.assertLess(nodes.index(neg), nodes.index(relu))
53+ self.assertEqual(nodes.index(neg), nodes.index(relu) - 1)
54+ self.assertEqual(neg.args, (x,))
55+ self.assertEqual(relu.args, (neg,))
56+ self.assertEqual(neg.target, torch.neg)
57+ 
58+ gm = GraphModule(torch.nn.Module(), graph)
59+ input_tensor = torch.randn(2, 3).to(device_type)
60+ self.assertEqual(gm(input_tensor), torch.relu(torch.neg(input_tensor)))
61+ 
62+ def test_magic_methods_format_codegen(self):
63+ class MyModule(torch.nn.Module):
64+ def forward(self, x):
65+ return x << 3, x >> 3
66+ 
67+ input_tensor = torch.LongTensor(10).random_(0, 1024).to(device_type)
68+ gm = symbolic_trace(MyModule())
69+ gm.graph.lint()
70+ 
71+ # Symbolic tracing should create proxy nodes for shift operators.
72+ nodes = list(gm.graph.nodes)
73+ x_node = next(node for node in nodes if node.op == "placeholder")
74+ lshift_node = next(node for node in nodes if node.target == operator.lshift)
75+ rshift_node = next(node for node in nodes if node.target == operator.rshift)
76+ self.assertEqual(lshift_node.args, (x_node, 3))
77+ self.assertEqual(rshift_node.args, (x_node, 3))
78+ 
79+ self.assertIn("x << 3", gm.code)
80+ self.assertIn("x >> 3", gm.code)
81+ 
82+ expected = MyModule()(input_tensor)
83+ self.assertEqual(gm(input_tensor), expected)
84+ 
85+ def test_inplace_methods_format_codegen(self):
86+ graph = torch.fx.Graph()
87+ a = graph.placeholder("a")
88+ b = graph.placeholder("b")
89+ # Build imul directly because tracing "a *= b" lowers to operator.mul.
90+ imul = graph.call_function(operator.imul, (a, b), {})
91+ graph.output(a)
92+ graph.lint()
93+ 
94+ self.assertEqual(imul.args, (a, b))
95+ self.assertEqual(imul.target, operator.imul)
96+ 
97+ gm = GraphModule(torch.nn.Module(), graph)
98+ gm.recompile()
99+ self.assertIn("a *= b", gm.code)
100+ 
101+ input_tensor = torch.ones(2, 3).to(device_type)
102+ scale = torch.full((2, 3), 3.0).to(device_type)
103+ output = gm(input_tensor, scale)
104+ self.assertEqual(output, torch.full((2, 3), 3.0).to(device_type))
105+ self.assertEqual(input_tensor, torch.full((2, 3), 3.0).to(device_type))
106+ 
107+ 
108+if __name__ == "__main__":
109+ run_tests()