Skip to content

Commit 0779d69

Browse files
committed
[Backend Tester] Add upsample tests
ghstack-source-id: a8b8cea ghstack-comment-id: 3116317107 Pull-Request: #12856
1 parent 3231928 commit 0779d69

File tree

2 files changed

+246
-0
lines changed

2 files changed

+246
-0
lines changed
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
# pyre-strict
4+
5+
from typing import Callable, Optional, Tuple, Union
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 ModelWithSize(torch.nn.Module):
16+
def __init__(
17+
self,
18+
size: Optional[Tuple[int, int]] = None,
19+
align_corners: Optional[bool] = None,
20+
):
21+
super().__init__()
22+
self.size = size
23+
self.align_corners = align_corners
24+
25+
def forward(self, x):
26+
return torch.nn.functional.interpolate(x, size=self.size, mode='bilinear', align_corners=self.align_corners)
27+
28+
class ModelWithScale(torch.nn.Module):
29+
def __init__(
30+
self,
31+
scale_factor: Union[float, Tuple[float, float]] = 2.0,
32+
align_corners: Optional[bool] = None,
33+
):
34+
super().__init__()
35+
self.scale_factor = scale_factor
36+
self.align_corners = align_corners
37+
38+
def forward(self, x):
39+
return torch.nn.functional.interpolate(x, scale_factor=self.scale_factor, mode='bilinear', align_corners=self.align_corners)
40+
41+
@operator_test
42+
class TestUpsampleBilinear2d(OperatorTest):
43+
@dtype_test
44+
def test_upsample_bilinear2d_dtype(self, dtype, tester_factory: Callable) -> None:
45+
# Input shape: (batch_size, channels, height, width)
46+
model = ModelWithSize(size=(10, 10), align_corners=False).to(dtype)
47+
self._test_op(model, (torch.rand(2, 3, 5, 5).to(dtype),), tester_factory)
48+
49+
def test_upsample_bilinear2d_basic(self, tester_factory: Callable) -> None:
50+
# Basic test with default parameters
51+
self._test_op(ModelWithSize(size=(10, 10), align_corners=False), (torch.randn(2, 3, 5, 5),), tester_factory)
52+
self._test_op(ModelWithSize(size=(10, 10), align_corners=True), (torch.randn(2, 3, 5, 5),), tester_factory)
53+
54+
def test_upsample_bilinear2d_sizes(self, tester_factory: Callable) -> None:
55+
# Test with different input and output sizes
56+
57+
# Small input, larger output
58+
self._test_op(ModelWithSize(size=(8, 8), align_corners=False), (torch.randn(1, 2, 4, 4),), tester_factory)
59+
self._test_op(ModelWithSize(size=(8, 8), align_corners=True), (torch.randn(1, 2, 4, 4),), tester_factory)
60+
61+
# Larger input, even larger output
62+
self._test_op(ModelWithSize(size=(16, 16), align_corners=False), (torch.randn(1, 2, 8, 8),), tester_factory)
63+
self._test_op(ModelWithSize(size=(16, 16), align_corners=True), (torch.randn(1, 2, 8, 8),), tester_factory)
64+
65+
# Different height and width
66+
self._test_op(ModelWithSize(size=(16, 8), align_corners=False), (torch.randn(1, 2, 8, 4),), tester_factory)
67+
self._test_op(ModelWithSize(size=(16, 8), align_corners=True), (torch.randn(1, 2, 8, 4),), tester_factory)
68+
69+
# Asymmetric upsampling
70+
self._test_op(ModelWithSize(size=(20, 10), align_corners=False), (torch.randn(1, 2, 5, 5),), tester_factory)
71+
self._test_op(ModelWithSize(size=(20, 10), align_corners=True), (torch.randn(1, 2, 5, 5),), tester_factory)
72+
73+
def test_upsample_bilinear2d_scale_factors(self, tester_factory: Callable) -> None:
74+
# Test with different scale factors
75+
76+
# Scale by 2
77+
self._test_op(ModelWithScale(scale_factor=2.0, align_corners=False), (torch.randn(1, 2, 5, 5),), tester_factory)
78+
self._test_op(ModelWithScale(scale_factor=2.0, align_corners=True), (torch.randn(1, 2, 5, 5),), tester_factory)
79+
80+
# Scale by 3
81+
self._test_op(ModelWithScale(scale_factor=3.0, align_corners=False), (torch.randn(1, 2, 5, 5),), tester_factory)
82+
self._test_op(ModelWithScale(scale_factor=3.0, align_corners=True), (torch.randn(1, 2, 5, 5),), tester_factory)
83+
84+
# Scale by 1.5
85+
self._test_op(ModelWithScale(scale_factor=1.5, align_corners=False), (torch.randn(1, 2, 6, 6),), tester_factory)
86+
self._test_op(ModelWithScale(scale_factor=1.5, align_corners=True), (torch.randn(1, 2, 6, 6),), tester_factory)
87+
88+
# Different scales for height and width
89+
self._test_op(ModelWithScale(scale_factor=(2.0, 1.5), align_corners=False), (torch.randn(1, 2, 5, 6),), tester_factory)
90+
self._test_op(ModelWithScale(scale_factor=(2.0, 1.5), align_corners=True), (torch.randn(1, 2, 5, 6),), tester_factory)
91+
92+
def test_upsample_bilinear2d_batch_sizes(self, tester_factory: Callable) -> None:
93+
# Test with different batch sizes
94+
self._test_op(ModelWithSize(size=(10, 10), align_corners=False), (torch.randn(1, 3, 5, 5),), tester_factory)
95+
self._test_op(ModelWithSize(size=(10, 10), align_corners=False), (torch.randn(4, 3, 5, 5),), tester_factory)
96+
self._test_op(ModelWithSize(size=(10, 10), align_corners=False), (torch.randn(8, 3, 5, 5),), tester_factory)
97+
98+
def test_upsample_bilinear2d_channels(self, tester_factory: Callable) -> None:
99+
# Test with different numbers of channels
100+
self._test_op(ModelWithSize(size=(10, 10), align_corners=False), (torch.randn(2, 1, 5, 5),), tester_factory) # Grayscale
101+
self._test_op(ModelWithSize(size=(10, 10), align_corners=False), (torch.randn(2, 3, 5, 5),), tester_factory) # RGB
102+
self._test_op(ModelWithSize(size=(10, 10), align_corners=False), (torch.randn(2, 4, 5, 5),), tester_factory) # RGBA
103+
self._test_op(ModelWithSize(size=(10, 10), align_corners=False), (torch.randn(2, 16, 5, 5),), tester_factory) # Multi-channel
104+
105+
def test_upsample_bilinear2d_same_size(self, tester_factory: Callable) -> None:
106+
# Test with output size same as input size (should be identity)
107+
self._test_op(ModelWithSize(size=(5, 5), align_corners=False), (torch.randn(2, 3, 5, 5),), tester_factory)
108+
self._test_op(ModelWithSize(size=(5, 5), align_corners=True), (torch.randn(2, 3, 5, 5),), tester_factory)
109+
self._test_op(ModelWithScale(scale_factor=1.0, align_corners=False), (torch.randn(2, 3, 5, 5),), tester_factory)
110+
self._test_op(ModelWithScale(scale_factor=1.0, align_corners=True), (torch.randn(2, 3, 5, 5),), tester_factory)
111+
112+
def test_upsample_bilinear2d_downsampling(self, tester_factory: Callable) -> None:
113+
# Test downsampling
114+
self._test_op(ModelWithSize(size=(4, 4), align_corners=False), (torch.randn(2, 3, 8, 8),), tester_factory)
115+
self._test_op(ModelWithSize(size=(4, 4), align_corners=True), (torch.randn(2, 3, 8, 8),), tester_factory)
116+
self._test_op(ModelWithScale(scale_factor=0.5, align_corners=False), (torch.randn(2, 3, 8, 8),), tester_factory)
117+
self._test_op(ModelWithScale(scale_factor=0.5, align_corners=True), (torch.randn(2, 3, 8, 8),), tester_factory)
118+
119+
# Test with non-integer downsampling factor
120+
self._test_op(ModelWithScale(scale_factor=0.75, align_corners=False), (torch.randn(2, 3, 8, 8),), tester_factory)
121+
self._test_op(ModelWithScale(scale_factor=0.75, align_corners=True), (torch.randn(2, 3, 8, 8),), tester_factory)
122+
123+
def test_upsample_bilinear2d_large_scale(self, tester_factory: Callable) -> None:
124+
# Test with large scale factor
125+
self._test_op(ModelWithScale(scale_factor=4.0, align_corners=False), (torch.randn(1, 2, 4, 4),), tester_factory)
126+
self._test_op(ModelWithScale(scale_factor=4.0, align_corners=True), (torch.randn(1, 2, 4, 4),), tester_factory)
127+
128+
def test_upsample_bilinear2d_non_square(self, tester_factory: Callable) -> None:
129+
# Test with non-square input
130+
self._test_op(ModelWithSize(size=(10, 20), align_corners=False), (torch.randn(2, 3, 5, 10),), tester_factory)
131+
self._test_op(ModelWithSize(size=(10, 20), align_corners=True), (torch.randn(2, 3, 5, 10),), tester_factory)
132+
self._test_op(ModelWithScale(scale_factor=2.0, align_corners=False), (torch.randn(2, 3, 5, 10),), tester_factory)
133+
self._test_op(ModelWithScale(scale_factor=2.0, align_corners=True), (torch.randn(2, 3, 5, 10),), tester_factory)
134+
135+
def test_upsample_bilinear2d_odd_sizes(self, tester_factory: Callable) -> None:
136+
# Test with odd input and output sizes (where interpolation behavior might be more noticeable)
137+
self._test_op(ModelWithSize(size=(9, 9), align_corners=False), (torch.randn(2, 3, 5, 5),), tester_factory)
138+
self._test_op(ModelWithSize(size=(9, 9), align_corners=True), (torch.randn(2, 3, 5, 5),), tester_factory)
139+
self._test_op(ModelWithSize(size=(7, 7), align_corners=False), (torch.randn(2, 3, 3, 3),), tester_factory)
140+
self._test_op(ModelWithSize(size=(7, 7), align_corners=True), (torch.randn(2, 3, 3, 3),), tester_factory)
141+
self._test_op(ModelWithScale(scale_factor=1.5, align_corners=False), (torch.randn(2, 3, 5, 5),), tester_factory)
142+
self._test_op(ModelWithScale(scale_factor=1.5, align_corners=True), (torch.randn(2, 3, 5, 5),), tester_factory)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary.
2+
3+
# pyre-strict
4+
5+
from typing import Callable, Optional, Tuple, Union
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 ModelWithSize(torch.nn.Module):
16+
def __init__(
17+
self,
18+
size: Optional[Tuple[int, int]] = None,
19+
):
20+
super().__init__()
21+
self.size = size
22+
23+
def forward(self, x):
24+
return torch.nn.functional.interpolate(x, size=self.size, mode='nearest')
25+
26+
class ModelWithScale(torch.nn.Module):
27+
def __init__(
28+
self,
29+
scale_factor: Union[float, Tuple[float, float]] = 2.0,
30+
):
31+
super().__init__()
32+
self.scale_factor = scale_factor
33+
34+
def forward(self, x):
35+
return torch.nn.functional.interpolate(x, scale_factor=self.scale_factor, mode='nearest')
36+
37+
@operator_test
38+
class TestUpsampleNearest2d(OperatorTest):
39+
@dtype_test
40+
def test_upsample_nearest2d_dtype(self, dtype, tester_factory: Callable) -> None:
41+
# Input shape: (batch_size, channels, height, width)
42+
model = ModelWithSize(size=(10, 10)).to(dtype)
43+
self._test_op(model, (torch.rand(2, 3, 5, 5).to(dtype),), tester_factory)
44+
45+
def test_upsample_nearest2d_basic(self, tester_factory: Callable) -> None:
46+
# Basic test with default parameters
47+
self._test_op(ModelWithSize(size=(10, 10)), (torch.randn(2, 3, 5, 5),), tester_factory)
48+
49+
def test_upsample_nearest2d_sizes(self, tester_factory: Callable) -> None:
50+
# Test with different input and output sizes
51+
52+
# Small input, larger output
53+
self._test_op(ModelWithSize(size=(8, 8)), (torch.randn(1, 2, 4, 4),), tester_factory)
54+
55+
# Larger input, even larger output
56+
self._test_op(ModelWithSize(size=(16, 16)), (torch.randn(1, 2, 8, 8),), tester_factory)
57+
58+
# Different height and width
59+
self._test_op(ModelWithSize(size=(16, 8)), (torch.randn(1, 2, 8, 4),), tester_factory)
60+
61+
# Asymmetric upsampling
62+
self._test_op(ModelWithSize(size=(20, 10)), (torch.randn(1, 2, 5, 5),), tester_factory)
63+
64+
def test_upsample_nearest2d_scale_factors(self, tester_factory: Callable) -> None:
65+
# Test with different scale factors
66+
67+
# Scale by 2
68+
self._test_op(ModelWithScale(scale_factor=2.0), (torch.randn(1, 2, 5, 5),), tester_factory)
69+
70+
# Scale by 3
71+
self._test_op(ModelWithScale(scale_factor=3.0), (torch.randn(1, 2, 5, 5),), tester_factory)
72+
73+
# Scale by 1.5
74+
self._test_op(ModelWithScale(scale_factor=1.5), (torch.randn(1, 2, 6, 6),), tester_factory)
75+
76+
# Different scales for height and width
77+
self._test_op(ModelWithScale(scale_factor=(2.0, 1.5)), (torch.randn(1, 2, 5, 6),), tester_factory)
78+
79+
def test_upsample_nearest2d_batch_sizes(self, tester_factory: Callable) -> None:
80+
# Test with different batch sizes
81+
self._test_op(ModelWithSize(size=(10, 10)), (torch.randn(1, 3, 5, 5),), tester_factory)
82+
self._test_op(ModelWithSize(size=(10, 10)), (torch.randn(4, 3, 5, 5),), tester_factory)
83+
self._test_op(ModelWithSize(size=(10, 10)), (torch.randn(8, 3, 5, 5),), tester_factory)
84+
85+
def test_upsample_nearest2d_channels(self, tester_factory: Callable) -> None:
86+
# Test with different numbers of channels
87+
self._test_op(ModelWithSize(size=(10, 10)), (torch.randn(2, 1, 5, 5),), tester_factory) # Grayscale
88+
self._test_op(ModelWithSize(size=(10, 10)), (torch.randn(2, 3, 5, 5),), tester_factory) # RGB
89+
self._test_op(ModelWithSize(size=(10, 10)), (torch.randn(2, 4, 5, 5),), tester_factory) # RGBA
90+
self._test_op(ModelWithSize(size=(10, 10)), (torch.randn(2, 16, 5, 5),), tester_factory) # Multi-channel
91+
92+
def test_upsample_nearest2d_same_size(self, tester_factory: Callable) -> None:
93+
# Test with output size same as input size (should be identity)
94+
self._test_op(ModelWithSize(size=(5, 5)), (torch.randn(2, 3, 5, 5),), tester_factory)
95+
self._test_op(ModelWithScale(scale_factor=1.0), (torch.randn(2, 3, 5, 5),), tester_factory)
96+
97+
def test_upsample_nearest2d_large_scale(self, tester_factory: Callable) -> None:
98+
# Test with large scale factor
99+
self._test_op(ModelWithScale(scale_factor=4.0), (torch.randn(1, 2, 4, 4),), tester_factory)
100+
101+
def test_upsample_nearest2d_non_square(self, tester_factory: Callable) -> None:
102+
# Test with non-square input
103+
self._test_op(ModelWithSize(size=(10, 20)), (torch.randn(2, 3, 5, 10),), tester_factory)
104+
self._test_op(ModelWithScale(scale_factor=2.0), (torch.randn(2, 3, 5, 10),), tester_factory)

0 commit comments

Comments
 (0)