44# LICENSE file in the root directory of this source tree.
55
66import numpy as np
7+
8+ # noinspection PyUnusedImports
79import pytest
810import torch
911
1012from executorch .backends .nxp .backend .edge_program_converter import (
1113 EdgeProgramToIRConverter ,
1214)
15+ from executorch .backends .nxp .tests .dataset_creator import RandomDatasetCreator
1316from executorch .backends .nxp .tests .executorch_pipeline import to_quantized_edge_program
1417from executorch .backends .nxp .tests .executors import (
1518 convert_run_compare ,
1619 graph_contains_any_of_ops ,
1720 ToChannelFirstPreprocess ,
1821 ToChannelLastPreprocess ,
1922)
20- from executorch .exir .dialects ._ops import ops as exir_ops
23+ from executorch .backends .nxp .tests .graph_verifier import DetailedGraphVerifier
24+ from executorch .backends .nxp .tests .nsys_testing import lower_run_compare
25+ from executorch .backends .nxp .tests .ops_aliases import (
26+ AddTensor ,
27+ ExecutorchDelegateCall ,
28+ UpsampleNearest2D ,
29+ )
30+ from executorch .backends .nxp .tests .use_qat import * # noqa F403
2131
2232
2333@pytest .fixture (autouse = True )
@@ -26,11 +36,6 @@ def reseed_model_per_test_run():
2636 np .random .seed (23 )
2737
2838
29- # noinspection PyProtectedMember
30- ExecutorchDelegateCall = torch .ops .higher_order .executorch_call_delegate
31- UpsampleNearest2D = exir_ops .edge .aten .upsample_nearest2d .vec
32-
33-
3439class UpsampleNearestModule (torch .nn .Module ):
3540
3641 def __init__ (self , size = None , scale = None ):
@@ -41,6 +46,13 @@ def forward(self, x):
4146 return self .upsample (x )
4247
4348
49+ class UpsampleNearestAddModule (UpsampleNearestModule ):
50+
51+ def forward (self , x ):
52+ x = super ().forward (x )
53+ return x + x
54+
55+
4456@pytest .mark .parametrize (
4557 "input_shape, size" ,
4658 [
@@ -181,3 +193,120 @@ def test_convert_upsample_nearest2d__no_delegation__unsupported_size(input_shape
181193 # Make sure the `upsample` was NOT delegated (size != double of input).
182194 assert not graph_contains_any_of_ops (delegated_ep .graph , [ExecutorchDelegateCall ])
183195 assert graph_contains_any_of_ops (delegated_ep .graph , [UpsampleNearest2D ])
196+
197+
198+ class TestUpsampleNearest2DNewNeutronFlow :
199+
200+ # noinspection PyMethodMayBeStatic
201+ def assert_delegated (
202+ self ,
203+ model ,
204+ input_shape ,
205+ mocker ,
206+ use_qat = False ,
207+ expected_delegated_ops = None ,
208+ ):
209+ if expected_delegated_ops is None :
210+ expected_delegated_ops = {UpsampleNearest2D : 1 }
211+
212+ graph_verifier = DetailedGraphVerifier (
213+ mocker ,
214+ expected_delegated_ops = expected_delegated_ops ,
215+ expected_non_delegated_ops = {},
216+ )
217+
218+ # Cover also negative values to thoroughly test the operator.
219+ dataset_creator = RandomDatasetCreator (low = - 2 , high = 2 )
220+
221+ lower_run_compare (
222+ model ,
223+ input_shape ,
224+ graph_verifier ,
225+ dataset_creator ,
226+ use_qat = use_qat ,
227+ use_new_flow_neutron_c = True , # Use the new flow.
228+ )
229+
230+ # noinspection PyMethodMayBeStatic
231+ def assert_not_delegated (self , model , input_shape ):
232+ delegated_ep = to_quantized_edge_program (
233+ model , input_shape , use_new_flow_neutron_c = True
234+ ).exported_program ()
235+
236+ assert not graph_contains_any_of_ops (
237+ delegated_ep .graph , [ExecutorchDelegateCall ]
238+ )
239+ assert graph_contains_any_of_ops (delegated_ep .graph , [UpsampleNearest2D ])
240+
241+ def test__qat (self , mocker , use_qat ):
242+ input_shape = (1 , 2 , 3 , 4 )
243+ output_size = (6 , 8 )
244+ model = UpsampleNearestModule (size = output_size )
245+ self .assert_delegated (model , input_shape , mocker , use_qat = use_qat )
246+
247+ @pytest .mark .parametrize (
248+ "input_shape, output_size" ,
249+ [
250+ pytest .param ((1 , 2 , 3 , 4 ), (6 , 8 ), id = "batch=1, scale_h=scale_w=2" ),
251+ pytest .param ((1 , 2 , 3 , 3 ), 6 , id = "batch=1, scale_h=scale_w=2, scalar size" ),
252+ pytest .param (
253+ (3 , 3 , 3 , 5 ),
254+ (6 , 5 ),
255+ id = "batch=3, scale_h=2, scale_w=1 (no num_macs multiples)" ,
256+ ),
257+ pytest .param ((2 , 2 , 3 , 4 ), (3 , 16 ), id = "batch=2, scale_h=1, scale_w=4" ),
258+ pytest .param ((2 , 2 , 3 , 4 ), (24 , 8 ), id = "batch=2, scale_h=8, scale_w=2" ),
259+ ],
260+ )
261+ def test__output_size (self , mocker , input_shape , output_size ):
262+ model = UpsampleNearestModule (size = output_size )
263+ self .assert_delegated (model , input_shape , mocker )
264+
265+ def test__output_size__unsupported (self ):
266+ input_shape = (1 , 2 , 3 , 4 )
267+ output_size = (9 , 12 ) # scale = (3, 3)
268+ model = UpsampleNearestModule (size = output_size )
269+ self .assert_not_delegated (model , input_shape )
270+
271+ @pytest .mark .parametrize (
272+ "input_shape, scale" ,
273+ [
274+ pytest .param ((1 , 2 , 3 , 4 ), (2 , 2 ), id = "batch=1, scale_h=scale_w=2" ),
275+ pytest .param (
276+ (1 , 2 , 3 , 4 ), 4 , id = "batch=1, scale_h=scale_w=4, scalar scale"
277+ ),
278+ pytest .param (
279+ (3 , 3 , 3 , 5 ),
280+ (2 , 1 ),
281+ id = "batch=3, scale_h=2, scale_w=1 (no num_macs multiples)" ,
282+ ),
283+ pytest .param ((2 , 2 , 3 , 4 ), (4 , 1 ), id = "batch=2, scale_h=4, scale_w=1" ),
284+ pytest .param ((2 , 2 , 3 , 4 ), (2 , 8 ), id = "batch=2, scale_h=2, scale_w=8" ),
285+ ],
286+ )
287+ def test__scales (self , mocker , input_shape , scale ):
288+ model = UpsampleNearestModule (scale = scale )
289+ self .assert_delegated (model , input_shape , mocker )
290+
291+ def test__scales__unsupported (self ):
292+ input_shape = (1 , 2 , 3 , 4 )
293+ scale = (3 , 3 )
294+ model = UpsampleNearestModule (scale = scale )
295+ self .assert_not_delegated (model , input_shape )
296+
297+ def test__noop__alone_in_partition__not_delegated (self ):
298+ input_shape = (1 , 2 , 3 , 4 )
299+ scale = 1
300+ model = UpsampleNearestModule (scale = scale )
301+ self .assert_not_delegated (model , input_shape )
302+
303+ def test__noop__not_alone_in_partition__delegated (self , mocker ):
304+ input_shape = (1 , 2 , 3 , 4 )
305+ scale = 1
306+ model = UpsampleNearestAddModule (scale = scale )
307+ self .assert_delegated (
308+ model ,
309+ input_shape ,
310+ mocker ,
311+ expected_delegated_ops = {UpsampleNearest2D : 1 , AddTensor : 1 },
312+ )
0 commit comments