Skip to content

Commit 3231928

Browse files
committed
[Backend Tester] Add more pointwise op tests
ghstack-source-id: 2bdf179 ghstack-comment-id: 3116317028 Pull-Request: #12855
1 parent de402e6 commit 3231928

File tree

9 files changed

+920
-0
lines changed

9 files changed

+920
-0
lines changed
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
# pyre-strict
4+
5+
from typing import Callable
6+
7+
import torch
8+
9+
from executorch.backends.test.compliance_suite import (
10+
dtype_test,
11+
operator_test,
12+
OperatorTest,
13+
)
14+
15+
class AbsModel(torch.nn.Module):
16+
def __init__(self):
17+
super().__init__()
18+
19+
def forward(self, x):
20+
return torch.abs(x)
21+
22+
@operator_test
23+
class TestAbs(OperatorTest):
24+
@dtype_test
25+
def test_abs_dtype(self, dtype, tester_factory: Callable) -> None:
26+
# Test with different dtypes
27+
model = AbsModel().to(dtype)
28+
self._test_op(model, (torch.rand(10, 10).to(dtype) * 2 - 1,), tester_factory)
29+
30+
def test_abs_basic(self, tester_factory: Callable) -> None:
31+
# Basic test with default parameters
32+
# Input: tensor with positive and negative values
33+
self._test_op(AbsModel(), (torch.randn(10, 10),), tester_factory)
34+
35+
def test_abs_shapes(self, tester_factory: Callable) -> None:
36+
# Test with different tensor shapes
37+
38+
# 1D tensor
39+
self._test_op(AbsModel(), (torch.randn(20),), tester_factory)
40+
41+
# 2D tensor
42+
self._test_op(AbsModel(), (torch.randn(5, 10),), tester_factory)
43+
44+
# 3D tensor
45+
self._test_op(AbsModel(), (torch.randn(3, 4, 5),), tester_factory)
46+
47+
# 4D tensor
48+
self._test_op(AbsModel(), (torch.randn(2, 3, 4, 5),), tester_factory)
49+
50+
# 5D tensor
51+
self._test_op(AbsModel(), (torch.randn(2, 2, 3, 4, 5),), tester_factory)
52+
53+
def test_abs_values(self, tester_factory: Callable) -> None:
54+
# Test with different value ranges
55+
56+
# Small values
57+
self._test_op(AbsModel(), (torch.randn(10, 10) * 0.01,), tester_factory)
58+
59+
# Large values
60+
self._test_op(AbsModel(), (torch.randn(10, 10) * 1000,), tester_factory)
61+
62+
# Mixed positive and negative values
63+
self._test_op(AbsModel(), (torch.randn(10, 10) * 10,), tester_factory)
64+
65+
# All positive values
66+
self._test_op(AbsModel(), (torch.rand(10, 10) * 10,), tester_factory)
67+
68+
# All negative values
69+
self._test_op(AbsModel(), (torch.rand(10, 10) * -10,), tester_factory)
70+
71+
# Values close to zero
72+
self._test_op(AbsModel(), (torch.randn(10, 10) * 1e-5,), tester_factory)
73+
74+
def test_abs_edge_cases(self, tester_factory: Callable) -> None:
75+
# Test edge cases
76+
77+
# Zero tensor
78+
self._test_op(AbsModel(), (torch.zeros(10, 10),), tester_factory)
79+
80+
# Tensor with infinity
81+
x = torch.tensor([float('inf'), float('-inf'), 1.0, -1.0])
82+
self._test_op(AbsModel(), (x,), tester_factory)
83+
84+
# Tensor with NaN
85+
x = torch.tensor([float('nan'), 1.0, -1.0])
86+
self._test_op(AbsModel(), (x,), tester_factory)
87+
88+
def test_abs_scalar(self, tester_factory: Callable) -> None:
89+
# Test with scalar input (1-element tensor)
90+
self._test_op(AbsModel(), (torch.tensor([-5.0]),), tester_factory)
91+
self._test_op(AbsModel(), (torch.tensor([5.0]),), tester_factory)
92+
self._test_op(AbsModel(), (torch.tensor([0.0]),), tester_factory)
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
# pyre-strict
4+
5+
from typing import Callable
6+
7+
import torch
8+
9+
from executorch.backends.test.compliance_suite import (
10+
dtype_test,
11+
operator_test,
12+
OperatorTest,
13+
)
14+
15+
class CeilModel(torch.nn.Module):
16+
def __init__(self):
17+
super().__init__()
18+
19+
def forward(self, x):
20+
return torch.ceil(x)
21+
22+
@operator_test
23+
class TestCeil(OperatorTest):
24+
@dtype_test
25+
def test_ceil_dtype(self, dtype, tester_factory: Callable) -> None:
26+
# Test with different dtypes
27+
model = CeilModel().to(dtype)
28+
self._test_op(model, (torch.rand(10, 10).to(dtype) * 2 - 1,), tester_factory)
29+
30+
def test_ceil_basic(self, tester_factory: Callable) -> None:
31+
# Basic test with default parameters
32+
# Input: tensor with fractional values
33+
self._test_op(CeilModel(), (torch.randn(10, 10),), tester_factory)
34+
35+
def test_ceil_shapes(self, tester_factory: Callable) -> None:
36+
# Test with different tensor shapes
37+
38+
# 1D tensor
39+
self._test_op(CeilModel(), (torch.randn(20),), tester_factory)
40+
41+
# 2D tensor
42+
self._test_op(CeilModel(), (torch.randn(5, 10),), tester_factory)
43+
44+
# 3D tensor
45+
self._test_op(CeilModel(), (torch.randn(3, 4, 5),), tester_factory)
46+
47+
# 4D tensor
48+
self._test_op(CeilModel(), (torch.randn(2, 3, 4, 5),), tester_factory)
49+
50+
# 5D tensor
51+
self._test_op(CeilModel(), (torch.randn(2, 2, 3, 4, 5),), tester_factory)
52+
53+
def test_ceil_values(self, tester_factory: Callable) -> None:
54+
# Test with different value ranges
55+
56+
# Small fractional values
57+
self._test_op(CeilModel(), (torch.rand(10, 10) * 0.01,), tester_factory)
58+
59+
# Large fractional values
60+
self._test_op(CeilModel(), (torch.randn(10, 10) * 1000,), tester_factory)
61+
62+
# Mixed positive and negative values
63+
self._test_op(CeilModel(), (torch.randn(10, 10) * 10,), tester_factory)
64+
65+
# Values with specific fractional parts
66+
self._test_op(CeilModel(), (torch.arange(0, 10, 0.5).reshape(4, 5),), tester_factory)
67+
68+
# Values close to integers
69+
x = torch.randn(10, 10)
70+
x = x.round() + torch.rand(10, 10) * 0.01
71+
self._test_op(CeilModel(), (x,), tester_factory)
72+
73+
def test_ceil_edge_cases(self, tester_factory: Callable) -> None:
74+
# Test edge cases
75+
76+
# Integer values
77+
self._test_op(CeilModel(), (torch.arange(10).reshape(2, 5).float(),), tester_factory)
78+
79+
# Zero tensor
80+
self._test_op(CeilModel(), (torch.zeros(10, 10),), tester_factory)
81+
82+
# Tensor with infinity
83+
x = torch.tensor([float('inf'), float('-inf'), 1.0, -1.0])
84+
self._test_op(CeilModel(), (x,), tester_factory)
85+
86+
# Tensor with NaN
87+
x = torch.tensor([float('nan'), 1.0, -1.0])
88+
self._test_op(CeilModel(), (x,), tester_factory)
89+
90+
# Values just below integers
91+
x = torch.arange(10).float() - 0.01
92+
self._test_op(CeilModel(), (x,), tester_factory)
93+
94+
# Values just above integers
95+
x = torch.arange(10).float() + 0.01
96+
self._test_op(CeilModel(), (x,), tester_factory)
97+
98+
def test_ceil_scalar(self, tester_factory: Callable) -> None:
99+
# Test with scalar input (1-element tensor)
100+
self._test_op(CeilModel(), (torch.tensor([1.5]),), tester_factory)
101+
self._test_op(CeilModel(), (torch.tensor([-1.5]),), tester_factory)
102+
self._test_op(CeilModel(), (torch.tensor([0.0]),), tester_factory)
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
# pyre-strict
4+
5+
from typing import Callable
6+
7+
import torch
8+
9+
from executorch.backends.test.compliance_suite import (
10+
dtype_test,
11+
operator_test,
12+
OperatorTest,
13+
)
14+
15+
class ClampModel(torch.nn.Module):
16+
def __init__(self, min_val=None, max_val=None):
17+
super().__init__()
18+
self.min_val = min_val
19+
self.max_val = max_val
20+
21+
def forward(self, x):
22+
return torch.clamp(x, min=self.min_val, max=self.max_val)
23+
24+
@operator_test
25+
class TestClamp(OperatorTest):
26+
@dtype_test
27+
def test_clamp_dtype(self, dtype, tester_factory: Callable) -> None:
28+
# Test with different dtypes
29+
model = ClampModel(min_val=-0.5, max_val=0.5).to(dtype)
30+
self._test_op(model, (torch.rand(10, 10).to(dtype) * 2 - 1,), tester_factory)
31+
32+
def test_clamp_basic(self, tester_factory: Callable) -> None:
33+
# Basic test with default parameters
34+
# Input: tensor with values outside the clamp range
35+
self._test_op(ClampModel(min_val=-0.5, max_val=0.5), (torch.randn(10, 10),), tester_factory)
36+
37+
def test_clamp_min_only(self, tester_factory: Callable) -> None:
38+
# Test with only min value specified
39+
self._test_op(ClampModel(min_val=0.0), (torch.randn(10, 10),), tester_factory)
40+
41+
def test_clamp_max_only(self, tester_factory: Callable) -> None:
42+
# Test with only max value specified
43+
self._test_op(ClampModel(max_val=0.0), (torch.randn(10, 10),), tester_factory)
44+
45+
def test_clamp_shapes(self, tester_factory: Callable) -> None:
46+
# Test with different tensor shapes
47+
model = ClampModel(min_val=-1.0, max_val=1.0)
48+
49+
# 1D tensor
50+
self._test_op(model, (torch.randn(20),), tester_factory)
51+
52+
# 2D tensor
53+
self._test_op(model, (torch.randn(5, 10),), tester_factory)
54+
55+
# 3D tensor
56+
self._test_op(model, (torch.randn(3, 4, 5),), tester_factory)
57+
58+
# 4D tensor
59+
self._test_op(model, (torch.randn(2, 3, 4, 5),), tester_factory)
60+
61+
# 5D tensor
62+
self._test_op(model, (torch.randn(2, 2, 3, 4, 5),), tester_factory)
63+
64+
def test_clamp_values(self, tester_factory: Callable) -> None:
65+
# Test with different value ranges
66+
67+
# Small values with narrow clamp range
68+
self._test_op(ClampModel(min_val=-0.01, max_val=0.01), (torch.randn(10, 10) * 0.1,), tester_factory)
69+
70+
# Large values with wide clamp range
71+
self._test_op(ClampModel(min_val=-100, max_val=100), (torch.randn(10, 10) * 1000,), tester_factory)
72+
73+
# Mixed positive and negative values
74+
self._test_op(ClampModel(min_val=-5, max_val=5), (torch.randn(10, 10) * 10,), tester_factory)
75+
76+
# All values within clamp range
77+
self._test_op(ClampModel(min_val=-10, max_val=10), (torch.randn(10, 10),), tester_factory)
78+
79+
# All values outside clamp range (below min)
80+
self._test_op(ClampModel(min_val=1.0, max_val=2.0), (torch.randn(10, 10) - 10,), tester_factory)
81+
82+
# All values outside clamp range (above max)
83+
self._test_op(ClampModel(min_val=-2.0, max_val=-1.0), (torch.randn(10, 10) + 10,), tester_factory)
84+
85+
def test_clamp_edge_cases(self, tester_factory: Callable) -> None:
86+
# Test edge cases
87+
88+
# Zero tensor
89+
self._test_op(ClampModel(min_val=-1.0, max_val=1.0), (torch.zeros(10, 10),), tester_factory)
90+
91+
# Min equals max
92+
self._test_op(ClampModel(min_val=0.0, max_val=0.0), (torch.randn(10, 10),), tester_factory)
93+
94+
# Tensor with infinity
95+
x = torch.tensor([float('inf'), float('-inf'), 1.0, -1.0])
96+
self._test_op(ClampModel(min_val=-2.0, max_val=2.0), (x,), tester_factory)
97+
98+
# Tensor with NaN
99+
x = torch.tensor([float('nan'), 1.0, -1.0])
100+
self._test_op(ClampModel(min_val=-2.0, max_val=2.0), (x,), tester_factory)
101+
102+
# Values at exactly min/max bounds
103+
x = torch.tensor([-1.0, -0.5, 0.0, 0.5, 1.0])
104+
self._test_op(ClampModel(min_val=-0.5, max_val=0.5), (x,), tester_factory)
105+
106+
def test_clamp_scalar(self, tester_factory: Callable) -> None:
107+
# Test with scalar input (1-element tensor)
108+
model = ClampModel(min_val=-1.0, max_val=1.0)
109+
self._test_op(model, (torch.tensor([-5.0]),), tester_factory)
110+
self._test_op(model, (torch.tensor([5.0]),), tester_factory)
111+
self._test_op(model, (torch.tensor([0.0]),), tester_factory)

0 commit comments

Comments
 (0)