Skip to content

Commit a94f8c5

Browse files
committed
Merge branch 'fix/sonatype' of github.com:rapidsai/cuvs into fix/sonatype
2 parents 0fbdc3b + c5060bb commit a94f8c5

25 files changed

Lines changed: 1620 additions & 427 deletions

cpp/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,7 @@ if(NOT BUILD_CPU_ONLY)
11771177
${iface_pq_inst_files}
11781178
src/neighbors/detail/cagra/topk_for_cagra/topk.cu
11791179
${cuvs_cagra_search_cuda_inst_files}
1180+
src/neighbors/detail/cagra/cagra_helpers.cpp
11801181
src/neighbors/dynamic_batching.cu
11811182
src/neighbors/composite/index.cu
11821183
$<$<BOOL:${BUILD_CAGRA_HNSWLIB}>:src/neighbors/cagra.cpp>

cpp/bench/ann/src/cuvs/cuvs_cagra_hnswlib.cu

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

@@ -40,38 +40,8 @@ auto parse_build_param(const nlohmann::json& conf) ->
4040

4141
// Reuse the CAGRA wrapper params parser
4242
::parse_build_param<T, IdxT>(conf, cagra_params);
43-
// If the users provides parameter M, we can use the CAGRA-HNSW heuristics to find optimal
44-
// parameters for the dataset and HNSW reference.
45-
if (conf.contains("M")) {
46-
// Postpone the parsing of the CAGRA build params until the dataset extents are known.
47-
// We the default parameters depend on the dataset extents; and we still would like to be able
48-
// to override them.
49-
cagra_params.cagra_params = [conf, hnsw_params](raft::matrix_extent<int64_t> extents,
50-
cuvs::distance::DistanceType dist_type) {
51-
auto ps = cuvs::neighbors::cagra::index_params::from_hnsw_params(
52-
extents,
53-
conf.at("M"),
54-
hnsw_params.ef_construction,
55-
cuvs::neighbors::cagra::hnsw_heuristic_type::SAME_GRAPH_FOOTPRINT,
56-
dist_type);
57-
ps.metric = dist_type;
58-
// Parse ACE parameters if provided
59-
if (conf.contains("npartitions") || conf.contains("build_dir") ||
60-
conf.contains("ef_construction") || conf.contains("use_disk")) {
61-
auto ace_params = cuvs::neighbors::cagra::graph_build_params::ace_params();
62-
if (conf.contains("npartitions")) { ace_params.npartitions = conf.at("npartitions"); }
63-
if (conf.contains("build_dir")) { ace_params.build_dir = conf.at("build_dir"); }
64-
if (conf.contains("ef_construction")) {
65-
ace_params.ef_construction = conf.at("ef_construction");
66-
}
67-
if (conf.contains("use_disk")) { ace_params.use_disk = conf.at("use_disk"); }
68-
ps.graph_build_params = ace_params;
69-
}
70-
// NB: above, we only provide the defaults. Below we parse the explicit parameters as usual.
71-
::parse_build_param<T, uint32_t>(conf, ps);
72-
return ps;
73-
};
74-
}
43+
44+
if (conf.contains("M")) { hnsw_params.M = conf.at("M"); }
7545
return param;
7646
}
7747

cpp/bench/ann/src/cuvs/cuvs_cagra_hnswlib_wrapper.h

Lines changed: 3 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: Copyright (c) 2023-2025, NVIDIA CORPORATION.
2+
* SPDX-FileCopyrightText: Copyright (c) 2023-2026, NVIDIA CORPORATION.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55
#pragma once
@@ -85,38 +85,9 @@ void cuvs_cagra_hnswlib<T, IdxT>::build(const T* dataset, size_t nrow)
8585
// when the data set is on host, we can pass it directly to HNSW
8686
bool dataset_is_on_host = raft::get_device_for_address(dataset) == -1;
8787

