Skip to content

Commit 0881b22

Browse files
NXP backend: Update eIQ Neutron SDK to 3.1.2 (pytorch#19938)
### Summary This PR updates the Neutron SDK to the most recent version (3.1.2). This version removes the old conversion flow and forces the use of the new MLIR flow. This change is reflected in ExecuTorch NXP backend by the removal of the `use_new_flow_neutron_c` flag. ### Test plan Tested by all NXP backend tests. cc @robert-kalmar @JakeStevens @digantdesai @rascani
1 parent 968fff9 commit 0881b22

48 files changed

Lines changed: 468 additions & 3535 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

backends/nxp/backend/ir/converter/node_converters/ops_converters/abs_converter.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,11 @@ def _is_supported_on_target(
3434
parameters_mapping: dict[str, Parameter],
3535
custom_delegation_options: CustomDelegationOptions,
3636
) -> bool:
37-
38-
if neutron_target_spec.use_new_flow_neutron_c:
39-
# Requirements specified by the new Neutron flow documentation.
40-
41-
supported_types = [torch.int8, torch.uint8]
42-
if not NodeConverter.uses_quantization_type_for_io(
43-
node, supported_types, [0], [0]
44-
):
45-
return False
37+
supported_types = [torch.int8, torch.uint8]
38+
if not NodeConverter.uses_quantization_type_for_io(
39+
node, supported_types, [0], [0]
40+
):
41+
return False
4642

4743
return True
4844

backends/nxp/backend/ir/converter/node_converters/ops_converters/adaptive_avg_pool_2d_converter.py

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -78,22 +78,19 @@ def _is_supported_on_target(
7878
AdaptiveAvgPool2dConverter._get_equivalent_avg_pool_parameters(node)
7979
)
8080

81-
if neutron_target_spec.use_new_flow_neutron_c:
82-
# Requirements specified by the new Neutron flow documentation.
83-
84-
if not NodeConverter.uses_quantization_type_for_io(
85-
node,
86-
supported_types=[torch.int8, torch.uint8],
87-
input_indices=[0],
88-
output_indices=[0],
89-
):
90-
return False
91-
92-
if any(k > 4096 for k in kernel_size):
93-
return False
94-
95-
if any(s > 4096 for s in stride):
96-
return False
81+
if not NodeConverter.uses_quantization_type_for_io(
82+
node,
83+
supported_types=[torch.int8, torch.uint8],
84+
input_indices=[0],
85+
output_indices=[0],
86+
):
87+
return False
88+
89+
if any(k > 4096 for k in kernel_size):
90+
return False
91+
92+
if any(s > 4096 for s in stride):
93+
return False
9794

9895
return True
9996

backends/nxp/backend/ir/converter/node_converters/ops_converters/add_tensor_converter.py

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,24 @@ def _is_supported_on_target(
2626
parameters_mapping: dict[str, Parameter],
2727
custom_delegation_options: CustomDelegationOptions,
2828
) -> bool:
29-
if neutron_target_spec.use_new_flow_neutron_c:
30-
if not NodeConverter.at_least_one_input_shape_matches_the_output_shape(
31-
node
32-
):
33-
return False
34-
35-
# If one input is in channel first and ranks of input tensors are not equal, we need to add Transposes
36-
# Transpose is currently not supported for new flow
37-
if any(
38-
input_node.meta[NXP_NODE_FORMAT].is_channels_first()
39-
for input_node in node.all_input_nodes
40-
) and NodeConverter._node_inputs_ranks_not_equal(node):
41-
return False
29+
if not NodeConverter.at_least_one_input_shape_matches_the_output_shape(node):
30+
return False
4231

43-
supported_types = [torch.int8, torch.uint8]
44-
if not NodeConverter.uses_quantization_type_for_io(
45-
node, supported_types, [0, 1], [0]
46-
):
47-
return False
32+
# If one input is in channel first and ranks of input tensors are not equal, we need to add Transposes
33+
# Transpose is currently not supported for new flow
34+
if any(
35+
input_node.meta[NXP_NODE_FORMAT].is_channels_first()
36+
for input_node in node.all_input_nodes
37+
) and NodeConverter._node_inputs_ranks_not_equal(node):
38+
return False
4839

49-
return True
50-
else:
51-
if NodeConverter.uses_shape_broadcasting(node):
52-
# Shape broadcasting may require the addition of `Transpose` ops during conversion.
53-
return False
40+
supported_types = [torch.int8, torch.uint8]
41+
if not NodeConverter.uses_quantization_type_for_io(
42+
node, supported_types, [0, 1], [0]
43+
):
44+
return False
5445

55-
return True
46+
return True
5647

5748
@staticmethod
5849
def _is_supported_in_IR(

backends/nxp/backend/ir/converter/node_converters/ops_converters/avg_pool_2d_converter.py

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,20 +64,17 @@ def _is_supported_on_target(
6464
kernel = node.args[1]
6565
stride = node.args[2]
6666

67-
if neutron_target_spec.use_new_flow_neutron_c:
68-
# Requirements specified by the new Neutron flow documentation.
69-
70-
supported_types = [torch.int8, torch.uint8]
71-
if not NodeConverter.uses_quantization_type_for_io(
72-
node, supported_types, [0], [0]
73-
):
74-
return False
67+
supported_types = [torch.int8, torch.uint8]
68+
if not NodeConverter.uses_quantization_type_for_io(
69+
node, supported_types, [0], [0]
70+
):
71+
return False
7572

76-
if any(k > 4096 for k in kernel):
77-
return False
73+
if any(k > 4096 for k in kernel):
74+
return False
7875

79-
if any(s > 4096 for s in stride):
80-
return False
76+
if any(s > 4096 for s in stride):
77+
return False
8178

8279
return True
8380

backends/nxp/backend/ir/converter/node_converters/ops_converters/clamp_converter.py

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,21 +109,18 @@ def _is_supported_on_target(
109109
if all(b is None or math.isinf(b) for b in bounds):
110110
return False
111111

112-
if neutron_target_spec.use_new_flow_neutron_c:
113-
io_quant_consistent = ClampConverter._io_quant_is_same(node)
114-
quant_supported = NodeConverter.uses_quantization_type_for_io(
115-
node,
116-
supported_types=[torch.int8, torch.uint8],
117-
input_indices=[0],
118-
output_indices=[0],
119-
)
120-
121-
# We either convert to ReLU -> SingleInputQuantization pattern
122-
# or we convert to Min/Max, which requires same quantization on
123-
# both input and output.
124-
return (relu_compatible | io_quant_consistent) and quant_supported
112+
io_quant_consistent = ClampConverter._io_quant_is_same(node)
113+
quant_supported = NodeConverter.uses_quantization_type_for_io(
114+
node,
115+
supported_types=[torch.int8, torch.uint8],
116+
input_indices=[0],
117+
output_indices=[0],
118+
)
125119

126-
return relu_compatible
120+
# We either convert to ReLU -> SingleInputQuantization pattern
121+
# or we convert to Min/Max, which requires same quantization on
122+
# both input and output.
123+
return (relu_compatible | io_quant_consistent) and quant_supported
127124

128125
@classmethod
129126
def supports_partitioning_result(
@@ -183,7 +180,7 @@ def convert(self, node: Node):
183180
t_op = self._create_tflite_op_with_io_tensors(node)
184181

185182
# Clamp convertible to some variant of ReLU
186-
if not self.neutron_target_spec.use_new_flow_neutron_c or to_relu:
183+
if to_relu:
187184
# noinspection PyTypeChecker,PyUnboundLocalVariable
188185
t_op.opcode_index = self.builder.op_code_index_for_op_type(
189186
self.BOUNDS_TO_RELU_NEUTRON_IR_OP[bounds]

backends/nxp/backend/ir/converter/node_converters/ops_converters/constant_pad_nd_converter.py

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@
99
import numpy as np
1010
import torch
1111

12-
from executorch.backends.nxp.backend.data_format import NXP_NODE_FORMAT
13-
1412
from executorch.backends.nxp.backend.edge_helper import input_rank
1513
from executorch.backends.nxp.backend.ir.converter.conversion.translator import (
1614
apply_permutation_to,
@@ -42,33 +40,15 @@ def _is_supported_on_target(
4240
parameters_mapping: dict[str, Parameter],
4341
custom_delegation_options: CustomDelegationOptions,
4442
) -> bool:
45-
if neutron_target_spec.use_new_flow_neutron_c:
46-
# Requirements specified by the new Neutron flow documentation.
47-
48-
if not NodeConverter.uses_quantization_type_for_io(
49-
node,
50-
supported_types=[torch.int8, torch.uint8],
51-
input_indices=[0],
52-
output_indices=[0],
53-
):
54-
return False
55-
56-
return True
43+
if not NodeConverter.uses_quantization_type_for_io(
44+
node,
45+
supported_types=[torch.int8, torch.uint8],
46+
input_indices=[0],
47+
output_indices=[0],
48+
):
49+
return False
5750

58-
else:
59-
paddings = node.args[1]
60-
if node.meta[NXP_NODE_FORMAT].is_channels_first():
61-
# Dim `1` will end up being the channels. It is padded by paddings[4:6].
62-
if len(paddings) > 4 and paddings[4:6] != [0, 0]:
63-
# Attempt to Pad channels dimension -> currently not supported
64-
return False
65-
else:
66-
# Dim `-1` will end up being the channels. It is padded by paddings[:2].
67-
if len(paddings) > 0 and paddings[:2] != [0, 0]:
68-
# Attempt to Pad channels dimension -> currently not supported
69-
return False
70-
71-
return True
51+
return True
7252

7353
@staticmethod
7454
def _is_supported_in_IR(

backends/nxp/backend/ir/converter/node_converters/ops_converters/leaky_relu_converter.py

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,15 @@ def _is_supported_on_target(
3535
parameters_mapping: dict[str, Parameter],
3636
custom_delegation_options: CustomDelegationOptions,
3737
) -> bool:
38-
if neutron_target_spec.use_new_flow_neutron_c:
39-
# Requirements specified by the new Neutron flow documentation.
38+
if not NodeConverter.uses_quantization_type_for_io(
39+
node,
40+
supported_types=[torch.int8, torch.uint8],
41+
input_indices=[0],
42+
output_indices=[0],
43+
):
44+
return False
4045

41-
if not NodeConverter.uses_quantization_type_for_io(
42-
node,
43-
supported_types=[torch.int8, torch.uint8],
44-
input_indices=[0],
45-
output_indices=[0],
46-
):
47-
return False
48-
49-
return True
50-
else:
51-
52-
return True
46+
return True
5347

5448
def convert(self, node: Node):
5549
"""Convert the `aten.leaky_relu.default` operator to Neutron IR `LeakyRelu`.

backends/nxp/backend/ir/converter/node_converters/ops_converters/max_pool2d_with_indices_converter.py

Lines changed: 12 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -73,50 +73,18 @@ def _is_supported_on_target(
7373
MaxPool2DWithIndicesConverter._get_node_args(node)
7474
)
7575

76-
if neutron_target_spec.use_new_flow_neutron_c:
77-
# Requirements specified by the new Neutron flow documentation.
78-
79-
supported_types = [torch.int8, torch.uint8]
80-
if not NodeConverter.uses_quantization_type_for_io(
81-
node, supported_types, [0], [0]
82-
):
83-
return False
84-
85-
# If there is no padding, Neutron allows maximum stride of 4096. Otherwise, it's 32. But the converter
86-
# always inserts a `Pad` operator to add the padding, so the `MaxPool` never pads it's input itself, so
87-
# 4096 is always the limit. And similarly, the `MaxPool` input padding limitation does not apply either.
88-
maximum_supported_stride = 4096
89-
if any(s > maximum_supported_stride for s in stride):
90-
return False
91-
92-
else:
93-
# Shape of the main output (index 0)
94-
output_shape = node.meta["val"][0].shape
95-
if output_shape[0] != 1:
96-
# /neutron-converter/src/OperatorC/MaxPoolPlugin.cpp?at=NEUTRON_SOFTWARE_2.2.2#106
97-
return False
98-
99-
# Neutron only has a restriction on `stride_h`. `stride_w` is not restricted.
100-
stride_h = stride[0]
101-
if stride_h not in (1, 2):
102-
# /neutron-library/src/utils/NeutronLibraryInterrogation.cpp?at=refs%2Ftags%2FNEUTRON_SOFTWARE_2.2.2#901
103-
# /neutron-library/src/utils/NeutronLibraryInterrogation.cpp?at=refs%2Ftags%2FNEUTRON_SOFTWARE_2.2.2#923
104-
return False
105-
106-
channels = output_shape[1]
107-
if channels % neutron_target_spec.get_num_macs() != 0:
108-
# /neutron-library/src/utils/NeutronLibraryInterrogation.cpp?at=refs%2Ftags%2FNEUTRON_SOFTWARE_2.2.2#903
109-
# /neutron-library/src/utils/NeutronLibraryInterrogation.cpp?at=refs%2Ftags%2FNEUTRON_SOFTWARE_2.2.2#925
110-
return False
111-
112-
if any(pad > kernel_dim for pad, kernel_dim in zip(padding, kernel_size)):
113-
# /neutron-library/src/utils/NeutronLibraryInterrogation.cpp?at=refs%2Ftags%2FNEUTRON_SOFTWARE_2.2.2#904-907
114-
# /neutron-library/src/utils/NeutronLibraryInterrogation.cpp?at=refs%2Ftags%2FNEUTRON_SOFTWARE_2.2.2#926-929
115-
116-
# Cannot be tested as PyTorch crashes in this case. It requires the padding to be at most half of the
117-
# effective kernel size, which is an even stricter requirement than what Neutron imposes.
118-
# https://github.com/pytorch/pytorch/blob/449b1768410104d3ed79d3bcfe4ba1d65c7f22c0/torch/_meta_registrations.py#L4483-L4489
119-
return False
76+
supported_types = [torch.int8, torch.uint8]
77+
if not NodeConverter.uses_quantization_type_for_io(
78+
node, supported_types, [0], [0]
79+
):
80+
return False
81+
82+
# If there is no padding, Neutron allows maximum stride of 4096. Otherwise, it's 32. But the converter
83+
# always inserts a `Pad` operator to add the padding, so the `MaxPool` never pads it's input itself, so
84+
# 4096 is always the limit. And similarly, the `MaxPool` input padding limitation does not apply either.
85+
maximum_supported_stride = 4096
86+
if any(s > maximum_supported_stride for s in stride):
87+
return False
12088

12189
return True
12290

0 commit comments

Comments
 (0)