Skip to content

Commit 165fb74

Browse files
authored
[ExecuTorch][WebGPU] max_pool2d op tests (#20862)
Stack from [ghstack](https://github.com/ezyang/ghstack/tree/0.15.0) (oldest at bottom): * #20868 * #20996 * #20995 * #20994 * #20993 * #20992 * #20991 * #20990 * #20989 * #20988 * #20987 * #20986 * #20876 * #20875 * #20874 * #20873 * #20872 * #20871 * #20866 * #20865 * #20864 * #20863 * __->__ #20862 * #20861 * #20860 * #20859 * #20858 * #20857 * #20856 * #20855 * #20854 * #20852 * #20851 * #20850 * #20849 * #20848 * #20846 * #20845 * #20844 * #20843 * #20842 Splits the `max_pool2d` op tests into their own diff, stacked directly above the `max_pool2d` op — keeping an op and its tests in separate diffs (op below, tests above) per this backend's convention. Adds `test/ops/test_max_pool2d.py` and registers the `max_pool2d` `@register_op_test` suite in `test/op_tests/cases.py`. Co-authored-with: Claude Code. @exported-using-ghexport Differential Revision: [D111072724](https://our.internmc.facebook.com/intern/diff/D111072724/) Differential Revision: [D111072724](https://our.internmc.facebook.com/intern/diff/D111072724)
1 parent fd8e1a1 commit 165fb74

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

backends/webgpu/test/op_tests/cases.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,3 +677,45 @@ def _upsample_nearest2d_suite() -> WebGPUTestSuite:
677677
atol=1e-4,
678678
rtol=1e-3,
679679
)
680+
681+
682+
from executorch.backends.webgpu.test.ops.test_max_pool2d import (
683+
_det_input as _maxpool_det_input,
684+
MaxPool2dModule,
685+
)
686+
687+
688+
@register_op_test("max_pool2d")
689+
def _max_pool2d_suite() -> WebGPUTestSuite:
690+
# SAM2 Hiera q_pool (native shape) + real Hiera channel count (ch768) +
691+
# a padding case + a tiny eyeball case.
692+
return WebGPUTestSuite(
693+
module_factory=lambda kernel_size, stride, padding: MaxPool2dModule(
694+
kernel_size, stride, padding
695+
),
696+
cases=[
697+
Case(
698+
name="q_pool",
699+
construct={"kernel_size": 2, "stride": 2, "padding": 0},
700+
inputs=(InputSpec(shape=(1, 8, 12, 12), gen=_maxpool_det_input),),
701+
),
702+
Case(
703+
name="ch768",
704+
construct={"kernel_size": 2, "stride": 2, "padding": 0},
705+
inputs=(InputSpec(shape=(1, 768, 14, 14), gen=_maxpool_det_input),),
706+
),
707+
Case(
708+
name="pad1",
709+
construct={"kernel_size": 3, "stride": 2, "padding": 1},
710+
inputs=(InputSpec(shape=(1, 8, 7, 7), gen=_maxpool_det_input),),
711+
),
712+
Case(
713+
name="tiny",
714+
construct={"kernel_size": 2, "stride": 2, "padding": 0},
715+
inputs=(InputSpec(shape=(1, 4, 5, 5), gen=_maxpool_det_input),),
716+
),
717+
],
718+
golden_dtype="float32",
719+
atol=1e-4,
720+
rtol=1e-3,
721+
)
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
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+
"""`aten.max_pool2d_with_indices.default` module for the WebGPU op-test
8+
framework.
9+
10+
`F.max_pool2d` decomposes to `aten.max_pool2d_with_indices.default`, a
11+
multi-output op whose out is a ValueList `[values, indices]`; the handler
12+
writes the VALUES only and never the int64 indices
13+
(`runtime/ops/max_pool2d/MaxPool2d.cpp`). Max-pool is on the SAM2 Hiera
14+
q_pool path.
15+
"""
16+
17+
import torch
18+
19+
20+
class MaxPool2dModule(torch.nn.Module):
21+
def __init__(self, kernel_size: int, stride: int, padding: int) -> None:
22+
super().__init__()
23+
self.kernel_size = kernel_size
24+
self.stride = stride
25+
self.padding = padding
26+
27+
def forward(self, x: torch.Tensor) -> torch.Tensor:
28+
return torch.nn.functional.max_pool2d(
29+
x,
30+
kernel_size=self.kernel_size,
31+
stride=self.stride,
32+
padding=self.padding,
33+
)
34+
35+
36+
def _det_input(shape) -> torch.Tensor:
37+
# ((i % 23) - 11) / 16: exact in fp32, spans negatives through positives.
38+
n = 1
39+
for s in shape:
40+
n *= s
41+
idx = torch.arange(n, dtype=torch.int64)
42+
return (((idx % 23) - 11).to(torch.float32) / 16.0).reshape(shape)

0 commit comments

Comments
 (0)