88-
// re-use the CAGRA wrapper to parse build params
89-
auto bps = build_param_.cagra_build_params;
90-
// Not very conveniently, the CAGRA wrapper resolves parameters after the dataset shape is known,
91-
// so it takes a lambda to do it. Even though we know the shape, we want to use the wrapper as-is,
92-
// so we just modify that lambda.
93-
bps.cagra_params = [dataset_is_on_host, orig_cagra_params = bps.cagra_params](
94-
auto dataset_extents, auto metric) {
95-
auto params = orig_cagra_params(dataset_extents, metric);
96-
params.attach_dataset_on_build = !dataset_is_on_host;
97-
return params;
98-
};
99-
cuvs_cagra<T, IdxT> cagra_wrapper{this->metric_, this->dim_, bps};
100-
101-
// build the CAGRA index
102-
cagra_wrapper.build(dataset, nrow);
103-
auto& cagra_index = *cagra_wrapper.get_index();
104-
105-
// pass the dataset directly to HNSW if it's on the host
106-
std::optional<raft::host_matrix_view<const T, int64_t>> opt_dataset_view = std::nullopt;
107-
if (dataset_is_on_host) {
108-
opt_dataset_view.emplace(
109-
raft::make_host_matrix_view<const T, int64_t>(dataset, nrow, this->dim_));
110-
}
111-
88+
auto dataset_view = raft::make_host_matrix_view<const T, int64_t>(dataset, nrow, this->dim_);
11289
// convert the index to HNSW format
113-
hnsw_index_ = cuvs::neighbors::hnsw::from_cagra(
114-
handle_, build_param_.hnsw_index_params, cagra_index, opt_dataset_view);
115-
116-
// special treatment in save/serialize step
117-
if (cagra_index.dataset_fd().has_value() && cagra_index.graph_fd().has_value()) {
118-
cagra_ace_build_ = true;
119-
}
90+
hnsw_index_ = cuvs::neighbors::hnsw::build(handle_, build_param_.hnsw_index_params, dataset_view);
12091
}
12192

12293
template <typename T, typename IdxT>

