Skip to content

Fix _EfficientKMeans cluster reduction to use intra-cluster errors (fixes #2698)#2700

Merged
TobyRoseman merged 1 commit into
apple:mainfrom
LeSingh1:fix/efficient-kmeans-cluster-reduction
May 21, 2026
Merged

Fix _EfficientKMeans cluster reduction to use intra-cluster errors (fixes #2698)#2700
TobyRoseman merged 1 commit into
apple:mainfrom
LeSingh1:fix/efficient-kmeans-cluster-reduction

Conversation

@LeSingh1
Copy link
Copy Markdown
Contributor

Summary

_EfficientKMeans.fit reduces n_clusters when removing the smallest-population centroid still keeps the per-point RMSE under error_bnd. The candidate reduce_inertia was being computed from reduce_cluster_centers_.sum() (the sum of the remaining centroid coordinates), which is the wrong quantity:

  • The comparison reduce_inertia / N is meant to be a mean squared error, but summing centroid coordinates produces a value with no consistent sign or magnitude relative to error_bnd.
  • When the data pushes the centroid sum negative, _torch.sqrt(negative / N) silently produces NaN. NaN < self.error_bnd evaluates to False, so cluster reduction is skipped even when it should fire.

Fix

Sum the per-point min distance errors instead, mirroring the pattern already used a few lines above for cur_inertia:

cur_inertia    = min_error.sum()         # line 247 (unchanged)
reduce_inertia = reduce_min_error.sum()  # line 262 (this change)

This is the fix suggested by the reporter in #2698.

Verification

Added coremltools/test/optimize/torch/palettization/test_efficient_kmeans.py covering the all-negative-data case from the issue. Without the patch the test fails with assert 3 == 2; with the patch it passes:

coremltools/test/optimize/torch/palettization/test_efficient_kmeans.py . [100%]
============================== 1 passed in 0.01s ===============================

Issue

Fixes #2698

`_EfficientKMeans.fit` reduces `n_clusters` when removing the
smallest-population centroid still keeps the per-point RMSE under
`error_bnd`. The candidate `reduce_inertia` was being computed from
`reduce_cluster_centers_.sum()` (the sum of the remaining centroid
coordinates), so:

  * the RMSE comparison against `error_bnd` was meaningless;
  * when data pushed the centroid sum negative, `sqrt(negative / N)`
    silently produced NaN and `NaN < error_bnd` evaluated false, so
    no cluster was ever reduced.

This patch sums the per-point min distance errors instead, matching
the pattern already used a few lines above for `cur_inertia`:

    cur_inertia    = min_error.sum()        # line 247 (unchanged)
    reduce_inertia = reduce_min_error.sum() # line 262 (this change)

A regression test covers the all-negative-data case from the issue.

Fixes apple#2698
@TobyRoseman
Copy link
Copy Markdown
Collaborator

@TobyRoseman TobyRoseman merged commit 74cd4ba into apple:main May 21, 2026
@TobyRoseman
Copy link
Copy Markdown
Collaborator

Thanks @LeSingh1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

_EfficientKMeans.fit uses cluster centroids sum instead of intra-cluster errors for cluster reduction

3 participants