99from executorch .backends .nxp .backend .edge_program_converter import (
1010 EdgeProgramToIRConverter ,
1111)
12- from executorch .backends .nxp .tests .executors import (
13- convert_run_compare ,
14- graph_contains_any_of_ops ,
12+ from executorch .backends .nxp .tests .executors import graph_contains_any_of_ops
13+ from executorch .backends .nxp .tests .graph_verifier import DetailedGraphVerifier
14+ from executorch .backends .nxp .tests .model_output_comparator import (
15+ AllCloseOutputComparator ,
1516)
1617from executorch .backends .nxp .tests .models import (
18+ ConvPReLUModule ,
1719 LinearPReLUModule ,
1820 TwoPartitionPReLUModel ,
1921)
22+
23+ from executorch .backends .nxp .tests .nsys_testing import lower_run_compare
24+ from executorch .backends .nxp .tests .ops_aliases import (
25+ AddMm ,
26+ Convolution ,
27+ ExecutorchDelegateCall ,
28+ GtScalar ,
29+ MulTensor ,
30+ PermuteCopy ,
31+ Prelu ,
32+ ViewCopy ,
33+ WhereSelf ,
34+ )
2035from torch .export import ExportedProgram
2136from executorch .backends .nxp .tests .use_qat import * # noqa F403
2237from executorch .backends .nxp .tests .executorch_pipeline import to_quantized_edge_program
23- from executorch .exir .dialects ._ops import ops as exir_ops
2438
2539
2640@pytest .fixture (autouse = True )
@@ -29,123 +43,148 @@ def reseed_model_per_test_run():
2943 np .random .seed (23 )
3044
3145
32- # noinspection PyProtectedMember
33- ExecutorchDelegateCall = torch .ops .higher_order .executorch_call_delegate
34-
35-
36- @pytest .mark .parametrize (
37- "input_shape" ,
38- [
39- pytest .param ((1 , 8 , 24 , 32 ), id = "4D." ),
40- ],
41- )
42- def test_prelu_with_linear_quant_conversion (mocker , input_shape ):
43- converter_spy = mocker .spy (EdgeProgramToIRConverter , "convert_program" )
44-
45- # Run conversion
46- channels = input_shape [- 1 ]
47- edge_program = to_quantized_edge_program (
48- LinearPReLUModule (in_features = channels , out_features = channels ),
46+ class TestPreluConverter :
47+ # noinspection PyMethodMayBeStatic
48+ def assert_delegated (
49+ self ,
50+ model ,
4951 input_shape ,
50- ).exported_program ()
51-
52- # Capture generated entities
53- neutron_ir_model , * _ = converter_spy .spy_return
54- exported_program : ExportedProgram = converter_spy .call_args .args [1 ]
55-
56- # Check `prelu` was not decomposed into simpler edge operators
57- assert not graph_contains_any_of_ops (
58- exported_program .graph ,
52+ mocker ,
53+ request ,
54+ expected_delegated_ops = None ,
55+ use_qat = False ,
56+ ):
57+ rank = len (input_shape )
58+ graph_verifier = DetailedGraphVerifier (
59+ mocker ,
60+ expected_delegated_ops = expected_delegated_ops
61+ or {
62+ Prelu : 1 ,
63+ AddMm : 1 ,
64+ PermuteCopy : 1 ,
65+ ViewCopy : 0 if rank == 2 else 2 ,
66+ },
67+ expected_non_delegated_ops = {},
68+ )
69+ comparator = AllCloseOutputComparator (atol = 1 )
70+
71+ lower_run_compare (
72+ model ,
73+ input_shape ,
74+ graph_verifier ,
75+ request ,
76+ output_comparator = comparator ,
77+ remove_quant_io_ops = True ,
78+ use_qat = use_qat ,
79+ )
80+
81+ @pytest .mark .parametrize (
82+ "input_shape" ,
5983 [
60- exir_ops .edge .aten .gt .Scalar ,
61- exir_ops .edge .aten .mul .Tensor ,
62- exir_ops .edge .aten .where .self ,
84+ pytest .param ((1 ,), id = "1D." ),
85+ pytest .param (
86+ (36 , 487 ),
87+ id = "2D incorrect results." ,
88+ marks = pytest .mark .xfail (
89+ reason = "AIR-14737: incorrect results" , strict = True
90+ ),
91+ ),
92+ pytest .param (
93+ (87 , 842 ),
94+ id = "2D incorrect results alt." ,
95+ marks = pytest .mark .xfail (
96+ reason = "AIR-14737: incorrect results" , strict = True
97+ ),
98+ ),
99+ pytest .param ((7 , 83 ), id = "2D." ),
100+ pytest .param (
101+ (1 , 43 , 183 ),
102+ id = "3D incorrect results alt." ,
103+ marks = pytest .mark .xfail (
104+ reason = "AIR-14737: incorrect results" , strict = True
105+ ),
106+ ),
107+ pytest .param ((1 , 43 , 93 ), id = "3D." ),
108+ pytest .param ((1 , 4 , 7 , 8 ), id = "4D." ),
109+ pytest .param ((1 , 4 , 3 , 4 , 14 ), id = "5D." ),
63110 ],
64111 )
65-
66- assert graph_contains_any_of_ops (
67- exported_program .graph ,
68- [exir_ops .edge .aten .prelu .default ],
69- )
70-
71- # Check `prelu` was delegated
72- assert not graph_contains_any_of_ops (
73- edge_program .graph ,
74- [exir_ops .edge .aten .prelu .default ],
75- )
76-
77- input_data = (
78- (2 * np .random .random (input_shape ).astype (np .float32 ) - 1 ) * 50
79- ).astype (np .int8 )
80-
81- convert_run_compare (exported_program , input_data , tfl_model = neutron_ir_model )
82-
83-
84- @pytest .mark .parametrize (
85- "input_shape" ,
86- [
87- pytest .param ((1 , 8 , 24 , 32 ), id = "4D." ),
88- ],
89- )
90- def test_prelu_2_partitions (mocker , input_shape ):
91- # TODO (Martin) Add a channels last dim order variant of this test to verify correct partitioning.
92- # Run conversion
93- edge_program = to_quantized_edge_program (
94- TwoPartitionPReLUModel (), [input_shape , input_shape ]
95- ).exported_program ()
96-
97- # Check `prelu` was delegated
98- assert not graph_contains_any_of_ops (
99- edge_program .graph ,
100- [exir_ops .edge .aten .prelu .default ],
101- )
102-
103- # Check there are two partitions
104- edge_nodes = list (edge_program .graph .nodes )
105- assert sum (n .target == ExecutorchDelegateCall for n in edge_nodes ) == 2
106-
107-
108- @pytest .mark .parametrize (
109- "input_shape" ,
110- [
111- pytest .param ((1 ,), id = "1D not supported." ),
112- pytest .param ((1 , 8 ), id = "2D not supported." ),
113- pytest .param ((1 , 8 , 16 ), id = "3D not supported." ),
114- pytest .param ((1 , 8 , 16 , 32 , 64 ), id = "5D not supported." ),
115- pytest .param ((1 , 8 , 16 , 31 ), id = "channels must be divisible by NUM_MACS" ),
116- pytest .param ((1 , 8 , 1024 , 8 ), id = "width*height is too big (limit 4096)" ),
117- ],
118- )
119- def test_prelu__no_delegation__unsupported_conversion (mocker , input_shape ):
120- # Run conversion
121- channels = input_shape [- 1 ]
122- edge_program = to_quantized_edge_program (
123- LinearPReLUModule (in_features = channels , out_features = channels ),
124- input_shape ,
125- ).exported_program ()
126-
127- # Check `prelu` was not delegated (only `linear` was)
128- edge_nodes = list (edge_program .graph .nodes )
129- assert sum (n .target == ExecutorchDelegateCall for n in edge_nodes ) == 1
130-
131- # Check `prelu` was decomposed into simpler edge operators
132- assert graph_contains_any_of_ops (
133- edge_program .graph ,
134- [
135- exir_ops .edge .aten .gt .Scalar ,
136- ],
137- )
138-
139- assert graph_contains_any_of_ops (
140- edge_program .graph ,
141- [
142- exir_ops .edge .aten .mul .Tensor ,
143- ],
144- )
145-
146- assert graph_contains_any_of_ops (
147- edge_program .graph ,
112+ def test__basic_nsys_inference (self , mocker , request , input_shape ):
113+ channels = input_shape [- 1 ]
114+ model = LinearPReLUModule (in_features = channels , out_features = channels )
115+
116+ converter_spy = mocker .spy (EdgeProgramToIRConverter , "convert_program" )
117+
118+ self .assert_delegated (model , input_shape , mocker , request )
119+
120+ # Capture generated entities
121+ exported_program : ExportedProgram = converter_spy .call_args .args [1 ]
122+
123+ # Check `prelu` was not decomposed into simpler edge operators
124+ assert not graph_contains_any_of_ops (
125+ exported_program .graph ,
126+ [
127+ GtScalar ,
128+ MulTensor ,
129+ WhereSelf ,
130+ ],
131+ )
132+
133+ def test__basic_nsys_inference_qat (self , mocker , request ):
134+ input_shape = (2 , 4 , 6 , 7 )
135+ channels = input_shape [- 1 ]
136+ model = LinearPReLUModule (in_features = channels , out_features = channels )
137+
138+ self .assert_delegated (model , input_shape , mocker , request , use_qat = True )
139+
140+ def test__num_parameters_param (self , mocker , request ):
141+ input_shape = (1 , 43 , 93 )
142+ channels = input_shape [- 1 ]
143+ num_parameters = input_shape [1 ]
144+ model = LinearPReLUModule (
145+ in_features = channels , out_features = channels , num_parameters = num_parameters
146+ )
147+
148+ self .assert_delegated (model , input_shape , mocker , request )
149+
150+ def test_prelu_2_partitions (self ):
151+ input_shape = (1 , 8 , 24 , 32 )
152+ # Run conversion
153+ edge_program = to_quantized_edge_program (
154+ TwoPartitionPReLUModel (), [input_shape , input_shape ]
155+ ).exported_program ()
156+
157+ # Check `prelu` was delegated
158+ assert not graph_contains_any_of_ops (
159+ edge_program .graph ,
160+ [Prelu ],
161+ )
162+
163+ # Check there are two partitions
164+ edge_nodes = list (edge_program .graph .nodes )
165+ assert sum (n .target == ExecutorchDelegateCall for n in edge_nodes ) == 2
166+
167+ @pytest .mark .parametrize (
168+ "input_shape" ,
148169 [
149- exir_ops .edge .aten .where .self ,
170+ pytest .param ((1 , 8 , 42 , 24 ), id = "4D." ),
171+ pytest .param (
172+ (1 , 8 , 42 , 21 ),
173+ id = "4D incorrect results." ,
174+ marks = pytest .mark .xfail (
175+ reason = "AIR-14737: incorrect results" , strict = True
176+ ),
177+ ),
150178 ],
151179 )
180+ def test__w_conv (self , mocker , request , input_shape ):
181+ channels = input_shape [1 ]
182+ model = ConvPReLUModule (in_channels = channels )
183+ expected_delegated_ops = {
184+ Prelu : 1 ,
185+ Convolution : 1 ,
186+ }
187+
188+ self .assert_delegated (
189+ model , input_shape , mocker , request , expected_delegated_ops
190+ )
0 commit comments