44# LICENSE file in the root directory of this source tree.
55
66import numpy as np
7+
8+ # noinspection PyUnusedImports
79import pytest
810import torch
11+
912from executorch .backends .nxp .backend .ir .conversion_config import ConversionConfig
13+ from executorch .backends .nxp .backend .ir .converter .builder .model_builder import (
14+ ModelBuilder ,
15+ )
1016from executorch .backends .nxp .backend .ir .converter .node_converters .ops_converters .constant_pad_nd_converter import (
1117 ConstantPadNDConverter ,
1218)
1723from executorch .backends .nxp .tests .executors import (
1824 convert_run_compare ,
1925 graph_contains_any_of_ops ,
26+ OverrideTargetSupportCheck ,
2027 ToNCHWPreprocess ,
2128 ToNHWCPreprocess ,
2229)
30+ from executorch .backends .nxp .tests .graph_verifier import DetailedGraphVerifier
2331from executorch .backends .nxp .tests .models import (
2432 ConstantPadNDConvModule ,
2533 ConstantPadNDModule ,
2634)
35+ from executorch .backends .nxp .tests .nsys_testing import lower_run_compare
36+ from executorch .backends .nxp .tests .ops_aliases import ConstantPadND , Convolution
2737from executorch .backends .nxp .tests .use_qat import * # noqa F403
28- from executorch .backends .nxp .tests .executors import OverrideTargetSupportCheck
29- from executorch .exir .dialects ._ops import ops as exir_ops
3038
3139
3240@pytest .fixture (autouse = True )
@@ -158,9 +166,8 @@ def test_constant_pad_nd__unsupported_paddings(input_shape, paddings, use_qat):
158166 model , input_shape , use_qat = use_qat
159167 ).exported_program ()
160168
161- nodes = list (exec_program .graph .nodes )
162169 # There is at least one non-delegated Pad node
163- assert any ( node . name == "aten_constant_pad_nd_default" for node in nodes )
170+ assert graph_contains_any_of_ops ( exec_program . graph , [ ConstantPadND ] )
164171
165172
166173@pytest .mark .xfail (reason = "EIEX=855" )
@@ -173,9 +180,7 @@ def test_constant_pad_nd__delegation__formatless__supported_padding(use_qat):
173180 ).exported_program ()
174181
175182 # Make sure the `pad` was delegated.
176- assert not graph_contains_any_of_ops (
177- exec_program .graph , [exir_ops .edge .aten .constant_pad_nd .default ]
178- )
183+ assert not graph_contains_any_of_ops (exec_program .graph , [ConstantPadND ])
179184
180185
181186def test_constant_pad_nd__delegation__formatless__unsupported_padding (use_qat ):
@@ -187,9 +192,7 @@ def test_constant_pad_nd__delegation__formatless__unsupported_padding(use_qat):
187192 ).exported_program ()
188193
189194 # Make sure the `pad` was NOT delegated.
190- assert graph_contains_any_of_ops (
191- exec_program .graph , [exir_ops .edge .aten .constant_pad_nd .default ]
192- )
195+ assert graph_contains_any_of_ops (exec_program .graph , [ConstantPadND ])
193196
194197
195198@pytest .mark .xfail (reason = "Regression in Neutron SW 3.0.1 (AIR-14264)" , strict = True )
@@ -202,9 +205,7 @@ def test_constant_pad_nd__delegation__channels_first__supported_padding(use_qat)
202205 ).exported_program ()
203206
204207 # Make sure the `pad` was delegated.
205- assert not graph_contains_any_of_ops (
206- exec_program .graph , [exir_ops .edge .aten .constant_pad_nd .default ]
207- )
208+ assert not graph_contains_any_of_ops (exec_program .graph , [ConstantPadND ])
208209
209210
210211def test_constant_pad_nd__delegation__channels_first__unsupported_padding (use_qat ):
@@ -216,6 +217,122 @@ def test_constant_pad_nd__delegation__channels_first__unsupported_padding(use_qa
216217 ).exported_program ()
217218
218219 # Make sure the `pad` was NOT delegated.
219- assert graph_contains_any_of_ops (
220- exec_program .graph , [exir_ops .edge .aten .constant_pad_nd .default ]
220+ assert graph_contains_any_of_ops (exec_program .graph , [ConstantPadND ])
221+
222+
223+ class TestConstantPadNDNewNeutronFlow :
224+ """The PyTorch padding is added to the individual dimensions from the back (slightly confusing), see:
225+ https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html#torch.nn.functional.pad
226+ """
227+
228+ # noinspection PyMethodMayBeStatic
229+ def assert_delegated (self , model , input_shape , mocker , use_qat = False ):
230+ graph_verifier = DetailedGraphVerifier (
231+ mocker ,
232+ expected_delegated_ops = {ConstantPadND : 1 },
233+ expected_non_delegated_ops = {},
234+ )
235+
236+ lower_run_compare (
237+ model ,
238+ input_shape ,
239+ graph_verifier ,
240+ use_qat = use_qat ,
241+ use_new_flow_neutron_c = True ,
242+ )
243+
244+ def assert_delegated_and_output_shape_equals (
245+ self , model , input_shape , expected_output_shape , mocker
246+ ):
247+ model_builder_spy = mocker .spy (ModelBuilder , "finish" )
248+
249+ self .assert_delegated (model , input_shape , mocker )
250+
251+ neutron_ir_subgraph = model_builder_spy .call_args [0 ][0 ].get_sub_graph ()
252+ assert neutron_ir_subgraph .outputs .tmp_outputs [0 ].shape .vector == list (
253+ expected_output_shape
254+ )
255+
256+ @pytest .mark .parametrize (
257+ "input_shape, paddings" ,
258+ [
259+ pytest .param ((2 ,), tuple (range (2 )), id = "1D, padding H" ),
260+ pytest .param ((2 , 4 ), tuple (range (2 )), id = "2D, padding H" ),
261+ pytest .param ((2 , 4 ), tuple (range (4 )), id = "2D, padding N, H" ),
262+ pytest .param ((2 , 4 , 6 ), tuple (range (2 )), id = "3D, padding H" ),
263+ pytest .param ((2 , 4 , 6 ), tuple (range (4 )), id = "3D, padding C, H" ),
264+ pytest .param ((2 , 4 , 6 , 8 ), tuple (range (2 )), id = "4D, padding W" ),
265+ pytest .param ((2 , 4 , 6 , 8 ), tuple (range (4 )), id = "4D, padding H, W" ),
266+ pytest .param ((1 , 2 , 3 , 4 , 5 ), tuple (range (2 )), id = "5D, padding D" ),
267+ pytest .param ((1 , 2 , 3 , 4 , 5 ), tuple (range (4 )), id = "5D, padding W, D" ),
268+ ],
269+ )
270+ def test__basic_nsys_inference (self , mocker , input_shape , paddings , use_qat ):
271+ # These test cases are also supported by the old flow.
272+ model = ConstantPadNDModule (paddings )
273+ self .assert_delegated (model , input_shape , mocker , use_qat )
274+
275+ def test__channels_padding (self , mocker ):
276+ input_shape = (2 , 4 , 6 )
277+ # These paddings will be applied to the last dimension, which is the channels as the input is formatless.
278+ paddings = (1 , 1 )
279+ expected_output_shape = (2 , 4 , 8 ) # Padded channels.
280+ model = ConstantPadNDModule (paddings )
281+
282+ self .assert_delegated_and_output_shape_equals (
283+ model , input_shape , expected_output_shape , mocker
284+ )
285+
286+ def test__batch_padding (self , mocker ):
287+ input_shape = (2 , 4 , 6 )
288+ paddings = (0 , 0 , 0 , 0 , 1 , 1 ) # Padding applied to the batch dimension.
289+ expected_output_shape = (4 , 4 , 6 ) # Padded batch.
290+ model = ConstantPadNDModule (paddings )
291+
292+ self .assert_delegated_and_output_shape_equals (
293+ model , input_shape , expected_output_shape , mocker
294+ )
295+
296+ @pytest .mark .parametrize ("constant" , [0.0 , - 13.37 ])
297+ def test__specific_constant (self , mocker , constant ):
298+ input_shape = (2 , 4 , 6 )
299+ paddings = (1 , 1 )
300+ model = ConstantPadNDModule (paddings , constant )
301+ self .assert_delegated (model , input_shape , mocker )
302+
303+ @pytest .mark .parametrize (
304+ "input_shape, paddings" ,
305+ [
306+ pytest .param ((1 , 4 , 6 , 8 ), tuple (range (2 )), id = "4D, padding W" ),
307+ pytest .param ((1 , 4 , 6 , 8 ), tuple (range (4 )), id = "4D, padding H, W" ),
308+ ],
221309 )
310+ def test__channels_first (self , mocker , input_shape , paddings ):
311+ model = ConstantPadNDConvModule (paddings )
312+ graph_verifier = DetailedGraphVerifier (
313+ mocker ,
314+ expected_delegated_ops = {ConstantPadND : 1 , Convolution : 1 },
315+ expected_non_delegated_ops = {},
316+ )
317+
318+ lower_run_compare (
319+ model , input_shape , graph_verifier , use_new_flow_neutron_c = True
320+ )
321+
322+ @pytest .mark .xfail (
323+ strict = True ,
324+ raises = RuntimeError ,
325+ reason = "Known issue in Neutron: https://jira.sw.nxp.com/browse/AIR-14624" , # @lint-ignore
326+ )
327+ def test__bugged_channels_first_case (self , mocker ):
328+ input_shape , paddings = (1 , 2 , 6 , 8 ), (0 , 1 , 2 , 3 , 1 , 1 )
329+ model = ConstantPadNDConvModule (paddings )
330+ graph_verifier = DetailedGraphVerifier (
331+ mocker ,
332+ expected_delegated_ops = {ConstantPadND : 1 , Convolution : 1 },
333+ expected_non_delegated_ops = {},
334+ )
335+
336+ lower_run_compare (
337+ model , input_shape , graph_verifier , use_new_flow_neutron_c = True
338+ )
0 commit comments