Skip to content

Commit 1fc1bb4

Browse files
committed
Arm backend: Add constant ops unittests.
Adds unittests for eye, ones and zeros. These ops are supported by the ComputeConstantOpsAOT pass, add unittests for coverage. This exposes an edge case bug similar as for the clone, where a partion with one single constant op results in an empty network. Signed-off-by: Adrian Lundell <[email protected]> Change-Id: Ieabf8bc7b28ad887f0238c1e889332dc663cb7d6
1 parent d8c26ee commit 1fc1bb4

File tree

3 files changed

+341
-0
lines changed

3 files changed

+341
-0
lines changed

backends/arm/test/ops/test_eye.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# Copyright 2025 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+
import torch
7+
from executorch.backends.arm.test import common
8+
from executorch.backends.arm.test.tester.test_pipeline import (
9+
EthosU55PipelineBI,
10+
EthosU85PipelineBI,
11+
OpNotSupportedPipeline,
12+
TosaPipelineBI,
13+
TosaPipelineMI,
14+
)
15+
16+
input_t = tuple[torch.Tensor]
17+
test_data_t = tuple[int, torch.dtype]
18+
19+
20+
class EyeAdd(torch.nn.Module):
21+
aten_op: str = "torch.ops.aten.eye.default"
22+
23+
def __init__(self, n: int, dtype: torch.dtype):
24+
super().__init__()
25+
self.args = (n,)
26+
self.dtype = dtype
27+
28+
def forward(self, x: torch.Tensor) -> torch.Tensor:
29+
return torch.eye(*self.args, dtype=self.dtype) + x
30+
31+
test_data: dict[str, test_data_t] = {
32+
"10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)),
33+
"10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)),
34+
"int32_int32": (
35+
lambda: (torch.randint(0, 10, [10], dtype=torch.int32),),
36+
(10, torch.int32),
37+
),
38+
}
39+
40+
test_data_not_delegated: dict[str, test_data_t] = {
41+
"fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)),
42+
"fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)),
43+
"int32_int64": (
44+
lambda: (torch.randint(0, 10, [10], dtype=torch.int32),),
45+
(10, torch.int64),
46+
),
47+
}
48+
49+
50+
@common.parametrize("test_data", EyeAdd.test_data)
51+
def test_eye_tosa_MI(test_data: test_data_t):
52+
input_data, init_data = test_data
53+
pipeline = TosaPipelineMI[input_t](
54+
EyeAdd(*init_data),
55+
input_data(),
56+
EyeAdd.aten_op,
57+
)
58+
pipeline.run()
59+
60+
61+
@common.parametrize("test_data", EyeAdd.test_data)
62+
def test_eye_tosa_BI(test_data: test_data_t):
63+
input_data, init_data = test_data
64+
pipeline = TosaPipelineBI[input_t](
65+
EyeAdd(*init_data),
66+
input_data(),
67+
EyeAdd.aten_op,
68+
)
69+
pipeline.pop_stage("check.quant_nodes")
70+
pipeline.run()
71+
72+
73+
@common.parametrize("test_data", EyeAdd.test_data)
74+
def test_eye_u55_BI(test_data: test_data_t):
75+
input_data, init_data = test_data
76+
pipeline = EthosU55PipelineBI[input_t](
77+
EyeAdd(*init_data),
78+
input_data(),
79+
EyeAdd.aten_op,
80+
use_to_edge_transform_and_lower=True,
81+
)
82+
pipeline.pop_stage("check.quant_nodes")
83+
pipeline.run()
84+
85+
86+
@common.parametrize("test_data", EyeAdd.test_data)
87+
def test_eye_u85_BI(test_data: test_data_t):
88+
input_data, init_data = test_data
89+
pipeline = EthosU85PipelineBI[input_t](
90+
EyeAdd(*init_data),
91+
input_data(),
92+
EyeAdd.aten_op,
93+
use_to_edge_transform_and_lower=True,
94+
).dump_artifact("to_edge_transform_and_lower")
95+
pipeline.pop_stage("check.quant_nodes")
96+
pipeline.run()
97+
98+
99+
@common.parametrize(
100+
"test_data",
101+
EyeAdd.test_data_not_delegated,
102+
xfails={
103+
"fp32_int32": "MLETORCG-716: Do not delegate empty networks to vela",
104+
"fp32_int64": "MLETORCG-716: Do not delegate empty networks to vela",
105+
"int32_int64": "MLETORCG-716: Do not delegate empty networks to vela",
106+
},
107+
)
108+
def test_eye_tosa_BI_not_delegated(test_data: test_data_t):
109+
input_data, init_data = test_data
110+
pipeline = OpNotSupportedPipeline[input_t](
111+
EyeAdd(*init_data), input_data(), non_delegated_ops={}, quantize=True
112+
)
113+
pipeline.run()

