Skip to content

Commit 2688c34

Browse files
blazingphoenix7meta-codesync[bot]
authored andcommitted
Parallelize the k-means++ D^2 seeding update (#5457)
Summary: The k-means++ centroid initialization (`init_kmeans_plus_plus` in `ClusteringInitialization`) recomputes each point's squared distance to the newly chosen centroid in a serial loop, while the Lloyd iterations that follow (assignment through `index.search`, and the centroid update) are already OpenMP-parallel. This adds a `#pragma omp parallel for` to that per-point min-distance update. Each `min_distances[i]` is an independent write, and the serial cumulative sum and D^2 sampling that pick the next centroid are untouched, so the chosen-centroid sequence and the output stay bit-identical to the serial version. The determinism test in `test_clustering_initialization.py` continues to hold, and a standalone check confirms the seeding output is bit-identical across 1, 2, 4, and 10 threads. Only the k-means++ init path is affected; RANDOM (the default) and AFK-MC2 are unchanged. The loop is memory-bandwidth-bound, so it is not a linear speedup: on a 10-core dual-channel machine the seeding update measures about 2.7x at 4 threads and saturates there. End-to-end the seeding is a small share of a full clustering, so the effect on `Clustering.train` is modest and shrinks as niter grows. The value is removing the last serial loop in an otherwise parallel init, most visible for large n with many centroids. Pull Request resolved: #5457 Reviewed By: mnorris11 Differential Revision: D115373675 Pulled By: alibeklfc fbshipit-source-id: 485236ed4eb4310480ef4f48a20a731597d07e33
1 parent 151452e commit 2688c34

1 file changed

Lines changed: 5 additions & 2 deletions

File tree

faiss/impl/ClusteringInitialization.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -235,8 +235,11 @@ void ClusteringInitialization::init_kmeans_plus_plus(
235235
float* new_centroid = centroids + c * d;
236236
std::memcpy(new_centroid, x + next_idx * d, d * sizeof(float));
237237

238-
// Update min distances incrementally
239-
for (size_t i = 0; i < n; i++) {
238+
// Update min distances incrementally. The writes are independent,
239+
// so the loop parallelizes without changing the output.
240+
const int64_t ni = static_cast<int64_t>(n);
241+
#pragma omp parallel for
242+
for (int64_t i = 0; i < ni; i++) {
240243
double dist = fvec_L2sqr<SL>(x + i * d, new_centroid, d);
241244
min_distances[i] = std::min(min_distances[i], dist);
242245
}

0 commit comments

Comments
 (0)