-
Notifications
You must be signed in to change notification settings - Fork 1k
NXP backend: Enable Sub Tensor with new Neutron flow #19588
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
base: main
Are you sure you want to change the base?
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 |
|---|---|---|
|
|
@@ -2,25 +2,39 @@ | |
| # | ||
| # This source code is licensed under the BSD-style license found in the | ||
| # LICENSE file in the root directory of this source tree. | ||
|
|
||
| import numpy as np | ||
| 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.executorch_pipeline import ( | ||
| ModelInputSpec, | ||
| 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.graph_verifier import DetailedGraphVerifier | ||
| from executorch.backends.nxp.tests.model_output_comparator import ( | ||
| NumericalStatsOutputComparator, | ||
| ) | ||
| from executorch.backends.nxp.tests.models import ( | ||
| SubTensorConvModule, | ||
| SubTensorModule, | ||
| SubTensorOneInputModule, | ||
| ) | ||
| from executorch.exir.dialects._ops import ops as exir_ops | ||
| from executorch.backends.nxp.tests.nsys_testing import lower_run_compare | ||
| from executorch.backends.nxp.tests.ops_aliases import ( | ||
| Convolution, | ||
| ExecutorchDelegateCall, | ||
| SubTensor, | ||
| ) | ||
| from torch.export import ExportedProgram | ||
| from executorch.backends.nxp.tests.use_qat import * # noqa F403 | ||
|
|
||
|
|
@@ -63,7 +77,7 @@ def test_sub_tensor_quant_conversion(mocker, input_shape, use_qat): | |
| input_data = {0: input_data_1, 1: input_data_2} | ||
|
|
||
| nodes = list(exported_program.graph.nodes) | ||
| assert nodes[4].target == exir_ops.edge.aten.sub.Tensor | ||
| assert nodes[4].target == SubTensor | ||
|
|
||
| convert_run_compare( | ||
| exported_program, tfl_model=tflite_flatbuffers_model, input_data=input_data | ||
|
|
@@ -96,7 +110,7 @@ def test_sub_tensor_one_input_quant_conversion(mocker, input_shape, use_qat): | |
| input_data = (np.random.random(input_shape).astype(np.float32) * 50).astype(np.int8) | ||
|
|
||
| nodes = list(exported_program.graph.nodes) | ||
| assert nodes[2].target == exir_ops.edge.aten.sub.Tensor | ||
| assert nodes[2].target == SubTensor | ||
|
|
||
| convert_run_compare( | ||
| exported_program, tfl_model=tflite_flatbuffers_model, input_data=input_data | ||
|
|
@@ -141,7 +155,7 @@ def test_sub_tensor_w_conv_quant_conversion(mocker, x_input_shape, use_qat): | |
| input_data = {0: input_data_1, 1: input_data_2} | ||
|
|
||
| nodes = list(exported_program.graph.nodes) | ||
| assert nodes[15].target == exir_ops.edge.aten.sub.Tensor | ||
| assert nodes[15].target == SubTensor | ||
|
|
||
| convert_run_compare( | ||
| exported_program, | ||
|
|
@@ -176,6 +190,164 @@ def test_sub_tensor_broadcasting_unsupported_quant_conversion( | |
| nodes = list(edge_program.graph.nodes) | ||
|
|
||
| # Broadcast is not supported, node is not converted | ||
| assert ( | ||
| nodes[6].target == exir_ops.edge.aten.sub.Tensor | ||
| ) # Sub Tensor is not delegated. | ||
| assert nodes[6].target == SubTensor # Sub Tensor is not delegated. | ||
|
|
||
|
|
||
| class TestSubTensorNewNeutronFlow: | ||
| @pytest.mark.skip("AIR-14602: incorrect results") | ||
|
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. I think using This applies to other tests too, not just this one. |
||
| @pytest.mark.parametrize( | ||
| "x_input_shape", | ||
| [ | ||
| pytest.param((6, 8), id="2D."), | ||
| pytest.param((1, 4, 8), id="3D."), | ||
| pytest.param((1, 4, 8, 8), id="4D."), | ||
|
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. Please don't use multiples of 8 in the shapes, to make sure there is no |
||
| ], | ||
| ) | ||
| def test__basic_nsys_inference(self, x_input_shape, mocker): | ||
|
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. Please separate out the passing and failing cases (I assume at least some cases produce correct outputs. If not, please try to find some :D). Right now everything is skipped. It's desirable to have at least some passing tests. |
||
| x_input_spec = ModelInputSpec(x_input_shape) | ||
| model = SubTensorModule() | ||
| graph_verifier = DetailedGraphVerifier( | ||
| mocker, expected_delegated_ops={SubTensor: 1}, expected_non_delegated_ops={} | ||
| ) | ||
|
|
||
| lower_run_compare( | ||
| model, | ||
| [x_input_spec, x_input_spec], | ||
| graph_verifier, | ||
| use_new_flow_neutron_c=True, | ||
| ) | ||
|
|
||
| @pytest.mark.skip("AIR-14602: incorrect results") | ||
| @pytest.mark.parametrize( | ||
| "x_input_shape", | ||
| [ | ||
| pytest.param((6, 8), id="2D."), | ||
| pytest.param((1, 4, 8), id="3D."), | ||
| pytest.param((1, 4, 8, 8), id="4D."), | ||
| ], | ||
| ) | ||
| def test__basic_nsys_inference_qat(self, x_input_shape, mocker): | ||
| x_input_spec = ModelInputSpec(x_input_shape) | ||
| model = SubTensorModule() | ||
| comparator = NumericalStatsOutputComparator() | ||
| graph_verifier = DetailedGraphVerifier( | ||
| mocker, expected_delegated_ops={SubTensor: 1}, expected_non_delegated_ops={} | ||
| ) | ||
|
|
||
| lower_run_compare( | ||
| model, | ||
| [x_input_spec, x_input_spec], | ||
| graph_verifier, | ||
| output_comparator=comparator, | ||
| use_new_flow_neutron_c=True, | ||
| use_qat=True, | ||
| ) | ||
|
|
||
| @pytest.mark.skip("AIR-14602: incorrect results") | ||
| @pytest.mark.parametrize( | ||
| "input_spec", | ||
| [ | ||
| pytest.param( | ||
| [ModelInputSpec((4, 6)), ModelInputSpec((1, 6))], id="2 inputs 2D." | ||
| ), | ||
| pytest.param( | ||
| [ModelInputSpec((5, 3, 4)), ModelInputSpec((1, 3, 1))], | ||
| id="2 inputs 3D.", | ||
| ), | ||
| pytest.param( | ||
| [ModelInputSpec((4,)), ModelInputSpec((4, 4))], id="2 inputs 2D+3D." | ||
|
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. The id seems incorrect. Looks like |
||
| ), | ||
| ], | ||
| ) | ||
| def test__correct_broadcast(self, input_spec, mocker): | ||
| model = SubTensorModule() | ||
| graph_verifier = DetailedGraphVerifier( | ||
| mocker, expected_delegated_ops={SubTensor: 1}, expected_non_delegated_ops={} | ||
| ) | ||
|
|
||
| lower_run_compare( | ||
| model, input_spec, graph_verifier, use_new_flow_neutron_c=True | ||
| ) | ||
|
|
||
| @pytest.mark.parametrize( | ||
| "input_spec", | ||
| [ | ||
| pytest.param( | ||
| [ModelInputSpec((4, 1)), ModelInputSpec((1, 6))], id="2 inputs 2D." | ||
| ), | ||
| pytest.param( | ||
| [ModelInputSpec((1, 3, 4)), ModelInputSpec((5, 3, 1))], | ||
| id="2 inputs 3D.", | ||
| ), | ||
| pytest.param( | ||
| [ModelInputSpec((6, 4)), ModelInputSpec((6, 6, 1))], | ||
| id="2 inputs 2D+3D.", | ||
| ), | ||
| ], | ||
| ) | ||
| def test__incorrect_broadcast(self, input_spec): | ||
| # Broadcast where at least one of the inputs is not equal to output is not supported | ||
| model = SubTensorModule() | ||
|
|
||
| delegated_ep = to_quantized_edge_program( | ||
| model, input_spec, use_new_flow_neutron_c=True | ||
| ).exported_program() | ||
|
|
||
| # Make sure the `add.Tensor` was NOT delegated. | ||
| assert not graph_contains_any_of_ops( | ||
| delegated_ep.graph, [ExecutorchDelegateCall] | ||
| ) | ||
| assert graph_contains_any_of_ops(delegated_ep.graph, [SubTensor]) | ||
|
|
||
| @pytest.mark.skip("AIR-14602: incorrect results") | ||
|
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. Would it be possible to find a working example so we can have a passing test? |
||
| @pytest.mark.parametrize( | ||
| "x_input_shape", | ||
| [ | ||
| pytest.param( | ||
| (1, 4, 5, 5), id="4D, product of dims is not a multiple of 8." | ||
| ), | ||
| ], | ||
| ) | ||
| def test__w_conv(self, x_input_shape, mocker): | ||
| model = SubTensorConvModule() | ||
|
|
||
| n, c, h, w = x_input_shape | ||
| y_input_spec = ModelInputSpec((n, 8, h, w)) | ||
| x_input_spec = ModelInputSpec(x_input_shape) | ||
|
|
||
| graph_verifier = DetailedGraphVerifier( | ||
| mocker, | ||
| expected_delegated_ops={SubTensor: 1, Convolution: 1}, | ||
| expected_non_delegated_ops={}, | ||
| ) | ||
|
|
||
| lower_run_compare( | ||
| model, | ||
| [x_input_spec, y_input_spec], | ||
| graph_verifier, | ||
| use_new_flow_neutron_c=True, | ||
| ) | ||
|
|
||
| @pytest.mark.parametrize( | ||
| "input_spec", | ||
| [ | ||
| pytest.param( | ||
| [ModelInputSpec((1, 4, 5, 5)), ModelInputSpec((1, 5))], | ||
| id="2 inputs 4D + 2D.", | ||
| ), | ||
| pytest.param( | ||
| [ModelInputSpec((1, 4, 4, 10)), ModelInputSpec((1, 4, 1))], | ||
| id="2 inputs last + 3D.", | ||
| ), | ||
| ], | ||
| ) | ||
| def test__w_conv_unsupported(self, input_spec): | ||
|
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. Please also add a test for the supported channels first broadcasting case. |
||
| model = SubTensorConvModule() | ||
|
|
||
| delegated_ep = to_quantized_edge_program( | ||
| model, input_spec, use_new_flow_neutron_c=True | ||
| ).exported_program() | ||
|
|
||
| # Make sure the `add.Tensor` was NOT delegated. | ||
| assert graph_contains_any_of_ops(delegated_ep.graph, [ExecutorchDelegateCall]) | ||
| assert graph_contains_any_of_ops(delegated_ep.graph, [SubTensor]) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The AIR-14602 refers to the
Addoperator. Are you sure this is correct?