Repository navigation
[FEA] Binary IVF Flat Index - #1099
tarang-jain wants to merge 192 commits into
Conversation
|
Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually. Contributors can view more details about this message here. |
…nto binary-kmeans
|
/ok to test 1aa722d |
|
/ok to test 64d103b |
tfeher
left a comment
There was a problem hiding this comment.
Hi Tarang, I have looked through the PR again. Overall the ivf_flat::search() implementation looks good.
My main concern is that the balanced kmeans method is inefficient because it expands the bits. But I think it is better to treat that in a separate PR.
A few additional issues:
- the benchmark wrapper should be updated to have a binary option for IVF-Flat.
- Ideally we should use the dataset API to represent the binary quantized input.
| handle, kmeans_params, trainset_const_view, decoded_centers_view, raft::identity_op{}); | ||
|
|
||
| // Convert decoded centers back to binary format | ||
| cuvs::preprocessing::quantize::binary::quantizer<float> temp_quantizer(handle); |
There was a problem hiding this comment.
We don't train temp_quantizer because the centers are guaranteed to be +/-1?
There was a problem hiding this comment.
we must use the same method we used to expand the data, right? temp_quantizer need not be trained since we must use zero as the binary threshold.
This index does not yet use the datasets API, no? So this would mean a much bigger change. Shall we do that in a follow-up for IVF-Flat as a whole? |
I will do this in a follow-up. I want to keep this PR limited to the index itself since it is easier to review. |
I am fine with that. But I would like to hear @achirkin's opinion, because he had some issues in his previous review regarding how the binary quantized data is represented. |
|
I've dug into the matter and this case turns out to be more interesting than I initially thought. I believe we have two ways to integrate this into the dataset API. In both cases I assume the spec-based dataset struct from #2858
I think both cases make sense, but it's not clear which is better, because I don't know the target use case. Do we want to compute symmetric Hamming distance (1) or have an option to quantize the query during search or compute asymetric distance (similar to IVF-PQ) (2). |
|
@achirkin this PR currently does symmetric distances (so the query is already pre-quantized). But I agree that we can have asymmetric too. The only important piece would be to use the exact same quantizer that was used to quantize the training data. |
|
Thanks @tarang-jain , I've noticed it does symmetric distance now. I'm asking what is the original use case for this? Because I think the answer to that should determine whether we want to go route 1 or 2 from my message above. Anyway, let me know if you consider any of the two mergeable or your concerns otherwise. |
|
@achirkin I have studied your PRs and I am more inclined to use the new IVF Binary index. It seems much cleaner and simpler and having a new index type for a new quantization regime is along the same lines as IVF-PQ and IVF-RaBitQ. It will also avoid having to keep two getters: binary_centers() and centers() inside IVF Flat. About the search API, currently I would say we can stick to SDC. The user can binary quantize the queries themselves using our binary quantizer. And just using SDC should not deter us from introducing the new index type for binary datasets. Note however that there might be some inconsistency wrt cagra and nn descent which support bitwise hamming metric, but do not explicitly call their datasets "binary". |
Binary dataset and new binary ivf index.
|
/ok to test 54b8d65 |
achirkin
left a comment
There was a problem hiding this comment.
Yes, my main concern about binary-as-quantized-dataset path is that the primary API for all other indices is ADC search, and this one becomes SDC. However, I think we can bolt ADC later for API completeness.
Also couples suggestions below to fix small inconsistencies in the changes that I rushed in in my refactor.
| /** The number of bits in each vector. */ | ||
| uint32_t dim() const noexcept; | ||
| /** The number of bytes in each encoded vector. */ | ||
| uint32_t encoded_dim() const noexcept; |
There was a problem hiding this comment.
Would it make sense to rename it to something like storage_dim to make it clear that the member has to do with the underlying bytes rather than binary encoding?
| struct index : cuvs::neighbors::index { | ||
| using index_params_type = ivf_binary::index_params; | ||
| using search_params_type = ivf_binary::search_params; | ||
| using index_type = int64_t; |
There was a problem hiding this comment.
Shall we keep it IdxT template defaulted to int64_t for symmetry with other indices?
Depends on NVIDIA/raft#2770
Implementation of binary ivf flat index (bitwise hamming metric for the IVF Flat index)
Key Features
1. Binary Index Structure
binary_centers_field to store cluster centers as packeduint8_tarrays for binary datauint8_tinputs with BitwiseHamming and add only single instantiations of newly added kernels2. K-means Clustering for Binary Data
The clustering approach for binary data required special handling:
Expanded Space Clustering: Binary data (uint8_t) is expanded to signed representation (int8_t) where each bit becomes ±1
Centroid Quantization: After computing float centroids in expanded space, they are converted back to binary format:
3. Distance Kernels
Coarse Search (Cluster Selection)
bitwise_hamming_distance_opfor query-to-centroid distances in order to computePairwiseDistancesFine-Grained Search (Within Clusters)
Extended the interleaved scan kernel (
ivf_flat_interleaved_scan.cuh) with specialized templates for BitwiseHamming:Veclen-based optimization: Different code paths based on vectorization width
uint32_t, use__popc(x ^ y)for 4-byte Hamming distanceEfficient memory access patterns:
loadAndComputeDisttemplates foruint8_tthat leverage vectorized loadscuvs-bench Benchmarks (latency):



