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