Skip to content

Commit 78e59a6

Browse files
authored
Merge pull request #2356 from NVIDIA/release/26.08
Forward-merge release/26.08 into main
2 parents 59e6376 + ab79f9a commit 78e59a6

22 files changed

Lines changed: 141 additions & 142 deletions

File tree

c/include/cuvs/cluster/kmeans.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -112,7 +112,7 @@ struct cuvsKMeansParams {
112112
* Number of samples to process per GPU batch for the batched (host-data) API.
113113
* When set to 0, defaults to n_samples (process all at once).
114114
*/
115-
int64_t streaming_batch_size;
115+
int64_t device_buffer_samples;
116116

117117
/**
118118
* Number of samples to draw for KMeansPlusPlus initialization.
@@ -191,7 +191,7 @@ struct cuvsKMeansParams {
191191
* Number of samples to process per GPU batch for the batched (host-data) API.
192192
* When set to 0, defaults to n_samples (process all at once).
193193
*/
194-
int64_t streaming_batch_size;
194+
int64_t device_buffer_samples;
195195

196196
/**
197197
* Number of samples to draw for KMeansPlusPlus initialization.
@@ -267,8 +267,8 @@ typedef enum { CUVS_KMEANS_TYPE_KMEANS = 0, CUVS_KMEANS_TYPE_KMEANS_BALANCED = 1
267267
* k-means++ algorithm.
268268
*
269269
* X may reside on either host (CPU) or device (GPU) memory.
270-
* When X is on the host the data is streamed to the GPU in
271-
* batches controlled by params->streaming_batch_size.
270+
* When X is on the host the data is buffered to the GPU in
271+
* batches controlled by params->device_buffer_samples.
272272
*
273273
* @note In cuVS 26.08 (next ABI major version) this signature will be
274274
* replaced by cuvsKMeansFit_v2.

c/src/cluster/kmeans.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2025-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -31,7 +31,7 @@ cuvs::cluster::kmeans::params convert_params(const ParamsT& params)
3131
kmeans_params.batch_samples = params.batch_samples;
3232
kmeans_params.batch_centroids = params.batch_centroids;
3333
kmeans_params.init_size = params.init_size;
34-
kmeans_params.streaming_batch_size = params.streaming_batch_size;
34+
kmeans_params.device_buffer_samples = params.device_buffer_samples;
3535
return kmeans_params;
3636
}
3737

@@ -243,7 +243,7 @@ extern "C" cuvsError_t cuvsKMeansParamsCreate(cuvsKMeansParams_t* params)
243243
.inertia_check = false,
244244
.hierarchical = false,
245245
.hierarchical_n_iters = static_cast<int>(cpp_balanced_params.n_iters),
246-
.streaming_batch_size = cpp_params.streaming_batch_size,
246+
.device_buffer_samples = cpp_params.device_buffer_samples,
247247
.init_size = cpp_params.init_size};
248248
});
249249
}
@@ -315,7 +315,7 @@ extern "C" cuvsError_t cuvsKMeansParamsCreate_v2(cuvsKMeansParams_v2_t* params)
315315
.batch_centroids = cpp_params.batch_centroids,
316316
.hierarchical = false,
317317
.hierarchical_n_iters = static_cast<int>(cpp_balanced_params.n_iters),
318-
.streaming_batch_size = cpp_params.streaming_batch_size,
318+
.device_buffer_samples = cpp_params.device_buffer_samples,
319319
.init_size = cpp_params.init_size};
320320
});
321321
}

c/src/cluster/mg_kmeans.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ cuvs::cluster::kmeans::params convert_params(const ParamsT& params)
3737
kmeans_params.batch_samples = params.batch_samples;
3838
kmeans_params.batch_centroids = params.batch_centroids;
3939
kmeans_params.init_size = params.init_size;
40-
kmeans_params.streaming_batch_size = params.streaming_batch_size;
40+
kmeans_params.device_buffer_samples = params.device_buffer_samples;
4141
return kmeans_params;
4242
}
4343

c/tests/cluster/kmeans_c.cu

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -128,7 +128,7 @@ void test_fit_predict()
128128
params->max_iter = 100;
129129
params->tol = 1e-6;
130130
params->init = Array;
131-
params->streaming_batch_size = 0;
131+
params->device_buffer_samples = 0;
132132

133133
DLManagedTensor dataset_t{};
134134
cuvs::core::to_dlpack(
@@ -195,7 +195,7 @@ void test_fit_host()
195195
params->max_iter = 100;
196196
params->tol = 1e-6;
197197
params->init = Array;
198-
params->streaming_batch_size = 4; // force at least 2 streamed batches
198+
params->device_buffer_samples = 4; // force at least 2 streamed batches
199199

200200
DLManagedTensor dataset_t{};
201201
cuvs::core::to_dlpack(

c/tests/cluster/kmeans_mg_c.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ void test_mg_fit_host()
7777
params->max_iter = 100;
7878
params->tol = 1e-6;
7979
params->init = Array;
80-
params->streaming_batch_size = 4; // force at least 2 streamed batches
80+
params->device_buffer_samples = 4; // force at least 2 streamed batches
8181

8282
DLManagedTensor dataset_t{};
8383
cuvs::core::to_dlpack(raft::make_host_matrix_view<float, int64_t>(

cpp/include/cuvs/cluster/kmeans.hpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,8 @@ struct params : base_params {
113113
* Default tile is [batch_samples x n_clusters] i.e. when batch_centroids is 0
114114
* then don't tile the centroids
115115
*
116-
* NB: These parameters are unrelated to streaming_batch_size, which controls how many
117-
* samples to transfer from host to device per batch when processing out-of-core
118-
* data.
116+
* NB: These parameters are unrelated to device_buffer_samples, which specifies the number of
117+
* training vectors that get buffered on device when the training vectors are passed in on host.
119118
*/
120119
int batch_samples = 1 << 15;
121120

@@ -154,7 +153,7 @@ struct params : base_params {
154153
* count. This is is ignored by device-data overloads.
155154
* Default: 0 (process all data at once).
156155
*/
157-
int64_t streaming_batch_size = 0;
156+
int64_t device_buffer_samples = 0;
158157
};
159158

160159
/**
@@ -239,7 +238,7 @@ enum class kmeans_type { KMeans = 0, KMeansBalanced = 1 };
239238
*
240239
* This overload supports out-of-core computation where the dataset resides
241240
* on the host. Data is processed in batches, streaming from host to
242-
* device. The batch size is controlled by `params.streaming_batch_size`.
241+
* device. The batch size is controlled by `params.device_buffer_samples`.
243242
*
244243
* Multi-GPU dispatch is selected automatically based on the handle state:
245244
* - If `raft::resource::is_multi_gpu(handle)` (cuVS SNMG): the full dataset X
@@ -261,7 +260,7 @@ enum class kmeans_type { KMeans = 0, KMeansBalanced = 1 };
261260
* raft::resources handle;
262261
* cuvs::cluster::kmeans::params params;
263262
* params.n_clusters = 100;
264-
* params.streaming_batch_size = 100000;
263+
* params.device_buffer_samples = 100000;
265264
* float inertia;
266265
* int64_t n_iter;
267266
*
@@ -285,7 +284,7 @@ enum class kmeans_type { KMeans = 0, KMeansBalanced = 1 };
285284
* @param[in] handle The raft handle. When a multi-GPU resource is
286285
* attached, multi-GPU dispatch is used automatically.
287286
* @param[in] params Parameters for KMeans model. Batch size is read from
288-
* params.streaming_batch_size.
287+
* params.device_buffer_samples.
289288
* @param[in] X Training instances on HOST memory. The data must
290289
* be in row-major format.
291290
* [dim = n_samples x n_features]
@@ -1688,8 +1687,8 @@ void cluster_cost(
16881687
*
16891688
* Each rank supplies its local training data as a vector of partitions. For
16901689
* host-resident partitions the implementation streams each partition using
1691-
* `params.streaming_batch_size` (per rank). For device-resident partitions
1692-
* `streaming_batch_size` is ignored and each local partition is processed in full.
1690+
* `params.device_buffer_samples` (per rank). For device-resident partitions
1691+
* `device_buffer_samples` is ignored and each local partition is processed in full.
16931692
*
16941693
* The active backend is selected by the resources attached to
16951694
* `handle`:
@@ -1705,7 +1704,7 @@ void cluster_cost(
17051704
* @param[in] params K-means parameters. For host-resident
17061705
* partitions the per-rank streaming batch
17071706
* size is read from
1708-
* `params.streaming_batch_size`; it is
1707+
* `params.device_buffer_samples`; it is
17091708
* ignored for device-resident partitions.
17101709
* @param[in] X_parts Per-partition local data on this rank.
17111710
* Each entry is [n_rows_i x n_features].

cpp/src/cluster/detail/kmeans.cuh

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -588,9 +588,9 @@ void kmeans_fit(
588588

589589
raft::default_logger().set_level(pams.verbosity);
590590

591-
IndexT streaming_batch_size = static_cast<IndexT>(pams.streaming_batch_size);
592-
if (streaming_batch_size <= 0 || streaming_batch_size > static_cast<IndexT>(n_samples)) {
593-
streaming_batch_size = static_cast<IndexT>(n_samples);
591+
IndexT device_buffer_samples = static_cast<IndexT>(pams.device_buffer_samples);
592+
if (device_buffer_samples <= 0 || device_buffer_samples > static_cast<IndexT>(n_samples)) {
593+
device_buffer_samples = static_cast<IndexT>(n_samples);
594594
}
595595

596596
constexpr bool data_on_device = raft::is_device_mdspan_v<decltype(X)>;
@@ -606,13 +606,13 @@ void kmeans_fit(
606606
rmm::device_uvector<char> local_workspace(0, stream);
607607
rmm::device_uvector<char>& ws = workspace.has_value() ? workspace->get() : local_workspace;
608608

609-
if (data_on_device && streaming_batch_size != static_cast<IndexT>(n_samples)) {
609+
if (data_on_device && device_buffer_samples != static_cast<IndexT>(n_samples)) {
610610
RAFT_LOG_WARN(
611-
"KMeans: streaming_batch_size (%zu) ignored when data resides on device; using n_samples "
611+
"KMeans: device_buffer_samples (%zu) ignored when data resides on device; using n_samples "
612612
"(%zu)",
613-
static_cast<size_t>(streaming_batch_size),
613+
static_cast<size_t>(device_buffer_samples),
614614
static_cast<size_t>(n_samples));
615-
streaming_batch_size = static_cast<IndexT>(n_samples);
615+
device_buffer_samples = static_cast<IndexT>(n_samples);
616616
}
617617

618618
// Preallocate the host-side KMeans++ init sample buffer.
@@ -685,26 +685,26 @@ void kmeans_fit(
685685
DataT* new_centroids_ptr = new_centroids_buf.data();
686686

687687
auto minClusterAndDistance = raft::make_device_vector<raft::KeyValuePair<IndexT, DataT>, IndexT>(
688-
handle, streaming_batch_size);
689-
auto L2NormBatch = raft::make_device_vector<DataT, IndexT>(handle, streaming_batch_size);
690-
auto batch_weights_buf = raft::make_device_vector<DataT, IndexT>(handle, streaming_batch_size);
688+
handle, device_buffer_samples);
689+
auto L2NormBatch = raft::make_device_vector<DataT, IndexT>(handle, device_buffer_samples);
690+
auto batch_weights_buf = raft::make_device_vector<DataT, IndexT>(handle, device_buffer_samples);
691691
rmm::device_uvector<DataT> L2NormBuf_OR_DistBuf(0, stream);
692692

693693
auto centroid_sums = raft::make_device_matrix<DataT, IndexT>(handle, n_clusters, n_features);
694694
auto weight_per_cluster = raft::make_device_vector<DataT, IndexT>(handle, n_clusters);
695695
auto clustering_cost = raft::make_device_scalar<DataT>(handle, DataT{0});
696696

697-
rmm::device_uvector<char> batch_workspace(streaming_batch_size, stream);
697+
rmm::device_uvector<char> batch_workspace(device_buffer_samples, stream);
698698

699699
auto data_batches = cuvs::spatial::knn::detail::utils::make_batch_load_iterator<DataT>(
700-
handle, X.data_handle(), n_samples, n_features, streaming_batch_size, stream);
700+
handle, X.data_handle(), n_samples, n_features, device_buffer_samples, stream);
701701
// Host-path weight batches: only materialized when weights are provided and
702702
// the data resides on host
703703
std::optional<cuvs::spatial::knn::detail::utils::batch_load_iterator_dyn<DataT>> weight_batches;
704704
if constexpr (!data_on_device) {
705705
if (weight_ptr != nullptr) {
706706
weight_batches = cuvs::spatial::knn::detail::utils::make_batch_load_iterator<DataT>(
707-
handle, weight_ptr, n_samples, IndexT{1}, streaming_batch_size, stream);
707+
handle, weight_ptr, n_samples, IndexT{1}, device_buffer_samples, stream);
708708
} else {
709709
raft::matrix::fill(handle, batch_weights_buf.view(), DataT{1});
710710
}
@@ -759,11 +759,11 @@ void kmeans_fit(
759759
};
760760

761761
RAFT_LOG_DEBUG(
762-
"KMeans.fit: n_samples=%zu, n_features=%zu, n_clusters=%d, streaming_batch_size=%zu",
762+
"KMeans.fit: n_samples=%zu, n_features=%zu, n_clusters=%d, device_buffer_samples=%zu",
763763
static_cast<size_t>(n_samples),
764764
static_cast<size_t>(n_features),
765765
n_clusters,
766-
static_cast<size_t>(streaming_batch_size));
766+
static_cast<size_t>(device_buffer_samples));
767767

768768
bool need_compute_norms = metric == cuvs::distance::DistanceType::L2Expanded ||
769769
metric == cuvs::distance::DistanceType::L2SqrtExpanded;

cpp/src/cluster/detail/kmeans_mg.cuh

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,18 @@ void mnmg_fit(
188188
static_cast<size_t>(n_features),
189189
static_cast<int>(n_clusters));
190190

191-
IndexT streaming_batch_size = static_cast<IndexT>(params.streaming_batch_size);
192-
if (streaming_batch_size <= 0 || streaming_batch_size > max_part_rows) {
193-
streaming_batch_size = std::max(max_part_rows, IndexT{1});
191+
IndexT device_buffer_samples = static_cast<IndexT>(params.device_buffer_samples);
192+
if (device_buffer_samples <= 0 || device_buffer_samples > max_part_rows) {
193+
device_buffer_samples = std::max(max_part_rows, IndexT{1});
194194
}
195195

196-
if (data_on_device && streaming_batch_size < max_part_rows) {
196+
if (data_on_device && device_buffer_samples < max_part_rows) {
197197
RAFT_LOG_WARN(
198-
"MNMG KMeans: streaming_batch_size (%zu) ignored when partitions reside on device; using "
198+
"MNMG KMeans: device_buffer_samples (%zu) ignored when partitions reside on device; using "
199199
"max partition size (%zu)",
200-
static_cast<size_t>(streaming_batch_size),
200+
static_cast<size_t>(device_buffer_samples),
201201
static_cast<size_t>(max_part_rows));
202-
streaming_batch_size = max_part_rows;
202+
device_buffer_samples = max_part_rows;
203203
}
204204

205205
auto rank_centroids_arr =
@@ -212,7 +212,7 @@ void mnmg_fit(
212212
auto clustering_cost = raft::make_device_vector<DataT, IndexT>(dev_res, 1);
213213
auto batch_clustering_cost = raft::make_device_vector<DataT, IndexT>(dev_res, 1);
214214
auto sqrd_norm_error_dev = raft::make_device_scalar<DataT>(dev_res, DataT{0});
215-
IndexT alloc_batch_size = streaming_batch_size;
215+
IndexT alloc_batch_size = device_buffer_samples;
216216
auto batch_weights = raft::make_device_vector<DataT, IndexT>(dev_res, alloc_batch_size);
217217
auto minClusterAndDistance =
218218
raft::make_device_vector<raft::KeyValuePair<IndexT, DataT>, IndexT>(dev_res, alloc_batch_size);
@@ -363,7 +363,7 @@ void mnmg_fit(
363363

364364
init_centroids_for_mg_batched<DataT, IndexT, Accessor>(dev_res,
365365
iter_params,
366-
streaming_batch_size,
366+
device_buffer_samples,
367367
X_parts,
368368
n_features,
369369
input_centroids_const,
@@ -404,7 +404,7 @@ void mnmg_fit(
404404

405405
data_batch_iterator_t data_batches(dev_res,
406406
X_part,
407-
static_cast<size_t>(streaming_batch_size),
407+
static_cast<size_t>(device_buffer_samples),
408408
stream,
409409
rmm::mr::get_current_device_resource_ref(),
410410
true);
@@ -532,7 +532,7 @@ void mnmg_fit(
532532

533533
data_batch_iterator_t data_batches(dev_res,
534534
X_part,
535-
static_cast<size_t>(streaming_batch_size),
535+
static_cast<size_t>(device_buffer_samples),
536536
stream,
537537
rmm::mr::get_current_device_resource_ref(),
538538
true);

cpp/src/cluster/detail/kmeans_mg_batched_init.cuh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ template <typename DataT, typename IndexT, typename Accessor>
247247
void init_centroids_for_mg_batched(
248248
raft::resources const& handle,
249249
const cuvs::cluster::kmeans::params& params,
250-
IndexT /*streaming_batch_size*/,
250+
IndexT /*device_buffer_samples*/,
251251
const std::vector<
252252
raft::mdspan<const DataT, raft::matrix_extent<IndexT>, raft::row_major, Accessor>>& X_parts,
253253
IndexT n_features,

cpp/tests/cluster/kmeans.cu

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2022-2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

@@ -339,7 +339,7 @@ struct KmeansBatchedInputs {
339339
int n_clusters;
340340
T tol;
341341
bool weighted;
342-
int streaming_batch_size;
342+
int device_buffer_samples;
343343
};
344344

345345
template <typename T>
@@ -416,7 +416,7 @@ class KmeansFitBatchedTest : public ::testing::TestWithParam<KmeansBatchedInputs
416416
raft::make_host_scalar_view<int>(&ref_n_iter));
417417

