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
166173def test_constant_pad_nd__delegation__formatless__supported_padding (use_qat ):
@@ -172,9 +179,7 @@ def test_constant_pad_nd__delegation__formatless__supported_padding(use_qat):
172179 ).exported_program ()
173180
174181 # Make sure the `pad` was delegated.
175- assert not graph_contains_any_of_ops (
176- exec_program .graph , [exir_ops .edge .aten .constant_pad_nd .default ]
177- )
182+ assert not graph_contains_any_of_ops (exec_program .graph , [ConstantPadND ])
178183
179184
180185def test_constant_pad_nd__delegation__formatless__unsupported_padding (use_qat ):
@@ -186,9 +191,7 @@ def test_constant_pad_nd__delegation__formatless__unsupported_padding(use_qat):
186191 ).exported_program ()
187192
188193 # Make sure the `pad` was NOT delegated.
189- assert graph_contains_any_of_ops (
190- exec_program .graph , [exir_ops .edge .aten .constant_pad_nd .default ]
191- )
194+ assert graph_contains_any_of_ops (exec_program .graph , [ConstantPadND ])
192195
193196
194197def test_constant_pad_nd__delegation__channels_first__supported_padding (use_qat ):
@@ -200,9 +203,7 @@ def test_constant_pad_nd__delegation__channels_first__supported_padding(use_qat)
200203 ).exported_program ()
201204
202205 # Make sure the `pad` was delegated.
203- assert not graph_contains_any_of_ops (
204- exec_program .graph , [exir_ops .edge .aten .constant_pad_nd .default ]
205- )
206+ assert not graph_contains_any_of_ops (exec_program .graph , [ConstantPadND ])
206207
207208
208209def test_constant_pad_nd__delegation__channels_first__unsupported_padding (use_qat ):
@@ -214,6 +215,122 @@ def test_constant_pad_nd__delegation__channels_first__unsupported_padding(use_qa
214215 ).exported_program ()
215216
216217 # Make sure the `pad` was NOT delegated.
217- assert graph_contains_any_of_ops (
218- exec_program .graph , [exir_ops .edge .aten .constant_pad_nd .default ]
218+ assert graph_contains_any_of_ops (exec_program .graph , [ConstantPadND ])
219+
220+
221+ class TestConstantPadNDNewNeutronFlow :
222+ """The PyTorch padding is added to the individual dimensions from the back (slightly confusing), see:
223+ https://pytorch.org/docs/stable/generated/torch.nn.functional.pad.html#torch.nn.functional.pad
224+ """
225+
226+ # noinspection PyMethodMayBeStatic
227+ def assert_delegated (self , model , input_shape , mocker , use_qat = False ):
228+ graph_verifier = DetailedGraphVerifier (
229+ mocker ,
230+ expected_delegated_ops = {ConstantPadND : 1 },
231+ expected_non_delegated_ops = {},
232+ )
233+
234+ lower_run_compare (
235+ model ,
236+ input_shape ,
237+ graph_verifier ,
238+ use_qat = use_qat ,
239+ use_new_flow_neutron_c = True ,
240+ )
241+
242+ def assert_delegated_and_output_shape_equals (
243+ self , model , input_shape , expected_output_shape , mocker
244+ ):
245+ model_builder_spy = mocker .spy (ModelBuilder , "finish" )
246+
247+ self .assert_delegated (model , input_shape , mocker )
248+
249+ neutron_ir_subgraph = model_builder_spy .call_args [0 ][0 ].get_sub_graph ()
250+ assert neutron_ir_subgraph .outputs .tmp_outputs [0 ].shape .vector == list (
251+ expected_output_shape
252+ )
253+
254+ @pytest .mark .parametrize (
255+ "input_shape, paddings" ,
256+ [
257+ pytest .param ((2 ,), tuple (range (2 )), id = "1D, padding H" ),
258+ pytest .param ((2 , 4 ), tuple (range (2 )), id = "2D, padding H" ),
259+ pytest .param ((2 , 4 ), tuple (range (4 )), id = "2D, padding N, H" ),
260+ pytest .param ((2 , 4 , 6 ), tuple (range (2 )), id = "3D, padding H" ),
261+ pytest .param ((2 , 4 , 6 ), tuple (range (4 )), id = "3D, padding C, H" ),
262+ pytest .param ((2 , 4 , 6 , 8 ), tuple (range (2 )), id = "4D, padding W" ),
263+ pytest .param ((2 , 4 , 6 , 8 ), tuple (range (4 )), id = "4D, padding H, W" ),
264+ pytest .param ((1 , 2 , 3 , 4 , 5 ), tuple (range (2 )), id = "5D, padding D" ),
265+ pytest .param ((1 , 2 , 3 , 4 , 5 ), tuple (range (4 )), id = "5D, padding W, D" ),
266+ ],
267+ )
268+ def test__basic_nsys_inference (self , mocker , input_shape , paddings , use_qat ):
269+ # These test cases are also supported by the old flow.
270+ model = ConstantPadNDModule (paddings )
271+ self .assert_delegated (model , input_shape , mocker , use_qat )
272+
273+ def test__channels_padding (self , mocker ):
274+ input_shape = (2 , 4 , 6 )
275+ # These paddings will be applied to the last dimension, which is the channels as the input is formatless.
276+ paddings = (1 , 1 )
277+ expected_output_shape = (2 , 4 , 8 ) # Padded channels.
278+ model = ConstantPadNDModule (paddings )
279+
280+ self .assert_delegated_and_output_shape_equals (
281+ model , input_shape , expected_output_shape , mocker
282+ )
283+
284+ def test__batch_padding (self , mocker ):
285+ input_shape = (2 , 4 , 6 )
286+ paddings = (0 , 0 , 0 , 0 , 1 , 1 ) # Padding applied to the batch dimension.
287+ expected_output_shape = (4 , 4 , 6 ) # Padded batch.
288+ model = ConstantPadNDModule (paddings )
289+
290+ self .assert_delegated_and_output_shape_equals (
291+ model , input_shape , expected_output_shape , mocker
292+ )
293+
294+ @pytest .mark .parametrize ("constant" , [0.0 , - 13.37 ])
295+ def test__specific_constant (self , mocker , constant ):
296+ input_shape = (2 , 4 , 6 )
297+ paddings = (1 , 1 )
298+ model = ConstantPadNDModule (paddings , constant )
299+ self .assert_delegated (model , input_shape , mocker )
300+
301+ @pytest .mark .parametrize (
302+ "input_shape, paddings" ,
303+ [
304+ pytest .param ((1 , 4 , 6 , 8 ), tuple (range (2 )), id = "4D, padding W" ),
305+ pytest .param ((1 , 4 , 6 , 8 ), tuple (range (4 )), id = "4D, padding H, W" ),
306+ ],
219307 )
308+ def test__channels_first (self , mocker , input_shape , paddings ):
309+ model = ConstantPadNDConvModule (paddings )
310+ graph_verifier = DetailedGraphVerifier (
311+ mocker ,
312+ expected_delegated_ops = {ConstantPadND : 1 , Convolution : 1 },
313+ expected_non_delegated_ops = {},
314+ )
315+
316+ lower_run_compare (
317+ model , input_shape , graph_verifier , use_new_flow_neutron_c = True
318+ )
319+
320+ @pytest .mark .xfail (
321+ strict = True ,
322+ raises = RuntimeError ,
323+ reason = "Known issue in Neutron: https://jira.sw.nxp.com/browse/AIR-14624" , # @lint-ignore
324+ )
325+ def test__bugged_channels_first_case (self , mocker ):
326+ input_shape , paddings = (1 , 2 , 6 , 8 ), (0 , 1 , 2 , 3 , 1 , 1 )
327+ model = ConstantPadNDConvModule (paddings )
328+ graph_verifier = DetailedGraphVerifier (
329+ mocker ,
330+ expected_delegated_ops = {ConstantPadND : 1 , Convolution : 1 },
331+ expected_non_delegated_ops = {},
332+ )
333+
334+ lower_run_compare (
335+ model , input_shape , graph_verifier , use_new_flow_neutron_c = True
336+ )
0 commit comments