diff --git a/backends/arm/test/ops/test_sum.py b/backends/arm/test/ops/test_sum.py index 1075055c4f0..91334290975 100644 --- a/backends/arm/test/ops/test_sum.py +++ b/backends/arm/test/ops/test_sum.py @@ -5,6 +5,8 @@ from typing import Callable, Tuple +import pytest + import torch from executorch.backends.arm.test import common @@ -96,7 +98,27 @@ def test_sum_dim_intlist_tosa_INT(test_data: input_t1): pipeline.run() -@common.parametrize("test_data", Sum.test_parameters) +# Pre-existing failure that only surfaced after this diff registered +# ops/test_sum.py in targets.bzl (Meta CI never ran these tests before): +# bundled_program (used by the FVP _INT_1_0 tests) cannot serialize None +# as a model input -- the input flatten/sanity check in +# executorch.devtools.bundled_program.config rejects NoneType. dim=None is +# already covered by the SumDefault class below. Marked skip rather than +# xfail because the per-id xfails= argument does not compose with the +# XfailIfNoCorstone* decorator (verified empirically); common.parametrize +# explicitly supports skips= for "fail markers don't work in buck CI". +_DIM_NONE_SKIP_REASON = ( + "bundled_program cannot serialize None as a model input " + "(pre-existing failure -- only surfaced after ops/test_sum.py was " + "registered in targets.bzl)" +) +_dim_none_skips = { + "dim_None": _DIM_NONE_SKIP_REASON, + "dim_None_4d_tensor": _DIM_NONE_SKIP_REASON, +} + + +@common.parametrize("test_data", Sum.test_parameters, skips=_dim_none_skips) @common.XfailIfNoCorstone300 def test_sum_u55_INT_1_0(test_data: Tuple): pipeline = EthosU55PipelineINT[input_t1]( @@ -108,7 +130,7 @@ def test_sum_u55_INT_1_0(test_data: Tuple): pipeline.run() -@common.parametrize("test_data", Sum.test_parameters) +@common.parametrize("test_data", Sum.test_parameters, skips=_dim_none_skips) @common.XfailIfNoCorstone320 def test_sum_u85_INT_1_0(test_data: Tuple): pipeline = EthosU85PipelineINT[input_t1]( @@ -220,3 +242,60 @@ def test_sum_tosa_FP(test_data: Callable[[], input_t2]): def test_sum_tosa_INT(test_data: Callable[[], input_t2]): pipeline = TosaPipelineINT[input_t1](SumDefault(), test_data(), SumDefault.aten_op) pipeline.run() + + +# a16w8 (int16 IO + int8 weights) coverage for sum.dim_IntList. Surfaces the +# Ethos-U85 int16 ReduceSum silent-zero issue tracked upstream at +# https://gitlab.arm.com/artificial-intelligence/ethos-u/ethos-u-vela/-/issues/23. + + +class SumLastDim(torch.nn.Module): + """Reduce the last dim with keepdim=True.""" + + def forward(self, x: torch.Tensor) -> torch.Tensor: + return x.sum(dim=-1, keepdim=True) + + +a16w8_sum_test_parameters = { + "rank1_16": lambda: (torch.rand(16),), + "rank3_8x1x16": lambda: (torch.rand(8, 1, 16),), + "rank3_4x4x16": lambda: (torch.rand(4, 4, 16),), +} + + +@common.parametrize("test_data", a16w8_sum_test_parameters) +@common.XfailIfNoCorstone300 +def test_sum_dim_intlist_a16w8_u55_INT(test_data: Callable[[], input_t1]): + pipeline = EthosU55PipelineINT[input_t1]( + SumLastDim(), + test_data(), + aten_op, + exir_ops=[], + a16w8_quantization=True, + symmetric_io_quantization=True, + qtol=128, + epsilon=2**-16, + ) + pipeline.run() + + +# All cases hit upstream Vela issue #23 (linked above). strict=False so the +# test target stays green both on stock Vela 5.0 (cases XFAIL) and once the +# Vela fix is in tree (cases XPASS). +@common.parametrize("test_data", a16w8_sum_test_parameters) +@common.XfailIfNoCorstone320 +@pytest.mark.xfail( + reason="Ethos-U85 int16 ReduceSum returns zero (vela#23)", strict=False +) +def test_sum_dim_intlist_a16w8_u85_INT(test_data: Callable[[], input_t1]): + pipeline = EthosU85PipelineINT[input_t1]( + SumLastDim(), + test_data(), + aten_op, + exir_ops=[], + a16w8_quantization=True, + symmetric_io_quantization=True, + qtol=128, + epsilon=2**-16, + ) + pipeline.run() diff --git a/backends/arm/test/targets.bzl b/backends/arm/test/targets.bzl index 6e2539cf2dc..bad8a3eac76 100644 --- a/backends/arm/test/targets.bzl +++ b/backends/arm/test/targets.bzl @@ -30,6 +30,7 @@ def define_arm_tests(): "ops/test_slice.py", "ops/test_sigmoid.py", "ops/test_sub.py", + "ops/test_sum.py", "ops/test_tanh.py", "ops/test_view.py", "ops/test_cos.py",