Skip to content

Commit 15f6345

Browse files
committed
[Backend Tester] Add more pointwise op tests
ghstack-source-id: b37c6bc ghstack-comment-id: 3116317028 Pull-Request: #12855
1 parent c876f6e commit 15f6345

File tree

9 files changed

+1159
-0
lines changed

9 files changed

+1159
-0
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
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+
# pyre-unsafe
8+
9+
10+
import torch
11+
from executorch.backends.test.suite.flow import TestFlow
12+
13+
from executorch.backends.test.suite.operators import (
14+
dtype_test,
15+
operator_test,
16+
OperatorTest,
17+
)
18+
19+
20+
class AbsModel(torch.nn.Module):
21+
def __init__(self):
22+
super().__init__()
23+
24+
def forward(self, x):
25+
return torch.abs(x)
26+
27+
28+
@operator_test
29+
class TestAbs(OperatorTest):
30+
@dtype_test
31+
def test_abs_dtype(self, flow: TestFlow, dtype) -> None:
32+
# Test with different dtypes
33+
model = AbsModel().to(dtype)
34+
self._test_op(model, (torch.rand(10, 10).to(dtype) * 2 - 1,), flow)
35+
36+
def test_abs_basic(self, flow: TestFlow) -> None:
37+
# Basic test with default parameters
38+
# Input: tensor with positive and negative values
39+
self._test_op(AbsModel(), (torch.randn(10, 10),), flow)
40+
41+
def test_abs_shapes(self, flow: TestFlow) -> None:
42+
# Test with different tensor shapes
43+
44+
# 1D tensor
45+
self._test_op(AbsModel(), (torch.randn(20),), flow)
46+
47+
# 2D tensor
48+
self._test_op(AbsModel(), (torch.randn(5, 10),), flow)
49+
50+
# 3D tensor
51+
self._test_op(AbsModel(), (torch.randn(3, 4, 5),), flow)
52+
53+
# 4D tensor
54+
self._test_op(AbsModel(), (torch.randn(2, 3, 4, 5),), flow)
55+
56+
# 5D tensor
57+
self._test_op(AbsModel(), (torch.randn(2, 2, 3, 4, 5),), flow)
58+
59+
def test_abs_values(self, flow: TestFlow) -> None:
60+
# Test with different value ranges
61+
62+
# Small values
63+
self._test_op(AbsModel(), (torch.randn(10, 10) * 0.01,), flow)
64+
65+
# Large values
66+
self._test_op(AbsModel(), (torch.randn(10, 10) * 1000,), flow)
67+
68+
# Mixed positive and negative values
69+
self._test_op(AbsModel(), (torch.randn(10, 10) * 10,), flow)
70+
71+
# All positive values
72+
self._test_op(AbsModel(), (torch.rand(10, 10) * 10,), flow)
73+
74+
# All negative values
75+
self._test_op(AbsModel(), (torch.rand(10, 10) * -10,), flow)
76+
77+
# Values close to zero
78+
self._test_op(AbsModel(), (torch.randn(10, 10) * 1e-5,), flow)
79+
80+
def test_abs_edge_cases(self, flow: TestFlow) -> None:
81+
# Test edge cases
82+
83+
# Zero tensor
84+
self._test_op(
85+
AbsModel(), (torch.zeros(10, 10),), flow, generate_random_test_inputs=False
86+
)
87+
88+
# Tensor with infinity
89+
x = torch.tensor([float("inf"), float("-inf"), 1.0, -1.0])
90+
self._test_op(AbsModel(), (x,), flow, generate_random_test_inputs=False)
91+
92+
# Tensor with NaN
93+
x = torch.tensor([float("nan"), 1.0, -1.0])
94+
self._test_op(AbsModel(), (x,), flow, generate_random_test_inputs=False)
95+
96+
def test_abs_scalar(self, flow: TestFlow) -> None:
97+
# Test with scalar input (1-element tensor)
98+
self._test_op(
99+
AbsModel(), (torch.tensor([-5.0]),), flow, generate_random_test_inputs=False
100+
)
101+
self._test_op(
102+
AbsModel(), (torch.tensor([5.0]),), flow, generate_random_test_inputs=False
103+
)
104+
self._test_op(
105+
AbsModel(), (torch.tensor([0.0]),), flow, generate_random_test_inputs=False
106+
)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
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+
# pyre-unsafe
8+
9+
10+
import torch
11+
from executorch.backends.test.suite.flow import TestFlow
12+
13+
from executorch.backends.test.suite.operators import (
14+
dtype_test,
15+
operator_test,
16+
OperatorTest,
17+
)
18+
19+
20+
class CeilModel(torch.nn.Module):
21+
def __init__(self):
22+
super().__init__()
23+
24+
def forward(self, x):
25+
return torch.ceil(x)
26+
27+
28+
@operator_test
29+
class TestCeil(OperatorTest):
30+
@dtype_test
31+
def test_ceil_dtype(self, flow: TestFlow, dtype) -> None:
32+
# Test with different dtypes
33+
model = CeilModel().to(dtype)
34+
self._test_op(model, (torch.rand(10, 10).to(dtype) * 2 - 1,), flow)
35+
36+
def test_ceil_basic(self, flow: TestFlow) -> None:
37+
# Basic test with default parameters
38+
# Input: tensor with fractional values
39+
self._test_op(CeilModel(), (torch.randn(10, 10),), flow)
40+
41+
def test_ceil_shapes(self, flow: TestFlow) -> None:
42+
# Test with different tensor shapes
43+
44+
# 1D tensor
45+
self._test_op(CeilModel(), (torch.randn(20),), flow)
46+
47+
# 2D tensor
48+
self._test_op(CeilModel(), (torch.randn(5, 10),), flow)
49+
50+
# 3D tensor
51+
self._test_op(CeilModel(), (torch.randn(3, 4, 5),), flow)
52+
53+
# 4D tensor
54+
self._test_op(CeilModel(), (torch.randn(2, 3, 4, 5),), flow)
55+
56+
# 5D tensor
57+
self._test_op(CeilModel(), (torch.randn(2, 2, 3, 4, 5),), flow)
58+
59+
def test_ceil_values(self, flow: TestFlow) -> None:
60+
# Test with different value ranges
61+
62+
# Small fractional values
63+
self._test_op(CeilModel(), (torch.rand(10, 10) * 0.01,), flow)
64+
65+
# Large fractional values
66+
self._test_op(CeilModel(), (torch.randn(10, 10) * 1000,), flow)
67+
68+
# Mixed positive and negative values
69+
self._test_op(CeilModel(), (torch.randn(10, 10) * 10,), flow)
70+
71+
# Values with specific fractional parts
72+
self._test_op(
73+
CeilModel(),
74+
(torch.arange(0, 10, 0.5).reshape(4, 5),),
75+
flow,
76+
generate_random_test_inputs=False,
77+
)
78+
79+
# Values close to integers
80+
x = torch.randn(10, 10)
81+
x = x.round() + torch.rand(10, 10) * 0.01
82+
self._test_op(CeilModel(), (x,), flow)
83+
84+
def test_ceil_edge_cases(self, flow: TestFlow) -> None:
85+
# Test edge cases
86+
87+
# Integer values
88+
self._test_op(
89+
CeilModel(),
90+
(torch.arange(10).reshape(2, 5).float(),),
91+
flow,
92+
generate_random_test_inputs=False,
93+
)
94+
95+
# Zero tensor
96+
self._test_op(
97+
CeilModel(), (torch.zeros(10, 10),), flow, generate_random_test_inputs=False
98+
)
99+
100+
# Tensor with infinity
101+
x = torch.tensor([float("inf"), float("-inf"), 1.0, -1.0])
102+
self._test_op(CeilModel(), (x,), flow, generate_random_test_inputs=False)
103+
104+
# Tensor with NaN
105+
x = torch.tensor([float("nan"), 1.0, -1.0])
106+
self._test_op(CeilModel(), (x,), flow, generate_random_test_inputs=False)
107+
108+
# Values just below integers
109+
x = torch.arange(10).float() - 0.01
110+
self._test_op(CeilModel(), (x,), flow, generate_random_test_inputs=False)
111+
112+
# Values just above integers
113+
x = torch.arange(10).float() + 0.01
114+
self._test_op(CeilModel(), (x,), flow, generate_random_test_inputs=False)
115+
116+
def test_ceil_scalar(self, flow: TestFlow) -> None:
117+
# Test with scalar input (1-element tensor)
118+
self._test_op(
119+
CeilModel(), (torch.tensor([1.5]),), flow, generate_random_test_inputs=False
120+
)
121+
self._test_op(
122+
CeilModel(),
123+
(torch.tensor([-1.5]),),
124+
flow,
125+
generate_random_test_inputs=False,
126+
)
127+
self._test_op(
128+
CeilModel(), (torch.tensor([0.0]),), flow, generate_random_test_inputs=False
129+
)
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
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+
# pyre-unsafe
8+
9+
10+
import torch
11+
from executorch.backends.test.suite.flow import TestFlow
12+
13+
from executorch.backends.test.suite.operators import (
14+
dtype_test,
15+
operator_test,
16+
OperatorTest,
17+
)
18+
19+
20+
class ClampModel(torch.nn.Module):
21+
def __init__(self, min_val=None, max_val=None):
22+
super().__init__()
23+
self.min_val = min_val
24+
self.max_val = max_val
25+
26+
def forward(self, x):
27+
return torch.clamp(x, min=self.min_val, max=self.max_val)
28+
29+
30+
@operator_test
31+
class TestClamp(OperatorTest):
32+
@dtype_test
33+
def test_clamp_dtype(self, flow: TestFlow, dtype) -> None:
34+
# Test with different dtypes
35+
model = ClampModel(min_val=-0.5, max_val=0.5).to(dtype)
36+
self._test_op(model, (torch.rand(10, 10).to(dtype) * 2 - 1,), flow)
37+
38+
def test_clamp_basic(self, flow: TestFlow) -> None:
39+
# Basic test with default parameters
40+
# Input: tensor with values outside the clamp range
41+
self._test_op(
42+
ClampModel(min_val=-0.5, max_val=0.5), (torch.randn(10, 10),), flow
43+
)
44+
45+
def test_clamp_min_only(self, flow: TestFlow) -> None:
46+
# Test with only min value specified
47+
self._test_op(ClampModel(min_val=0.0), (torch.randn(10, 10),), flow)
48+
49+
def test_clamp_max_only(self, flow: TestFlow) -> None:
50+
# Test with only max value specified
51+
self._test_op(ClampModel(max_val=0.0), (torch.randn(10, 10),), flow)
52+
53+
def test_clamp_shapes(self, flow: TestFlow) -> None:
54+
# Test with different tensor shapes
55+
model = ClampModel(min_val=-1.0, max_val=1.0)
56+
57+
# 1D tensor
58+
self._test_op(model, (torch.randn(20),), flow)
59+
60+
# 2D tensor
61+
self._test_op(model, (torch.randn(5, 10),), flow)
62+
63+
# 3D tensor
64+
self._test_op(model, (torch.randn(3, 4, 5),), flow)
65+
66+
# 4D tensor
67+
self._test_op(model, (torch.randn(2, 3, 4, 5),), flow)
68+
69+
# 5D tensor
70+
self._test_op(model, (torch.randn(2, 2, 3, 4, 5),), flow)
71+
72+
def test_clamp_values(self, flow: TestFlow) -> None:
73+
# Test with different value ranges
74+
75+
# Small values with narrow clamp range
76+
self._test_op(
77+
ClampModel(min_val=-0.01, max_val=0.01), (torch.randn(10, 10) * 0.1,), flow
78+
)
79+
80+
# Large values with wide clamp range
81+
self._test_op(
82+
ClampModel(min_val=-100, max_val=100), (torch.randn(10, 10) * 1000,), flow
83+
)
84+
85+
# Mixed positive and negative values
86+
self._test_op(
87+
ClampModel(min_val=-5, max_val=5), (torch.randn(10, 10) * 10,), flow
88+
)
89+
90+
# All values within clamp range
91+
self._test_op(ClampModel(min_val=-10, max_val=10), (torch.randn(10, 10),), flow)
92+
93+
# All values outside clamp range (below min)
94+
self._test_op(
95+
ClampModel(min_val=1.0, max_val=2.0), (torch.randn(10, 10) - 10,), flow
96+
)
97+
98+
# All values outside clamp range (above max)
99+
self._test_op(
100+
ClampModel(min_val=-2.0, max_val=-1.0), (torch.randn(10, 10) + 10,), flow
101+
)
102+
103+
def test_clamp_edge_cases(self, flow: TestFlow) -> None:
104+
# Test edge cases
105+
106+
# Zero tensor
107+
self._test_op(
108+
ClampModel(min_val=-1.0, max_val=1.0),
109+
(torch.zeros(10, 10),),
110+
flow,
111+
generate_random_test_inputs=False,
112+
)
113+
114+
# Min equals max
115+
self._test_op(
116+
ClampModel(min_val=0.0, max_val=0.0), (torch.randn(10, 10),), flow
117+
)
118+
119+
# Tensor with infinity
120+
x = torch.tensor([float("inf"), float("-inf"), 1.0, -1.0])
121+
self._test_op(
122+
ClampModel(min_val=-2.0, max_val=2.0),
123+
(x,),
124+
flow,
125+
generate_random_test_inputs=False,
126+
)
127+
128+
# Tensor with NaN
129+
x = torch.tensor([float("nan"), 1.0, -1.0])
130+
self._test_op(
131+
ClampModel(min_val=-2.0, max_val=2.0),
132+
(x,),
133+
flow,
134+
generate_random_test_inputs=False,
135+
)
136+
137+
# Values at exactly min/max bounds
138+
x = torch.tensor([-1.0, -0.5, 0.0, 0.5, 1.0])
139+
self._test_op(
140+
ClampModel(min_val=-0.5, max_val=0.5),
141+
(x,),
142+
flow,
143+
generate_random_test_inputs=False,
144+
)
145+
146+
def test_clamp_scalar(self, flow: TestFlow) -> None:
147+
# Test with scalar input (1-element tensor)
148+
model = ClampModel(min_val=-1.0, max_val=1.0)
149+
self._test_op(
150+
model, (torch.tensor([-5.0]),), flow, generate_random_test_inputs=False
151+
)
152+
self._test_op(
153+
model, (torch.tensor([5.0]),), flow, generate_random_test_inputs=False
154+
)
155+
self._test_op(
156+
model, (torch.tensor([0.0]),), flow, generate_random_test_inputs=False
157+
)

0 commit comments

Comments
 (0)