faiss 0.6.2 → 0.6.4
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 +8 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +3 -1
- data/vendor/faiss/faiss/Clustering.cpp +9 -1
- data/vendor/faiss/faiss/Clustering.h +8 -0
- data/vendor/faiss/faiss/IVFlib.cpp +14 -3
- data/vendor/faiss/faiss/Index.h +2 -2
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +9 -10
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +2 -3
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +24 -4
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +16 -145
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +0 -6
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +5 -9
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +8 -18
- data/vendor/faiss/faiss/IndexBinaryIVF.h +8 -1
- data/vendor/faiss/faiss/IndexEDEN.cpp +273 -0
- data/vendor/faiss/faiss/IndexEDEN.h +57 -0
- data/vendor/faiss/faiss/IndexFastScan.cpp +15 -4
- data/vendor/faiss/faiss/IndexFlat.cpp +21 -54
- data/vendor/faiss/faiss/IndexFlat.h +2 -2
- data/vendor/faiss/faiss/IndexHNSW.cpp +311 -102
- data/vendor/faiss/faiss/IndexHNSW.h +31 -7
- data/vendor/faiss/faiss/IndexIDMap.cpp +26 -8
- data/vendor/faiss/faiss/IndexIDMap.h +2 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +36 -10
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFEDEN.cpp +302 -0
- data/vendor/faiss/faiss/IndexIVFEDEN.h +70 -0
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +5 -6
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +3 -4
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +49 -23
- data/vendor/faiss/faiss/IndexIVFPQ.h +11 -0
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +0 -1
- data/vendor/faiss/faiss/IndexIVFRaBitQ.cpp +19 -49
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.cpp +180 -76
- data/vendor/faiss/faiss/IndexIVFRaBitQFastScan.h +5 -4
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +8 -6
- data/vendor/faiss/faiss/IndexLSH.cpp +2 -3
- data/vendor/faiss/faiss/IndexLattice.cpp +5 -0
- data/vendor/faiss/faiss/IndexNNDescent.cpp +9 -2
- data/vendor/faiss/faiss/IndexNSG.cpp +7 -2
- data/vendor/faiss/faiss/IndexPQ.cpp +6 -8
- data/vendor/faiss/faiss/IndexPreTransform.cpp +15 -0
- data/vendor/faiss/faiss/IndexRaBitQ.cpp +2 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.cpp +1 -2
- data/vendor/faiss/faiss/IndexRaBitQFastScan.h +5 -1
- data/vendor/faiss/faiss/IndexRefine.cpp +30 -1
- data/vendor/faiss/faiss/IndexReplicas.cpp +1 -2
- data/vendor/faiss/faiss/IndexShards.cpp +5 -5
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +6 -5
- data/vendor/faiss/faiss/MetaIndexes.cpp +2 -4
- data/vendor/faiss/faiss/SuperKMeans.cpp +286 -247
- data/vendor/faiss/faiss/SuperKMeans.h +33 -2
- data/vendor/faiss/faiss/VectorTransform.cpp +71 -2
- data/vendor/faiss/faiss/VectorTransform.h +3 -0
- data/vendor/faiss/faiss/clone_index.cpp +8 -0
- data/vendor/faiss/faiss/factory_tools.cpp +47 -4
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +11 -11
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +1 -5
- data/vendor/faiss/faiss/gpu/GpuDistance.h +2 -5
- data/vendor/faiss/faiss/gpu/GpuIndex.h +38 -16
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +71 -1
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +17 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +16 -0
- data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
- data/vendor/faiss/faiss/gpu/perf/PerfIVFPQAdd.cpp +2 -2
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFScalarQuantizer.cpp +180 -0
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFFlat.h +1 -5
- data/vendor/faiss/faiss/gpu_metal/MetalIndexIVFPQ.h +88 -0
- data/vendor/faiss/faiss/gpu_metal/impl/MetalIVFPQ.h +134 -0
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +1 -1
- data/vendor/faiss/faiss/impl/ClusteringInitialization.cpp +7 -4
- data/vendor/faiss/faiss/impl/DistanceComputer.h +34 -0
- data/vendor/faiss/faiss/impl/EDENQuantizer.h +119 -0
- data/vendor/faiss/faiss/impl/HNSW.cpp +528 -267
- data/vendor/faiss/faiss/impl/HNSW.h +46 -7
- data/vendor/faiss/faiss/impl/IDSelector.h +44 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +2 -2
- data/vendor/faiss/faiss/impl/NNDescent.cpp +10 -3
- data/vendor/faiss/faiss/impl/NSG.cpp +3 -1
- data/vendor/faiss/faiss/impl/Panorama.h +20 -9
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +152 -84
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +38 -26
- data/vendor/faiss/faiss/impl/RaBitQUtils.cpp +45 -37
- data/vendor/faiss/faiss/impl/RaBitQUtils.h +35 -0
- data/vendor/faiss/faiss/impl/RaBitQuantizer.cpp +239 -72
- data/vendor/faiss/faiss/impl/RaBitQuantizer.h +66 -4
- data/vendor/faiss/faiss/impl/RaBitQuantizerMultiBit.cpp +4 -13
- data/vendor/faiss/faiss/impl/ResultHandler.h +34 -34
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +287 -84
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +26 -10
- data/vendor/faiss/faiss/impl/ThreadedIndex-inl.h +2 -2
- data/vendor/faiss/faiss/impl/VisitedTable.cpp +22 -2
- data/vendor/faiss/faiss/impl/VisitedTable.h +20 -0
- data/vendor/faiss/faiss/impl/binary_hamming/IndexBinaryIVF_impl.h +90 -14
- data/vendor/faiss/faiss/impl/binary_hamming/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/expanded_scanners.h +5 -1
- data/vendor/faiss/faiss/impl/fast_scan/decompose_qbs.h +1 -0
- data/vendor/faiss/faiss/impl/fast_scan/dispatching.h +35 -2
- data/vendor/faiss/faiss/impl/hnsw/LockVector.cpp +1 -1
- data/vendor/faiss/faiss/impl/index_read.cpp +491 -50
- data/vendor/faiss/faiss/impl/index_write.cpp +86 -30
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +8 -9
- data/vendor/faiss/faiss/impl/platform_macros.h +3 -1
- data/vendor/faiss/faiss/impl/polysemous_training/avx512.cpp +284 -0
- data/vendor/faiss/faiss/impl/polysemous_training/dispatch.h +115 -0
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQScanner_impl.h +73 -39
- data/vendor/faiss/faiss/impl/pq_code_distance/IVFPQ_QueryTables.cpp +0 -1
- data/vendor/faiss/faiss/impl/pq_code_distance/PQDistanceComputer_impl.h +26 -15
- data/vendor/faiss/faiss/impl/pq_code_distance/avx2.cpp +4 -4
- data/vendor/faiss/faiss/impl/pq_code_distance/pq_code_distance-generic.cpp +4 -4
- data/vendor/faiss/faiss/impl/result_handler/ResultHandler.cpp +195 -0
- data/vendor/faiss/faiss/impl/result_handler/avx2.cpp +133 -0
- data/vendor/faiss/faiss/impl/result_handler/avx512.cpp +281 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx2.cpp +72 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer-avx512.cpp +228 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/EDENQuantizer.cpp +887 -0
- data/vendor/faiss/faiss/impl/scalar_quantizer/distance_computers.h +2 -2
- data/vendor/faiss/faiss/impl/scalar_quantizer/quantizers.h +9 -8
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx2.cpp +90 -24
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-impl.h +30 -30
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512-spr.cpp +4 -5
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-avx512.cpp +101 -34
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-dispatch.h +169 -13
- data/vendor/faiss/faiss/impl/scalar_quantizer/sq-neon.cpp +125 -26
- data/vendor/faiss/faiss/impl/simd_dispatch.h +70 -31
- data/vendor/faiss/faiss/index_factory.cpp +40 -7
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +9 -6
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +29 -8
- data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -1
- data/vendor/faiss/faiss/svs/IndexSVSFaissUtils.h +60 -0
- data/vendor/faiss/faiss/svs/IndexSVSFlat.cpp +26 -1
- data/vendor/faiss/faiss/svs/IndexSVSFlat.h +13 -0
- data/vendor/faiss/faiss/svs/IndexSVSIVF.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSIVFLeanVec.cpp +1 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamana.cpp +47 -5
- data/vendor/faiss/faiss/svs/IndexSVSVamana.h +23 -3
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.cpp +4 -2
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLVQ.h +2 -1
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.cpp +10 -4
- data/vendor/faiss/faiss/svs/IndexSVSVamanaLeanVec.h +2 -1
- data/vendor/faiss/faiss/utils/approx_topk_hamming/approx_topk_hamming.h +1 -1
- data/vendor/faiss/faiss/utils/distances.cpp +30 -11
- data/vendor/faiss/faiss/utils/distances_dispatch.h +30 -24
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +1 -1
- data/vendor/faiss/faiss/utils/distances_simd.cpp +4 -3
- data/vendor/faiss/faiss/utils/extra_distances.cpp +4 -14
- data/vendor/faiss/faiss/utils/extra_distances.h +1 -2
- data/vendor/faiss/faiss/utils/hamming.cpp +16 -10
- data/vendor/faiss/faiss/utils/hamming.h +10 -1
- data/vendor/faiss/faiss/utils/hamming_distance/common.h +14 -3
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_vpopcnt.cpp +24 -0
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_computer-avx512.h +1 -1
- data/vendor/faiss/faiss/utils/hamming_distance/{hamming_computer-avx512_spr.h → hamming_computer-avx512_vpopcnt.h} +85 -24
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_impl.h +141 -0
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +29 -8
- data/vendor/faiss/faiss/utils/rabitq_simd.h +202 -0
- data/vendor/faiss/faiss/utils/simd_impl/distances_arm_sve.cpp +194 -30
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx2.cpp +0 -1
- data/vendor/faiss/faiss/utils/simd_impl/distances_avx512.cpp +263 -15
- data/vendor/faiss/faiss/utils/simd_impl/distances_rvv.cpp +198 -18
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx2.cpp +245 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_avx512.cpp +330 -40
- data/vendor/faiss/faiss/utils/simd_impl/{rabitq_avx512_spr.cpp → rabitq_avx512_vpopcnt.cpp} +112 -23
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_neon.cpp +11 -0
- data/vendor/faiss/faiss/utils/simd_impl/rabitq_rvv.cpp +143 -6
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_dispatch.h +2 -7
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels.h +6 -1
- data/vendor/faiss/faiss/utils/simd_impl/super_kmeans_kernels_sve.cpp +34 -0
- data/vendor/faiss/faiss/utils/simd_levels.cpp +196 -47
- data/vendor/faiss/faiss/utils/simd_levels.h +33 -8
- data/vendor/faiss/faiss/utils/utils.cpp +9 -27
- metadata +21 -5
- data/vendor/faiss/faiss/utils/hamming_distance/hamming_avx512_spr.cpp +0 -15
|
@@ -13,8 +13,9 @@
|
|
|
13
13
|
// "A Super Fast K-means for Indexing Vector Embeddings."
|
|
14
14
|
// arXiv preprint arXiv:2603.20009.
|
|
15
15
|
//
|
|
16
|
-
// Use when: L2 metric,
|
|
17
|
-
//
|
|
16
|
+
// Use when: L2 metric, or spherical inner-product clustering with
|
|
17
|
+
// cp.spherical=true, k >= 1024, d >= 128, dense float embeddings.
|
|
18
|
+
// Do not use for: small k,
|
|
18
19
|
// binary data (use IndexBinaryIVF), or near-unit-sphere embeddings with
|
|
19
20
|
// k < 4096 (chi-squared assumption breaks down).
|
|
20
21
|
//
|
|
@@ -23,6 +24,7 @@
|
|
|
23
24
|
|
|
24
25
|
#pragma once
|
|
25
26
|
|
|
27
|
+
#include <cstdint>
|
|
26
28
|
#include <vector>
|
|
27
29
|
|
|
28
30
|
#include <faiss/Clustering.h>
|
|
@@ -94,4 +96,33 @@ struct SuperKMeans {
|
|
|
94
96
|
void train(idx_t n, const float* x);
|
|
95
97
|
};
|
|
96
98
|
|
|
99
|
+
/// Reusable scratch for super_kmeans_assign_iteration; pass one instance across
|
|
100
|
+
/// a loop of calls to avoid reallocating (buffers grow only as needed).
|
|
101
|
+
struct SuperKMeansAssignScratch {
|
|
102
|
+
std::vector<float> Y_trail; // (k, d_trail) row-major, input to pdxify
|
|
103
|
+
std::vector<float> Y_pdx; // PDX-laid-out trailing block
|
|
104
|
+
std::vector<float> x_norms_partial; // ||X[i, 0:d_prime]||^2
|
|
105
|
+
std::vector<float> y_norms_partial; // ||Y[j, 0:d_prime]||^2
|
|
106
|
+
std::vector<float> partial_ip; // partial-GEMM tile buffer
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
/// One SuperKMeans iter-1+ assignment pass: partial GEMM over the front
|
|
110
|
+
/// `d_prime` dims + ADSampling progressive pruning over the PDX-laid-out
|
|
111
|
+
/// trailing block. Updates `tau` and `assignments` in place.
|
|
112
|
+
void super_kmeans_assign_iteration(
|
|
113
|
+
const float* X_tilde, // (n, d) points, row-major, rotated space
|
|
114
|
+
int n,
|
|
115
|
+
int d,
|
|
116
|
+
const float* Y_tilde, // (k, d) centroids, row-major, rotated space
|
|
117
|
+
int k,
|
|
118
|
+
float* tau, // in/out, len n; entry = exact full-d L2 to assignment
|
|
119
|
+
int32_t* assignments, // in/out, len n
|
|
120
|
+
int d_prime, // GEMM/pruning split, 1 <= d_prime < d
|
|
121
|
+
const float* ad_coeff, // ADSampling threshold table, len d+1
|
|
122
|
+
const SuperKMeansParameters& cp,
|
|
123
|
+
int64_t* total_pairs = nullptr, // optional out-counter
|
|
124
|
+
int64_t* pruned_at_gemm = nullptr, // optional out-counter
|
|
125
|
+
SuperKMeansAssignScratch* scratch =
|
|
126
|
+
nullptr); // optional, reuse across calls
|
|
127
|
+
|
|
97
128
|
} // namespace faiss
|
|
@@ -47,6 +47,19 @@ int sgemm_(
|
|
|
47
47
|
float* c,
|
|
48
48
|
FINTEGER* ldc);
|
|
49
49
|
|
|
50
|
+
int sgemv_(
|
|
51
|
+
const char* trans,
|
|
52
|
+
FINTEGER* m,
|
|
53
|
+
FINTEGER* n,
|
|
54
|
+
float* alpha,
|
|
55
|
+
const float* a,
|
|
56
|
+
FINTEGER* lda,
|
|
57
|
+
const float* x,
|
|
58
|
+
FINTEGER* incx,
|
|
59
|
+
float* beta,
|
|
60
|
+
float* y,
|
|
61
|
+
FINTEGER* incy);
|
|
62
|
+
|
|
50
63
|
int dgemm_(
|
|
51
64
|
const char* transa,
|
|
52
65
|
const char* transb,
|
|
@@ -192,6 +205,25 @@ void LinearTransform::apply_noalloc(idx_t n, const float* x, float* xt) const {
|
|
|
192
205
|
|
|
193
206
|
float one = 1;
|
|
194
207
|
FINTEGER nbiti = d_out, ni = static_cast<FINTEGER>(n), di = d_in;
|
|
208
|
+
if (n == 1) {
|
|
209
|
+
FINTEGER onei = 1;
|
|
210
|
+
// Avoid GEMM packing overhead for single-vector transforms. GEMV is
|
|
211
|
+
// mathematically equivalent but may not be bit-exact with GEMM because
|
|
212
|
+
// BLAS implementations can use different accumulation orders.
|
|
213
|
+
sgemv_("Transposed",
|
|
214
|
+
&di,
|
|
215
|
+
&nbiti,
|
|
216
|
+
&one,
|
|
217
|
+
A.data(),
|
|
218
|
+
&di,
|
|
219
|
+
x,
|
|
220
|
+
&onei,
|
|
221
|
+
&c_factor,
|
|
222
|
+
xt,
|
|
223
|
+
&onei);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
195
227
|
sgemm_("Transposed",
|
|
196
228
|
"Not transposed",
|
|
197
229
|
&nbiti,
|
|
@@ -481,6 +513,44 @@ void HadamardRotation::apply_noalloc(idx_t n, const float* x, float* xt) const {
|
|
|
481
513
|
}
|
|
482
514
|
}
|
|
483
515
|
|
|
516
|
+
void HadamardRotation::reverse_transform(idx_t n, const float* xt, float* x)
|
|
517
|
+
const {
|
|
518
|
+
FAISS_THROW_IF_NOT_MSG(is_trained, "Transformation not trained yet");
|
|
519
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
520
|
+
d_in == d_out,
|
|
521
|
+
"HadamardRotation inverse requires equal input/output dimensions");
|
|
522
|
+
|
|
523
|
+
const size_t p = d_out;
|
|
524
|
+
// Reverse of apply_noalloc: three unnormalized FWHT rounds scale norms
|
|
525
|
+
// by (sqrt(p))^3 = p*sqrt(p); the forward pass cancels this with
|
|
526
|
+
// total_scale = 1/(p*sqrt(p)), so the inverse applies the same factor.
|
|
527
|
+
const float inverse_scale = 1.0f / (p * std::sqrt(static_cast<float>(p)));
|
|
528
|
+
|
|
529
|
+
#pragma omp parallel for schedule(dynamic)
|
|
530
|
+
for (idx_t i = 0; i < n; i++) {
|
|
531
|
+
const float* xi = xt + i * p;
|
|
532
|
+
float* xo = x + i * p;
|
|
533
|
+
|
|
534
|
+
// The inverse reverses the three sign-flip/Hadamard factors.
|
|
535
|
+
std::memcpy(xo, xi, p * sizeof(float));
|
|
536
|
+
fwht_inplace(xo, p);
|
|
537
|
+
|
|
538
|
+
for (size_t j = 0; j < p; j++) {
|
|
539
|
+
xo[j] *= signs3[j];
|
|
540
|
+
}
|
|
541
|
+
fwht_inplace(xo, p);
|
|
542
|
+
|
|
543
|
+
for (size_t j = 0; j < p; j++) {
|
|
544
|
+
xo[j] *= signs2[j];
|
|
545
|
+
}
|
|
546
|
+
fwht_inplace(xo, p);
|
|
547
|
+
|
|
548
|
+
for (size_t j = 0; j < p; j++) {
|
|
549
|
+
xo[j] *= signs1[j] * inverse_scale;
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
484
554
|
void HadamardRotation::check_identical(const VectorTransform& other) const {
|
|
485
555
|
auto* hr = dynamic_cast<const HadamardRotation*>(&other);
|
|
486
556
|
FAISS_THROW_IF_NOT_MSG(hr, "failed to cast to HadamardRotation");
|
|
@@ -1064,8 +1134,7 @@ ITQTransform::ITQTransform(int din, int dout, bool do_pca_in)
|
|
|
1064
1134
|
}
|
|
1065
1135
|
|
|
1066
1136
|
void ITQTransform::train(idx_t n, const float* x_in) {
|
|
1067
|
-
|
|
1068
|
-
!is_trained, "ITQTransform has already been trained");
|
|
1137
|
+
FAISS_THROW_IF_MSG(is_trained, "ITQTransform has already been trained");
|
|
1069
1138
|
|
|
1070
1139
|
size_t max_train_points = std::max(d_in * max_train_per_dim, 32768);
|
|
1071
1140
|
const float* x =
|
|
@@ -144,6 +144,9 @@ struct HadamardRotation : VectorTransform {
|
|
|
144
144
|
|
|
145
145
|
void apply_noalloc(idx_t n, const float* x, float* xt) const override;
|
|
146
146
|
|
|
147
|
+
/// Apply the inverse transform when d_in == d_out.
|
|
148
|
+
void reverse_transform(idx_t n, const float* xt, float* x) const override;
|
|
149
|
+
|
|
147
150
|
void check_identical(const VectorTransform& other) const override;
|
|
148
151
|
|
|
149
152
|
HadamardRotation() {}
|
|
@@ -18,10 +18,12 @@
|
|
|
18
18
|
#include <faiss/IndexBinaryFlat.h>
|
|
19
19
|
#include <faiss/IndexBinaryHNSW.h>
|
|
20
20
|
#include <faiss/IndexBinaryIVF.h>
|
|
21
|
+
#include <faiss/IndexEDEN.h>
|
|
21
22
|
#include <faiss/IndexFlat.h>
|
|
22
23
|
#include <faiss/IndexHNSW.h>
|
|
23
24
|
#include <faiss/IndexIVF.h>
|
|
24
25
|
#include <faiss/IndexIVFAdditiveQuantizerFastScan.h>
|
|
26
|
+
#include <faiss/IndexIVFEDEN.h>
|
|
25
27
|
#include <faiss/IndexIVFFlat.h>
|
|
26
28
|
#include <faiss/IndexIVFFlatPanorama.h>
|
|
27
29
|
#include <faiss/IndexIVFPQ.h>
|
|
@@ -36,6 +38,7 @@
|
|
|
36
38
|
#include <faiss/IndexPQ.h>
|
|
37
39
|
#include <faiss/IndexPQFastScan.h>
|
|
38
40
|
#include <faiss/IndexPreTransform.h>
|
|
41
|
+
#include <faiss/IndexRaBitQ.h>
|
|
39
42
|
#include <faiss/IndexRefine.h>
|
|
40
43
|
#include <faiss/IndexRowwiseMinMax.h>
|
|
41
44
|
#include <faiss/IndexScalarQuantizer.h>
|
|
@@ -77,6 +80,7 @@ VectorTransform* Cloner::clone_VectorTransform(const VectorTransform* vt) {
|
|
|
77
80
|
TRYCLONE(PCAMatrix, vt)
|
|
78
81
|
TRYCLONE(ITQMatrix, vt)
|
|
79
82
|
TRYCLONE(RandomRotationMatrix, vt)
|
|
83
|
+
TRYCLONE(HadamardRotation, vt)
|
|
80
84
|
TRYCLONE(LinearTransform, vt) {
|
|
81
85
|
FAISS_THROW_MSG("clone not supported for this type of VectorTransform");
|
|
82
86
|
}
|
|
@@ -98,6 +102,7 @@ IndexIVF* Cloner::clone_IndexIVF(const IndexIVF* ivf) {
|
|
|
98
102
|
TRYCLONE(IndexIVFResidualQuantizerFastScan, ivf)
|
|
99
103
|
TRYCLONE(IndexIVFPQFastScan, ivf)
|
|
100
104
|
|
|
105
|
+
TRYCLONE(IndexIVFEDEN, ivf)
|
|
101
106
|
TRYCLONE(IndexIVFRaBitQFastScan, ivf)
|
|
102
107
|
TRYCLONE(IndexIVFRaBitQ, ivf)
|
|
103
108
|
|
|
@@ -135,6 +140,7 @@ IndexIDMap* clone_IndexIDMap(const IndexIDMap* im) {
|
|
|
135
140
|
IndexHNSW* clone_IndexHNSW(const IndexHNSW* ihnsw) {
|
|
136
141
|
TRYCLONE(IndexHNSW2Level, ihnsw)
|
|
137
142
|
TRYCLONE(IndexHNSWFlatPanorama, ihnsw)
|
|
143
|
+
TRYCLONE(IndexHNSWRaBitQ, ihnsw)
|
|
138
144
|
TRYCLONE(IndexHNSWFlat, ihnsw)
|
|
139
145
|
TRYCLONE(IndexHNSWPQ, ihnsw)
|
|
140
146
|
TRYCLONE(IndexHNSWSQ, ihnsw)
|
|
@@ -287,8 +293,10 @@ Index* Cloner::clone_Index(const Index* index) {
|
|
|
287
293
|
TRYCLONE(IndexLattice, index)
|
|
288
294
|
TRYCLONE(IndexRandom, index)
|
|
289
295
|
TRYCLONE(IndexPQFastScan, index)
|
|
296
|
+
TRYCLONE(IndexEDEN, index)
|
|
290
297
|
|
|
291
298
|
TRYCLONE(IndexScalarQuantizer, index)
|
|
299
|
+
TRYCLONE(IndexRaBitQ, index)
|
|
292
300
|
TRYCLONE(MultiIndexQuantizer, index)
|
|
293
301
|
|
|
294
302
|
if (const IndexIVF* ivf = dynamic_cast<const IndexIVF*>(index)) {
|
|
@@ -14,8 +14,10 @@
|
|
|
14
14
|
#include <faiss/IndexBinaryFlat.h>
|
|
15
15
|
#include <faiss/IndexBinaryHNSW.h>
|
|
16
16
|
#include <faiss/IndexBinaryIVF.h>
|
|
17
|
+
#include <faiss/IndexEDEN.h>
|
|
17
18
|
#include <faiss/IndexHNSW.h>
|
|
18
19
|
#include <faiss/IndexIDMap.h>
|
|
20
|
+
#include <faiss/IndexIVFEDEN.h>
|
|
19
21
|
#include <faiss/IndexIVFFlat.h>
|
|
20
22
|
#include <faiss/IndexIVFPQFastScan.h>
|
|
21
23
|
#include <faiss/IndexIVFRaBitQ.h>
|
|
@@ -33,11 +35,17 @@ namespace {
|
|
|
33
35
|
const std::map<faiss::ScalarQuantizer::QuantizerType, std::string> sq_types = {
|
|
34
36
|
{faiss::ScalarQuantizer::QT_8bit, "SQ8"},
|
|
35
37
|
{faiss::ScalarQuantizer::QT_4bit, "SQ4"},
|
|
38
|
+
// QT_8bit_uniform and QT_4bit_uniform have no round-trippable
|
|
39
|
+
// index_factory string; the names below are synthetic identifiers used
|
|
40
|
+
// for telemetry logging only.
|
|
41
|
+
{faiss::ScalarQuantizer::QT_8bit_uniform, "SQ8u"},
|
|
42
|
+
{faiss::ScalarQuantizer::QT_4bit_uniform, "SQ4u"},
|
|
36
43
|
{faiss::ScalarQuantizer::QT_6bit, "SQ6"},
|
|
37
44
|
{faiss::ScalarQuantizer::QT_fp16, "SQfp16"},
|
|
38
45
|
{faiss::ScalarQuantizer::QT_bf16, "SQbf16"},
|
|
39
46
|
{faiss::ScalarQuantizer::QT_8bit_direct_signed, "SQ8_direct_signed"},
|
|
40
47
|
{faiss::ScalarQuantizer::QT_8bit_direct, "SQ8_direct"},
|
|
48
|
+
{faiss::ScalarQuantizer::QT_0bit, "SQ0"},
|
|
41
49
|
{faiss::ScalarQuantizer::QT_1bit_tqmse, "SQtqmse1"},
|
|
42
50
|
{faiss::ScalarQuantizer::QT_2bit_tqmse, "SQtqmse2"},
|
|
43
51
|
{faiss::ScalarQuantizer::QT_3bit_tqmse, "SQtqmse3"},
|
|
@@ -65,6 +73,19 @@ int get_hnsw_M(const faiss::IndexBinaryHNSW* index) {
|
|
|
65
73
|
return 0;
|
|
66
74
|
}
|
|
67
75
|
|
|
76
|
+
std::string eden_factory_string(
|
|
77
|
+
const faiss::ScalarQuantizer& sq,
|
|
78
|
+
faiss::EDENScaleType scale_type) {
|
|
79
|
+
std::string result = "EDEN";
|
|
80
|
+
if (sq.bits != 1) {
|
|
81
|
+
result += std::to_string(sq.bits);
|
|
82
|
+
}
|
|
83
|
+
if (scale_type == faiss::EDENScaleType_BIASED) {
|
|
84
|
+
result += "BIASED";
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
|
|
68
89
|
} // namespace
|
|
69
90
|
|
|
70
91
|
// Reference for reverse_index_factory:
|
|
@@ -114,8 +135,17 @@ std::string reverse_index_factory(const faiss::Index* index) {
|
|
|
114
135
|
ivf_index)) {
|
|
115
136
|
return prefix + ",PQ" + std::to_string(ivfpqfs_index->pq.M) + "x" +
|
|
116
137
|
std::to_string(ivfpqfs_index->pq.nbits) + "fs";
|
|
117
|
-
} else if (
|
|
118
|
-
|
|
138
|
+
} else if (
|
|
139
|
+
const faiss::IndexIVFRaBitQ* ivfrabitq_index =
|
|
140
|
+
dynamic_cast<const faiss::IndexIVFRaBitQ*>(ivf_index)) {
|
|
141
|
+
size_t nb_bits = ivfrabitq_index->rabitq.nb_bits;
|
|
142
|
+
return prefix + ",RaBitQ" +
|
|
143
|
+
(nb_bits == 1 ? "" : std::to_string(nb_bits));
|
|
144
|
+
} else if (
|
|
145
|
+
const faiss::IndexIVFEDEN* ivf_eden =
|
|
146
|
+
dynamic_cast<const faiss::IndexIVFEDEN*>(ivf_index)) {
|
|
147
|
+
return prefix + "," +
|
|
148
|
+
eden_factory_string(ivf_eden->sq, ivf_eden->scale_type);
|
|
119
149
|
}
|
|
120
150
|
} else if (
|
|
121
151
|
const faiss::IndexPreTransform* pretransform_index =
|
|
@@ -184,12 +214,25 @@ std::string reverse_index_factory(const faiss::Index* index) {
|
|
|
184
214
|
const faiss::IndexScalarQuantizer* sq_index =
|
|
185
215
|
dynamic_cast<const faiss::IndexScalarQuantizer*>(index)) {
|
|
186
216
|
return sq_types.at(sq_index->sq.qtype);
|
|
217
|
+
} else if (
|
|
218
|
+
// IndexIDMap2 inherits IndexIDMap — check subclass first.
|
|
219
|
+
const faiss::IndexIDMap2* idmap2 =
|
|
220
|
+
dynamic_cast<const faiss::IndexIDMap2*>(index)) {
|
|
221
|
+
return std::string("IDMap2,") + reverse_index_factory(idmap2->index);
|
|
187
222
|
} else if (
|
|
188
223
|
const faiss::IndexIDMap* idmap =
|
|
189
224
|
dynamic_cast<const faiss::IndexIDMap*>(index)) {
|
|
190
225
|
return std::string("IDMap,") + reverse_index_factory(idmap->index);
|
|
191
|
-
} else if (
|
|
192
|
-
|
|
226
|
+
} else if (
|
|
227
|
+
const faiss::IndexRaBitQ* rabitq_index =
|
|
228
|
+
dynamic_cast<const faiss::IndexRaBitQ*>(index)) {
|
|
229
|
+
size_t nb_bits = rabitq_index->rabitq.nb_bits;
|
|
230
|
+
return "RaBitQ" +
|
|
231
|
+
(nb_bits == 1 ? std::string() : std::to_string(nb_bits));
|
|
232
|
+
} else if (
|
|
233
|
+
const faiss::IndexEDEN* eden =
|
|
234
|
+
dynamic_cast<const faiss::IndexEDEN*>(index)) {
|
|
235
|
+
return eden_factory_string(eden->sq, eden->scale_type);
|
|
193
236
|
}
|
|
194
237
|
// Avoid runtime error, just return empty string for logging.
|
|
195
238
|
return "";
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
#include <faiss/IndexBinaryFlat.h>
|
|
16
16
|
#include <faiss/IndexFlat.h>
|
|
17
|
-
#if defined
|
|
17
|
+
#if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
|
|
18
18
|
#include <faiss/IndexBinaryHNSW.h>
|
|
19
19
|
#include <faiss/IndexHNSW.h>
|
|
20
20
|
#endif
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
#include <faiss/MetaIndexes.h>
|
|
29
29
|
#include <faiss/gpu/GpuIndex.h>
|
|
30
30
|
#include <faiss/gpu/GpuIndexBinaryFlat.h>
|
|
31
|
-
#if defined
|
|
31
|
+
#if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
|
|
32
32
|
#include <faiss/gpu/GpuIndexBinaryCagra.h>
|
|
33
33
|
#include <faiss/gpu/GpuIndexCagra.h>
|
|
34
34
|
#endif
|
|
@@ -92,7 +92,7 @@ Index* ToCPUCloner::clone_Index(const Index* index) {
|
|
|
92
92
|
// (inverse op of ToGpuClonerMultiple)
|
|
93
93
|
|
|
94
94
|
}
|
|
95
|
-
#if defined
|
|
95
|
+
#if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
|
|
96
96
|
else if (auto icg = dynamic_cast<const GpuIndexCagra*>(index)) {
|
|
97
97
|
IndexHNSWCagra* res = new IndexHNSWCagra();
|
|
98
98
|
if (icg->get_numeric_type() != faiss::NumericType::Float32) {
|
|
@@ -150,8 +150,8 @@ Index* ToGpuCloner::clone_Index(const Index* index) {
|
|
|
150
150
|
GpuIndexFlatConfig config;
|
|
151
151
|
config.device = device;
|
|
152
152
|
config.useFloat16 = true;
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
FAISS_THROW_IF_MSG(
|
|
154
|
+
use_cuvs, "this type of index is not implemented for cuVS");
|
|
155
155
|
GpuIndexFlat* gif = new GpuIndexFlat(
|
|
156
156
|
provider, index->d, index->metric_type, config);
|
|
157
157
|
// transfer data by blocks
|
|
@@ -187,8 +187,8 @@ Index* ToGpuCloner::clone_Index(const Index* index) {
|
|
|
187
187
|
config.device = device;
|
|
188
188
|
config.indicesOptions = indicesOptions;
|
|
189
189
|
config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
config.use_cuvs = use_cuvs;
|
|
191
|
+
config.allowCpuCoarseQuantizer = allowCpuCoarseQuantizer;
|
|
192
192
|
|
|
193
193
|
GpuIndexIVFScalarQuantizer* res = new GpuIndexIVFScalarQuantizer(
|
|
194
194
|
provider,
|
|
@@ -233,7 +233,7 @@ Index* ToGpuCloner::clone_Index(const Index* index) {
|
|
|
233
233
|
|
|
234
234
|
return res;
|
|
235
235
|
}
|
|
236
|
-
#if defined
|
|
236
|
+
#if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
|
|
237
237
|
else if (auto icg = dynamic_cast<const faiss::IndexHNSWCagra*>(index)) {
|
|
238
238
|
GpuIndexCagraConfig config;
|
|
239
239
|
config.device = device;
|
|
@@ -533,7 +533,7 @@ faiss::IndexBinary* index_binary_gpu_to_cpu(
|
|
|
533
533
|
ii->copyTo(ret);
|
|
534
534
|
return ret;
|
|
535
535
|
}
|
|
536
|
-
#if defined
|
|
536
|
+
#if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
|
|
537
537
|
else if (auto ii = dynamic_cast<const GpuIndexBinaryCagra*>(gpu_index)) {
|
|
538
538
|
IndexBinaryHNSWCagra* ret = new IndexBinaryHNSWCagra();
|
|
539
539
|
ii->copyTo(ret);
|
|
@@ -549,13 +549,13 @@ faiss::IndexBinary* index_binary_cpu_to_gpu(
|
|
|
549
549
|
GpuResourcesProvider* provider,
|
|
550
550
|
int device,
|
|
551
551
|
const faiss::IndexBinary* index,
|
|
552
|
-
const GpuClonerOptions* options) {
|
|
552
|
+
const GpuClonerOptions* /*options*/) {
|
|
553
553
|
if (auto ii = dynamic_cast<const IndexBinaryFlat*>(index)) {
|
|
554
554
|
GpuIndexBinaryFlatConfig config;
|
|
555
555
|
config.device = device;
|
|
556
556
|
return new GpuIndexBinaryFlat(provider, ii, config);
|
|
557
557
|
}
|
|
558
|
-
#if defined
|
|
558
|
+
#if defined(USE_NVIDIA_CUVS) && !defined(FAISS_CUVS_NO_CAGRA)
|
|
559
559
|
else if (
|
|
560
560
|
auto ii = dynamic_cast<const faiss::IndexBinaryHNSWCagra*>(index)) {
|
|
561
561
|
GpuIndexCagraConfig config;
|
|
@@ -39,12 +39,8 @@ struct GpuClonerOptions {
|
|
|
39
39
|
/// Set verbose options on the index
|
|
40
40
|
bool verbose = false;
|
|
41
41
|
|
|
42
|
-
///
|
|
43
|
-
#if defined USE_NVIDIA_CUVS
|
|
44
|
-
bool use_cuvs = true;
|
|
45
|
-
#else
|
|
42
|
+
/// Use the cuVS implementation. Opt-in: see GpuIndexConfig::use_cuvs.
|
|
46
43
|
bool use_cuvs = false;
|
|
47
|
-
#endif
|
|
48
44
|
|
|
49
45
|
/// This flag controls the CPU fallback logic for coarse quantizer
|
|
50
46
|
/// component of the index. When set to false (default), the cloner will
|
|
@@ -107,12 +107,9 @@ struct GpuDistanceParams {
|
|
|
107
107
|
/// execution
|
|
108
108
|
int device = -1;
|
|
109
109
|
|
|
110
|
-
/// Should the
|
|
111
|
-
|
|
112
|
-
bool use_cuvs = true;
|
|
113
|
-
#else
|
|
110
|
+
/// Should the search dispatch down to cuVS? Opt-in: see
|
|
111
|
+
/// GpuIndexConfig::use_cuvs.
|
|
114
112
|
bool use_cuvs = false;
|
|
115
|
-
#endif
|
|
116
113
|
};
|
|
117
114
|
|
|
118
115
|
/// A function that determines whether cuVS should be used based on various
|
|
@@ -38,12 +38,11 @@ struct GpuIndexConfig {
|
|
|
38
38
|
/// more memory than is available on the GPU.
|
|
39
39
|
MemorySpace memorySpace = MemorySpace::Device;
|
|
40
40
|
|
|
41
|
-
/// Should the index dispatch down to cuVS?
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
/// Should the index dispatch down to cuVS? Opt-in: dispatching to cuVS
|
|
42
|
+
/// selects a different implementation with its own numerical behaviour, so
|
|
43
|
+
/// it must be an explicit choice by the caller rather than a consequence of
|
|
44
|
+
/// how the binary happened to be built.
|
|
45
45
|
bool use_cuvs = false;
|
|
46
|
-
#endif
|
|
47
46
|
};
|
|
48
47
|
|
|
49
48
|
/// A centralized function that determines whether cuVS should
|
|
@@ -177,6 +176,33 @@ class GpuIndex : public faiss::Index {
|
|
|
177
176
|
}
|
|
178
177
|
};
|
|
179
178
|
|
|
179
|
+
virtual void addImplPrecomputed_(
|
|
180
|
+
idx_t n,
|
|
181
|
+
const float* x,
|
|
182
|
+
const idx_t* ids,
|
|
183
|
+
const idx_t* precomputed_idx);
|
|
184
|
+
|
|
185
|
+
virtual void addImplPrecomputed_ex_(
|
|
186
|
+
idx_t n,
|
|
187
|
+
const void* x,
|
|
188
|
+
NumericType numeric_type,
|
|
189
|
+
const idx_t* ids,
|
|
190
|
+
const idx_t* precomputed_idx);
|
|
191
|
+
|
|
192
|
+
/// Handles paged adds if the add set is too large, passes to
|
|
193
|
+
/// addImpl_ to actually perform the add for the current page
|
|
194
|
+
void addPaged_(
|
|
195
|
+
idx_t n,
|
|
196
|
+
const float* x,
|
|
197
|
+
const idx_t* ids,
|
|
198
|
+
const idx_t* precomputed_idx = nullptr);
|
|
199
|
+
void addPaged_ex_(
|
|
200
|
+
idx_t n,
|
|
201
|
+
const void* x,
|
|
202
|
+
NumericType numeric_type,
|
|
203
|
+
const idx_t* ids,
|
|
204
|
+
const idx_t* precomputed_idx = nullptr);
|
|
205
|
+
|
|
180
206
|
/// Overridden to actually perform the search
|
|
181
207
|
/// All data is guaranteed to be resident on our device
|
|
182
208
|
virtual void searchImpl_(
|
|
@@ -209,22 +235,18 @@ class GpuIndex : public faiss::Index {
|
|
|
209
235
|
}
|
|
210
236
|
|
|
211
237
|
private:
|
|
212
|
-
/// Handles paged adds if the add set is too large, passes to
|
|
213
|
-
/// addImpl_ to actually perform the add for the current page
|
|
214
|
-
void addPaged_(idx_t n, const float* x, const idx_t* ids);
|
|
215
|
-
void addPaged_ex_(
|
|
216
|
-
idx_t n,
|
|
217
|
-
const void* x,
|
|
218
|
-
NumericType numeric_type,
|
|
219
|
-
const idx_t* ids);
|
|
220
|
-
|
|
221
238
|
/// Calls addImpl_ for a single page of GPU-resident data
|
|
222
|
-
void addPage_(
|
|
239
|
+
void addPage_(
|
|
240
|
+
idx_t n,
|
|
241
|
+
const float* x,
|
|
242
|
+
const idx_t* ids,
|
|
243
|
+
const idx_t* precomputed_idx = nullptr);
|
|
223
244
|
void addPage_ex_(
|
|
224
245
|
idx_t n,
|
|
225
246
|
const void* x,
|
|
226
247
|
NumericType numeric_type,
|
|
227
|
-
const idx_t* ids
|
|
248
|
+
const idx_t* ids,
|
|
249
|
+
const idx_t* precomputed_idx = nullptr);
|
|
228
250
|
|
|
229
251
|
/// Calls searchImpl_ for a single page of GPU-resident data
|
|
230
252
|
void searchNonPaged_(
|
|
@@ -47,7 +47,9 @@ enum class graph_build_algo {
|
|
|
47
47
|
/// Use NN-Descent to build all-neighbors knn graph
|
|
48
48
|
NN_DESCENT,
|
|
49
49
|
/// Use iterative search to build knn graph
|
|
50
|
-
ITERATIVE_SEARCH
|
|
50
|
+
ITERATIVE_SEARCH,
|
|
51
|
+
/// Exact knn graph via tiled brute force
|
|
52
|
+
BRUTE_FORCE
|
|
51
53
|
};
|
|
52
54
|
|
|
53
55
|
/// A type for specifying how PQ codebooks are created.
|
|
@@ -173,6 +175,34 @@ struct IVFPQSearchCagraConfig {
|
|
|
173
175
|
uint32_t max_internal_batch_size = 4096;
|
|
174
176
|
};
|
|
175
177
|
|
|
178
|
+
/// Knobs for the multi-GPU build path, selected by listing more than one
|
|
179
|
+
/// device in GpuIndexCagraConfig::devices. Degrees, build_algo and metric
|
|
180
|
+
/// still come from GpuIndexCagraConfig.
|
|
181
|
+
struct AllNeighborsCagraConfig {
|
|
182
|
+
/// Number of overlapping clusters the dataset is partitioned into.
|
|
183
|
+
/// 0 selects max(2 * number of devices, 4).
|
|
184
|
+
size_t n_clusters = 0;
|
|
185
|
+
|
|
186
|
+
/// Clusters each vector is assigned to. Must be >= 2: with 1 there are no
|
|
187
|
+
/// cross-cluster edges and recall collapses. 0 selects 2.
|
|
188
|
+
size_t overlap_factor = 2;
|
|
189
|
+
|
|
190
|
+
/// Bounds IVF-PQ search memory during the knn build. cuVS's default can
|
|
191
|
+
/// exhaust device memory around 100M vectors; 8192 avoids that and does
|
|
192
|
+
/// not change recall. 0 keeps cuVS's default.
|
|
193
|
+
uint32_t ivf_pq_search_batch_size = 0;
|
|
194
|
+
|
|
195
|
+
/// IVF-PQ refinement multiplier. The refine pass runs on the CPU, so cost
|
|
196
|
+
/// scales with this. Raising it above 1.0 measured both slower and less
|
|
197
|
+
/// accurate, so it is separate from the shared refine_rate.
|
|
198
|
+
float refinement_rate = 1.0f;
|
|
199
|
+
|
|
200
|
+
/// Size the IVF-PQ index for one cluster rather than the whole dataset.
|
|
201
|
+
/// cuVS reuses these params for every cluster without rescaling, so
|
|
202
|
+
/// sizing from the full dataset badly over-partitions each one.
|
|
203
|
+
bool ivf_pq_size_from_cluster = true;
|
|
204
|
+
};
|
|
205
|
+
|
|
176
206
|
struct GpuIndexCagraConfig : public GpuIndexConfig {
|
|
177
207
|
/// Degree of input graph for pruning.
|
|
178
208
|
size_t intermediate_graph_degree = 128;
|
|
@@ -190,6 +220,27 @@ struct GpuIndexCagraConfig : public GpuIndexConfig {
|
|
|
190
220
|
|
|
191
221
|
/// Whether to use MST optimization to guarantee graph connectivity.
|
|
192
222
|
bool guarantee_connectivity = false;
|
|
223
|
+
|
|
224
|
+
/// Devices to build on. More than one selects the multi-GPU build in
|
|
225
|
+
/// train(); see AllNeighborsCagraConfig and train() for its restrictions.
|
|
226
|
+
/// Empty or one device uses GpuIndexConfig::device as usual.
|
|
227
|
+
std::vector<int> devices;
|
|
228
|
+
|
|
229
|
+
AllNeighborsCagraConfig all_neighbors_params;
|
|
230
|
+
|
|
231
|
+
/// Build the HNSW upper levels on the GPU during copyTo() instead of by
|
|
232
|
+
/// CPU insertion. Roughly 10x faster, but measured worse recall than
|
|
233
|
+
/// base_level_only, which is cheaper still. Off by default.
|
|
234
|
+
bool gpu_hnsw_upper_levels = false;
|
|
235
|
+
|
|
236
|
+
/// intermediate_graph_degree for the per-level subgraph builds.
|
|
237
|
+
/// 0 = twice the upper-level degree.
|
|
238
|
+
size_t gpu_hnsw_intermediate_degree = 0;
|
|
239
|
+
|
|
240
|
+
/// MST connectivity pass on the per-level subgraphs. On by default:
|
|
241
|
+
/// upper levels are walked greedily with no backtracking, so a
|
|
242
|
+
/// disconnected component is a trap the descent cannot escape.
|
|
243
|
+
bool gpu_hnsw_guarantee_connectivity = true;
|
|
193
244
|
};
|
|
194
245
|
|
|
195
246
|
enum class search_algo {
|
|
@@ -317,6 +368,20 @@ struct GpuIndexCagra : public GpuIndex {
|
|
|
317
368
|
idx_t* labels,
|
|
318
369
|
const SearchParameters* search_params) const override;
|
|
319
370
|
|
|
371
|
+
/// Multi-GPU build path taken by train() when cagraConfig_.devices lists
|
|
372
|
+
/// more than one device: cuVS `all_neighbors` knn graph construction over
|
|
373
|
+
/// overlapping clusters, followed by graph pruning. Leaves the result in
|
|
374
|
+
/// merged_knngraph_ for copyTo(); index_ stays empty.
|
|
375
|
+
void trainAllNeighbors_(idx_t n, const float* x);
|
|
376
|
+
|
|
377
|
+
/// Populate HNSW levels >= 1 of `index` by building a CAGRA graph over
|
|
378
|
+
/// each level's node subset on the GPU. Requires the level table to be
|
|
379
|
+
/// prepared and the storage populated. Returns the max level.
|
|
380
|
+
void buildHnswUpperLevelsGpu_(faiss::IndexHNSWCagra* index, int max_lvl)
|
|
381
|
+
const;
|
|
382
|
+
|
|
383
|
+
void copyToMultiGpu_(faiss::IndexHNSWCagra* index) const;
|
|
384
|
+
|
|
320
385
|
/// Our configuration options
|
|
321
386
|
const GpuIndexCagraConfig cagraConfig_;
|
|
322
387
|
|
|
@@ -329,6 +394,11 @@ struct GpuIndexCagra : public GpuIndex {
|
|
|
329
394
|
std::shared_ptr<CuvsCagra<half>>,
|
|
330
395
|
std::shared_ptr<CuvsCagra<int8_t>>>
|
|
331
396
|
index_;
|
|
397
|
+
|
|
398
|
+
/// Multi-GPU state: populated by trainAllNeighbors_(), used by copyTo()
|
|
399
|
+
std::vector<idx_t> merged_knngraph_;
|
|
400
|
+
idx_t merged_knngraph_degree_ = 0;
|
|
401
|
+
const float* multi_gpu_dataset_ = nullptr;
|
|
332
402
|
};
|
|
333
403
|
|
|
334
404
|
} // namespace gpu
|
|
@@ -98,6 +98,17 @@ class GpuIndexIVF : public GpuIndex, public IndexIVFInterface {
|
|
|
98
98
|
/// debugging purposes.
|
|
99
99
|
virtual std::vector<idx_t> getListIndices(idx_t listId) const;
|
|
100
100
|
|
|
101
|
+
/// Add vectors with precomputed IVF list assignments.
|
|
102
|
+
/// Same naming and argument order as IndexIVF::add_core.
|
|
103
|
+
/// `x`, `xids`, and `precomputed_idx` can be resident on the CPU or any
|
|
104
|
+
/// GPU; copies are performed as needed.
|
|
105
|
+
void add_core(
|
|
106
|
+
idx_t n,
|
|
107
|
+
const float* x,
|
|
108
|
+
const idx_t* xids,
|
|
109
|
+
const idx_t* precomputed_idx,
|
|
110
|
+
void* inverted_list_context = nullptr);
|
|
111
|
+
|
|
101
112
|
void search_preassigned(
|
|
102
113
|
idx_t n,
|
|
103
114
|
const float* x,
|
|
@@ -133,6 +144,12 @@ class GpuIndexIVF : public GpuIndex, public IndexIVFInterface {
|
|
|
133
144
|
/// Called from GpuIndex for add/add_with_ids
|
|
134
145
|
void addImpl_(idx_t n, const float* x, const idx_t* ids) override;
|
|
135
146
|
|
|
147
|
+
void addImplPrecomputed_(
|
|
148
|
+
idx_t n,
|
|
149
|
+
const float* x,
|
|
150
|
+
const idx_t* xids,
|
|
151
|
+
const idx_t* precomputed_idx) override;
|
|
152
|
+
|
|
136
153
|
/// Called from GpuIndex for search
|
|
137
154
|
void searchImpl_(
|
|
138
155
|
idx_t n,
|
|
@@ -93,6 +93,22 @@ class GpuIndexIVFScalarQuantizer : public GpuIndexIVF {
|
|
|
93
93
|
/// Validates index SQ parameters
|
|
94
94
|
void verifySQSettings_() const;
|
|
95
95
|
|
|
96
|
+
/// Whether this index configuration can use cuVS IVF-SQ
|
|
97
|
+
bool shouldUseCuvs_() const;
|
|
98
|
+
|
|
99
|
+
/// Construct the backing IVF implementation
|
|
100
|
+
void setIndex_(
|
|
101
|
+
GpuResources* resources,
|
|
102
|
+
int dim,
|
|
103
|
+
idx_t nlist,
|
|
104
|
+
faiss::MetricType metric,
|
|
105
|
+
float metricArg,
|
|
106
|
+
bool useResidual,
|
|
107
|
+
faiss::ScalarQuantizer* scalarQ,
|
|
108
|
+
bool interleavedLayout,
|
|
109
|
+
IndicesOptions indicesOptions,
|
|
110
|
+
MemorySpace space);
|
|
111
|
+
|
|
96
112
|
/// Called from train to handle SQ residual training
|
|
97
113
|
void trainResiduals_(idx_t n, const float* x);
|
|
98
114
|
|