-
Notifications
You must be signed in to change notification settings - Fork 1.1k
NXP backend: Enable Neg with new Neutron flow #20451
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -4,20 +4,19 @@ | |
| # LICENSE file in the root directory of this source tree. | ||
|
|
||
| import numpy as np | ||
|
|
||
| # noinspection PyUnusedImports | ||
| import pytest | ||
| import torch | ||
|
|
||
| from executorch.backends.nxp.backend.edge_program_converter import ( | ||
| EdgeProgramToIRConverter, | ||
| ) | ||
| from executorch.backends.nxp.tests.executorch_pipeline import to_quantized_edge_program | ||
| from executorch.backends.nxp.tests.executors import ( | ||
| convert_run_compare, | ||
| graph_contains_any_of_ops, | ||
| ToChannelFirstPreprocess, | ||
| ToChannelLastPreprocess, | ||
| from executorch.backends.nxp.tests.dataset_creator import ( | ||
| LinearRampDatasetCreator, | ||
| RandomDatasetCreator, | ||
| ) | ||
| from executorch.exir.dialects._ops import ops as exir_ops | ||
| from executorch.backends.nxp.tests.graph_verifier import DetailedGraphVerifier | ||
| from executorch.backends.nxp.tests.nsys_testing import lower_run_compare | ||
| from executorch.backends.nxp.tests.ops_aliases import Convolution, Neg | ||
| from executorch.backends.nxp.tests.use_qat import * # noqa F403 | ||
|
|
||
|
|
||
| @pytest.fixture(autouse=True) | ||
|
|
@@ -26,11 +25,6 @@ def reseed_model_per_test_run(): | |
| np.random.seed(23) | ||
|
|
||
|
|
||
| # noinspection PyProtectedMember | ||
| ExecutorchDelegateCall = torch.ops.higher_order.executorch_call_delegate | ||
| Neg = exir_ops.edge.aten.neg.default | ||
|
|
||
|
|
||
| class NegModule(torch.nn.Module): | ||
|
|
||
| def __init__(self): | ||
|
|
@@ -45,79 +39,78 @@ class ConvNegModule(torch.nn.Module): | |
|
|
||
| def __init__(self): | ||
| super().__init__() | ||
| self.conv = torch.nn.Conv2d(3, 3, 1) | ||
| self.conv = torch.nn.Conv2d(4, 4, 1) | ||
|
|
||
| # noinspection PyMethodMayBeStatic | ||
| def forward(self, x): | ||
| x = self.conv(x) | ||
| return -x | ||
|
|
||
|
|
||
| @pytest.mark.parametrize( | ||
| "input_shape", | ||
| [ | ||
| pytest.param((8,), id="1D"), | ||
| pytest.param((4, 2), id="2D"), | ||
| pytest.param((1, 2, 3), id="3D"), | ||
| pytest.param((1, 2, 3, 4), id="4D"), | ||
| ], | ||
| ) | ||
| def test_convert_neg(mocker, input_shape): | ||
| model = NegModule() | ||
|
|
||
| converter_spy = mocker.spy(EdgeProgramToIRConverter, "convert_program") | ||
| delegated_ep = to_quantized_edge_program(model, input_shape).exported_program() | ||
|
|
||
| # Make sure the `neg` was delegated. | ||
| assert graph_contains_any_of_ops(delegated_ep.graph, [ExecutorchDelegateCall]) | ||
| assert not graph_contains_any_of_ops(delegated_ep.graph, [Neg]) | ||
|
|
||
| # Verify correct behavior of the converted NeutronIR model. | ||
| intermediate_ep = converter_spy.call_args.args[1] | ||
| neutron_ir_model, *_ = converter_spy.spy_return | ||
|
|
||
| input_data = ( | ||
| np.random.random(input_shape).astype(np.float32) * 256.0 - 128.0 | ||
| ).astype(np.int8) | ||
|
|
||
| # Make sure the tested program contains the `neg`. | ||
| assert graph_contains_any_of_ops(intermediate_ep.graph, [Neg]) | ||
|
|
||
| convert_run_compare( | ||
| intermediate_ep, | ||
| tfl_model=neutron_ir_model, | ||
| input_data=input_data, | ||
| ) | ||
|
|
||
|
|
||
| def test_convert_neg__channels_last(mocker): | ||
| model = ConvNegModule() | ||
| input_shape = (1, 3, 4, 5) | ||
|
|
||
| converter_spy = mocker.spy(EdgeProgramToIRConverter, "convert_program") | ||
| delegated_ep = to_quantized_edge_program( | ||
| model, input_shape, use_neutron_for_format_conversion=False | ||
| ).exported_program() | ||
|
|
||
| # Make sure the `neg` was delegated. | ||
| assert graph_contains_any_of_ops(delegated_ep.graph, [ExecutorchDelegateCall]) | ||
| assert not graph_contains_any_of_ops(delegated_ep.graph, [Neg]) | ||
|
|
||
| # Verify correct behavior of the converted NeutronIR model. | ||
| intermediate_ep = converter_spy.call_args.args[1] | ||
| neutron_ir_model, *_ = converter_spy.spy_return | ||
|
|
||
| input_data = ( | ||
| np.random.random(input_shape).astype(np.float32) * 256.0 - 128.0 | ||
| ).astype(np.int8) | ||
|
|
||
| # Make sure the tested program contains the `neg`. | ||
| assert graph_contains_any_of_ops(intermediate_ep.graph, [Neg]) | ||
|
|
||
| convert_run_compare( | ||
| intermediate_ep, | ||
| tfl_model=neutron_ir_model, | ||
| input_data=input_data, | ||
| tflite_input_preprocess=ToChannelLastPreprocess(), | ||
| tflite_output_preprocess=ToChannelFirstPreprocess(), | ||
| class TestNeg: | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You removed tests with multiple different input shapes, and left only 2, both with multiples of
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was inspired by Exp operator. As the op is internally Sub, I considered it tested with various shapes there. Do you think I should add them back?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Personally I would definitely test with a similar coverage of shapes as we do for other similar operators. We never know what sort of edge case it might uncover. Or if we ever decide to support the operator some other way (e.g. we decide |
||
| @pytest.mark.parametrize( | ||
| "input_shape", | ||
| [ | ||
| pytest.param((8,), id="1D"), | ||
| pytest.param((4, 2), id="2D"), | ||
| pytest.param((1, 2, 6), id="3D"), | ||
| pytest.param((1, 5, 3, 4), id="4D"), | ||
| ], | ||
| ) | ||
| def test__basic_nsys_inference(self, mocker, request, input_shape): | ||
| model = NegModule() | ||
|
|
||
| graph_verifier = DetailedGraphVerifier( | ||
| mocker, expected_delegated_ops={Neg: 1}, expected_non_delegated_ops={} | ||
| ) | ||
|
|
||
| lower_run_compare( | ||
| model, | ||
| input_shape, | ||
| graph_verifier, | ||
| request, | ||
| dataset_creator=RandomDatasetCreator(low=-1.0, high=1.0), | ||
| ) | ||
|
|
||
| def test__all_possible_values(self, mocker, request, use_qat): | ||
| # Use 256 elements so that, after quantization to int8, the input can | ||
|
roman-janik-nxp marked this conversation as resolved.
|
||
| # cover the full discrete range [-128, 127]. | ||
| # The dataset is generated as a linear float ramp and later quantized, | ||
| # which effectively exercises all int8 values. | ||
| input_shape = (256,) | ||
| model = NegModule() | ||
|
|
||
| graph_verifier = DetailedGraphVerifier( | ||
| mocker, expected_delegated_ops={Neg: 1}, expected_non_delegated_ops={} | ||
| ) | ||
|
|
||
| lower_run_compare( | ||
| model, | ||
| input_shape, | ||
| graph_verifier, | ||
| request, | ||
| dataset_creator=LinearRampDatasetCreator(low=-1.0, high=1.0), | ||
| use_qat=use_qat, | ||
| ) | ||
|
|
||
| def test__channels_first_input(self, mocker, request): | ||
| # Use 256 elements so that, after quantization to int8, the input can | ||
| # cover the full discrete range [-128, 127]. | ||
| # The dataset is generated as a linear float ramp and later quantized, | ||
| # which effectively exercises all int8 values. | ||
| input_shape = (1, 4, 8, 8) | ||
| model = ConvNegModule() | ||
|
|
||
| graph_verifier = DetailedGraphVerifier( | ||
| mocker, | ||
| expected_delegated_ops={Neg: 1, Convolution: 1}, | ||
| expected_non_delegated_ops={}, | ||
| ) | ||
|
|
||
| lower_run_compare( | ||
| model, | ||
| input_shape, | ||
| graph_verifier, | ||
| request, | ||
| dataset_creator=LinearRampDatasetCreator(low=-1.0, high=1.0), | ||
| ) | ||
Uh oh!
There was an error while loading. Please reload this page.