Skip to content

Commit a9b1f19

Browse files
Add support for conversion and quantization of Adaptive Average Pool operator
1 parent 7787b6d commit a9b1f19

File tree

5 files changed

+70
-1
lines changed

5 files changed

+70
-1
lines changed

backends/nxp/backend/edge_program_converter.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
functions_converters = {
2323
exir_ops.edge.aten.addmm.default: AddMMConverter,
2424
exir_ops.edge.aten.avg_pool2d.default: AvgPool2dConverter,
25+
exir_ops.edge.aten._adaptive_avg_pool2d.default: AdaptiveAvgPool2dConverter,
2526
exir_ops.edge.aten.constant_pad_nd.default: ConstantPadNDConverter,
2627
exir_ops.edge.aten.convolution.default: ConvolutionConverter,
2728
exir_ops.edge.aten.max_pool2d.default: MaxPool2dConverter,

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020
AvgPool2dConverter
2121
from executorch.backends.nxp.backend.ir.converter.node_converters.ops_converters.add_tensor_converter import \
2222
AddTensorConverter
23+
from executorch.backends.nxp.backend.ir.converter.node_converters.ops_converters.adaptive_avg_pool_2d_converter import \
24+
AdaptiveAvgPool2dConverter
2325
from executorch.backends.nxp.backend.ir.converter.node_converters.ops_converters.relu_converter import \
2426
ReLUConverter
2527
from executorch.backends.nxp.backend.ir.converter.node_converters.ops_converters.mean_dim_converter import \
2628
MeanDimConverter
2729
__all__ = [
2830
"AddMMConverter", "ConvolutionConverter", "MMConverter", "PermuteCopyConverter", "SoftmaxConverter",
2931
"ViewCopyConverter", "QDQDequantizeConverter", "QDQQuantizeConverter", "ConstantPadNDConverter", "ReLUConverter",
30-
"MaxPool2dConverter", "AvgPool2dConverter", "AddTensorConverter", "MeanDimConverter"
32+
"MaxPool2dConverter", "AvgPool2dConverter", "AddTensorConverter", "MeanDimConverter", "AdaptiveAvgPool2dConverter"
3133
]
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Copyright (c) 2025 NXP
2+
# All rights reserved.
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
from torch import Size
8+
from torch.fx import Node
9+
from torch.nn import Parameter
10+
11+
import executorch.backends.nxp.backend.ir.lib.tflite.Padding as tflPadding
12+
from executorch.backends.nxp.backend.ir.converter.conversion import common
13+
from executorch.backends.nxp.backend.ir.converter.node_converter import NodeConverter, Target
14+
from executorch.backends.nxp.backend.ir.tflite_generator import tflite_model
15+
from executorch.backends.nxp.backend.ir.tflite_generator.builtin_options import average_pool_2d_options
16+
17+
18+
class AdaptiveAvgPool2dConverter(NodeConverter):
19+
supported_targets = [Target.RT700]
20+
21+
@staticmethod
22+
def _is_supported_in_IR(node: Node, parameters_mapping: dict[str, Parameter]) -> bool:
23+
input_size = node.args[0].meta['val'].shape
24+
output_size = node.args[1]
25+
26+
if (input_size[-1] % output_size[-1] != 0) or (input_size[-2] % output_size[-2] != 0):
27+
return False
28+
29+
if not NodeConverter._has_shared_q_params_if_quantized(node):
30+
return False
31+
32+
return True
33+
34+
# noinspection PyMethodMayBeStatic
35+
def _convert_adaptive_avg_pool_2d(self, input_size: Size, output_size: list[int], t_op: tflite_model.Operator):
36+
t_op.builtin_options = average_pool_2d_options.AveragePool2D()
37+
stride = [input_size[-2] // output_size[-2], input_size[-1] // output_size[-1]]
38+
common.assign_2d_strides(t_op.builtin_options, stride)
39+
t_op.builtin_options.filter_h = input_size[-2] - (output_size[-2] - 1) * stride[-2]
40+
t_op.builtin_options.filter_w = input_size[-1] - (output_size[-1] - 1) * stride[-1]
41+
t_op.builtin_options.padding = tflPadding.Padding.VALID
42+
43+
# AdaptiveAvgPool2d Node format: (Tensor self, SymInt[2] output_size)
44+
def convert(self, node: Node):
45+
""" Convert '_adaptive_avg_pool2d' operator to TFLite 'AveragePool2D'.
46+
"""
47+
self.assert_convertible(node)
48+
49+
input_size = node.args[0].meta['val'].shape
50+
output_size = node.args[1]
51+
52+
t_op = self._create_tflite_op_with_io_tensors(node)
53+
54+
self._convert_adaptive_avg_pool_2d(input_size, output_size, t_op)
55+
self.builder.append_operators([t_op])

backends/nxp/neutron_partitioner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ def tag_qdq_clusters(self, nodes: List[torch.fx.Node]):
191191
exir_ops.edge.aten.view_copy.default: ViewCopyConverter,
192192
exir_ops.edge.aten.add.Tensor: AddTensorConverter,
193193
exir_ops.edge.aten.mean.dim: MeanDimConverter,
194+
exir_ops.edge.aten._adaptive_avg_pool2d.default: AdaptiveAvgPool2dConverter,
194195
}
195196

196197

backends/nxp/quantizer/neutron_quantizer.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ def partition_types(self):
123123
return [torch.ops.aten.avg_pool2d.default]
124124

125125

126+
class AdaptiveAvgPoolPattern(SharedSpecPattern):
127+
"""
128+
Quantizer for AdaptiveAvgPool2D operator.
129+
"""
130+
131+
def partition_types(self):
132+
return [torch.ops.aten.adaptive_avg_pool2d.default]
133+
134+
126135
class PadPattern(SharedSpecPattern):
127136
"""
128137
Quantizer for Pad operator.
@@ -293,6 +302,7 @@ def __init__(self):
293302
CadenceAtenQuantizer(ReluInPlacePattern(), static_qconfig),
294303
CadenceAtenQuantizer(AvgPoolPattern(), static_qconfig),
295304
CadenceAtenQuantizer(ViewPattern(), static_qconfig),
305+
CadenceAtenQuantizer(AdaptiveAvgPoolPattern(), static_qconfig),
296306
CadenceAtenQuantizer(MeanDimPattern(), static_qconfig),
297307
CadenceAtenQuantizer(FlattenPattern(), static_qconfig),
298308
]

0 commit comments

Comments
 (0)