-
Notifications
You must be signed in to change notification settings - Fork 1.1k
NXP backend: Enable amin with new Neutron flow #20549
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 |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| # Copyright 2026 NXP | ||
| # | ||
| # This source code is licensed under the BSD-style license found in the | ||
| # LICENSE file in the root directory of this source tree. | ||
|
|
||
| import torch | ||
|
|
||
| from executorch.backends.nxp.backend.ir.converter.conversion.common import OpsList | ||
| from executorch.backends.nxp.backend.ir.converter.node_converter import ( | ||
| CustomDelegationOptions, | ||
| is_not_qdq_node, | ||
| NodeConverter, | ||
| ) | ||
| from executorch.backends.nxp.backend.ir.converter.node_converters.shared.reduce_utils import ( | ||
| convert_axes_from_attribute, | ||
| get_dim_and_handle_io_formats, | ||
| get_reduce_node_attrs, | ||
| ) | ||
| from executorch.backends.nxp.backend.ir.tflite_generator.builtin_options import ( | ||
| reduce_min_options, | ||
| ) | ||
| from executorch.backends.nxp.backend.neutron_target_spec import NeutronTargetSpec | ||
| from torch.fx import Node | ||
| from torch.fx.passes.infra.partitioner import Partition | ||
| from torch.nn import Parameter | ||
|
|
||
|
|
||
| class AminConverter(NodeConverter): | ||
|
|
||
| @classmethod | ||
| def supports_partitioning_result( | ||
| cls, | ||
| node: Node, | ||
| partition_list: list[Partition], | ||
| custom_delegation_options: CustomDelegationOptions, | ||
| neutron_target_spec: NeutronTargetSpec, | ||
| parameters_mapping: dict[str, Parameter], | ||
| ) -> bool: | ||
| dim, keepdim = get_reduce_node_attrs(node) | ||
| input_shape = node.args[0].meta["val"].shape | ||
|
|
||
| is_alone_in_partition = cls.is_node_alone_in_partition( | ||
| node, partition_list, filter_fn=is_not_qdq_node | ||
| ) | ||
|
|
||
| if is_alone_in_partition and keepdim and all(input_shape[d] == 1 for d in dim): | ||
| # The operator is a no-op, so the Neutron Converter will skip it. If it's the only node in the | ||
| # partition, the graph would end up empty. | ||
| return False | ||
|
|
||
| return True | ||
|
|
||
| @staticmethod | ||
| def _is_supported_on_target( | ||
| node: Node, | ||
| neutron_target_spec: NeutronTargetSpec, | ||
| parameters_mapping: dict[str, Parameter], | ||
| custom_delegation_options: CustomDelegationOptions, | ||
| ) -> bool: | ||
| if not NodeConverter.uses_quantization_type_for_io( | ||
| node, | ||
| supported_types=[torch.int8, torch.uint8], | ||
| input_indices=[0], | ||
| output_indices=[0], | ||
| ): | ||
| return False | ||
|
|
||
| return True | ||
|
|
||
| @staticmethod | ||
| def _is_supported_in_IR( | ||
| node: Node, | ||
| parameters_mapping: dict[str, Parameter], | ||
| custom_delegation_options: CustomDelegationOptions, | ||
| ) -> bool: | ||
| if not NodeConverter._has_shared_q_params_if_quantized(node): | ||
| return False | ||
|
Comment on lines
+76
to
+77
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. Where did you find this requirement?
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. In your mean dim converter, I kept it, but I don't think it's necessary.
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. It depends on the requirements of Neutron/Neutron IR. Often we can see requirements for equal input and output quantization here: https://developers.google.com/edge/litert/conversion/tensorflow/quantization/quantization_spec P.S.: We can handle |
||
|
|
||
| return True | ||
|
|
||
| def convert(self, node: Node): | ||
| """Convert the 'amin' operator to NeutronIR 'ReduceMin'. | ||
| The ExecuTorch schema is: | ||
| amin( | ||
| Tensor self, | ||
| int[1]? dim, | ||
| bool keepdim=False, | ||
| ) -> Tensor | ||
| """ | ||
| self.assert_convertible(node) | ||
|
|
||
| dim, keepdim = get_reduce_node_attrs(node) | ||
|
|
||
| t_op = self._create_tflite_op_with_io_tensors(node) | ||
| t_op.builtin_options = reduce_min_options.ReduceMin(keepdim) | ||
|
|
||
| ops = OpsList(middle_op=t_op) | ||
| dim = get_dim_and_handle_io_formats(self.builder, ops, dim, keepdim) | ||
|
|
||
| convert_axes_from_attribute(t_op, self.builder, dim) | ||
| self.builder.append_operators(ops.flatten()) | ||
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.
Well done for considering this case 👍🏻
Just FYI,
NeutronPartitionerautomatically tries to identify all no-ops by running every operator selected for delegation with random data. If it produces outputs that are exactly equal to the inputs (data, shape, type), it considers the node to be a no-op, and it will not delegate it as long as the operator is in a list of allowed no-ops. In the case ofamin, I believe this system would have always correctly identified the no-ops, so simply adding theaten.amininto the list of allowed no-ops would have done the job.But your solution is valid as well. No change needed.
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.
Thanks, I learn from the best (you 😄 ). However I don't see any logic for said identifying in
NeutronPartitionerand when I omit these checks insupports_partitioning_result()the tests fail. So I'm keeping it.