cpp/include/cuvs/neighbors/cagra.hpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3245,6 +3245,38 @@ namespace neighbors {
32453245
namespace cagra {
32463246
namespace helpers {
32473247

3248+
/** Calculates the workspace for graph optimization
3249+
*
3250+
* @param[in] n_rows number of rows in the dataset (or number of points in the graph)
3251+
* @param[in] graph_degree degree of the output graph
3252+
* @param[in] intermediate_graph_degree degree of the input graph for the optimization process
3253+
* @param[in] index_size
3254+
* @param[in] mst_optimize whether to use MST optimization
3255+
* @return tuple of [host_size, device_size, host_fixed_size, device_fixed_size] memory sizes in
3256+
* bytes
3257+
*/
3258+
std::tuple<size_t, size_t, size_t, size_t> optimize_workspace_size(size_t n_rows,
3259+
size_t graph_degree,
3260+
size_t intermediate_degree,
3261+
size_t index_size,
3262+
bool mst_optimize = false);
3263+
3264+
/**
3265+
* Calculate memory usage of CAGRA build.
3266+
*
3267+
* @param[in] res raft resource
3268+
* @param[in] dataset shape of the dataset
3269+
* @param[in] dtype element type of the dataset
3270+
* (e.g. `CUDA_R_32F`, `CUDA_R_16F`, `CUDA_R_8I`, `CUDA_R_8U`)
3271+
* @param[in] cparams CAGRA index building parameters
3272+
*
3273+
* @return pair of [host_size, device_size] memory sizes in bytes
3274+
*/
3275+
std::pair<size_t, size_t> cagra_build_mem_usage(raft::resources const& res,
3276+
raft::matrix_extent<int64_t> dataset,
3277+
cudaDataType_t dtype,
3278+
cuvs::neighbors::cagra::index_params cparams);
3279+
32483280
/**
32493281
* @brief Optimize a KNN graph into a CAGRA graph.
32503282
*

cpp/include/cuvs/neighbors/ivf_pq.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3294,6 +3294,18 @@ void make_rotation_matrix(
32943294
raft::device_matrix_view<float, uint32_t, raft::row_major> rotation_matrix,
32953295
bool force_random_rotation);
32963296

3297+
/** Calculate the size of the compressed dataset.
3298+
*
3299+
* @param[in] res raft resource
3300+
* @param[in] dataset shape of the dataset
3301+
* @param[in] param ivf-pq compression params
3302+
*
3303+
* @return compressed dataset size in bytes
3304+
*/
3305+
size_t compressed_dataset_size(raft::resources const& res,
3306+
raft::matrix_extent<int64_t> dataset,
3307+
cuvs::neighbors::ivf_pq::index_params params);
3308+
32973309
/**
32983310
* @brief Resize an IVF-PQ list with flat layout.
32993311
*
@@ -3355,6 +3367,7 @@ void resize_list(raft::resources const& res,
33553367
const list_spec_interleaved<uint32_t, int64_t>& spec,
33563368
uint32_t new_used_size,
33573369
uint32_t old_used_size);
3370+
33583371
/**
33593372
* @}
33603373
*/

cpp/include/cuvs/neighbors/nn_descent.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
#include <cuvs/core/cuda_fp16.hpp>
2020
#include <cuvs/core/export.hpp>
2121

22+
#include <utility>
23+
2224
namespace CUVS_EXPORT cuvs {
2325
namespace neighbors {
2426
namespace nn_descent {
@@ -535,6 +537,24 @@ bool has_enough_device_memory(raft::resources const& res,
535537
raft::matrix_extent<int64_t> dataset,
536538
size_t idx_size = 4);
537539

540+
/**
541+
* @brief Estimate the host and device memory (in bytes) required to build an
542+
* all-neighbors kNN graph with NN-descent for a dataset of the given shape.
543+
*
544+
* The estimate mirrors the persistent allocations performed by the GNND solver.
545+
* It does not include the input dataset nor the output graph.
546+
*
547+
* @param res
548+
* @param dataset shape of the dataset
549+
* @param graph_degree the degree of the all-neighbors graph
550+
* @param idx_size the size of the graph index type in bytes
551+
* @return std::pair<host_bytes, device_bytes>
552+
*/
553+
std::pair<size_t, size_t> build_mem_usage(raft::resources const& res,
554+
raft::matrix_extent<int64_t> dataset,
555+
size_t graph_degree,
556+
size_t idx_size = 4);
557+
538558
} // namespace nn_descent
539559
} // namespace neighbors
540560
} // namespace CUVS_EXPORT cuvs

cpp/src/cluster/detail/kmeans_balanced.cuh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -743,7 +743,6 @@ void build_clusters(const raft::resources& handle,
743743
const MathT* dataset_norm = nullptr)
744744
{
745745
auto stream = raft::resource::get_cuda_stream(handle);
746-
747746
// "randomly" initialize labels
748747
auto labels_view = raft::make_device_vector_view<LabelT, IdxT>(cluster_labels, n_rows);
749748
raft::linalg::map_offset(
@@ -886,7 +885,10 @@ auto build_fine_clusters(const raft::resources& handle,
886885
{
887886
auto stream = raft::resource::get_cuda_stream(handle);
888887
rmm::device_uvector<IdxT> mc_trainset_ids_buf(mesocluster_size_max, stream, managed_memory);
889-
rmm::device_uvector<MathT> mc_trainset_buf(mesocluster_size_max * dim, stream, device_memory);
888+
// for small cluster counts the maximum mesocluster size is proportional to the number of rows, so
889+
// we use large workspace
890+
auto large_ws = raft::resource::get_large_workspace_resource_ref(handle);
891+
rmm::device_uvector<MathT> mc_trainset_buf(mesocluster_size_max * dim, stream, large_ws);
890892
rmm::device_uvector<MathT> mc_trainset_norm_buf(mesocluster_size_max, stream, device_memory);
891893
auto mc_trainset_ids = mc_trainset_ids_buf.data();
892894
auto mc_trainset = mc_trainset_buf.data();

0 commit comments

Comments
 (0)