backends/arm/test/ops/test_ones.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Copyright 2025 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+
7+
import torch
8+
from executorch.backends.arm.test import common
9+
from executorch.backends.arm.test.tester.test_pipeline import (
10+
EthosU55PipelineBI,
11+
EthosU85PipelineBI,
12+
OpNotSupportedPipeline,
13+
TosaPipelineBI,
14+
TosaPipelineMI,
15+
)
16+
17+
input_t = tuple[torch.Tensor]
18+
test_data_t = tuple[int, torch.dtype]
19+
20+
21+
class OnesAdd(torch.nn.Module):
22+
aten_op: str = "torch.ops.aten.ones.default"
23+
24+
def __init__(self, n: int, dtype: torch.dtype):
25+
super().__init__()
26+
self.args = (n,)
27+
self.dtype = dtype
28+
29+
def forward(self, x: torch.Tensor) -> torch.Tensor:
30+
return torch.ones(*self.args, dtype=self.dtype) + x
31+
32+
test_data: dict[str, test_data_t] = {
33+
"10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)),
34+
"10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)),
35+
"int32_int32": (
36+
lambda: (torch.randint(0, 10, [10], dtype=torch.int32),),
37+
(10, torch.int32),
38+
),
39+
}
40+
41+
test_data_not_delegated: dict[str, test_data_t] = {
42+
"fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)),
43+
"fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)),
44+
"int32_int64": (
45+
lambda: (torch.randint(0, 10, [10], dtype=torch.int32),),
46+
(10, torch.int64),
47+
),
48+
}
49+
50+
51+
@common.parametrize("test_data", OnesAdd.test_data)
52+
def test_ones_tosa_MI(test_data: test_data_t):
53+
input_data, init_data = test_data
54+
pipeline = TosaPipelineMI[input_t](
55+
OnesAdd(*init_data),
56+
input_data(),
57+
OnesAdd.aten_op,
58+
)
59+
pipeline.run()
60+
61+
62+
@common.parametrize("test_data", OnesAdd.test_data)
63+
def test_ones_tosa_BI(test_data: test_data_t):
64+
input_data, init_data = test_data
65+
pipeline = TosaPipelineBI[input_t](
66+
OnesAdd(*init_data),
67+
input_data(),
68+
OnesAdd.aten_op,
69+
)
70+
pipeline.pop_stage("check.quant_nodes")
71+
pipeline.run()
72+
73+
74+
@common.parametrize("test_data", OnesAdd.test_data)
75+
def test_ones_u55_BI(test_data: test_data_t):
76+
input_data, init_data = test_data
77+
pipeline = EthosU55PipelineBI[input_t](
78+
OnesAdd(*init_data),
79+
input_data(),
80+
OnesAdd.aten_op,
81+
use_to_edge_transform_and_lower=True,
82+
)
83+
pipeline.pop_stage("check.quant_nodes")
84+
pipeline.run()
85+
86+
87+
@common.parametrize("test_data", OnesAdd.test_data)
88+
def test_ones_u85_BI(test_data: test_data_t):
89+
input_data, init_data = test_data
90+
pipeline = EthosU85PipelineBI[input_t](
91+
OnesAdd(*init_data),
92+
input_data(),
93+
OnesAdd.aten_op,
94+
use_to_edge_transform_and_lower=True,
95+
).dump_artifact("to_edge_transform_and_lower")
96+
pipeline.pop_stage("check.quant_nodes")
97+
pipeline.run()
98+
99+
100+
@common.parametrize(
101+
"test_data",
102+
OnesAdd.test_data_not_delegated,
103+
xfails={
104+
"fp32_int32": "MLETORCG-716: Do not delegate empty networks to vela",
105+
"fp32_int64": "MLETORCG-716: Do not delegate empty networks to vela",
106+
"int32_int64": "MLETORCG-716: Do not delegate empty networks to vela",
107+
},
108+
)
109+
def test_ones_tosa_BI_not_delegated(test_data: test_data_t):
110+
input_data, init_data = test_data
111+
pipeline = OpNotSupportedPipeline[input_t](
112+
OnesAdd(*init_data), input_data(), non_delegated_ops={}, quantize=True
113+
)
114+
pipeline.run()

