Skip to content

Commit 5d2193f

Browse files
Arm backend: Add U55 operator check for View (#12106)
In order for the view operator to be compatible with the channels-last format of TosaBackend, transposes may need to be inserted before and after the view op. The transose operator comes with some constraints on U55. One such constraint is that the product of the axes should not exceed 65536. With this patch a check if implemented for the view operator to prevent such operators from being delegated. Signed-off-by: Sebastian Larsson <[email protected]>
1 parent f0a7d10 commit 5d2193f

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

backends/arm/operator_support/ethos_u55_support.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,69 @@ def is_node_supported(
174174
shape_t = list[int]
175175

176176

177+
class EthosU55ViewCheck(OperatorSupportBase):
178+
179+
def __init__(self, reporter: WhyNoPartitionReporter):
180+
super().__init__()
181+
self.reporter = reporter
182+
183+
def axes_product(self, nhwc_shape: shape_t) -> int:
184+
product = 1
185+
for axes in nhwc_shape:
186+
product *= axes
187+
return product
188+
189+
# TODO: Extend this check to comply with u55 restrictions
190+
def is_node_supported(
191+
self, submodules: typing.Mapping[str, torch.nn.Module], node: fx.Node
192+
) -> bool:
193+
"""
194+
Check whether a given view node is supported on U55.
195+
196+
Currently only checks dtypes and product of axes.
197+
198+
It is not the view operator itself that is not supported on U55. In order for the
199+
view operator to be compatible with the channels-last format of TosaBackend,
200+
transposes may need to be inserted before and after the view op. If that happens
201+
and that transpose operator does not adhere to the limitations then it will
202+
result in the following error:
203+
204+
CPU performance estimation for "Transpose" not implemented.
205+
...
206+
CPU operations are not supported for GraphAPI input
207+
208+
Args:
209+
node: The FX node representing the view_copy operator.
210+
211+
Returns:
212+
False if the operator is not support and True if it is supported.
213+
"""
214+
if not node.target == exir_ops.edge.aten.view_copy.default:
215+
return True
216+
217+
shape = list(get_first_fake_tensor(node).shape)
218+
dtype = _try_determine_dtype(node)
219+
permutation = list(typing.cast(list[int], node.args[1]))
220+
221+
rank = len(shape)
222+
if rank > 4:
223+
if dtype == torch.int32:
224+
self.reporter.report_reject(
225+
node, f"No support for {permutation=} in int32."
226+
)
227+
return False
228+
229+
if dtype in (torch.int8, torch.int16):
230+
if self.axes_product(shape) > 65536:
231+
self.reporter.report_reject(
232+
node,
233+
f"No support for {shape=}, {dtype=}. Product of axes must be <65536",
234+
)
235+
return False
236+
237+
return True
238+
239+
177240
class EthosU55TransposeCheck(OperatorSupportBase):
178241

179242
def __init__(self, reporter: WhyNoPartitionReporter):

backends/arm/operator_support/tosa_supported_operators.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
EthosU55DtypeSupport,
2424
EthosU55NotSupported,
2525
EthosU55TransposeCheck,
26+
EthosU55ViewCheck,
2627
)
2728
from executorch.backends.arm.tosa_quant_utils import dq_ops, q_ops
2829
from executorch.backends.arm.tosa_specification import TosaSpecification
@@ -133,6 +134,7 @@ def tosa_support_factory(
133134
negative_checks.append(EthosU55NotSupported(reporter))
134135
negative_checks.append(EthosU55DtypeSupport(reporter))
135136
negative_checks.append(EthosU55TransposeCheck(reporter))
137+
negative_checks.append(EthosU55ViewCheck(reporter))
136138

137139
return chain(
138140
reporter.wrap_check(

backends/arm/test/ops/test_view.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from executorch.backends.arm.test.tester.test_pipeline import (
1616
EthosU55PipelineBI,
1717
EthosU85PipelineBI,
18+
OpNotSupportedPipeline,
1819
TosaPipelineBI,
1920
TosaPipelineMI,
2021
)
@@ -44,6 +45,10 @@ class View(torch.nn.Module):
4445
"rand_4d_2_4_same": lambda: (torch.rand(2, 3, 2, 3), (2, 3, 3, 2)),
4546
}
4647

48+
rank_product_too_large = {
49+
"rand_4d_large": lambda: (torch.rand(1, 49, 16, 128), (1, 16, 49, 128)),
50+
}
51+
4752
def __init__(self, new_shape):
4853
super().__init__()
4954
self.new_shape = new_shape
@@ -104,6 +109,21 @@ def test_view_u55_BI(test_data: Tuple):
104109
pipeline.run()
105110

106111

112+
@common.parametrize("test_data", View.rank_product_too_large, xfails=xfails)
113+
@common.XfailIfNoCorstone300
114+
def test_view_u55_BI_not_delegated(test_data: Tuple):
115+
test_tensor, new_shape = test_data()
116+
pipeline = OpNotSupportedPipeline[input_t1](
117+
View(new_shape),
118+
(test_tensor,),
119+
{"executorch_exir_dialects_edge__ops_aten_view_copy": 1},
120+
n_expected_delegates=0,
121+
quantize=True,
122+
u55_subset=True,
123+
)
124+
pipeline.run()
125+
126+
107127
@common.parametrize("test_data", View.needs_transpose_tests, xfails=xfails)
108128
@common.XfailIfNoCorstone320
109129
def test_view_u85_BI(test_data: Tuple):

0 commit comments

Comments
 (0)