faiss 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.h +1 -1
- data/vendor/faiss/faiss/Clustering.cpp +35 -4
- data/vendor/faiss/faiss/Clustering.h +10 -1
- data/vendor/faiss/faiss/IVFlib.cpp +4 -1
- data/vendor/faiss/faiss/Index.h +21 -6
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +1 -1
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +1 -1
- data/vendor/faiss/faiss/IndexFastScan.cpp +22 -4
- data/vendor/faiss/faiss/IndexFlat.cpp +11 -7
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +159 -5
- data/vendor/faiss/faiss/IndexFlatCodes.h +20 -3
- data/vendor/faiss/faiss/IndexHNSW.cpp +143 -90
- data/vendor/faiss/faiss/IndexHNSW.h +52 -3
- data/vendor/faiss/faiss/IndexIVF.cpp +3 -3
- data/vendor/faiss/faiss/IndexIVF.h +9 -1
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +15 -0
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +3 -0
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +130 -57
- data/vendor/faiss/faiss/IndexIVFFastScan.h +14 -7
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +1 -3
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +21 -2
- data/vendor/faiss/faiss/IndexLattice.cpp +1 -19
- data/vendor/faiss/faiss/IndexLattice.h +3 -22
- data/vendor/faiss/faiss/IndexNNDescent.cpp +0 -29
- data/vendor/faiss/faiss/IndexNNDescent.h +1 -1
- data/vendor/faiss/faiss/IndexNSG.h +1 -1
- data/vendor/faiss/faiss/IndexNeuralNetCodec.cpp +56 -0
- data/vendor/faiss/faiss/IndexNeuralNetCodec.h +49 -0
- data/vendor/faiss/faiss/IndexPreTransform.h +1 -1
- data/vendor/faiss/faiss/IndexRefine.cpp +5 -5
- data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +3 -1
- data/vendor/faiss/faiss/MetricType.h +7 -2
- data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +95 -17
- data/vendor/faiss/faiss/cppcontrib/factory_tools.cpp +152 -0
- data/vendor/faiss/faiss/cppcontrib/factory_tools.h +24 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +83 -30
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +36 -4
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +6 -0
- data/vendor/faiss/faiss/gpu/GpuFaissAssert.h +1 -1
- data/vendor/faiss/faiss/gpu/GpuIndex.h +2 -8
- data/vendor/faiss/faiss/gpu/GpuIndexCagra.h +282 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +6 -0
- data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +2 -0
- data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +25 -0
- data/vendor/faiss/faiss/gpu/impl/InterleavedCodes.cpp +26 -21
- data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +6 -0
- data/vendor/faiss/faiss/gpu/test/TestCodePacking.cpp +8 -5
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +65 -0
- data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +1 -1
- data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +6 -0
- data/vendor/faiss/faiss/gpu/utils/Timer.cpp +4 -1
- data/vendor/faiss/faiss/gpu/utils/Timer.h +1 -1
- data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +25 -0
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +9 -1
- data/vendor/faiss/faiss/impl/DistanceComputer.h +46 -0
- data/vendor/faiss/faiss/impl/FaissAssert.h +4 -2
- data/vendor/faiss/faiss/impl/HNSW.cpp +358 -190
- data/vendor/faiss/faiss/impl/HNSW.h +43 -22
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +8 -8
- data/vendor/faiss/faiss/impl/LookupTableScaler.h +34 -0
- data/vendor/faiss/faiss/impl/NNDescent.cpp +13 -8
- data/vendor/faiss/faiss/impl/NSG.cpp +0 -29
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +1 -0
- data/vendor/faiss/faiss/impl/ProductQuantizer.h +5 -1
- data/vendor/faiss/faiss/impl/ResultHandler.h +151 -32
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +719 -102
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +3 -0
- data/vendor/faiss/faiss/impl/code_distance/code_distance-avx2.h +5 -0
- data/vendor/faiss/faiss/impl/code_distance/code_distance-avx512.h +248 -0
- data/vendor/faiss/faiss/impl/index_read.cpp +29 -15
- data/vendor/faiss/faiss/impl/index_read_utils.h +37 -0
- data/vendor/faiss/faiss/impl/index_write.cpp +28 -10
- data/vendor/faiss/faiss/impl/io.cpp +13 -5
- data/vendor/faiss/faiss/impl/io.h +4 -4
- data/vendor/faiss/faiss/impl/io_macros.h +6 -0
- data/vendor/faiss/faiss/impl/platform_macros.h +22 -0
- data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +11 -0
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +1 -1
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +448 -1
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +5 -5
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.h +1 -1
- data/vendor/faiss/faiss/impl/simd_result_handlers.h +143 -59
- data/vendor/faiss/faiss/index_factory.cpp +31 -13
- data/vendor/faiss/faiss/index_io.h +12 -5
- data/vendor/faiss/faiss/invlists/BlockInvertedLists.cpp +28 -8
- data/vendor/faiss/faiss/invlists/BlockInvertedLists.h +3 -0
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +9 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +55 -17
- data/vendor/faiss/faiss/invlists/InvertedLists.h +18 -9
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +21 -6
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.h +2 -1
- data/vendor/faiss/faiss/python/python_callbacks.cpp +3 -3
- data/vendor/faiss/faiss/utils/Heap.h +105 -0
- data/vendor/faiss/faiss/utils/NeuralNet.cpp +342 -0
- data/vendor/faiss/faiss/utils/NeuralNet.h +147 -0
- data/vendor/faiss/faiss/utils/bf16.h +36 -0
- data/vendor/faiss/faiss/utils/distances.cpp +58 -88
- data/vendor/faiss/faiss/utils/distances.h +5 -5
- data/vendor/faiss/faiss/utils/distances_simd.cpp +997 -9
- data/vendor/faiss/faiss/utils/extra_distances-inl.h +70 -0
- data/vendor/faiss/faiss/utils/extra_distances.cpp +85 -137
- data/vendor/faiss/faiss/utils/extra_distances.h +3 -2
- data/vendor/faiss/faiss/utils/hamming.cpp +1 -1
- data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +4 -1
- data/vendor/faiss/faiss/utils/hamming_distance/hamdis-inl.h +2 -1
- data/vendor/faiss/faiss/utils/random.cpp +43 -0
- data/vendor/faiss/faiss/utils/random.h +25 -0
- data/vendor/faiss/faiss/utils/simdlib.h +10 -1
- data/vendor/faiss/faiss/utils/simdlib_avx512.h +296 -0
- data/vendor/faiss/faiss/utils/simdlib_neon.h +5 -2
- data/vendor/faiss/faiss/utils/simdlib_ppc64.h +1084 -0
- data/vendor/faiss/faiss/utils/transpose/transpose-avx512-inl.h +176 -0
- data/vendor/faiss/faiss/utils/utils.cpp +10 -3
- data/vendor/faiss/faiss/utils/utils.h +3 -0
- metadata +16 -4
- data/vendor/faiss/faiss/impl/code_distance/code_distance_avx512.h +0 -102
@@ -5,8 +5,6 @@
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
6
6
|
*/
|
7
7
|
|
8
|
-
// -*- c++ -*-
|
9
|
-
|
10
8
|
#include <faiss/IndexHNSW.h>
|
11
9
|
|
12
10
|
#include <omp.h>
|
@@ -17,7 +15,10 @@
|
|
17
15
|
#include <cstdlib>
|
18
16
|
#include <cstring>
|
19
17
|
|
18
|
+
#include <limits>
|
19
|
+
#include <memory>
|
20
20
|
#include <queue>
|
21
|
+
#include <random>
|
21
22
|
#include <unordered_set>
|
22
23
|
|
23
24
|
#include <sys/stat.h>
|
@@ -34,26 +35,6 @@
|
|
34
35
|
#include <faiss/utils/random.h>
|
35
36
|
#include <faiss/utils/sorting.h>
|
36
37
|
|
37
|
-
extern "C" {
|
38
|
-
|
39
|
-
/* declare BLAS functions, see http://www.netlib.org/clapack/cblas/ */
|
40
|
-
|
41
|
-
int sgemm_(
|
42
|
-
const char* transa,
|
43
|
-
const char* transb,
|
44
|
-
FINTEGER* m,
|
45
|
-
FINTEGER* n,
|
46
|
-
FINTEGER* k,
|
47
|
-
const float* alpha,
|
48
|
-
const float* a,
|
49
|
-
FINTEGER* lda,
|
50
|
-
const float* b,
|
51
|
-
FINTEGER* ldb,
|
52
|
-
float* beta,
|
53
|
-
float* c,
|
54
|
-
FINTEGER* ldc);
|
55
|
-
}
|
56
|
-
|
57
38
|
namespace faiss {
|
58
39
|
|
59
40
|
using MinimaxHeap = HNSW::MinimaxHeap;
|
@@ -68,52 +49,6 @@ HNSWStats hnsw_stats;
|
|
68
49
|
|
69
50
|
namespace {
|
70
51
|
|
71
|
-
/* Wrap the distance computer into one that negates the
|
72
|
-
distances. This makes supporting INNER_PRODUCE search easier */
|
73
|
-
|
74
|
-
struct NegativeDistanceComputer : DistanceComputer {
|
75
|
-
/// owned by this
|
76
|
-
DistanceComputer* basedis;
|
77
|
-
|
78
|
-
explicit NegativeDistanceComputer(DistanceComputer* basedis)
|
79
|
-
: basedis(basedis) {}
|
80
|
-
|
81
|
-
void set_query(const float* x) override {
|
82
|
-
basedis->set_query(x);
|
83
|
-
}
|
84
|
-
|
85
|
-
/// compute distance of vector i to current query
|
86
|
-
float operator()(idx_t i) override {
|
87
|
-
return -(*basedis)(i);
|
88
|
-
}
|
89
|
-
|
90
|
-
void distances_batch_4(
|
91
|
-
const idx_t idx0,
|
92
|
-
const idx_t idx1,
|
93
|
-
const idx_t idx2,
|
94
|
-
const idx_t idx3,
|
95
|
-
float& dis0,
|
96
|
-
float& dis1,
|
97
|
-
float& dis2,
|
98
|
-
float& dis3) override {
|
99
|
-
basedis->distances_batch_4(
|
100
|
-
idx0, idx1, idx2, idx3, dis0, dis1, dis2, dis3);
|
101
|
-
dis0 = -dis0;
|
102
|
-
dis1 = -dis1;
|
103
|
-
dis2 = -dis2;
|
104
|
-
dis3 = -dis3;
|
105
|
-
}
|
106
|
-
|
107
|
-
/// compute distance between two stored vectors
|
108
|
-
float symmetric_dis(idx_t i, idx_t j) override {
|
109
|
-
return -basedis->symmetric_dis(i, j);
|
110
|
-
}
|
111
|
-
|
112
|
-
virtual ~NegativeDistanceComputer() {
|
113
|
-
delete basedis;
|
114
|
-
}
|
115
|
-
};
|
116
|
-
|
117
52
|
DistanceComputer* storage_distance_computer(const Index* storage) {
|
118
53
|
if (is_similarity_metric(storage->metric_type)) {
|
119
54
|
return new NegativeDistanceComputer(storage->get_distance_computer());
|
@@ -192,7 +127,9 @@ void hnsw_add_vertices(
|
|
192
127
|
|
193
128
|
int i1 = n;
|
194
129
|
|
195
|
-
for (int pt_level = hist.size() - 1;
|
130
|
+
for (int pt_level = hist.size() - 1;
|
131
|
+
pt_level >= !index_hnsw.init_level0;
|
132
|
+
pt_level--) {
|
196
133
|
int i0 = i1 - hist[pt_level];
|
197
134
|
|
198
135
|
if (verbose) {
|
@@ -228,7 +165,13 @@ void hnsw_add_vertices(
|
|
228
165
|
continue;
|
229
166
|
}
|
230
167
|
|
231
|
-
hnsw.add_with_locks(
|
168
|
+
hnsw.add_with_locks(
|
169
|
+
*dis,
|
170
|
+
pt_level,
|
171
|
+
pt_id,
|
172
|
+
locks,
|
173
|
+
vt,
|
174
|
+
index_hnsw.keep_max_size_level0 && (pt_level == 0));
|
232
175
|
|
233
176
|
if (prev_display >= 0 && i - i0 > prev_display + 10000) {
|
234
177
|
prev_display = i - i0;
|
@@ -248,7 +191,11 @@ void hnsw_add_vertices(
|
|
248
191
|
}
|
249
192
|
i1 = i0;
|
250
193
|
}
|
251
|
-
|
194
|
+
if (index_hnsw.init_level0) {
|
195
|
+
FAISS_ASSERT(i1 == 0);
|
196
|
+
} else {
|
197
|
+
FAISS_ASSERT((i1 - hist[0]) == 0);
|
198
|
+
}
|
252
199
|
}
|
253
200
|
if (verbose) {
|
254
201
|
printf("Done in %.3f ms\n", getmillisecs() - t0);
|
@@ -297,7 +244,8 @@ void hnsw_search(
|
|
297
244
|
const SearchParameters* params_in) {
|
298
245
|
FAISS_THROW_IF_NOT_MSG(
|
299
246
|
index->storage,
|
300
|
-
"
|
247
|
+
"No storage index, please use IndexHNSWFlat (or variants) "
|
248
|
+
"instead of IndexHNSW directly");
|
301
249
|
const SearchParametersHNSW* params = nullptr;
|
302
250
|
const HNSW& hnsw = index->hnsw;
|
303
251
|
|
@@ -307,7 +255,7 @@ void hnsw_search(
|
|
307
255
|
FAISS_THROW_IF_NOT_MSG(params, "params type invalid");
|
308
256
|
efSearch = params->efSearch;
|
309
257
|
}
|
310
|
-
size_t n1 = 0, n2 = 0,
|
258
|
+
size_t n1 = 0, n2 = 0, ndis = 0, nhops = 0;
|
311
259
|
|
312
260
|
idx_t check_period = InterruptCallback::get_period_hint(
|
313
261
|
hnsw.max_level * index->d * efSearch);
|
@@ -315,7 +263,7 @@ void hnsw_search(
|
|
315
263
|
for (idx_t i0 = 0; i0 < n; i0 += check_period) {
|
316
264
|
idx_t i1 = std::min(i0 + check_period, n);
|
317
265
|
|
318
|
-
#pragma omp parallel
|
266
|
+
#pragma omp parallel if (i1 - i0 > 1)
|
319
267
|
{
|
320
268
|
VisitedTable vt(index->ntotal);
|
321
269
|
typename BlockResultHandler::SingleResultHandler res(bres);
|
@@ -323,7 +271,7 @@ void hnsw_search(
|
|
323
271
|
std::unique_ptr<DistanceComputer> dis(
|
324
272
|
storage_distance_computer(index->storage));
|
325
273
|
|
326
|
-
#pragma omp for reduction(+ : n1, n2,
|
274
|
+
#pragma omp for reduction(+ : n1, n2, ndis, nhops) schedule(guided)
|
327
275
|
for (idx_t i = i0; i < i1; i++) {
|
328
276
|
res.begin(i);
|
329
277
|
dis->set_query(x + i * index->d);
|
@@ -331,16 +279,15 @@ void hnsw_search(
|
|
331
279
|
HNSWStats stats = hnsw.search(*dis, res, vt, params);
|
332
280
|
n1 += stats.n1;
|
333
281
|
n2 += stats.n2;
|
334
|
-
n3 += stats.n3;
|
335
282
|
ndis += stats.ndis;
|
336
|
-
|
283
|
+
nhops += stats.nhops;
|
337
284
|
res.end();
|
338
285
|
}
|
339
286
|
}
|
340
287
|
InterruptCallback::check();
|
341
288
|
}
|
342
289
|
|
343
|
-
hnsw_stats.combine({n1, n2,
|
290
|
+
hnsw_stats.combine({n1, n2, ndis, nhops});
|
344
291
|
}
|
345
292
|
|
346
293
|
} // anonymous namespace
|
@@ -374,7 +321,7 @@ void IndexHNSW::range_search(
|
|
374
321
|
RangeSearchResult* result,
|
375
322
|
const SearchParameters* params) const {
|
376
323
|
using RH = RangeSearchBlockResultHandler<HNSW::C>;
|
377
|
-
RH bres(result, radius);
|
324
|
+
RH bres(result, is_similarity_metric(metric_type) ? -radius : radius);
|
378
325
|
|
379
326
|
hnsw_search(this, n, x, bres, params);
|
380
327
|
|
@@ -453,10 +400,18 @@ void IndexHNSW::search_level_0(
|
|
453
400
|
float* distances,
|
454
401
|
idx_t* labels,
|
455
402
|
int nprobe,
|
456
|
-
int search_type
|
403
|
+
int search_type,
|
404
|
+
const SearchParameters* params_in) const {
|
457
405
|
FAISS_THROW_IF_NOT(k > 0);
|
458
406
|
FAISS_THROW_IF_NOT(nprobe > 0);
|
459
407
|
|
408
|
+
const SearchParametersHNSW* params = nullptr;
|
409
|
+
|
410
|
+
if (params_in) {
|
411
|
+
params = dynamic_cast<const SearchParametersHNSW*>(params_in);
|
412
|
+
FAISS_THROW_IF_NOT_MSG(params, "params type invalid");
|
413
|
+
}
|
414
|
+
|
460
415
|
storage_idx_t ntotal = hnsw.levels.size();
|
461
416
|
|
462
417
|
using RH = HeapBlockResultHandler<HNSW::C>;
|
@@ -483,13 +438,21 @@ void IndexHNSW::search_level_0(
|
|
483
438
|
nearest_d + i * nprobe,
|
484
439
|
search_type,
|
485
440
|
search_stats,
|
486
|
-
vt
|
441
|
+
vt,
|
442
|
+
params);
|
487
443
|
res.end();
|
488
444
|
vt.advance();
|
489
445
|
}
|
490
446
|
#pragma omp critical
|
491
447
|
{ hnsw_stats.combine(search_stats); }
|
492
448
|
}
|
449
|
+
if (is_similarity_metric(this->metric_type)) {
|
450
|
+
// we need to revert the negated distances
|
451
|
+
#pragma omp parallel for
|
452
|
+
for (int64_t i = 0; i < k * n; i++) {
|
453
|
+
distances[i] = -distances[i];
|
454
|
+
}
|
455
|
+
}
|
493
456
|
}
|
494
457
|
|
495
458
|
void IndexHNSW::init_level_0_from_knngraph(
|
@@ -650,6 +613,10 @@ void IndexHNSW::permute_entries(const idx_t* perm) {
|
|
650
613
|
hnsw.permute_entries(perm);
|
651
614
|
}
|
652
615
|
|
616
|
+
DistanceComputer* IndexHNSW::get_distance_computer() const {
|
617
|
+
return storage->get_distance_computer();
|
618
|
+
}
|
619
|
+
|
653
620
|
/**************************************************************
|
654
621
|
* IndexHNSWFlat implementation
|
655
622
|
**************************************************************/
|
@@ -673,8 +640,13 @@ IndexHNSWFlat::IndexHNSWFlat(int d, int M, MetricType metric)
|
|
673
640
|
|
674
641
|
IndexHNSWPQ::IndexHNSWPQ() = default;
|
675
642
|
|
676
|
-
IndexHNSWPQ::IndexHNSWPQ(
|
677
|
-
|
643
|
+
IndexHNSWPQ::IndexHNSWPQ(
|
644
|
+
int d,
|
645
|
+
int pq_m,
|
646
|
+
int M,
|
647
|
+
int pq_nbits,
|
648
|
+
MetricType metric)
|
649
|
+
: IndexHNSW(new IndexPQ(d, pq_m, pq_nbits, metric), M) {
|
678
650
|
own_fields = true;
|
679
651
|
is_trained = false;
|
680
652
|
}
|
@@ -800,7 +772,7 @@ void IndexHNSW2Level::search(
|
|
800
772
|
IndexHNSW::search(n, x, k, distances, labels);
|
801
773
|
|
802
774
|
} else { // "mixed" search
|
803
|
-
size_t n1 = 0, n2 = 0,
|
775
|
+
size_t n1 = 0, n2 = 0, ndis = 0, nhops = 0;
|
804
776
|
|
805
777
|
const IndexIVFPQ* index_ivfpq =
|
806
778
|
dynamic_cast<const IndexIVFPQ*>(storage);
|
@@ -829,10 +801,10 @@ void IndexHNSW2Level::search(
|
|
829
801
|
std::unique_ptr<DistanceComputer> dis(
|
830
802
|
storage_distance_computer(storage));
|
831
803
|
|
832
|
-
int candidates_size =
|
804
|
+
constexpr int candidates_size = 1;
|
833
805
|
MinimaxHeap candidates(candidates_size);
|
834
806
|
|
835
|
-
#pragma omp for reduction(+ : n1, n2,
|
807
|
+
#pragma omp for reduction(+ : n1, n2, ndis, nhops)
|
836
808
|
for (idx_t i = 0; i < n; i++) {
|
837
809
|
idx_t* idxi = labels + i * k;
|
838
810
|
float* simi = distances + i * k;
|
@@ -854,7 +826,7 @@ void IndexHNSW2Level::search(
|
|
854
826
|
|
855
827
|
candidates.clear();
|
856
828
|
|
857
|
-
for (int j = 0; j <
|
829
|
+
for (int j = 0; j < k; j++) {
|
858
830
|
if (idxi[j] < 0)
|
859
831
|
break;
|
860
832
|
candidates.push(idxi[j], simi[j]);
|
@@ -877,9 +849,8 @@ void IndexHNSW2Level::search(
|
|
877
849
|
k);
|
878
850
|
n1 += search_stats.n1;
|
879
851
|
n2 += search_stats.n2;
|
880
|
-
n3 += search_stats.n3;
|
881
852
|
ndis += search_stats.ndis;
|
882
|
-
|
853
|
+
nhops += search_stats.nhops;
|
883
854
|
|
884
855
|
vt.advance();
|
885
856
|
vt.advance();
|
@@ -888,7 +859,7 @@ void IndexHNSW2Level::search(
|
|
888
859
|
}
|
889
860
|
}
|
890
861
|
|
891
|
-
hnsw_stats.combine({n1, n2,
|
862
|
+
hnsw_stats.combine({n1, n2, ndis, nhops});
|
892
863
|
}
|
893
864
|
}
|
894
865
|
|
@@ -914,4 +885,86 @@ void IndexHNSW2Level::flip_to_ivf() {
|
|
914
885
|
delete storage2l;
|
915
886
|
}
|
916
887
|
|
888
|
+
/**************************************************************
|
889
|
+
* IndexHNSWCagra implementation
|
890
|
+
**************************************************************/
|
891
|
+
|
892
|
+
IndexHNSWCagra::IndexHNSWCagra() {
|
893
|
+
is_trained = true;
|
894
|
+
}
|
895
|
+
|
896
|
+
IndexHNSWCagra::IndexHNSWCagra(int d, int M, MetricType metric)
|
897
|
+
: IndexHNSW(
|
898
|
+
(metric == METRIC_L2)
|
899
|
+
? static_cast<IndexFlat*>(new IndexFlatL2(d))
|
900
|
+
: static_cast<IndexFlat*>(new IndexFlatIP(d)),
|
901
|
+
M) {
|
902
|
+
FAISS_THROW_IF_NOT_MSG(
|
903
|
+
((metric == METRIC_L2) || (metric == METRIC_INNER_PRODUCT)),
|
904
|
+
"unsupported metric type for IndexHNSWCagra");
|
905
|
+
own_fields = true;
|
906
|
+
is_trained = true;
|
907
|
+
init_level0 = true;
|
908
|
+
keep_max_size_level0 = true;
|
909
|
+
}
|
910
|
+
|
911
|
+
void IndexHNSWCagra::add(idx_t n, const float* x) {
|
912
|
+
FAISS_THROW_IF_NOT_MSG(
|
913
|
+
!base_level_only,
|
914
|
+
"Cannot add vectors when base_level_only is set to True");
|
915
|
+
|
916
|
+
IndexHNSW::add(n, x);
|
917
|
+
}
|
918
|
+
|
919
|
+
void IndexHNSWCagra::search(
|
920
|
+
idx_t n,
|
921
|
+
const float* x,
|
922
|
+
idx_t k,
|
923
|
+
float* distances,
|
924
|
+
idx_t* labels,
|
925
|
+
const SearchParameters* params) const {
|
926
|
+
if (!base_level_only) {
|
927
|
+
IndexHNSW::search(n, x, k, distances, labels, params);
|
928
|
+
} else {
|
929
|
+
std::vector<storage_idx_t> nearest(n);
|
930
|
+
std::vector<float> nearest_d(n);
|
931
|
+
|
932
|
+
#pragma omp for
|
933
|
+
for (idx_t i = 0; i < n; i++) {
|
934
|
+
std::unique_ptr<DistanceComputer> dis(
|
935
|
+
storage_distance_computer(this->storage));
|
936
|
+
dis->set_query(x + i * d);
|
937
|
+
nearest[i] = -1;
|
938
|
+
nearest_d[i] = std::numeric_limits<float>::max();
|
939
|
+
|
940
|
+
std::random_device rd;
|
941
|
+
std::mt19937 gen(rd());
|
942
|
+
std::uniform_int_distribution<idx_t> distrib(0, this->ntotal - 1);
|
943
|
+
|
944
|
+
for (idx_t j = 0; j < num_base_level_search_entrypoints; j++) {
|
945
|
+
auto idx = distrib(gen);
|
946
|
+
auto distance = (*dis)(idx);
|
947
|
+
if (distance < nearest_d[i]) {
|
948
|
+
nearest[i] = idx;
|
949
|
+
nearest_d[i] = distance;
|
950
|
+
}
|
951
|
+
}
|
952
|
+
FAISS_THROW_IF_NOT_MSG(
|
953
|
+
nearest[i] >= 0, "Could not find a valid entrypoint.");
|
954
|
+
}
|
955
|
+
|
956
|
+
search_level_0(
|
957
|
+
n,
|
958
|
+
x,
|
959
|
+
k,
|
960
|
+
nearest.data(),
|
961
|
+
nearest_d.data(),
|
962
|
+
distances,
|
963
|
+
labels,
|
964
|
+
1, // n_probes
|
965
|
+
1, // search_type
|
966
|
+
params);
|
967
|
+
}
|
968
|
+
}
|
969
|
+
|
917
970
|
} // namespace faiss
|
@@ -27,13 +27,25 @@ struct IndexHNSW;
|
|
27
27
|
struct IndexHNSW : Index {
|
28
28
|
typedef HNSW::storage_idx_t storage_idx_t;
|
29
29
|
|
30
|
-
// the link
|
30
|
+
// the link structure
|
31
31
|
HNSW hnsw;
|
32
32
|
|
33
33
|
// the sequential storage
|
34
34
|
bool own_fields = false;
|
35
35
|
Index* storage = nullptr;
|
36
36
|
|
37
|
+
// When set to false, level 0 in the knn graph is not initialized.
|
38
|
+
// This option is used by GpuIndexCagra::copyTo(IndexHNSWCagra*)
|
39
|
+
// as level 0 knn graph is copied over from the index built by
|
40
|
+
// GpuIndexCagra.
|
41
|
+
bool init_level0 = true;
|
42
|
+
|
43
|
+
// When set to true, all neighbors in level 0 are filled up
|
44
|
+
// to the maximum size allowed (2 * M). This option is used by
|
45
|
+
// IndexHHNSWCagra to create a full base layer graph that is
|
46
|
+
// used when GpuIndexCagra::copyFrom(IndexHNSWCagra*) is invoked.
|
47
|
+
bool keep_max_size_level0 = false;
|
48
|
+
|
37
49
|
explicit IndexHNSW(int d = 0, int M = 32, MetricType metric = METRIC_L2);
|
38
50
|
explicit IndexHNSW(Index* storage, int M = 32);
|
39
51
|
|
@@ -81,7 +93,8 @@ struct IndexHNSW : Index {
|
|
81
93
|
float* distances,
|
82
94
|
idx_t* labels,
|
83
95
|
int nprobe = 1,
|
84
|
-
int search_type = 1
|
96
|
+
int search_type = 1,
|
97
|
+
const SearchParameters* params = nullptr) const;
|
85
98
|
|
86
99
|
/// alternative graph building
|
87
100
|
void init_level_0_from_knngraph(int k, const float* D, const idx_t* I);
|
@@ -98,6 +111,8 @@ struct IndexHNSW : Index {
|
|
98
111
|
void link_singletons();
|
99
112
|
|
100
113
|
void permute_entries(const idx_t* perm);
|
114
|
+
|
115
|
+
DistanceComputer* get_distance_computer() const override;
|
101
116
|
};
|
102
117
|
|
103
118
|
/** Flat index topped with with a HNSW structure to access elements
|
@@ -114,7 +129,12 @@ struct IndexHNSWFlat : IndexHNSW {
|
|
114
129
|
*/
|
115
130
|
struct IndexHNSWPQ : IndexHNSW {
|
116
131
|
IndexHNSWPQ();
|
117
|
-
IndexHNSWPQ(
|
132
|
+
IndexHNSWPQ(
|
133
|
+
int d,
|
134
|
+
int pq_m,
|
135
|
+
int M,
|
136
|
+
int pq_nbits = 8,
|
137
|
+
MetricType metric = METRIC_L2);
|
118
138
|
void train(idx_t n, const float* x) override;
|
119
139
|
};
|
120
140
|
|
@@ -148,4 +168,33 @@ struct IndexHNSW2Level : IndexHNSW {
|
|
148
168
|
const SearchParameters* params = nullptr) const override;
|
149
169
|
};
|
150
170
|
|
171
|
+
struct IndexHNSWCagra : IndexHNSW {
|
172
|
+
IndexHNSWCagra();
|
173
|
+
IndexHNSWCagra(int d, int M, MetricType metric = METRIC_L2);
|
174
|
+
|
175
|
+
/// When set to true, the index is immutable.
|
176
|
+
/// This option is used to copy the knn graph from GpuIndexCagra
|
177
|
+
/// to the base level of IndexHNSWCagra without adding upper levels.
|
178
|
+
/// Doing so enables to search the HNSW index, but removes the
|
179
|
+
/// ability to add vectors.
|
180
|
+
bool base_level_only = false;
|
181
|
+
|
182
|
+
/// When `base_level_only` is set to `True`, the search function
|
183
|
+
/// searches only the base level knn graph of the HNSW index.
|
184
|
+
/// This parameter selects the entry point by randomly selecting
|
185
|
+
/// some points and using the best one.
|
186
|
+
int num_base_level_search_entrypoints = 32;
|
187
|
+
|
188
|
+
void add(idx_t n, const float* x) override;
|
189
|
+
|
190
|
+
/// entry point for search
|
191
|
+
void search(
|
192
|
+
idx_t n,
|
193
|
+
const float* x,
|
194
|
+
idx_t k,
|
195
|
+
float* distances,
|
196
|
+
idx_t* labels,
|
197
|
+
const SearchParameters* params = nullptr) const override;
|
198
|
+
};
|
199
|
+
|
151
200
|
} // namespace faiss
|
@@ -66,8 +66,8 @@ void Level1Quantizer::train_q1(
|
|
66
66
|
} else if (quantizer_trains_alone == 1) {
|
67
67
|
if (verbose)
|
68
68
|
printf("IVF quantizer trains alone...\n");
|
69
|
-
quantizer->train(n, x);
|
70
69
|
quantizer->verbose = verbose;
|
70
|
+
quantizer->train(n, x);
|
71
71
|
FAISS_THROW_IF_NOT_MSG(
|
72
72
|
quantizer->ntotal == nlist,
|
73
73
|
"nlist not consistent with quantizer size");
|
@@ -444,7 +444,7 @@ void IndexIVF::search_preassigned(
|
|
444
444
|
max_codes = unlimited_list_size;
|
445
445
|
}
|
446
446
|
|
447
|
-
bool do_parallel = omp_get_max_threads() >= 2 &&
|
447
|
+
[[maybe_unused]] bool do_parallel = omp_get_max_threads() >= 2 &&
|
448
448
|
(pmode == 0 ? false
|
449
449
|
: pmode == 3 ? n > 1
|
450
450
|
: pmode == 1 ? nprobe > 1
|
@@ -784,7 +784,7 @@ void IndexIVF::range_search_preassigned(
|
|
784
784
|
|
785
785
|
int pmode = this->parallel_mode & ~PARALLEL_MODE_NO_HEAP_INIT;
|
786
786
|
// don't start parallel section if single query
|
787
|
-
bool do_parallel = omp_get_max_threads() >= 2 &&
|
787
|
+
[[maybe_unused]] bool do_parallel = omp_get_max_threads() >= 2 &&
|
788
788
|
(pmode == 3 ? false
|
789
789
|
: pmode == 0 ? nx > 1
|
790
790
|
: pmode == 1 ? nprobe > 1
|
@@ -433,6 +433,14 @@ struct IndexIVF : Index, IndexIVFInterface {
|
|
433
433
|
|
434
434
|
/* The standalone codec interface (except sa_decode that is specific) */
|
435
435
|
size_t sa_code_size() const override;
|
436
|
+
|
437
|
+
/** encode a set of vectors
|
438
|
+
* sa_encode will call encode_vector with include_listno=true
|
439
|
+
* @param n nb of vectors to encode
|
440
|
+
* @param x the vectors to encode
|
441
|
+
* @param bytes output array for the codes
|
442
|
+
* @return nb of bytes written to codes
|
443
|
+
*/
|
436
444
|
void sa_encode(idx_t n, const float* x, uint8_t* bytes) const override;
|
437
445
|
|
438
446
|
IndexIVF();
|
@@ -471,7 +479,7 @@ struct InvertedListScanner {
|
|
471
479
|
virtual float distance_to_code(const uint8_t* code) const = 0;
|
472
480
|
|
473
481
|
/** scan a set of codes, compute distances to current query and
|
474
|
-
* update heap of results if necessary. Default
|
482
|
+
* update heap of results if necessary. Default implementation
|
475
483
|
* calls distance_to_code.
|
476
484
|
*
|
477
485
|
* @param n number of codes to scan
|
@@ -116,6 +116,21 @@ void IndexIVFAdditiveQuantizer::sa_decode(
|
|
116
116
|
}
|
117
117
|
}
|
118
118
|
|
119
|
+
void IndexIVFAdditiveQuantizer::reconstruct_from_offset(
|
120
|
+
int64_t list_no,
|
121
|
+
int64_t offset,
|
122
|
+
float* recons) const {
|
123
|
+
const uint8_t* code = invlists->get_single_code(list_no, offset);
|
124
|
+
aq->decode(code, recons, 1);
|
125
|
+
if (by_residual) {
|
126
|
+
std::vector<float> centroid(d);
|
127
|
+
quantizer->reconstruct(list_no, centroid.data());
|
128
|
+
for (int i = 0; i < d; ++i) {
|
129
|
+
recons[i] += centroid[i];
|
130
|
+
}
|
131
|
+
}
|
132
|
+
}
|
133
|
+
|
119
134
|
IndexIVFAdditiveQuantizer::~IndexIVFAdditiveQuantizer() = default;
|
120
135
|
|
121
136
|
/*********************************************
|
@@ -56,6 +56,9 @@ struct IndexIVFAdditiveQuantizer : IndexIVF {
|
|
56
56
|
|
57
57
|
void sa_decode(idx_t n, const uint8_t* codes, float* x) const override;
|
58
58
|
|
59
|
+
void reconstruct_from_offset(int64_t list_no, int64_t offset, float* recons)
|
60
|
+
const override;
|
61
|
+
|
59
62
|
~IndexIVFAdditiveQuantizer() override;
|
60
63
|
};
|
61
64
|
|