diff --git a/backends/webgpu/test/op_tests/cases.py b/backends/webgpu/test/op_tests/cases.py index 61afeb32dd7..4ef446e28f3 100644 --- a/backends/webgpu/test/op_tests/cases.py +++ b/backends/webgpu/test/op_tests/cases.py @@ -50,6 +50,11 @@ SigmoidModule, ) +from executorch.backends.webgpu.test.ops.slice.test_slice import ( + CONFIGS as _SLICE_CONFIGS, + SliceModule, +) + from executorch.backends.webgpu.test.ops.squeeze.test_squeeze import ( CONFIGS as _SQUEEZE_CONFIGS, SqueezeModule, @@ -220,3 +225,8 @@ def _unsqueeze_suite() -> WebGPUTestSuite: ], golden_dtype="float32", # reshape copies values; fp64 bit-identical ) + + +@register_op_test("slice") +def _slice_suite() -> WebGPUTestSuite: + return _fn_config_suite(SliceModule, _SLICE_CONFIGS) diff --git a/backends/webgpu/test/ops/slice/__init__.py b/backends/webgpu/test/ops/slice/__init__.py new file mode 100644 index 00000000000..2e41cd717f6 --- /dev/null +++ b/backends/webgpu/test/ops/slice/__init__.py @@ -0,0 +1,5 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. diff --git a/backends/webgpu/test/ops/slice/test_slice.py b/backends/webgpu/test/ops/slice/test_slice.py new file mode 100644 index 00000000000..d0920faa675 --- /dev/null +++ b/backends/webgpu/test/ops/slice/test_slice.py @@ -0,0 +1,65 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +"""`aten.slice_copy.Tensor` module + configs for the WebGPU op-test framework. + +`SliceModule` + `CONFIGS` are imported by `cases.py` to drive the declarative +op-test suite. `SliceTest` is the export-delegation smoke +test. +""" + +import unittest + +import torch + +from executorch.backends.vulkan.partitioner.vulkan_partitioner import VulkanPartitioner +from executorch.exir import to_edge_transform_and_lower + +# name -> (input_shape, slice_fn) +CONFIGS = { + "dim1_1_5": ((3, 8, 4), lambda x: x[:, 1:5]), + "lastdim": ((3, 8, 4), lambda x: x[..., 1:3]), + "step2": ((3, 8, 4), lambda x: x[:, 0:8:2]), + "neg_end": ((3, 8, 4), lambda x: x[:, 1:-1]), +} + + +class SliceModule(torch.nn.Module): + def __init__(self, fn): + super().__init__() + self.fn = fn + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return self.fn(x) + + +def _det_input(shape): + g = torch.Generator().manual_seed(0) + return torch.randn(*shape, generator=g, dtype=torch.float32) + + +def _export(fn, x: torch.Tensor): + ep = torch.export.export(SliceModule(fn).eval(), (x,)) + return to_edge_transform_and_lower( + ep, partitioner=[VulkanPartitioner()] + ).to_executorch() + + +def _delegated(et) -> bool: + return any( + d.id == "VulkanBackend" + for plan in et.executorch_program.execution_plan + for d in plan.delegates + ) + + +class SliceTest(unittest.TestCase): + def test_export_delegates(self) -> None: + for name, (shape, fn) in CONFIGS.items(): + et = _export(fn, _det_input(shape)) + self.assertTrue( + _delegated(et), f"Expected a VulkanBackend delegate (slice {name})" + ) diff --git a/backends/webgpu/test/tester.py b/backends/webgpu/test/tester.py index 53a745a16df..5668a783e21 100644 --- a/backends/webgpu/test/tester.py +++ b/backends/webgpu/test/tester.py @@ -27,6 +27,7 @@ exir_ops.edge.aten.sigmoid.default, exir_ops.edge.aten.squeeze_copy.dims, exir_ops.edge.aten.unsqueeze_copy.default, + exir_ops.edge.aten.slice_copy.Tensor, ]