418418
cuvs::cluster::kmeans::params batched_params = params;
419-
batched_params.streaming_batch_size = testparams.streaming_batch_size;
419+
batched_params.device_buffer_samples = testparams.device_buffer_samples;
420420

421421
std::optional<raft::host_vector_view<const T, int64_t>> h_sw = std::nullopt;
422422
auto h_sample_weight = raft::make_host_vector<T, int64_t>(testparams.weighted ? n_samples : 0);
@@ -496,15 +496,15 @@ class KmeansFitBatchedTest : public ::testing::TestWithParam<KmeansBatchedInputs
496496
auto stream = raft::resource::get_cuda_stream(handle);
497497

498498
cuvs::cluster::kmeans::params p;
499-
p.n_clusters = n_clusters;
500-
p.tol = testparams.tol;
501-
p.n_init = 1;
502-
p.init = cuvs::cluster::kmeans::params::KMeansPlusPlus;
503-
p.max_iter = 20;
504-
p.rng_state.seed = 1;
505-
p.oversampling_factor = 0;
506-
p.streaming_batch_size = testparams.streaming_batch_size;
507-
p.init_size = init_size_value;
499+
p.n_clusters = n_clusters;
500+
p.tol = testparams.tol;
501+
p.n_init = 1;
502+
p.init = cuvs::cluster::kmeans::params::KMeansPlusPlus;
503+
p.max_iter = 20;
504+
p.rng_state.seed = 1;
505+
p.oversampling_factor = 0;
506+
p.device_buffer_samples = testparams.device_buffer_samples;
507+
p.init_size = init_size_value;
508508

509509
auto d_centroids_buf = raft::make_device_matrix<T, int64_t>(handle, n_clusters, n_features);
510510
T inertia = 0;

0 commit comments

Comments
 (0)