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
10- from executorch .backends .nxp .backend .edge_program_converter import (
11- EdgeProgramToIRConverter ,
12- )
13- from executorch .backends .nxp .tests .executorch_pipeline import to_quantized_edge_program
14- from executorch .backends .nxp .tests .executors import (
15- convert_run_compare ,
16- graph_contains_any_of_ops ,
17- ToChannelFirstPreprocess ,
18- ToChannelLastPreprocess ,
12+ from executorch .backends .nxp .tests .dataset_creator import (
13+ LinearRampDatasetCreator ,
14+ RandomDatasetCreator ,
1915)
20- from executorch .exir .dialects ._ops import ops as exir_ops
16+ from executorch .backends .nxp .tests .graph_verifier import DetailedGraphVerifier
17+ from executorch .backends .nxp .tests .nsys_testing import lower_run_compare
18+ from executorch .backends .nxp .tests .ops_aliases import Convolution , Neg
19+ from executorch .backends .nxp .tests .use_qat import * # noqa F403
2120
2221
2322@pytest .fixture (autouse = True )
@@ -26,11 +25,6 @@ def reseed_model_per_test_run():
2625 np .random .seed (23 )
2726
2827
29- # noinspection PyProtectedMember
30- ExecutorchDelegateCall = torch .ops .higher_order .executorch_call_delegate
31- Neg = exir_ops .edge .aten .neg .default
32-
33-
3428class NegModule (torch .nn .Module ):
3529
3630 def __init__ (self ):
@@ -45,79 +39,78 @@ class ConvNegModule(torch.nn.Module):
4539
4640 def __init__ (self ):
4741 super ().__init__ ()
48- self .conv = torch .nn .Conv2d (3 , 3 , 1 )
42+ self .conv = torch .nn .Conv2d (4 , 4 , 1 )
4943
5044 # noinspection PyMethodMayBeStatic
5145 def forward (self , x ):
5246 x = self .conv (x )
5347 return - x
5448
5549
56- @pytest .mark .parametrize (
57- "input_shape" ,
58- [
59- pytest .param ((8 ,), id = "1D" ),
60- pytest .param ((4 , 2 ), id = "2D" ),
61- pytest .param ((1 , 2 , 3 ), id = "3D" ),
62- pytest .param ((1 , 2 , 3 , 4 ), id = "4D" ),
63- ],
64- )
65- def test_convert_neg (mocker , input_shape ):
66- model = NegModule ()
67-
68- converter_spy = mocker .spy (EdgeProgramToIRConverter , "convert_program" )
69- delegated_ep = to_quantized_edge_program (model , input_shape ).exported_program ()
70-
71- # Make sure the `neg` was delegated.
72- assert graph_contains_any_of_ops (delegated_ep .graph , [ExecutorchDelegateCall ])
73- assert not graph_contains_any_of_ops (delegated_ep .graph , [Neg ])
74-
75- # Verify correct behavior of the converted NeutronIR model.
76- intermediate_ep = converter_spy .call_args .args [1 ]
77- neutron_ir_model , * _ = converter_spy .spy_return
78-
79- input_data = (
80- np .random .random (input_shape ).astype (np .float32 ) * 256.0 - 128.0
81- ).astype (np .int8 )
82-
83- # Make sure the tested program contains the `neg`.
84- assert graph_contains_any_of_ops (intermediate_ep .graph , [Neg ])
85-
86- convert_run_compare (
87- intermediate_ep ,
88- tfl_model = neutron_ir_model ,
89- input_data = input_data ,
90- )
91-
92-
93- def test_convert_neg__channels_last (mocker ):
94- model = ConvNegModule ()
95- input_shape = (1 , 3 , 4 , 5 )
96-
97- converter_spy = mocker .spy (EdgeProgramToIRConverter , "convert_program" )
98- delegated_ep = to_quantized_edge_program (
99- model , input_shape , use_neutron_for_format_conversion = False
100- ).exported_program ()
101-
102- # Make sure the `neg` was delegated.
103- assert graph_contains_any_of_ops (delegated_ep .graph , [ExecutorchDelegateCall ])
104- assert not graph_contains_any_of_ops (delegated_ep .graph , [Neg ])
105-
106- # Verify correct behavior of the converted NeutronIR model.
107- intermediate_ep = converter_spy .call_args .args [1 ]
108- neutron_ir_model , * _ = converter_spy .spy_return
109-
110- input_data = (
111- np .random .random (input_shape ).astype (np .float32 ) * 256.0 - 128.0
112- ).astype (np .int8 )
113-
114- # Make sure the tested program contains the `neg`.
115- assert graph_contains_any_of_ops (intermediate_ep .graph , [Neg ])
116-
117- convert_run_compare (
118- intermediate_ep ,
119- tfl_model = neutron_ir_model ,
120- input_data = input_data ,
121- tflite_input_preprocess = ToChannelLastPreprocess (),
122- tflite_output_preprocess = ToChannelFirstPreprocess (),
50+ class TestNeg :
51+ @pytest .mark .parametrize (
52+ "input_shape" ,
53+ [
54+ pytest .param ((8 ,), id = "1D" ),
55+ pytest .param ((4 , 2 ), id = "2D" ),
56+ pytest .param ((1 , 2 , 6 ), id = "3D" ),
57+ pytest .param ((1 , 5 , 3 , 4 ), id = "4D" ),
58+ ],
12359 )
60+ def test__basic_nsys_inference (self , mocker , request , input_shape ):
61+ model = NegModule ()
62+
63+ graph_verifier = DetailedGraphVerifier (
64+ mocker , expected_delegated_ops = {Neg : 1 }, expected_non_delegated_ops = {}
65+ )
66+
67+ lower_run_compare (
68+ model ,
69+ input_shape ,
70+ graph_verifier ,
71+ request ,
72+ dataset_creator = RandomDatasetCreator (low = - 1.0 , high = 1.0 ),
73+ )
74+
75+ def test__all_possible_values (self , mocker , request , use_qat ):
76+ # Use 256 elements so that, after quantization to int8, the input can
77+ # cover the full discrete range [-128, 127].
78+ # The dataset is generated as a linear float ramp and later quantized,
79+ # which effectively exercises all int8 values.
80+ input_shape = (256 ,)
81+ model = NegModule ()
82+
83+ graph_verifier = DetailedGraphVerifier (
84+ mocker , expected_delegated_ops = {Neg : 1 }, expected_non_delegated_ops = {}
85+ )
86+
87+ lower_run_compare (
88+ model ,
89+ input_shape ,
90+ graph_verifier ,
91+ request ,
92+ dataset_creator = LinearRampDatasetCreator (low = - 1.0 , high = 1.0 ),
93+ use_qat = use_qat ,
94+ )
95+
96+ def test__channels_first_input (self , mocker , request ):
97+ # Use 256 elements so that, after quantization to int8, the input can
98+ # cover the full discrete range [-128, 127].
99+ # The dataset is generated as a linear float ramp and later quantized,
100+ # which effectively exercises all int8 values.
101+ input_shape = (1 , 4 , 8 , 8 )
102+ model = ConvNegModule ()
103+
104+ graph_verifier = DetailedGraphVerifier (
105+ mocker ,
106+ expected_delegated_ops = {Neg : 1 , Convolution : 1 },
107+ expected_non_delegated_ops = {},
108+ )
109+
110+ lower_run_compare (
111+ model ,
112+ input_shape ,
113+ graph_verifier ,
114+ request ,
115+ dataset_creator = LinearRampDatasetCreator (low = - 1.0 , high = 1.0 ),
116+ )
0 commit comments