faiss 0.6.4 → 0.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/ext/faiss/extconf.rb +1 -1
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +175 -0
- data/vendor/faiss/faiss/Clustering.cpp +150 -60
- data/vendor/faiss/faiss/Clustering.h +29 -0
- data/vendor/faiss/faiss/IVFlib.cpp +99 -0
- data/vendor/faiss/faiss/IVFlib.h +15 -0
- data/vendor/faiss/faiss/Index.cpp +44 -0
- data/vendor/faiss/faiss/Index.h +19 -14
- data/vendor/faiss/faiss/IndexBinary.cpp +8 -0
- data/vendor/faiss/faiss/IndexBinary.h +8 -0
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +82 -4
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +19 -0
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +34 -0
- data/vendor/faiss/faiss/IndexFastScan.cpp +33 -17
- data/vendor/faiss/faiss/IndexFastScan.h +6 -3
- data/vendor/faiss/faiss/IndexFlat.cpp +56 -0
- data/vendor/faiss/faiss/IndexFlat.h +31 -0
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +6 -1
- data/vendor/faiss/faiss/IndexHNSW.cpp +456 -10
- data/vendor/faiss/faiss/IndexHNSW.h +38 -0
- data/vendor/faiss/faiss/IndexIDMap.cpp +32 -0
- data/vendor/faiss/faiss/IndexIDMap.h +7 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +281 -31
- data/vendor/faiss/faiss/IndexIVF.h +53 -1
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +46 -14
- data/vendor/faiss/faiss/IndexIVFFastScan.h +4 -2
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +33 -0
- data/vendor/faiss/faiss/IndexIVFFlat.h +16 -0
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +1 -0
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +3 -20
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +50 -14
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -2
- data/vendor/faiss/faiss/IndexIVFSQFastScan.cpp +855 -0
- data/vendor/faiss/faiss/IndexIVFSQFastScan.h +145 -0
- data/vendor/faiss/faiss/IndexNNDescent.cpp +0 -3
- data/vendor/faiss/faiss/IndexPiPNN.cpp +201 -0
- data/vendor/faiss/faiss/IndexPiPNN.h +83 -0
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +6 -3
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +10 -4
- data/vendor/faiss/faiss/IndexReplicas.cpp +20 -0
- data/vendor/faiss/faiss/IndexReplicas.h +9 -0
- data/vendor/faiss/faiss/IndexSQFastScan.cpp +648 -0
- data/vendor/faiss/faiss/IndexSQFastScan.h +129 -0
- data/vendor/faiss/faiss/IndexShards.cpp +10 -0
- data/vendor/faiss/faiss/IndexShards.h +5 -0
- data/vendor/faiss/faiss/SuperKMeans.cpp +57 -15
- data/vendor/faiss/faiss/SuperKMeans.h +9 -4
- data/vendor/faiss/faiss/VectorTransform.cpp +3 -2
- data/vendor/faiss/faiss/clone_index.cpp +24 -0
- data/vendor/faiss/faiss/gpu/Dataset.h +112 -0
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +16 -13
- data/vendor/faiss/faiss/gpu/GpuCloner.h +4 -0
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +3 -0
- data/vendor/faiss/faiss/gpu/GpuIndex.h +4 -13
- data/vendor/faiss/faiss/gpu/GpuIndexBinaryCagra.h +26 -13
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +45 -22
- data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +11 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +6 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuDatasetHeader.cpp +18 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +215 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +98 -0
- data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +11 -0
- data/vendor/faiss/faiss/gpu/utils/StackDeviceMemory.cpp +1 -1
- data/vendor/faiss/faiss/gpu_metal/MetalCloner.h +11 -0
- data/vendor/faiss/faiss/gpu_metal/MetalDistance.h +92 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndex.h +4 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexBinaryFlat.h +69 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +38 -0
- data/vendor/faiss/faiss/gpu_metal/MetalKernels.h +106 -0
- data/vendor/faiss/faiss/gpu_metal/MetalPythonBridge.h +10 -0
- data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +2 -0
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -6
- data/vendor/faiss/faiss/impl/ClusteringHelpers.cpp +134 -45
- data/vendor/faiss/faiss/impl/ClusteringHelpers.h +36 -0
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +286 -136
- data/vendor/faiss/faiss/impl/DistanceComputer.cpp +63 -0
- data/vendor/faiss/faiss/impl/DistanceComputer.h +3 -29
- data/vendor/faiss/faiss/impl/HNSW.cpp +46 -10
- data/vendor/faiss/faiss/impl/HNSW.h +72 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +6 -19
- data/vendor/faiss/faiss/impl/NNDescent.cpp +2 -1
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -2
- data/vendor/faiss/faiss/impl/Panorama.h +3 -2
- data/vendor/faiss/faiss/impl/PiPNN.cpp +822 -0
- data/vendor/faiss/faiss/impl/PiPNN.h +122 -0
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +54 -11
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +1 -1
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +81 -57
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +15 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +29 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +1 -6
- data/vendor/faiss/faiss/impl/approx_topk/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/approx_topk/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryHash_impl.h +5 -2
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/binary_hamming/rvv.cpp +0 -4
- data/vendor/faiss/faiss/impl/expanded_scanners.h +88 -0
- data/vendor/faiss/faiss/impl/fast_scan/FastScanDistancePostProcessing.h +4 -0
- data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops.h +61 -64
- data/vendor/faiss/faiss/impl/fast_scan/accumulate_loops_512.h +13 -14
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +17 -129
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +25 -19
- data/vendor/faiss/faiss/impl/fast_scan/fast_scan.cpp +5 -0
- data/vendor/faiss/faiss/impl/fast_scan/impl-avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/impl-avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/impl-neon.cpp +0 -88
- data/vendor/faiss/faiss/impl/fast_scan/impl-riscv.cpp +0 -4
- data/vendor/faiss/faiss/impl/fast_scan/kernels_neon.h +155 -0
- data/vendor/faiss/faiss/impl/fast_scan/kernels_simd256.h +22 -1
- data/vendor/faiss/faiss/impl/fast_scan/kernels_simd512.h +3 -2
- data/vendor/faiss/faiss/impl/fast_scan/simd_result_handlers.h +41 -23
- data/vendor/faiss/faiss/impl/hnsw/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/hnsw/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/index_read.cpp +172 -0
- data/vendor/faiss/faiss/impl/index_write.cpp +95 -0
- data/vendor/faiss/faiss/impl/pipnn/HashPrune.cpp +159 -0
- data/vendor/faiss/faiss/impl/pipnn/HashPrune.h +69 -0
- data/vendor/faiss/faiss/impl/pipnn/Partition.cpp +587 -0
- data/vendor/faiss/faiss/impl/pipnn/Partition.h +93 -0
- data/vendor/faiss/faiss/impl/pipnn/kernels.cpp +326 -0
- data/vendor/faiss/faiss/impl/pipnn/kernels.h +92 -0
- data/vendor/faiss/faiss/impl/platform_macros.h +45 -0
- data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +79 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +6 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/neon.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx2.h +4 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-avx512.h +4 -1
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +19 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.h +6 -6
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-inl.h +131 -6
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-sve.cpp +0 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_rvv_kernel.h +89 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_scan_impl.h +21 -10
- data/vendor/faiss/faiss/impl/pq_code_distance/rvv.cpp +45 -18
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +2 -1
- data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +0 -4
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +5 -1
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +28 -52
- data/vendor/faiss/faiss/impl/scalar_quantizer/scanners.h +59 -11
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +226 -77
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +482 -103
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +2 -149
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +3 -698
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +66 -57
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +101 -96
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-rvv.cpp +3185 -144
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_coefficients.h +48 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq8_rvv_kernel.h +546 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/training.cpp +2 -2
- data/vendor/faiss/faiss/impl/simd_dispatch.h +7 -0
- data/vendor/faiss/faiss/impl/simdlib/simdlib_avx2.h +14 -0
- data/vendor/faiss/faiss/impl/simdlib/simdlib_dispatch.h +7 -8
- data/vendor/faiss/faiss/impl/sq_fastscan_utils.h +232 -0
- data/vendor/faiss/faiss/index_factory.cpp +76 -0
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +3 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +3 -2
- data/vendor/faiss/faiss/utils/AlignedTable.h +6 -1
- data/vendor/faiss/faiss/utils/Heap.cpp +4 -3
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +16 -5
- data/vendor/faiss/faiss/utils/bf16.h +36 -0
- data/vendor/faiss/faiss/utils/distances.cpp +226 -15
- data/vendor/faiss/faiss/utils/distances.h +34 -0
- data/vendor/faiss/faiss/utils/distances_dispatch.h +6 -4
- data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +2 -5
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +0 -14
- data/vendor/faiss/faiss/utils/distances_fused/rvv.cpp +25 -0
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +0 -4
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_kernel-inl.h +2 -1
- data/vendor/faiss/faiss/utils/distances_simd.cpp +9 -0
- data/vendor/faiss/faiss/utils/fp16-fp16c.h +4 -0
- data/vendor/faiss/faiss/utils/fp16-inl.h +26 -52
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +33 -5
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512_vpopcnt.h +15 -30
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-neon.h +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +2 -1
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_rvv.cpp +0 -4
- data/vendor/faiss/faiss/utils/pq_code_distance.h +8 -4
- data/vendor/faiss/faiss/utils/prefetch.h +1 -26
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +26 -27
- data/vendor/faiss/faiss/utils/quantize_lut.h +11 -0
- data/vendor/faiss/faiss/utils/rabitq_simd.h +51 -16
- data/vendor/faiss/faiss/utils/simd_impl/distances_aarch64.cpp +9 -4
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +37 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +64 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +64 -5
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +353 -71
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv_kernel.h +68 -0
- data/vendor/faiss/faiss/utils/simd_impl/exhaustive_L2sqr_blas_cmax.h +93 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels.h +76 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx2.cpp +52 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_avx512.cpp +52 -0
- data/vendor/faiss/faiss/utils/simd_impl/fp16_kernels_neon.cpp +48 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx2.h +44 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum-avx512.h +43 -0
- data/vendor/faiss/faiss/utils/simd_impl/masked_sum.h +38 -0
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/partitioning_neon.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +54 -15
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +38 -21
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512_vpopcnt.cpp +51 -14
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +297 -10
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx2.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_avx512.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +0 -4
- data/vendor/faiss/faiss/utils/simd_levels.cpp +19 -3
- data/vendor/faiss/faiss/utils/simd_levels.h +74 -1
- data/vendor/faiss/faiss/utils/transpose/transpose-avx2-inl.h +0 -4
- data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +0 -4
- data/vendor/faiss/faiss/utils/utils.cpp +80 -0
- data/vendor/faiss/faiss/utils/utils.h +24 -0
- metadata +33 -1
|
@@ -33,6 +33,7 @@ namespace faiss {
|
|
|
33
33
|
namespace gpu {
|
|
34
34
|
|
|
35
35
|
class BinaryCuvsCagra;
|
|
36
|
+
class Dataset;
|
|
36
37
|
|
|
37
38
|
struct GpuIndexBinaryCagra : public IndexBinary {
|
|
38
39
|
public:
|
|
@@ -49,22 +50,34 @@ struct GpuIndexBinaryCagra : public IndexBinary {
|
|
|
49
50
|
/// stream and handle resources on the GPU
|
|
50
51
|
std::shared_ptr<GpuResources> getResources();
|
|
51
52
|
|
|
52
|
-
///
|
|
53
|
-
/// NB: The use of the add function here is to build the CAGRA graph on
|
|
54
|
-
/// the base dataset. Use this function when you want to add vectors with
|
|
55
|
-
/// ids. Ref: https://github.com/facebookresearch/faiss/issues/4107
|
|
53
|
+
/// Pointer-based construction is unsupported. Use a caller-owned Dataset.
|
|
56
54
|
void add(idx_t n, const uint8_t* x) override;
|
|
57
|
-
|
|
58
|
-
/// Trains CAGRA based on the given vector data.
|
|
59
|
-
/// NB: The use of the train function here is to build the CAGRA graph on
|
|
60
|
-
/// the base dataset and is currently the only function to add the full set
|
|
61
|
-
/// of vectors (without IDs) to the index. There is no external quantizer to
|
|
62
|
-
/// be trained here.
|
|
63
55
|
void train(idx_t n, const uint8_t* x) override;
|
|
64
56
|
|
|
65
|
-
///
|
|
66
|
-
///
|
|
67
|
-
|
|
57
|
+
/// Build the full graph, borrowing UInt8 vectors with dim == d / 8.
|
|
58
|
+
/// The backing storage must remain alive and unchanged until all index
|
|
59
|
+
/// operations have completed. Does nothing if already trained; call reset()
|
|
60
|
+
/// before building again.
|
|
61
|
+
void train(const Dataset& dataset) override;
|
|
62
|
+
void add(const Dataset& dataset) override;
|
|
63
|
+
|
|
64
|
+
/// Rebind search storage without changing the graph. The vectors and their
|
|
65
|
+
/// ordering must match the training data. Requires compatible device data;
|
|
66
|
+
/// any padding must be zero and the caller retains ownership. Previous
|
|
67
|
+
/// work on the index stream completes before rebinding.
|
|
68
|
+
void updateDataset(const Dataset& dataset);
|
|
69
|
+
bool isSearchReady() const;
|
|
70
|
+
|
|
71
|
+
/// Copy the CPU graph. Without a Dataset, import only the graph and
|
|
72
|
+
/// metadata; attach vectors with updateDataset before search or copyTo.
|
|
73
|
+
/// If provided, dataset must describe writable, compatible storage on this
|
|
74
|
+
/// device with the CPU index's shape and UInt8 type. Copy CPU vectors into
|
|
75
|
+
/// that allocation, zero padding, and borrow it for search. The caller owns
|
|
76
|
+
/// the allocation and must keep it alive through index use. Copies complete
|
|
77
|
+
/// before return, so the CPU index can be released in either case.
|
|
78
|
+
void copyFrom(
|
|
79
|
+
const faiss::IndexBinaryHNSWCagra* index,
|
|
80
|
+
Dataset* dataset = nullptr);
|
|
68
81
|
|
|
69
82
|
/// Copy ourselves to the given CPU index; will overwrite all data
|
|
70
83
|
/// in the index instance
|
|
@@ -27,6 +27,11 @@
|
|
|
27
27
|
#include <faiss/gpu/GpuIndex.h>
|
|
28
28
|
#include <faiss/gpu/GpuIndexIVFPQ.h>
|
|
29
29
|
|
|
30
|
+
#ifndef SWIG
|
|
31
|
+
#include <faiss/gpu/Dataset.h>
|
|
32
|
+
#include <optional>
|
|
33
|
+
#endif
|
|
34
|
+
|
|
30
35
|
#include <variant>
|
|
31
36
|
#include <vector>
|
|
32
37
|
#include "faiss/Index.h"
|
|
@@ -216,7 +221,6 @@ struct GpuIndexCagraConfig : public GpuIndexConfig {
|
|
|
216
221
|
std::shared_ptr<IVFPQBuildCagraConfig> ivf_pq_params{nullptr};
|
|
217
222
|
std::shared_ptr<IVFPQSearchCagraConfig> ivf_pq_search_params{nullptr};
|
|
218
223
|
float refine_rate = 2.0f;
|
|
219
|
-
bool store_dataset = true;
|
|
220
224
|
|
|
221
225
|
/// Whether to use MST optimization to guarantee graph connectivity.
|
|
222
226
|
bool guarantee_connectivity = false;
|
|
@@ -309,28 +313,43 @@ struct GpuIndexCagra : public GpuIndex {
|
|
|
309
313
|
faiss::MetricType metric = faiss::METRIC_L2,
|
|
310
314
|
GpuIndexCagraConfig config = GpuIndexCagraConfig());
|
|
311
315
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
/// the
|
|
315
|
-
///
|
|
316
|
+
~GpuIndexCagra() override;
|
|
317
|
+
|
|
318
|
+
/// Build the full graph while borrowing dataset storage. The backing
|
|
319
|
+
/// allocation must remain alive and unchanged through index use and all
|
|
320
|
+
/// outstanding GPU work. Does nothing if already trained; call reset()
|
|
321
|
+
/// before building again.
|
|
322
|
+
void train(const Dataset& dataset) override;
|
|
323
|
+
|
|
324
|
+
/// Equivalent to train(dataset); incremental insertion is unsupported.
|
|
325
|
+
void add(const Dataset& dataset) override;
|
|
326
|
+
|
|
327
|
+
/// Attach search-compatible device storage without changing the graph.
|
|
328
|
+
/// Shape, dtype and vector ordering must match the trained dataset. The
|
|
329
|
+
/// values must be the same; this method does not rebuild for changed data.
|
|
330
|
+
/// Previous work on this index's stream completes before rebinding.
|
|
331
|
+
void updateDataset(const Dataset& dataset);
|
|
332
|
+
bool isSearchReady() const;
|
|
333
|
+
|
|
334
|
+
/// Copy the CPU graph and metadata. With no dataset, import only the
|
|
335
|
+
/// graph: no vector storage is retained and GPU search is unavailable.
|
|
336
|
+
/// When supplied, dataset must describe writable CAGRA-compatible device
|
|
337
|
+
/// storage with matching shape and dtype on this index's device. Its
|
|
338
|
+
/// contents are overwritten with CPU vectors and its padding is zeroed.
|
|
339
|
+
/// The index borrows that allocation and becomes search-ready. The caller
|
|
340
|
+
/// retains ownership and must keep the allocation alive through index use
|
|
341
|
+
/// and queued GPU work. Copies finish before return, so the CPU index may
|
|
342
|
+
/// then be released in either mode.
|
|
343
|
+
void copyFrom(
|
|
344
|
+
const faiss::IndexHNSWCagra* index,
|
|
345
|
+
Dataset* dataset = nullptr);
|
|
346
|
+
|
|
347
|
+
/// Legacy pointer entry points throw: use the Dataset overloads.
|
|
316
348
|
void add(idx_t n, const float* x) override;
|
|
317
349
|
void add_ex(idx_t n, const void* x, NumericType numeric_type) override;
|
|
318
|
-
|
|
319
|
-
/// Trains CAGRA based on the given vector data.
|
|
320
|
-
/// NB: The use of the train function here is to build the CAGRA graph on
|
|
321
|
-
/// the base dataset and is currently the only function to add the full set
|
|
322
|
-
/// of vectors (without IDs) to the index. There is no external quantizer to
|
|
323
|
-
/// be trained here.
|
|
324
350
|
void train(idx_t n, const float* x) override;
|
|
325
351
|
void train_ex(idx_t n, const void* x, NumericType numeric_type) override;
|
|
326
352
|
|
|
327
|
-
/// Initialize ourselves from the given CPU index; will overwrite
|
|
328
|
-
/// all data in ourselves
|
|
329
|
-
void copyFrom(const faiss::IndexHNSWCagra* index);
|
|
330
|
-
void copyFrom_ex(
|
|
331
|
-
const faiss::IndexHNSWCagra* index,
|
|
332
|
-
NumericType numeric_type);
|
|
333
|
-
|
|
334
353
|
/// Copy ourselves to the given CPU index; will overwrite all data
|
|
335
354
|
/// in the index instance
|
|
336
355
|
void copyTo(faiss::IndexHNSWCagra* index) const;
|
|
@@ -372,7 +391,9 @@ struct GpuIndexCagra : public GpuIndex {
|
|
|
372
391
|
/// more than one device: cuVS `all_neighbors` knn graph construction over
|
|
373
392
|
/// overlapping clusters, followed by graph pruning. Leaves the result in
|
|
374
393
|
/// merged_knngraph_ for copyTo(); index_ stays empty.
|
|
375
|
-
|
|
394
|
+
#ifndef SWIG
|
|
395
|
+
void trainAllNeighbors_(const Dataset& dataset);
|
|
396
|
+
#endif
|
|
376
397
|
|
|
377
398
|
/// Populate HNSW levels >= 1 of `index` by building a CAGRA graph over
|
|
378
399
|
/// each level's node subset on the GPU. Requires the level table to be
|
|
@@ -385,9 +406,9 @@ struct GpuIndexCagra : public GpuIndex {
|
|
|
385
406
|
/// Our configuration options
|
|
386
407
|
const GpuIndexCagraConfig cagraConfig_;
|
|
387
408
|
|
|
388
|
-
faiss::NumericType numeric_type_;
|
|
409
|
+
faiss::NumericType numeric_type_ = NumericType::Float32;
|
|
389
410
|
|
|
390
|
-
/// Instance that
|
|
411
|
+
/// Instance that owns the CAGRA graph and borrows dataset storage
|
|
391
412
|
std::variant<
|
|
392
413
|
std::monostate,
|
|
393
414
|
std::shared_ptr<CuvsCagra<float>>,
|
|
@@ -398,7 +419,9 @@ struct GpuIndexCagra : public GpuIndex {
|
|
|
398
419
|
/// Multi-GPU state: populated by trainAllNeighbors_(), used by copyTo()
|
|
399
420
|
std::vector<idx_t> merged_knngraph_;
|
|
400
421
|
idx_t merged_knngraph_degree_ = 0;
|
|
401
|
-
|
|
422
|
+
#ifndef SWIG
|
|
423
|
+
std::optional<Dataset> multiGpuDataset_;
|
|
424
|
+
#endif
|
|
402
425
|
};
|
|
403
426
|
|
|
404
427
|
} // namespace gpu
|
|
@@ -131,6 +131,17 @@ class GpuIndexFlat : public GpuIndex {
|
|
|
131
131
|
idx_t* labels,
|
|
132
132
|
const SearchParameters* params) const override;
|
|
133
133
|
|
|
134
|
+
/// Called from GpuIndex for search; Float16 queries are searched without
|
|
135
|
+
/// conversion against float16 storage
|
|
136
|
+
void searchImpl_ex_(
|
|
137
|
+
idx_t n,
|
|
138
|
+
const void* x,
|
|
139
|
+
NumericType numeric_type,
|
|
140
|
+
int k,
|
|
141
|
+
float* distances,
|
|
142
|
+
idx_t* labels,
|
|
143
|
+
const SearchParameters* params) const override;
|
|
144
|
+
|
|
134
145
|
protected:
|
|
135
146
|
/// Our configuration options
|
|
136
147
|
const GpuIndexFlatConfig flatConfig_;
|
|
@@ -32,6 +32,12 @@ struct GpuIndexIVFConfig : public GpuIndexConfig {
|
|
|
32
32
|
/// throw an exception for indices not implemented on GPU. When set to
|
|
33
33
|
/// true, it will fallback to a CPU implementation.
|
|
34
34
|
bool allowCpuCoarseQuantizer = false;
|
|
35
|
+
|
|
36
|
+
/// Break a distance tie on the smaller id, so a search repeats. Honoured
|
|
37
|
+
/// by GpuIndexIVFFlat and GpuIndexIVFScalarQuantizer with the interleaved
|
|
38
|
+
/// layout for k up to 1024, and by the cuVS GpuIndexIVFScalarQuantizer
|
|
39
|
+
/// and GpuIndexIVFPQ for k and nprobe up to 256.
|
|
40
|
+
bool deterministic_tie_break = false;
|
|
35
41
|
};
|
|
36
42
|
|
|
37
43
|
/// Base class of all GPU IVF index types. This (for now) deliberately does not
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Keep this translation unit ordinary C++ without CUDA, RAFT, or cuVS headers.
|
|
9
|
+
#include <faiss/gpu/Dataset.h>
|
|
10
|
+
|
|
11
|
+
#include <type_traits>
|
|
12
|
+
|
|
13
|
+
using faiss::gpu::Dataset;
|
|
14
|
+
|
|
15
|
+
static_assert(!std::is_copy_constructible_v<Dataset>);
|
|
16
|
+
static_assert(!std::is_copy_assignable_v<Dataset>);
|
|
17
|
+
static_assert(std::is_nothrow_move_constructible_v<Dataset>);
|
|
18
|
+
static_assert(std::is_nothrow_move_assignable_v<Dataset>);
|
|
@@ -5,14 +5,19 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
#include <faiss/Clustering.h>
|
|
8
9
|
#include <faiss/IndexFlat.h>
|
|
9
10
|
#include <faiss/gpu/GpuIndexFlat.h>
|
|
11
|
+
#include <faiss/gpu/GpuIndexIVFFlat.h>
|
|
10
12
|
#include <faiss/gpu/StandardGpuResources.h>
|
|
11
13
|
#include <faiss/gpu/impl/IndexUtils.h>
|
|
12
14
|
#include <faiss/gpu/test/TestUtils.h>
|
|
13
15
|
#include <faiss/gpu/utils/DeviceUtils.h>
|
|
14
16
|
#include <faiss/impl/IDSelector.h>
|
|
17
|
+
#include <faiss/utils/fp16.h>
|
|
15
18
|
#include <gtest/gtest.h>
|
|
19
|
+
#include <algorithm>
|
|
20
|
+
#include <cstdint>
|
|
16
21
|
#include <sstream>
|
|
17
22
|
#include <unordered_map>
|
|
18
23
|
#include <vector>
|
|
@@ -807,6 +812,216 @@ TEST(TestCuvsGpuIndexFlat, IDSelector_IP) {
|
|
|
807
812
|
}
|
|
808
813
|
#endif
|
|
809
814
|
|
|
815
|
+
// Packs float vectors as IEEE binary16, the Float16 input of search_ex
|
|
816
|
+
std::vector<uint16_t> toFp16(const std::vector<float>& v) {
|
|
817
|
+
std::vector<uint16_t> out(v.size());
|
|
818
|
+
std::transform(v.begin(), v.end(), out.begin(), [](float f) {
|
|
819
|
+
return faiss::encode_fp16(f);
|
|
820
|
+
});
|
|
821
|
+
return out;
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
std::vector<float> fromFp16(const std::vector<uint16_t>& v) {
|
|
825
|
+
std::vector<float> out(v.size());
|
|
826
|
+
std::transform(v.begin(), v.end(), out.begin(), [](uint16_t h) {
|
|
827
|
+
return faiss::decode_fp16(h);
|
|
828
|
+
});
|
|
829
|
+
return out;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
// A copy of host data on a GPU device
|
|
833
|
+
struct DeviceCopy {
|
|
834
|
+
DeviceCopy(int device, const void* src, size_t bytes) {
|
|
835
|
+
faiss::gpu::DeviceScope scope(device);
|
|
836
|
+
CUDA_VERIFY(cudaMalloc(&data, bytes));
|
|
837
|
+
CUDA_VERIFY(cudaMemcpy(data, src, bytes, cudaMemcpyHostToDevice));
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
DeviceCopy(const DeviceCopy&) = delete;
|
|
841
|
+
DeviceCopy& operator=(const DeviceCopy&) = delete;
|
|
842
|
+
|
|
843
|
+
~DeviceCopy() {
|
|
844
|
+
CUDA_VERIFY(cudaFree(data));
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
void* data = nullptr;
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
// search_ex on Float16 queries must return exactly what search returns on the
|
|
851
|
+
// float32 queries rounded to fp16, as the rounded values are what the index
|
|
852
|
+
// computes with, whether the queries are on the host (paged or not) or on the
|
|
853
|
+
// device
|
|
854
|
+
void testSearchExFloat16(faiss::gpu::GpuIndex& index) {
|
|
855
|
+
int numQuery = faiss::gpu::randVal(1, 512);
|
|
856
|
+
int k = std::min(faiss::gpu::randVal(1, 50), int(index.ntotal));
|
|
857
|
+
|
|
858
|
+
auto queries = faiss::gpu::randVecs(numQuery, index.d);
|
|
859
|
+
auto queries16 = toFp16(queries);
|
|
860
|
+
auto roundedQueries = fromFp16(queries16);
|
|
861
|
+
|
|
862
|
+
std::vector<float> refDistances(numQuery * k);
|
|
863
|
+
std::vector<faiss::idx_t> refLabels(numQuery * k);
|
|
864
|
+
index.search(
|
|
865
|
+
numQuery,
|
|
866
|
+
roundedQueries.data(),
|
|
867
|
+
k,
|
|
868
|
+
refDistances.data(),
|
|
869
|
+
refLabels.data());
|
|
870
|
+
|
|
871
|
+
auto expectSearchExMatches = [&](const void* x, const std::string& where) {
|
|
872
|
+
std::vector<float> distances(numQuery * k, 0);
|
|
873
|
+
std::vector<faiss::idx_t> labels(numQuery * k, -1);
|
|
874
|
+
index.search_ex(
|
|
875
|
+
numQuery,
|
|
876
|
+
x,
|
|
877
|
+
faiss::NumericType::Float16,
|
|
878
|
+
k,
|
|
879
|
+
distances.data(),
|
|
880
|
+
labels.data());
|
|
881
|
+
|
|
882
|
+
EXPECT_EQ(labels, refLabels) << where;
|
|
883
|
+
EXPECT_EQ(distances, refDistances) << where;
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
expectSearchExMatches(queries16.data(), "host queries");
|
|
887
|
+
|
|
888
|
+
auto minPagingSize = index.getMinPagingSize();
|
|
889
|
+
index.setMinPagingSize(0);
|
|
890
|
+
expectSearchExMatches(queries16.data(), "paged host queries");
|
|
891
|
+
index.setMinPagingSize(minPagingSize);
|
|
892
|
+
|
|
893
|
+
DeviceCopy queries16Device(
|
|
894
|
+
index.getDevice(),
|
|
895
|
+
queries16.data(),
|
|
896
|
+
queries16.size() * sizeof(uint16_t));
|
|
897
|
+
expectSearchExMatches(queries16Device.data, "device queries");
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// Covers both float32 storage (queries widened on the device) and float16
|
|
901
|
+
// storage (queries searched natively)
|
|
902
|
+
template <typename GpuIndexFlatT>
|
|
903
|
+
void testFlatSearchExFloat16() {
|
|
904
|
+
faiss::gpu::StandardGpuResources res;
|
|
905
|
+
res.noTempMemory();
|
|
906
|
+
|
|
907
|
+
int dim = faiss::gpu::randVal(50, 400);
|
|
908
|
+
int numVecs = faiss::gpu::randVal(1000, 5000);
|
|
909
|
+
auto vecs = faiss::gpu::randVecs(numVecs, dim);
|
|
910
|
+
|
|
911
|
+
for (bool useFloat16 : {false, true}) {
|
|
912
|
+
faiss::gpu::GpuIndexFlatConfig config;
|
|
913
|
+
config.device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
|
|
914
|
+
config.useFloat16 = useFloat16;
|
|
915
|
+
|
|
916
|
+
GpuIndexFlatT gpuIndex(&res, dim, config);
|
|
917
|
+
gpuIndex.add(numVecs, vecs.data());
|
|
918
|
+
|
|
919
|
+
SCOPED_TRACE(useFloat16 ? "useFloat16" : "float32 storage");
|
|
920
|
+
testSearchExFloat16(gpuIndex);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
TEST(TestGpuIndexFlat, SearchExFloat16_L2) {
|
|
925
|
+
testFlatSearchExFloat16<faiss::gpu::GpuIndexFlatL2>();
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
TEST(TestGpuIndexFlat, SearchExFloat16_IP) {
|
|
929
|
+
testFlatSearchExFloat16<faiss::gpu::GpuIndexFlatIP>();
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
// Indexes without a native fp16 search widen the queries on the device
|
|
933
|
+
TEST(TestGpuIndexFlat, SearchExFloat16_IVFFlatDefault) {
|
|
934
|
+
faiss::gpu::StandardGpuResources res;
|
|
935
|
+
res.noTempMemory();
|
|
936
|
+
|
|
937
|
+
int dim = 64;
|
|
938
|
+
int numVecs = 5000;
|
|
939
|
+
auto vecs = faiss::gpu::randVecs(numVecs, dim);
|
|
940
|
+
|
|
941
|
+
faiss::gpu::GpuIndexIVFFlatConfig config;
|
|
942
|
+
config.device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
|
|
943
|
+
|
|
944
|
+
int numLists = 32;
|
|
945
|
+
faiss::gpu::GpuIndexIVFFlat gpuIndex(
|
|
946
|
+
&res, dim, numLists, faiss::METRIC_L2, config);
|
|
947
|
+
gpuIndex.nprobe = 4;
|
|
948
|
+
gpuIndex.train(numVecs, vecs.data());
|
|
949
|
+
gpuIndex.add(numVecs, vecs.data());
|
|
950
|
+
|
|
951
|
+
testSearchExFloat16(gpuIndex);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// k-means on fp16 data with a GPU assignment index must match k-means on the
|
|
955
|
+
// float32 rounding of that data with the same kind of index
|
|
956
|
+
TEST(TestGpuIndexFlat, ClusteringTrainExFloat16) {
|
|
957
|
+
faiss::gpu::StandardGpuResources res;
|
|
958
|
+
res.noTempMemory();
|
|
959
|
+
|
|
960
|
+
int dim = 32;
|
|
961
|
+
int numCentroids = 20;
|
|
962
|
+
// Fits in a single decode block, so that both runs search the same batches
|
|
963
|
+
int numVecs = 2000;
|
|
964
|
+
auto vecs = faiss::gpu::randVecs(numVecs, dim);
|
|
965
|
+
auto vecs16 = toFp16(vecs);
|
|
966
|
+
auto roundedVecs = fromFp16(vecs16);
|
|
967
|
+
|
|
968
|
+
faiss::ClusteringParameters cp;
|
|
969
|
+
cp.niter = 10;
|
|
970
|
+
|
|
971
|
+
for (bool useFloat16 : {false, true}) {
|
|
972
|
+
faiss::gpu::GpuIndexFlatConfig config;
|
|
973
|
+
config.device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
|
|
974
|
+
config.useFloat16 = useFloat16;
|
|
975
|
+
|
|
976
|
+
faiss::gpu::GpuIndexFlatL2 refIndex(&res, dim, config);
|
|
977
|
+
faiss::Clustering refClustering(dim, numCentroids, cp);
|
|
978
|
+
refClustering.train(numVecs, roundedVecs.data(), refIndex);
|
|
979
|
+
|
|
980
|
+
faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, dim, config);
|
|
981
|
+
faiss::Clustering clustering(dim, numCentroids, cp);
|
|
982
|
+
clustering.train_ex(
|
|
983
|
+
numVecs, vecs16.data(), faiss::NumericType::Float16, gpuIndex);
|
|
984
|
+
|
|
985
|
+
ASSERT_EQ(clustering.centroids.size(), refClustering.centroids.size());
|
|
986
|
+
for (size_t i = 0; i < clustering.centroids.size(); ++i) {
|
|
987
|
+
EXPECT_NEAR(
|
|
988
|
+
clustering.centroids[i], refClustering.centroids[i], 1e-5f)
|
|
989
|
+
<< "useFloat16 " << useFloat16 << " element " << i;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
// add and reconstruct_n copy the whole vector set between host and device in
|
|
995
|
+
// one copy. On ROCm, a pageable copy of more than 64 KiB goes through 16 MiB
|
|
996
|
+
// pinned chunks: 17 vectors take one chunk, and 10,500 vectors take two full
|
|
997
|
+
// chunks and a partial one. Each size has its own resources, so the second
|
|
998
|
+
// size reuses the pinned chunks after the streams of the first are destroyed.
|
|
999
|
+
TEST(TestGpuIndexFlat, LargeHostCopyRoundTrip) {
|
|
1000
|
+
int dim = 1000;
|
|
1001
|
+
int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
|
|
1002
|
+
|
|
1003
|
+
for (int numVecs : {17, 10500}) {
|
|
1004
|
+
faiss::gpu::StandardGpuResources res;
|
|
1005
|
+
res.noTempMemory();
|
|
1006
|
+
|
|
1007
|
+
faiss::gpu::GpuIndexFlatConfig config;
|
|
1008
|
+
config.device = device;
|
|
1009
|
+
|
|
1010
|
+
faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, dim, config);
|
|
1011
|
+
std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
|
|
1012
|
+
gpuIndex.add(numVecs, vecs.data());
|
|
1013
|
+
|
|
1014
|
+
std::vector<float> out(vecs.size());
|
|
1015
|
+
gpuIndex.reconstruct_n(0, numVecs, out.data());
|
|
1016
|
+
|
|
1017
|
+
// Report the first difference; printing millions of values is useless
|
|
1018
|
+
size_t firstDiff =
|
|
1019
|
+
std::mismatch(out.begin(), out.end(), vecs.begin()).first -
|
|
1020
|
+
out.begin();
|
|
1021
|
+
EXPECT_EQ(firstDiff, out.size()) << "numVecs " << numVecs;
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
|
|
810
1025
|
int main(int argc, char** argv) {
|
|
811
1026
|
testing::InitGoogleTest(&argc, argv);
|
|
812
1027
|
|
|
@@ -31,8 +31,11 @@
|
|
|
31
31
|
#include <faiss/impl/IDSelector.h>
|
|
32
32
|
#include <faiss/utils/distances.h>
|
|
33
33
|
#include <gtest/gtest.h>
|
|
34
|
+
#include <algorithm>
|
|
34
35
|
#include <cmath>
|
|
36
|
+
#include <random>
|
|
35
37
|
#include <sstream>
|
|
38
|
+
#include <unordered_set>
|
|
36
39
|
#include <vector>
|
|
37
40
|
|
|
38
41
|
// FIXME: figure out a better way to test fp16
|
|
@@ -472,6 +475,101 @@ TEST(TestGpuIndexIVFFlat, Float32_32_CopyFrom) {
|
|
|
472
475
|
#endif
|
|
473
476
|
}
|
|
474
477
|
|
|
478
|
+
#if defined USE_NVIDIA_CUVS
|
|
479
|
+
class TestCuvsGpuIndexIVFFlatCopyFrom
|
|
480
|
+
: public testing::TestWithParam<faiss::MetricType> {};
|
|
481
|
+
|
|
482
|
+
TEST_P(TestCuvsGpuIndexIVFFlatCopyFrom, SearchLargeK) {
|
|
483
|
+
constexpr int numVecs = 16384;
|
|
484
|
+
constexpr int dim = 128;
|
|
485
|
+
constexpr int numCentroids = 32;
|
|
486
|
+
const auto metric = GetParam();
|
|
487
|
+
std::mt19937 rng(42);
|
|
488
|
+
std::uniform_int_distribution<int> random(-30, 30);
|
|
489
|
+
std::vector<float> vecs(numVecs * dim);
|
|
490
|
+
for (auto& value : vecs) {
|
|
491
|
+
value = random(rng);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
faiss::IndexFlat quantizer(dim, metric);
|
|
495
|
+
faiss::IndexIVFFlat cpuIndex(&quantizer, dim, numCentroids, metric);
|
|
496
|
+
cpuIndex.cp.niter = 5;
|
|
497
|
+
cpuIndex.train(numVecs, vecs.data());
|
|
498
|
+
cpuIndex.add(numVecs, vecs.data());
|
|
499
|
+
cpuIndex.nprobe = numCentroids;
|
|
500
|
+
|
|
501
|
+
faiss::gpu::StandardGpuResources res;
|
|
502
|
+
faiss::gpu::GpuIndexIVFFlatConfig config;
|
|
503
|
+
config.use_cuvs = true;
|
|
504
|
+
config.indicesOptions = faiss::gpu::INDICES_64_BIT;
|
|
505
|
+
faiss::gpu::GpuIndexIVFFlat gpuIndex(
|
|
506
|
+
&res, dim, numCentroids, metric, config);
|
|
507
|
+
gpuIndex.copyFrom(&cpuIndex);
|
|
508
|
+
|
|
509
|
+
faiss::IndexFlat exact(dim, metric);
|
|
510
|
+
exact.add(numVecs, vecs.data());
|
|
511
|
+
// k > 256 takes the cuVS path that sizes its workspace from the
|
|
512
|
+
// accumulated list sizes. Cloning must populate those sizes first.
|
|
513
|
+
for (int k : {256, 257, 500, 3500}) {
|
|
514
|
+
SCOPED_TRACE(testing::Message() << "k=" << k);
|
|
515
|
+
for (int numQueries : {1, 4}) {
|
|
516
|
+
SCOPED_TRACE(testing::Message() << "numQueries=" << numQueries);
|
|
517
|
+
std::vector<float> expected(numQueries * k);
|
|
518
|
+
std::vector<float> distances(numQueries * k);
|
|
519
|
+
std::vector<faiss::idx_t> expectedIds(numQueries * k);
|
|
520
|
+
std::vector<faiss::idx_t> ids(numQueries * k);
|
|
521
|
+
exact.search(
|
|
522
|
+
numQueries,
|
|
523
|
+
vecs.data(),
|
|
524
|
+
k,
|
|
525
|
+
expected.data(),
|
|
526
|
+
expectedIds.data());
|
|
527
|
+
for (int repeat = 0; repeat < 2; ++repeat) {
|
|
528
|
+
gpuIndex.search(
|
|
529
|
+
numQueries,
|
|
530
|
+
vecs.data(),
|
|
531
|
+
k,
|
|
532
|
+
distances.data(),
|
|
533
|
+
ids.data());
|
|
534
|
+
for (int q = 0; q < numQueries; ++q) {
|
|
535
|
+
std::unordered_set<faiss::idx_t> uniqueIds;
|
|
536
|
+
for (int i = q * k; i < (q + 1) * k; ++i) {
|
|
537
|
+
ASSERT_GE(ids[i], 0);
|
|
538
|
+
ASSERT_LT(ids[i], numVecs);
|
|
539
|
+
EXPECT_TRUE(uniqueIds.insert(ids[i]).second);
|
|
540
|
+
float score = 0;
|
|
541
|
+
for (int j = 0; j < dim; ++j) {
|
|
542
|
+
float a = vecs[q * dim + j];
|
|
543
|
+
float b = vecs[ids[i] * dim + j];
|
|
544
|
+
score += metric == faiss::METRIC_L2
|
|
545
|
+
? (a - b) * (a - b)
|
|
546
|
+
: a * b;
|
|
547
|
+
}
|
|
548
|
+
EXPECT_FLOAT_EQ(score, distances[i]);
|
|
549
|
+
}
|
|
550
|
+
// cuVS need not return sorted results, and tied scores
|
|
551
|
+
// may select different IDs at the top-k boundary.
|
|
552
|
+
std::vector<float> actual(
|
|
553
|
+
distances.begin() + q * k,
|
|
554
|
+
distances.begin() + (q + 1) * k);
|
|
555
|
+
auto begin = expected.begin() + q * k;
|
|
556
|
+
std::sort(begin, begin + k);
|
|
557
|
+
std::sort(actual.begin(), actual.end());
|
|
558
|
+
for (int i = 0; i < k; ++i) {
|
|
559
|
+
EXPECT_FLOAT_EQ(begin[i], actual[i]);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
INSTANTIATE_TEST_SUITE_P(
|
|
568
|
+
Cuvs,
|
|
569
|
+
TestCuvsGpuIndexIVFFlatCopyFrom,
|
|
570
|
+
testing::Values(faiss::METRIC_L2, faiss::METRIC_INNER_PRODUCT));
|
|
571
|
+
#endif
|
|
572
|
+
|
|
475
573
|
TEST(TestGpuIndexIVFFlat, Float32_negative) {
|
|
476
574
|
Options opt;
|
|
477
575
|
|
|
@@ -63,6 +63,17 @@ size_t getMaxSharedMemPerBlockCurrentDevice();
|
|
|
63
63
|
/// a device (deviceId >= 0) or the host (-1).
|
|
64
64
|
int getDeviceForAddress(const void* p);
|
|
65
65
|
|
|
66
|
+
/// cudaMemcpyAsync, except that on ROCm a copy of more than 64 KiB to or from
|
|
67
|
+
/// pageable host memory goes through pinned staging buffers. As with CUDA's
|
|
68
|
+
/// pageable copies, a host-to-device copy returns once the source can be
|
|
69
|
+
/// reused, and a device-to-host copy returns once the data is on the host.
|
|
70
|
+
void memcpyHostDeviceAsync(
|
|
71
|
+
void* dst,
|
|
72
|
+
const void* src,
|
|
73
|
+
size_t bytes,
|
|
74
|
+
cudaMemcpyKind kind,
|
|
75
|
+
cudaStream_t stream);
|
|
76
|
+
|
|
66
77
|
/// Does the given device support full unified memory sharing host
|
|
67
78
|
/// memory?
|
|
68
79
|
bool getFullUnifiedMemSupport(int device);
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
#pragma once
|
|
12
12
|
|
|
13
13
|
#include <faiss/Index.h>
|
|
14
|
+
#include <faiss/IndexBinary.h>
|
|
14
15
|
|
|
15
16
|
namespace faiss {
|
|
16
17
|
namespace gpu_metal {
|
|
@@ -31,5 +32,15 @@ faiss::Index* index_cpu_to_metal_gpu(
|
|
|
31
32
|
/// Caller owns the returned index.
|
|
32
33
|
faiss::Index* index_metal_gpu_to_cpu(const faiss::Index* index);
|
|
33
34
|
|
|
35
|
+
/// Clone IndexBinaryFlat to Metal. device must be 0; caller owns the result.
|
|
36
|
+
faiss::IndexBinary* index_binary_cpu_to_metal_gpu(
|
|
37
|
+
StandardMetalResources* res,
|
|
38
|
+
int device,
|
|
39
|
+
const faiss::IndexBinary* index);
|
|
40
|
+
|
|
41
|
+
/// Clone MetalIndexBinaryFlat to CPU. Caller owns the returned index.
|
|
42
|
+
faiss::IndexBinary* index_binary_metal_gpu_to_cpu(
|
|
43
|
+
const faiss::IndexBinary* index);
|
|
44
|
+
|
|
34
45
|
} // namespace gpu_metal
|
|
35
46
|
} // namespace faiss
|