Skip to content

Commit d0a8dd6

Browse files
authored
Arm backend: Add adaptive pooling node visitors (pytorch#20220)
- adds DecomposeAdaptiveMaxPool2dPass to pass manager Signed-off-by: Oscar Andersson <oscar.andersson@arm.com> Co-authored-by: Saoirse Stewart <saoirse.stewart@arm.com>
1 parent 80a9550 commit d0a8dd6

4 files changed

Lines changed: 135 additions & 0 deletions

File tree

backends/arm/_passes/arm_pass_manager.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
ConvertToClampPass,
3636
DecomposeAcoshPass,
3737
DecomposeAdaptiveAvgPool2dPass,
38+
DecomposeAdaptiveMaxPool2dPass,
3839
DecomposeAddmmPass,
3940
DecomposeAddSubAlphaPass,
4041
DecomposeAnyPass,
@@ -608,6 +609,7 @@ def _tosa_pipeline(
608609
[
609610
RewriteUpsamplePass(),
610611
RewriteMaxPool2dPass(),
612+
DecomposeAdaptiveMaxPool2dPass(),
611613
RewriteConvPass(exported_program),
612614
RewriteMatmulPass(),
613615
RewritePadPass(),

backends/arm/operators/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
op_tanh,
4848
op_to_dim_order_copy,
4949
op_tosa_avg_pool2d,
50+
op_tosa_avg_pool2d_adaptive,
5051
op_tosa_conv2d,
5152
op_tosa_conv3d,
5253
op_tosa_custom,
@@ -55,6 +56,7 @@
5556
op_tosa_identity,
5657
op_tosa_matmul,
5758
op_tosa_max_pool2d,
59+
op_tosa_max_pool2d_adaptive,
5860
op_tosa_pad,
5961
op_tosa_rescale,
6062
op_tosa_resize,
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Copyright 2026 Arm Limited and/or its affiliates.
2+
#
3+
# This source code is licensed under the BSD-style license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
from typing import Any, List
7+
8+
import torch
9+
import tosa_serializer as ts
10+
11+
from executorch.backends.arm.operators.node_visitor import (
12+
NodeVisitor,
13+
register_node_visitor,
14+
)
15+
from executorch.backends.arm.operators.operator_validation_utils import (
16+
validate_num_inputs,
17+
validate_same_dtype,
18+
validate_valid_dtype,
19+
)
20+
from executorch.backends.arm.tosa.mapping import TosaArg
21+
22+
23+
if hasattr(ts.Op, "AVG_POOL2D_ADAPTIVE"):
24+
25+
@register_node_visitor
26+
class AvgPool2dAdaptiveVisitor(NodeVisitor):
27+
"""Visitor for lowering TOSA AVG_POOL2D_ADAPTIVE operator."""
28+
29+
target = "tosa.AVG_POOL2D_ADAPTIVE.default"
30+
31+
def define_node(
32+
self,
33+
node: torch.fx.Node,
34+
tosa_graph: Any,
35+
inputs: List[TosaArg],
36+
output: TosaArg,
37+
) -> None:
38+
validate_num_inputs(self.target, inputs, [7])
39+
validate_same_dtype(self.target, [inputs[0], output], ts)
40+
41+
input_tensor, input_zp, output_zp, kernel, stride, pad, acc_arg = inputs
42+
43+
supported = [ts.DType.INT8, ts.DType.FP16, ts.DType.FP32, ts.DType.BF16]
44+
if self.tosa_spec.support_extension("int16"):
45+
supported.append(ts.DType.INT16)
46+
if self.tosa_spec.support_extension("fp8e4m3"):
47+
supported.append(ts.DType.FP8E4M3)
48+
if self.tosa_spec.support_extension("fp8e5m2"):
49+
supported.append(ts.DType.FP8E5M2)
50+
validate_valid_dtype(
51+
self.target, [input_tensor, output], supported, self.tosa_spec
52+
)
53+
54+
attr = ts.TosaSerializerAttribute()
55+
attr.AvgPool2dAdaptiveAttribute(acc_type=acc_arg.dtype)
56+
57+
self._serialize_operator(
58+
node,
59+
tosa_graph,
60+
ts.Op.AVG_POOL2D_ADAPTIVE,
61+
[
62+
input_tensor.name,
63+
input_zp.name,
64+
output_zp.name,
65+
kernel.name,
66+
stride.name,
67+
pad.name,
68+
],
69+
[output.name],
70+
attr,
71+
)
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Copyright 2026 Arm Limited and/or its affiliates.
2+
#
3+
# This source code is licensed under the BSD-style license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
from typing import Any, List
7+
8+
import torch
9+
import tosa_serializer as ts
10+
11+
from executorch.backends.arm.operators.node_visitor import (
12+
NodeVisitor,
13+
register_node_visitor,
14+
)
15+
from executorch.backends.arm.operators.operator_validation_utils import (
16+
validate_num_inputs,
17+
validate_same_dtype,
18+
validate_valid_dtype,
19+
)
20+
from executorch.backends.arm.tosa.mapping import TosaArg
21+
22+
23+
if hasattr(ts.Op, "MAX_POOL2D_ADAPTIVE"):
24+
25+
@register_node_visitor
26+
class MaxPool2dAdaptiveVisitor(NodeVisitor):
27+
"""Visitor for lowering TOSA MAX_POOL2D_ADAPTIVE operator."""
28+
29+
target = "tosa.MAX_POOL2D_ADAPTIVE.default"
30+
31+
def define_node(
32+
self,
33+
node: torch.fx.Node,
34+
tosa_graph: Any,
35+
inputs: List[TosaArg],
36+
output: TosaArg,
37+
) -> None:
38+
validate_num_inputs(self.target, inputs, [4])
39+
validate_same_dtype(self.target, [inputs[0], output], ts)
40+
41+
input_tensor, kernel, stride, pad = inputs
42+
43+
supported = [ts.DType.INT8, ts.DType.FP16, ts.DType.FP32, ts.DType.BF16]
44+
if self.tosa_spec.support_extension("int16"):
45+
supported.append(ts.DType.INT16)
46+
validate_valid_dtype(
47+
self.target, [input_tensor, output], supported, self.tosa_spec
48+
)
49+
50+
attr = ts.TosaSerializerAttribute()
51+
attr.MaxPool2dAdaptiveAttribute(nan_mode=ts.NanPropagationMode.PROPAGATE)
52+
53+
self._serialize_operator(
54+
node,
55+
tosa_graph,
56+
ts.Op.MAX_POOL2D_ADAPTIVE,
57+
[input_tensor.name, kernel.name, stride.name, pad.name],
58+
[output.name],
59+
attr,
60+
)

0 commit comments

Comments
 (0)