-
Notifications
You must be signed in to change notification settings - Fork 107
Serialize Vamana index with SSD sector alignment per MSFT DiskANN format, generate quantized dataset for integration with DiskANN #846
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: branch-25.08
Are you sure you want to change the base?
Changes from 41 commits
8c650ab
bad5463
ac4199f
4b6a4d4
c931f87
765ffcd
d8b1101
0bf35ee
d0aabc6
6e5d908
90eaf18
42630fe
38646cf
81cbd56
62b1392
44f479b
a40237e
673c087
f78ebcb
31a1ddb
b0feec1
912a651
40beb58
f38fd45
9118ad2
957fee1
5b1bc2e
bc1c546
7ba37ab
7901903
ce7b0d6
f4b3d9d
ed1e90d
6a36cfc
a716f7d
8464d13
868e6cb
910b465
c8660f2
e6078db
3fec92e
57d8554
950e5ca
7a92b2e
26feaaf
d36f91c
e84cbf0
111b7c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,6 +53,17 @@ namespace cuvs::neighbors::vamana { | |
*/ | ||
|
||
struct index_params : cuvs::neighbors::index_params { | ||
/** | ||
* @brief Parameters used to build quantized DiskANN index; to be generated using | ||
* deserialize_codebooks() | ||
*/ | ||
template <typename T = float> | ||
struct codebook_params { | ||
int pq_codebook_size; | ||
int pq_dim; | ||
std::vector<T> pq_encoding_table; | ||
std::vector<T> rotation_matrix; | ||
}; | ||
/** Maximum degree of output graph corresponds to the R parameter in the original Vamana | ||
* literature. */ | ||
uint32_t graph_degree = 32; | ||
|
@@ -72,6 +83,8 @@ struct index_params : cuvs::neighbors::index_params { | |
uint32_t queue_size = 127; | ||
/** Max batchsize of reverse edge processing (reduces memory footprint) */ | ||
uint32_t reverse_batchsize = 1000000; | ||
/** Codebooks and related parameters */ | ||
std::optional<codebook_params<float>> codebooks = std::nullopt; | ||
}; | ||
|
||
/** | ||
|
@@ -127,6 +140,13 @@ struct index : cuvs::neighbors::index { | |
return *dataset_; | ||
} | ||
|
||
/** Quantized dataset [size, codes_rowlen] */ | ||
[[nodiscard]] inline auto quantized_data() const noexcept | ||
-> raft::device_matrix_view<const uint8_t, int64_t, raft::row_major> | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wanted to model this function after There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The return type of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I agree that it would be nice to let users avoid the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah I did not realize that data() returns a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated to const |
||
return quantized_dataset_.view(); | ||
} | ||
|
||
/** vamana graph [size, graph-degree] */ | ||
[[nodiscard]] inline auto graph() const noexcept | ||
-> raft::device_matrix_view<const IdxT, int64_t, raft::row_major> | ||
|
@@ -150,7 +170,8 @@ struct index : cuvs::neighbors::index { | |
: cuvs::neighbors::index(), | ||
metric_(metric), | ||
graph_(raft::make_device_matrix<IdxT, int64_t>(res, 0, 0)), | ||
dataset_(new cuvs::neighbors::empty_dataset<int64_t>(0)) | ||
dataset_(new cuvs::neighbors::empty_dataset<int64_t>(0)), | ||
quantized_dataset_(raft::make_device_matrix<uint8_t, int64_t>(res, 0, 0)) | ||
{ | ||
} | ||
|
||
|
@@ -168,6 +189,7 @@ struct index : cuvs::neighbors::index { | |
metric_(metric), | ||
graph_(raft::make_device_matrix<IdxT, int64_t>(res, 0, 0)), | ||
dataset_(make_aligned_dataset(res, dataset, 16)), | ||
quantized_dataset_(raft::make_device_matrix<uint8_t, int64_t>(res, 0, 0)), | ||
medoid_id_(medoid_id) | ||
{ | ||
RAFT_EXPECTS(dataset.extent(0) == vamana_graph.extent(0), | ||
|
@@ -212,11 +234,28 @@ struct index : cuvs::neighbors::index { | |
graph_view_ = graph_.view(); | ||
} | ||
|
||
/** | ||
* @brief Replace the current quantized dataset with a new quantized dataset. | ||
* | ||
* Ownership of the new quantized dataset is transferred to the index. | ||
* | ||
* @param[in] res | ||
* @param[in] new_quantized_dataset the new quantized dataset for the index | ||
* | ||
*/ | ||
void update_quantized_dataset( | ||
raft::resources const& res, | ||
raft::device_matrix<uint8_t, int64_t, raft::row_major>&& new_quantized_dataset) | ||
{ | ||
quantized_dataset_ = new_quantized_dataset; | ||
} | ||
|
||
private: | ||
cuvs::distance::DistanceType metric_; | ||
raft::device_matrix<IdxT, int64_t, raft::row_major> graph_; | ||
raft::device_matrix_view<const IdxT, int64_t, raft::row_major> graph_view_; | ||
std::unique_ptr<neighbors::dataset<int64_t>> dataset_; | ||
raft::device_matrix<uint8_t, int64_t, raft::row_major> quantized_dataset_; | ||
IdxT medoid_id_; | ||
}; | ||
/** | ||
|
@@ -457,13 +496,15 @@ auto build(raft::resources const& res, | |
* @param[in] file_prefix prefix of path and name of index files | ||
* @param[in] index Vamana index | ||
* @param[in] include_dataset whether or not to serialize the dataset | ||
* @param[in] sector_aligned whether output file should be aligned to disk sectors of 4096 bytes | ||
* | ||
*/ | ||
|
||
void serialize(raft::resources const& handle, | ||
const std::string& file_prefix, | ||
const cuvs::neighbors::vamana::index<float, uint32_t>& index, | ||
bool include_dataset = true); | ||
bool include_dataset = true, | ||
bool sector_aligned = false); | ||
|
||
/** | ||
* Save the index to file. | ||
|
@@ -486,12 +527,14 @@ void serialize(raft::resources const& handle, | |
* @param[in] file_prefix prefix of path and name of index files | ||
* @param[in] index Vamana index | ||
* @param[in] include_dataset whether or not to serialize the dataset | ||
* @param[in] sector_aligned whether output file should be aligned to disk sectors of 4096 bytes | ||
* | ||
*/ | ||
void serialize(raft::resources const& handle, | ||
const std::string& file_prefix, | ||
const cuvs::neighbors::vamana::index<int8_t, uint32_t>& index, | ||
bool include_dataset = true); | ||
bool include_dataset = true, | ||
bool sector_aligned = false); | ||
|
||
/** | ||
* Save the index to file. | ||
|
@@ -514,12 +557,48 @@ void serialize(raft::resources const& handle, | |
* @param[in] file_prefix prefix of path and name of index files | ||
* @param[in] index Vamana index | ||
* @param[in] include_dataset whether or not to serialize the dataset | ||
* @param[in] sector_aligned whether output file should be aligned to disk sectors of 4096 bytes | ||
* | ||
*/ | ||
void serialize(raft::resources const& handle, | ||
const std::string& file_prefix, | ||
const cuvs::neighbors::vamana::index<uint8_t, uint32_t>& index, | ||
bool include_dataset = true); | ||
bool include_dataset = true, | ||
bool sector_aligned = false); | ||
|
||
/** | ||
* @} | ||
*/ | ||
|
||
/** | ||
* @defgroup vamana_cpp_codebook Vamana codebook functions | ||
* @{ | ||
*/ | ||
|
||
/** | ||
* @brief Construct codebook parameters from input codebook files | ||
* | ||
* Expects pq pivots file at | ||
* "${codebook_prefix}_pq_pivots.bin" and rotation matrix file at | ||
* "${codebook_prefix}_pq_pivots.bin_rotation_matrix.bin". | ||
* | ||
* @code{.cpp} | ||
* #include <cuvs/neighbors/vamana.hpp> | ||
* | ||
* // create a string with a filepath | ||
* std::string codebook_prefix("/path/to/index/prefix"); | ||
* // define dimension of vectors in dataset | ||
* int dim = 64; | ||
* // construct codebook parameters from input codebook files | ||
* auto codebooks = cuvs::neighbors::vamana::deserialize_codebooks(codebook_prefix, dim); | ||
* @endcode | ||
* | ||
* @param[in] codebook_prefix path prefix to pq pivots and rotation matrix files | ||
* @param[in] dim dimension of vectors in dataset | ||
* | ||
*/ | ||
auto deserialize_codebooks(const std::string& codebook_prefix, const int dim) | ||
-> index_params::codebook_params<float>; | ||
|
||
/** | ||
* @} | ||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will only work in GitHub Actions and will fail when reproducing CI locally. We need a solution that doesn't involve
${GITHUB_WORKSPACE}
.I would make the
get_test_data.sh
script aware of${RAPIDS_DATASET_ROOT_DIR}
. That way it has a default location in which it downloads, and you can continue to call that script from the repository root with./cpp/tests/get_test_data.sh
. Avoid changing directories if you can, just to keep this script cleaner.Also I would consider moving
get_test_data.sh
to a different folder. cuGraph uses adatasets/
directory to manage these scripts, which is good. https://github.com/rapidsai/cugraph/tree/branch-25.08/datasets Otherwise you could put it inci/
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoided
${GITHUB_WORKSPACE}
, movedget_test_data.sh
toci/
(there doesn't seem to be an existing location that's more fitting), letget_test_data.sh
get the download path from${RAPIDS_DATASET_ROOT_DIR}
if defined.