Skip to content

fix: cosine kmeans - #1723

Merged
eddyxu merged 16 commits into
mainfrom
lei/cosine_kmeans
Dec 15, 2023
Merged

fix: cosine kmeans#1723
eddyxu merged 16 commits into
mainfrom
lei/cosine_kmeans

Conversation

@eddyxu

@eddyxu eddyxu commented Dec 15, 2023

Copy link
Copy Markdown
Member

Use L2 over normalized vector to run cosine for kmeans.

@eddyxu
eddyxu marked this pull request as ready for review December 15, 2023 18:39

@wjones127 wjones127 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems reasonable.

Comment on lines +177 to +178
cnts[i] = cnts[largest_idx] / 2;
cnts[largest_idx] /= 2;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this handle odd counts? Is there any requirement for these counts to be exact?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this moment, it does not matter. The new centroids ( sum / cnt ) has already been computed. And here, the cnts are just useful to find the empty / largest clusters.

Comment on lines +475 to +481
MetricType::Cosine => {
let normalized = values
.chunks(dimension)
.flat_map(normalize)
.collect::<Vec<_>>();
return compute_partitions_l2(centroids_array, &normalized, dimension)
.collect();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, IIUC, the idea is that once you normalize, vectors that are close in L2 distance will also be close in cosine distance?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@eddyxu
eddyxu merged commit d8fe176 into main Dec 15, 2023
@eddyxu
eddyxu deleted the lei/cosine_kmeans branch December 15, 2023 20:35
LuciferYang added a commit to LuciferYang/lance that referenced this pull request Sep 7, 2026
…cking

The training and assignment dispatches accepted any distance type for a float
column, and the membership pass then panicked with "not supported" unless the
centroid HNSW happened to be built, which bypasses that match. Narrow both
dispatches to L2 and Dot so the existing descriptive error arms handle the rest.

lance.util.KMeans documents cosine, so the binding now normalizes its input and
clusters with l2, the way the index build path does. That makes cosine behave
the same at every k instead of panicking below the HNSW threshold.

The module and new_with_params doc comments claimed cosine inputs are
normalized each iteration. That was implemented in lance-format#1723 and removed in lance-format#2015
while the comment was carried forward.
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.

2 participants