backends/arm/test/ops/test_zeros.py

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Copyright 2025 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+
7+
import torch
8+
from executorch.backends.arm.test import common
9+
from executorch.backends.arm.test.tester.test_pipeline import (
10+
EthosU55PipelineBI,
11+
EthosU85PipelineBI,
12+
OpNotSupportedPipeline,
13+
TosaPipelineBI,
14+
TosaPipelineMI,
15+
)
16+
17+
input_t = tuple[torch.Tensor]
18+
test_data_t = tuple[int, torch.dtype]
19+
20+
21+
class ZerosAdd(torch.nn.Module):
22+
aten_op: str = "torch.ops.aten.zeros.default"
23+
24+
def __init__(self, n: int, dtype: torch.dtype):
25+
super().__init__()
26+
self.args = (n,)
27+
self.dtype = dtype
28+
29+
def forward(self, x: torch.Tensor) -> torch.Tensor:
30+
return torch.zeros(*self.args, dtype=self.dtype) + x
31+
32+
test_data: dict[str, test_data_t] = {
33+
"10x3x3": (lambda: (torch.randn(10, 3, 3),), (3, torch.float32)),
34+
"10x1": (lambda: (torch.randn(10, 1),), (10, torch.float32)),
35+
"int32_int32": (
36+
lambda: (torch.randint(0, 10, [10], dtype=torch.int32),),
37+
(10, torch.int32),
38+
),
39+
}
40+
41+
test_data_not_delegated: dict[str, test_data_t] = {
42+
"fp32_int64": (lambda: (torch.randn(10),), (10, torch.int64)),
43+
"fp32_int32": (lambda: (torch.randn(10),), (10, torch.int32)),
44+
"int32_int64": (
45+
lambda: (torch.randint(0, 10, [10], dtype=torch.int32),),
46+
(10, torch.int64),
47+
),
48+
}
49+
50+
51+
@common.parametrize("test_data", ZerosAdd.test_data)
52+
def test_zeros_tosa_MI(test_data: test_data_t):
53+
input_data, init_data = test_data
54+
pipeline = TosaPipelineMI[input_t](
55+
ZerosAdd(*init_data),
56+
input_data(),
57+
ZerosAdd.aten_op,
58+
)
59+
pipeline.run()
60+
61+
62+
@common.parametrize("test_data", ZerosAdd.test_data)
63+
def test_zeros_tosa_BI(test_data: test_data_t):
64+
input_data, init_data = test_data
65+
pipeline = TosaPipelineBI[input_t](
66+
ZerosAdd(*init_data),
67+
input_data(),
68+
ZerosAdd.aten_op,
69+
)
70+
pipeline.pop_stage("check.quant_nodes")
71+
pipeline.run()
72+
73+
74+
@common.parametrize("test_data", ZerosAdd.test_data)
75+
def test_zeros_u55_BI(test_data: test_data_t):
76+
input_data, init_data = test_data
77+
pipeline = EthosU55PipelineBI[input_t](
78+
ZerosAdd(*init_data),
79+
input_data(),
80+
ZerosAdd.aten_op,
81+
use_to_edge_transform_and_lower=True,
82+
)
83+
pipeline.pop_stage("check.quant_nodes")
84+
pipeline.run()
85+
86+
87+
@common.parametrize("test_data", ZerosAdd.test_data)
88+
def test_zeros_u85_BI(test_data: test_data_t):
89+
input_data, init_data = test_data
90+
pipeline = EthosU85PipelineBI[input_t](
91+
ZerosAdd(*init_data),
92+
input_data(),
93+
ZerosAdd.aten_op,
94+
use_to_edge_transform_and_lower=True,
95+
).dump_artifact("to_edge_transform_and_lower")
96+
pipeline.pop_stage("check.quant_nodes")
97+
pipeline.run()
98+
99+
100+
@common.parametrize(
101+
"test_data",
102+
ZerosAdd.test_data_not_delegated,
103+
xfails={
104+
"fp32_int32": "MLETORCG-716: Do not delegate empty networks to vela",
105+
"fp32_int64": "MLETORCG-716: Do not delegate empty networks to vela",
106+
"int32_int64": "MLETORCG-716: Do not delegate empty networks to vela",
107+
},
108+
)
109+
def test_zeros_tosa_BI_not_delegated(test_data: test_data_t):
110+
input_data, init_data = test_data
111+
pipeline = OpNotSupportedPipeline[input_t](
112+
ZerosAdd(*init_data), input_data(), non_delegated_ops={}, quantize=True
113+
)
114+
pipeline.run()

0 commit comments

Comments
 (0)