|
4 | 4 | # This source code is licensed under the BSD-style license found in the
|
5 | 5 | # LICENSE file in the root directory of this source tree.
|
6 | 6 |
|
| 7 | +# pyre-unsafe |
| 8 | + |
| 9 | +import itertools |
7 | 10 | import unittest
|
8 | 11 |
|
9 | 12 | import torch
|
10 |
| -from executorch.backends.xnnpack.test.tester import Tester |
| 13 | +from executorch.backends.xnnpack.test.tester import Export, Tester |
| 14 | +from torch.export.dynamic_shapes import Dim |
11 | 15 |
|
12 | 16 |
|
13 | 17 | class TestMaxPool2d(unittest.TestCase):
|
@@ -38,10 +42,12 @@ def __init__(self, kernel_size=3, stride=1, padding=0, dilation=1):
|
38 | 42 | def forward(self, x):
|
39 | 43 | return self.max_pool2d_module(x)[1]
|
40 | 44 |
|
41 |
| - class MaxPool2dUnsupportedCeilMode(torch.nn.Module): |
42 |
| - def __init__(self): |
| 45 | + class MaxPool2dCeilMode(torch.nn.Module): |
| 46 | + def __init__(self, kernel_size=3, stride=1, padding=0, dilation=1): |
43 | 47 | super().__init__()
|
44 |
| - self.max_pool2d_module = torch.nn.MaxPool2d(2, stride=2, ceil_mode=True) |
| 48 | + self.max_pool2d_module = torch.nn.MaxPool2d( |
| 49 | + kernel_size, stride, padding, dilation, ceil_mode=True |
| 50 | + ) |
45 | 51 |
|
46 | 52 | def forward(self, x):
|
47 | 53 | return self.max_pool2d_module(x)
|
@@ -93,14 +99,56 @@ def test_fp32_maxpool2d_unsupported(self):
|
93 | 99 | )
|
94 | 100 | )
|
95 | 101 |
|
96 |
| - def test_fp32_maxpool2d_unsupported_ceilmode(self): |
| 102 | + def test_fp32_maxpool2d_ceilmode(self): |
| 103 | + input_sizes = [[17, 32], [32, 37]] |
| 104 | + kernel_sizes = [2, 3, 12] |
| 105 | + strides = [1, 2, 4] |
| 106 | + padding = [0, 1, 5] |
| 107 | + dilations = [1, 2, 3] |
| 108 | + |
| 109 | + for input_size, kernel_size, stride, pad, dilation in itertools.product( |
| 110 | + input_sizes, kernel_sizes, strides, padding, dilations |
| 111 | + ): |
| 112 | + # Check XNNPACK and PyTorch constraints |
| 113 | + if pad > ((kernel_size - 1) * dilation + 1) / 2: |
| 114 | + continue |
| 115 | + if stride > kernel_size: |
| 116 | + continue |
| 117 | + if any( |
| 118 | + (size + 2 * pad - dilation * (kernel_size - 1) - 1) // stride + 1 <= 0 |
| 119 | + for size in input_size |
| 120 | + ): # Output size too small |
| 121 | + continue |
| 122 | + |
| 123 | + inputs = (torch.randn(1, 1, input_size[0], input_size[1]),) |
| 124 | + ( |
| 125 | + Tester( |
| 126 | + self.MaxPool2dCeilMode(kernel_size, stride, pad, dilation), inputs |
| 127 | + ) |
| 128 | + .export() |
| 129 | + .check_count({"torch.ops.aten.max_pool2d.default": 1}) |
| 130 | + .to_edge_transform_and_lower() |
| 131 | + .check_count({"torch.ops.higher_order.executorch_call_delegate": 1}) |
| 132 | + .check_not( |
| 133 | + [ |
| 134 | + "executorch_exir_dialects_edge__ops_aten_max_pool2d_with_indices_default" |
| 135 | + ] |
| 136 | + ) |
| 137 | + .to_executorch() |
| 138 | + .serialize() |
| 139 | + .run_method_and_compare_outputs() |
| 140 | + ) |
| 141 | + |
| 142 | + def test_fp32_maxpool2d_unsupported_dynamic_ceilmode(self): |
97 | 143 | """
|
98 |
| - MaxPool2d with ceil mode is not generally supported (see maxpool2d constraint). |
| 144 | + MaxPool2d with ceil mode is supported with dynamic shape (see maxpool2d constraint). |
99 | 145 | """
|
100 | 146 | inputs = (torch.randn(1, 32, 23, 23),)
|
| 147 | + dim3 = Dim("_dim3", min=11, max=50) |
| 148 | + dynamic_shapes = {"x": {3: 2 * dim3 - 1}} |
101 | 149 | (
|
102 |
| - Tester(self.MaxPool2dUnsupportedCeilMode(), inputs) |
103 |
| - .export() |
| 150 | + Tester(self.MaxPool2dCeilMode(), inputs) |
| 151 | + .export(Export(dynamic_shapes=dynamic_shapes)) |
104 | 152 | .check_count({"torch.ops.aten.max_pool2d.default": 1})
|
105 | 153 | .to_edge_transform_and_lower()
|
106 | 154 | # We expect it not be be delegated.
|
|
0 commit comments