Skip to content

Commit 737f772

Browse files
committed
NXP backend: Test avg_pool2d with new Neutron flow.
1 parent c213c9f commit 737f772

3 files changed

Lines changed: 109 additions & 8 deletions

File tree

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

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2025 NXP
1+
# Copyright 2025-2026 NXP
22
#
33
# This source code is licensed under the BSD-style license found in the
44
# LICENSE file in the root directory of this source tree.
@@ -21,6 +21,8 @@
2121
from executorch.backends.nxp.backend.ir.tflite_generator.builtin_options import (
2222
average_pool_2d_options,
2323
)
24+
25+
from executorch.backends.nxp.backend.neutron_target_spec import NeutronTargetSpec
2426
from torch.fx import Node
2527
from torch.nn import Parameter
2628

@@ -53,6 +55,23 @@ def _is_supported_in_IR(
5355

5456
return True
5557

58+
@staticmethod
59+
def _is_supported_on_target(
60+
node: Node,
61+
neutron_target_spec: NeutronTargetSpec,
62+
parameters_mapping: dict[str, Parameter],
63+
custom_delegation_options: CustomDelegationOptions,
64+
) -> bool:
65+
kernel = node.args[1]
66+
stride = node.args[2]
67+
if any(k > 4096 for k in kernel):
68+
return False # Neutron requirement.
69+
70+
if any(s > 4096 for s in stride):
71+
return False # Neutron requirement.
72+
73+
return True
74+
5675
# noinspection PyMethodMayBeStatic
5776
def _convert_2d_avg_pool(
5877
self, kernel_size, stride, padding, t_op: tflite_model.Operator
@@ -85,10 +104,19 @@ def _convert_2d_avg_pool(
85104

86105
return ops.flatten()
87106

88-
# AvgPool2d Node format: (Tensor self, int[2] kernel_size, int[2] stride=[], int[2] padding=0, bool ceil_mode=False
89-
# bool count_include_pad=True, int? divisor_override=None)
90107
def convert(self, node: Node):
91-
"""Convert 'avg_pool2d' operator to TFLite 'AveragePool2D'."""
108+
"""Convert 'avg_pool2d' operator to TFLite 'AveragePool2D'.
109+
The ExecuTorch schema is:
110+
aten.avg_pool2d(
111+
Tensor self,
112+
int[2] kernel_size,
113+
int[2] stride=[],
114+
int[2] padding=0,
115+
bool ceil_mode=False
116+
bool count_include_pad=True,
117+
int? divisor_override=None
118+
)
119+
"""
92120
self.assert_convertible(node)
93121

94122
kernel_size = node.args[1]

backends/nxp/tests/ir/converter/node_converter/test_avg_pool2d_converter.py

Lines changed: 74 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2024 NXP
1+
# Copyright 2024,2026 NXP
22
#
33
# This source code is licensed under the BSD-style license found in the
44
# LICENSE file in the root directory of this source tree.
@@ -28,7 +28,10 @@
2828
ToNCHWPreprocess,
2929
ToNHWCPreprocess,
3030
)
31+
from executorch.backends.nxp.tests.graph_verifier import BaseGraphVerifier
3132
from executorch.backends.nxp.tests.models import AvgPool2dConvModule, AvgPool2dModule
33+
34+
from executorch.backends.nxp.tests.nsys_testing import lower_run_compare
3235
from torch.export import ExportedProgram
3336
from executorch.backends.nxp.tests.use_qat import * # noqa F403
3437
from executorch.exir.dialects._ops import ops as exir_ops
@@ -296,3 +299,73 @@ def test_from_avg_pool_1d(mocker):
296299
tflite_input_preprocess=ToChannelLastPreprocess(),
297300
tflite_output_preprocess=ToChannelFirstPreprocess(),
298301
)
302+
303+
304+
class TestAvgPool2DNewNeutronFlow:
305+
def test__basic_nsys_inference(self):
306+
input_shape = (2, 4, 6, 7)
307+
model = AvgPool2dModule(False, 0)
308+
graph_verifier = BaseGraphVerifier(
309+
exp_num_delegate_call_nodes=1, # Delegated AvgPool.
310+
exp_non_delegated_nodes=[],
311+
)
312+
313+
lower_run_compare(
314+
model, input_shape, graph_verifier, use_new_flow_neutron_c=True
315+
)
316+
317+
def test__kernel_size_limit(self):
318+
kernel_size = (1, 4096)
319+
input_shape = (1, 4) + kernel_size
320+
model = AvgPool2dModule(False, 0, kernel_size)
321+
graph_verifier = BaseGraphVerifier(
322+
exp_num_delegate_call_nodes=1, # Delegated AvgPool.
323+
exp_non_delegated_nodes=[],
324+
)
325+
326+
lower_run_compare(
327+
model, input_shape, graph_verifier, use_new_flow_neutron_c=True
328+
)
329+
330+
def test__kernel_size_limit_exceeded(self):
331+
kernel_size = (1, 4097) # Exceeds the kernel size limit.
332+
input_shape = (1, 4) + kernel_size
333+
model = AvgPool2dModule(False, 0, kernel_size)
334+
335+
delegated_ep = to_quantized_edge_program(
336+
model, input_shape, use_new_flow_neutron_c=True
337+
).exported_program()
338+
339+
# Make sure the `avg_pool2d` was NOT delegated.
340+
assert not graph_contains_any_of_ops(
341+
delegated_ep.graph, [ExecutorchDelegateCall]
342+
)
343+
assert graph_contains_any_of_ops(delegated_ep.graph, [AvgPool2D])
344+
345+
def test__stride_limit(self):
346+
stride = 4096
347+
input_shape = (1, 4, 1, 4096)
348+
model = AvgPool2dModule(False, 0, 1, stride)
349+
graph_verifier = BaseGraphVerifier(
350+
exp_num_delegate_call_nodes=1, # Delegated AvgPool.
351+
exp_non_delegated_nodes=[],
352+
)
353+
354+
lower_run_compare(
355+
model, input_shape, graph_verifier, use_new_flow_neutron_c=True
356+
)
357+
358+
def test__stride_limit_exceeded(self):
359+
stride = 4097 # Exceeds the stride limit.
360+
input_shape = (1, 4, 1, 4096)
361+
model = AvgPool2dModule(False, 0, 1, stride)
362+
363+
delegated_ep = to_quantized_edge_program(
364+
model, input_shape, use_new_flow_neutron_c=True
365+
).exported_program()
366+
367+
# Make sure the `avg_pool2d` was NOT delegated.
368+
assert not graph_contains_any_of_ops(
369+
delegated_ep.graph, [ExecutorchDelegateCall]
370+
)
371+
assert graph_contains_any_of_ops(delegated_ep.graph, [AvgPool2D])

backends/nxp/tests/models.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,12 @@ def forward(self, x):
348348

349349

350350
class AvgPool2dModule(torch.nn.Module):
351-
def __init__(self, count_include_pad, padding=0):
351+
def __init__(self, count_include_pad, padding=0, kernel_size=3, stride=2):
352352
super().__init__()
353353

354354
self.avg_pool = torch.nn.AvgPool2d(
355-
kernel_size=3,
356-
stride=2,
355+
kernel_size=kernel_size,
356+
stride=stride,
357357
padding=padding,
358358
count_include_pad=count_include_pad,
359359
)

0 commit comments

Comments
 (0)