Skip to content

Commit 7c937c8

Browse files
committed
test: reject unsupported kmeans palettization combos on CoreML export
Replace the pytest.skip-based _skip_unsupported_mil_configs with a predicate (_has_unsupported_mil_combo) and assert finalize() raises CoreMLExportError, mirroring the existing float-LUT-dtype rejection path. Rename _assert_coreml_rejects_unsupported_lut to _assert_coreml_rejects since it's now shared by both rejection cases.
1 parent aafcc91 commit 7c937c8

1 file changed

Lines changed: 24 additions & 35 deletions

File tree

tests/export/test_kmeans_export.py

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,17 @@ def _has_float_lut(config: ParametrizedPalettConfigs) -> bool:
6363
return config.lut_qspec is not None and config.lut_qspec.dtype.is_floating_point
6464

6565

66-
def _assert_coreml_rejects_unsupported_lut(
66+
def _assert_coreml_rejects(
6767
model: torch.nn.Module,
6868
input_data: torch.Tensor,
6969
config: KMeansPalettizerConfig,
7070
) -> None:
71-
"""Assert finalize(CoreML) rejects an unsupported LUT dtype.
71+
"""Assert finalize(CoreML) rejects an unsupported palettization config.
7272
73-
CoreML/MIL does not support FP or INT2 LUT quantization, so finalize must raise
74-
rather than emit an invalid model.
73+
CoreML/MIL rejects certain LUT dtypes and certain combinations of
74+
palettization features (vector palettization, LUT quantization,
75+
per-channel scale), so finalize must raise rather than emit an invalid
76+
model.
7577
"""
7678
model.eval()
7779
palettizer = KMeansPalettizer(model, config)
@@ -95,32 +97,17 @@ def _skip_heavy_mnist_configs(config: ParametrizedPalettConfigs) -> None:
9597
pytest.skip(f"MNIST only tests lut_qspec with int8 and float8_e4m3fn, got {dtype}")
9698

9799

98-
def _skip_unsupported_mil_configs(
99-
backend: ExportBackend,
100-
config: ParametrizedPalettConfigs,
101-
) -> None:
102-
"""Skip CoreML configs with unsupported feature combinations."""
103-
if backend != ExportBackend.CoreML:
104-
return
105-
100+
def _has_unsupported_mil_combo(config: ParametrizedPalettConfigs) -> bool:
101+
"""Whether the config combines >=2 of {vector palettization, LUT
102+
quantization, per-channel scale} -- verified to be the exact set
103+
CoreML/MIL cannot export: any single one of these works in isolation, but
104+
combining two or more fails with a rank-mismatch, missing-vector_axis, or
105+
LUT-divisibility error depending on the pair.
106+
"""
106107
is_vector = config.cluster_dim > 1
107108
has_lut_quant = config.lut_qspec is not None
108109
has_pcs = config.enable_per_channel_scale
109-
110-
# Vector palettization + LUT quantization
111-
if is_vector and has_lut_quant:
112-
# TODO: add CoreML export support for palettization combos.
113-
pytest.skip("CoreML export not supported for vector palettization + LUT quantization.")
114-
115-
# Vector palettization + per-channel scale
116-
if is_vector and has_pcs:
117-
# TODO: add CoreML export support for palettization combos.
118-
pytest.skip("CoreML export not supported for vector palettization + per-channel scale.")
119-
120-
# LUT quantization + per-channel scale
121-
if has_lut_quant and has_pcs:
122-
# TODO: add CoreML export support for palettization combos.
123-
pytest.skip("CoreML export not supported for LUT quantization + per-channel scale.")
110+
return sum([is_vector, has_lut_quant, has_pcs]) >= 2
124111

125112

126113
@pytest.mark.parametrize("backend", [ExportBackend.CoreML, ExportBackend.CoreAI])
@@ -134,12 +121,13 @@ def test_simple_model_export(
134121
config = parametrized_palett_config.config
135122
granularity = parametrized_palett_config.granularity
136123

137-
if backend == ExportBackend.CoreML and _has_float_lut(parametrized_palett_config):
138-
_assert_coreml_rejects_unsupported_lut(simple_conv_linear_model, simple_model_input, config)
124+
if backend == ExportBackend.CoreML and (
125+
_has_float_lut(parametrized_palett_config)
126+
or _has_unsupported_mil_combo(parametrized_palett_config)
127+
):
128+
_assert_coreml_rejects(simple_conv_linear_model, simple_model_input, config)
139129
return
140130

141-
_skip_unsupported_mil_configs(backend, parametrized_palett_config)
142-
143131
if (
144132
backend == ExportBackend.CoreML
145133
and parametrized_palett_config.cluster_dim > 1
@@ -175,12 +163,13 @@ def test_mnist_export(
175163
config = parametrized_palett_config.config
176164
granularity = parametrized_palett_config.granularity
177165

178-
if backend == ExportBackend.CoreML and _has_float_lut(parametrized_palett_config):
179-
_assert_coreml_rejects_unsupported_lut(custom_test_mnist_model, mnist_example_input, config)
166+
if backend == ExportBackend.CoreML and (
167+
_has_float_lut(parametrized_palett_config)
168+
or _has_unsupported_mil_combo(parametrized_palett_config)
169+
):
170+
_assert_coreml_rejects(custom_test_mnist_model, mnist_example_input, config)
180171
return
181172

182-
_skip_unsupported_mil_configs(backend, parametrized_palett_config)
183-
184173
# The MNIST model has 6 weight-bearing layers (conv1, conv2, conv_transpose1,
185174
# conv_transpose2, dense1, dense2). For axis=1 with group_size=2, conv1's
186175
# axis-1 (in_channels=1) is not divisible, so palettization is skipped there.

0 commit comments

Comments
 (0)