faiss 0.2.7 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/ext/faiss/extconf.rb +9 -2
- data/ext/faiss/index.cpp +1 -1
- data/ext/faiss/index_binary.cpp +2 -2
- data/ext/faiss/product_quantizer.cpp +1 -1
- data/lib/faiss/version.rb +1 -1
- data/lib/faiss.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +7 -7
- data/vendor/faiss/faiss/AutoTune.h +0 -1
- data/vendor/faiss/faiss/Clustering.cpp +4 -18
- data/vendor/faiss/faiss/Clustering.h +31 -21
- data/vendor/faiss/faiss/IVFlib.cpp +22 -11
- data/vendor/faiss/faiss/Index.cpp +1 -1
- data/vendor/faiss/faiss/Index.h +20 -5
- data/vendor/faiss/faiss/Index2Layer.cpp +7 -7
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +176 -166
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +15 -15
- data/vendor/faiss/faiss/IndexBinary.cpp +9 -4
- data/vendor/faiss/faiss/IndexBinary.h +8 -19
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +2 -1
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +24 -31
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +25 -50
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +106 -187
- data/vendor/faiss/faiss/IndexFastScan.cpp +90 -159
- data/vendor/faiss/faiss/IndexFastScan.h +9 -8
- data/vendor/faiss/faiss/IndexFlat.cpp +195 -3
- data/vendor/faiss/faiss/IndexFlat.h +20 -1
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +11 -0
- data/vendor/faiss/faiss/IndexFlatCodes.h +3 -1
- data/vendor/faiss/faiss/IndexHNSW.cpp +112 -316
- data/vendor/faiss/faiss/IndexHNSW.h +12 -48
- data/vendor/faiss/faiss/IndexIDMap.cpp +69 -28
- data/vendor/faiss/faiss/IndexIDMap.h +24 -2
- data/vendor/faiss/faiss/IndexIVF.cpp +159 -53
- data/vendor/faiss/faiss/IndexIVF.h +37 -5
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +18 -26
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +3 -2
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +19 -46
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +4 -3
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +433 -405
- data/vendor/faiss/faiss/IndexIVFFastScan.h +56 -26
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +15 -5
- data/vendor/faiss/faiss/IndexIVFFlat.h +3 -2
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.cpp +172 -0
- data/vendor/faiss/faiss/IndexIVFIndependentQuantizer.h +56 -0
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +78 -122
- data/vendor/faiss/faiss/IndexIVFPQ.h +6 -7
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +18 -50
- data/vendor/faiss/faiss/IndexIVFPQFastScan.h +4 -3
- data/vendor/faiss/faiss/IndexIVFPQR.cpp +45 -29
- data/vendor/faiss/faiss/IndexIVFPQR.h +5 -2
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +25 -27
- data/vendor/faiss/faiss/IndexIVFSpectralHash.h +6 -6
- data/vendor/faiss/faiss/IndexLSH.cpp +14 -16
- data/vendor/faiss/faiss/IndexNNDescent.cpp +3 -4
- data/vendor/faiss/faiss/IndexNSG.cpp +11 -27
- data/vendor/faiss/faiss/IndexNSG.h +10 -10
- data/vendor/faiss/faiss/IndexPQ.cpp +72 -88
- data/vendor/faiss/faiss/IndexPQ.h +1 -4
- data/vendor/faiss/faiss/IndexPQFastScan.cpp +1 -1
- data/vendor/faiss/faiss/IndexPreTransform.cpp +25 -31
- data/vendor/faiss/faiss/IndexRefine.cpp +49 -19
- data/vendor/faiss/faiss/IndexRefine.h +7 -0
- data/vendor/faiss/faiss/IndexReplicas.cpp +23 -26
- data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +22 -16
- data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -4
- data/vendor/faiss/faiss/IndexShards.cpp +21 -29
- data/vendor/faiss/faiss/IndexShardsIVF.cpp +1 -2
- data/vendor/faiss/faiss/MatrixStats.cpp +17 -32
- data/vendor/faiss/faiss/MatrixStats.h +21 -9
- data/vendor/faiss/faiss/MetaIndexes.cpp +35 -35
- data/vendor/faiss/faiss/VectorTransform.cpp +13 -26
- data/vendor/faiss/faiss/VectorTransform.h +7 -7
- data/vendor/faiss/faiss/clone_index.cpp +15 -10
- data/vendor/faiss/faiss/clone_index.h +3 -0
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +87 -4
- data/vendor/faiss/faiss/gpu/GpuCloner.h +22 -0
- data/vendor/faiss/faiss/gpu/GpuClonerOptions.h +7 -0
- data/vendor/faiss/faiss/gpu/GpuDistance.h +46 -38
- data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
- data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +4 -4
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +8 -9
- data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +18 -3
- data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -11
- data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +1 -3
- data/vendor/faiss/faiss/gpu/GpuResources.cpp +24 -3
- data/vendor/faiss/faiss/gpu/GpuResources.h +39 -11
- data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +117 -17
- data/vendor/faiss/faiss/gpu/StandardGpuResources.h +57 -3
- data/vendor/faiss/faiss/gpu/perf/PerfClustering.cpp +1 -1
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +25 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +129 -9
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +267 -40
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +299 -208
- data/vendor/faiss/faiss/gpu/test/TestGpuMemoryException.cpp +1 -0
- data/vendor/faiss/faiss/gpu/utils/RaftUtils.h +75 -0
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +3 -1
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +5 -5
- data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +1 -1
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +1 -2
- data/vendor/faiss/faiss/impl/DistanceComputer.h +24 -1
- data/vendor/faiss/faiss/impl/FaissException.h +13 -34
- data/vendor/faiss/faiss/impl/HNSW.cpp +321 -70
- data/vendor/faiss/faiss/impl/HNSW.h +9 -8
- data/vendor/faiss/faiss/impl/IDSelector.h +4 -4
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +3 -1
- data/vendor/faiss/faiss/impl/NNDescent.cpp +29 -19
- data/vendor/faiss/faiss/impl/NSG.h +1 -1
- data/vendor/faiss/faiss/impl/PolysemousTraining.cpp +14 -12
- data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +1 -1
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +24 -22
- data/vendor/faiss/faiss/impl/ProductQuantizer.h +1 -1
- data/vendor/faiss/faiss/impl/Quantizer.h +1 -1
- data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +27 -1015
- data/vendor/faiss/faiss/impl/ResidualQuantizer.h +5 -63
- data/vendor/faiss/faiss/impl/ResultHandler.h +232 -176
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +444 -104
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +0 -8
- data/vendor/faiss/faiss/impl/code_distance/code_distance-avx2.h +280 -42
- data/vendor/faiss/faiss/impl/code_distance/code_distance-generic.h +21 -14
- data/vendor/faiss/faiss/impl/code_distance/code_distance.h +22 -12
- data/vendor/faiss/faiss/impl/index_read.cpp +45 -19
- data/vendor/faiss/faiss/impl/index_write.cpp +60 -41
- data/vendor/faiss/faiss/impl/io.cpp +10 -10
- data/vendor/faiss/faiss/impl/lattice_Zn.cpp +1 -1
- data/vendor/faiss/faiss/impl/platform_macros.h +18 -1
- data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +3 -0
- data/vendor/faiss/faiss/impl/pq4_fast_scan.h +7 -6
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +52 -38
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +40 -49
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.cpp +960 -0
- data/vendor/faiss/faiss/impl/residual_quantizer_encode_steps.h +176 -0
- data/vendor/faiss/faiss/impl/simd_result_handlers.h +374 -202
- data/vendor/faiss/faiss/index_factory.cpp +10 -7
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -1
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +27 -9
- data/vendor/faiss/faiss/invlists/InvertedLists.h +12 -3
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +3 -3
- data/vendor/faiss/faiss/python/python_callbacks.cpp +1 -1
- data/vendor/faiss/faiss/utils/Heap.cpp +3 -1
- data/vendor/faiss/faiss/utils/WorkerThread.h +1 -0
- data/vendor/faiss/faiss/utils/distances.cpp +128 -74
- data/vendor/faiss/faiss/utils/distances.h +81 -4
- data/vendor/faiss/faiss/utils/distances_fused/avx512.cpp +5 -5
- data/vendor/faiss/faiss/utils/distances_fused/avx512.h +2 -2
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.cpp +2 -2
- data/vendor/faiss/faiss/utils/distances_fused/distances_fused.h +1 -1
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.cpp +5 -5
- data/vendor/faiss/faiss/utils/distances_fused/simdlib_based.h +1 -1
- data/vendor/faiss/faiss/utils/distances_simd.cpp +428 -70
- data/vendor/faiss/faiss/utils/fp16-arm.h +29 -0
- data/vendor/faiss/faiss/utils/fp16.h +2 -0
- data/vendor/faiss/faiss/utils/hamming.cpp +162 -110
- data/vendor/faiss/faiss/utils/hamming.h +58 -0
- data/vendor/faiss/faiss/utils/hamming_distance/avx2-inl.h +16 -89
- data/vendor/faiss/faiss/utils/hamming_distance/common.h +1 -0
- data/vendor/faiss/faiss/utils/hamming_distance/generic-inl.h +15 -87
- data/vendor/faiss/faiss/utils/hamming_distance/hamdis-inl.h +57 -0
- data/vendor/faiss/faiss/utils/hamming_distance/neon-inl.h +14 -104
- data/vendor/faiss/faiss/utils/partitioning.cpp +3 -4
- data/vendor/faiss/faiss/utils/prefetch.h +77 -0
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +0 -14
- data/vendor/faiss/faiss/utils/simdlib_avx2.h +0 -6
- data/vendor/faiss/faiss/utils/simdlib_neon.h +72 -77
- data/vendor/faiss/faiss/utils/sorting.cpp +140 -5
- data/vendor/faiss/faiss/utils/sorting.h +27 -0
- data/vendor/faiss/faiss/utils/utils.cpp +112 -6
- data/vendor/faiss/faiss/utils/utils.h +57 -20
- metadata +11 -4
@@ -35,10 +35,12 @@ IndexIVFPQR::IndexIVFPQR(
|
|
35
35
|
refine_pq(d, M_refine, nbits_per_idx_refine),
|
36
36
|
k_factor(4) {
|
37
37
|
by_residual = true;
|
38
|
+
refine_pq.cp.max_points_per_centroid = 1000;
|
38
39
|
}
|
39
40
|
|
40
41
|
IndexIVFPQR::IndexIVFPQR() : k_factor(1) {
|
41
42
|
by_residual = true;
|
43
|
+
refine_pq.cp.max_points_per_centroid = 1000;
|
42
44
|
}
|
43
45
|
|
44
46
|
void IndexIVFPQR::reset() {
|
@@ -46,24 +48,39 @@ void IndexIVFPQR::reset() {
|
|
46
48
|
refine_codes.clear();
|
47
49
|
}
|
48
50
|
|
49
|
-
void IndexIVFPQR::
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
train_residual_o(n, x, residual_2);
|
54
|
-
|
55
|
-
if (verbose)
|
51
|
+
void IndexIVFPQR::train_encoder(idx_t n, const float* x, const idx_t* assign) {
|
52
|
+
IndexIVFPQ::train_encoder(n, x, assign);
|
53
|
+
if (verbose) {
|
56
54
|
printf("training %zdx%zd 2nd level PQ quantizer on %" PRId64
|
57
55
|
" %dD-vectors\n",
|
58
56
|
refine_pq.M,
|
59
57
|
refine_pq.ksub,
|
60
58
|
n,
|
61
59
|
d);
|
62
|
-
|
63
|
-
refine_pq.cp.max_points_per_centroid = 1000;
|
60
|
+
}
|
64
61
|
refine_pq.cp.verbose = verbose;
|
65
62
|
|
66
|
-
|
63
|
+
// 2nd level residual
|
64
|
+
std::vector<float> residual_2(n * d);
|
65
|
+
std::vector<uint8_t> train_codes(pq.code_size * n);
|
66
|
+
pq.compute_codes(x, train_codes.data(), n);
|
67
|
+
|
68
|
+
for (idx_t i = 0; i < n; i++) {
|
69
|
+
const float* xx = x + i * d;
|
70
|
+
float* res = residual_2.data() + i * d;
|
71
|
+
pq.decode(train_codes.data() + i * pq.code_size, res);
|
72
|
+
for (int j = 0; j < d; j++) {
|
73
|
+
res[j] = xx[j] - res[j];
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
refine_pq.train(n, residual_2.data());
|
78
|
+
}
|
79
|
+
|
80
|
+
idx_t IndexIVFPQR::train_encoder_num_vectors() const {
|
81
|
+
return std::max(
|
82
|
+
pq.cp.max_points_per_centroid * pq.ksub,
|
83
|
+
refine_pq.cp.max_points_per_centroid * refine_pq.ksub);
|
67
84
|
}
|
68
85
|
|
69
86
|
void IndexIVFPQR::add_with_ids(idx_t n, const float* x, const idx_t* xids) {
|
@@ -74,18 +91,18 @@ void IndexIVFPQR::add_core(
|
|
74
91
|
idx_t n,
|
75
92
|
const float* x,
|
76
93
|
const idx_t* xids,
|
77
|
-
const idx_t* precomputed_idx
|
78
|
-
|
79
|
-
|
94
|
+
const idx_t* precomputed_idx,
|
95
|
+
void* /*inverted_list_context*/) {
|
96
|
+
std::unique_ptr<float[]> residual_2(new float[n * d]);
|
80
97
|
|
81
98
|
idx_t n0 = ntotal;
|
82
99
|
|
83
|
-
add_core_o(n, x, xids, residual_2, precomputed_idx);
|
100
|
+
add_core_o(n, x, xids, residual_2.get(), precomputed_idx);
|
84
101
|
|
85
102
|
refine_codes.resize(ntotal * refine_pq.code_size);
|
86
103
|
|
87
104
|
refine_pq.compute_codes(
|
88
|
-
residual_2, &refine_codes[n0 * refine_pq.code_size], n);
|
105
|
+
residual_2.get(), &refine_codes[n0 * refine_pq.code_size], n);
|
89
106
|
}
|
90
107
|
#define TIC t0 = get_cycles()
|
91
108
|
#define TOC get_cycles() - t0
|
@@ -104,11 +121,10 @@ void IndexIVFPQR::search_preassigned(
|
|
104
121
|
uint64_t t0;
|
105
122
|
TIC;
|
106
123
|
size_t k_coarse = long(k * k_factor);
|
107
|
-
idx_t
|
108
|
-
|
109
|
-
|
110
|
-
float
|
111
|
-
ScopeDeleter<float> del(coarse_distances);
|
124
|
+
std::unique_ptr<idx_t[]> coarse_labels(new idx_t[k_coarse * n]);
|
125
|
+
{
|
126
|
+
// query with quantizer levels 1 and 2.
|
127
|
+
std::unique_ptr<float[]> coarse_distances(new float[k_coarse * n]);
|
112
128
|
|
113
129
|
IndexIVFPQ::search_preassigned(
|
114
130
|
n,
|
@@ -116,8 +132,8 @@ void IndexIVFPQR::search_preassigned(
|
|
116
132
|
k_coarse,
|
117
133
|
idx,
|
118
134
|
L1_dis,
|
119
|
-
coarse_distances,
|
120
|
-
coarse_labels,
|
135
|
+
coarse_distances.get(),
|
136
|
+
coarse_labels.get(),
|
121
137
|
true,
|
122
138
|
params);
|
123
139
|
}
|
@@ -131,13 +147,12 @@ void IndexIVFPQR::search_preassigned(
|
|
131
147
|
#pragma omp parallel reduction(+ : n_refine)
|
132
148
|
{
|
133
149
|
// tmp buffers
|
134
|
-
float
|
135
|
-
|
136
|
-
float* residual_2 = residual_1 + d;
|
150
|
+
std::unique_ptr<float[]> residual_1(new float[2 * d]);
|
151
|
+
float* residual_2 = residual_1.get() + d;
|
137
152
|
#pragma omp for
|
138
153
|
for (idx_t i = 0; i < n; i++) {
|
139
154
|
const float* xq = x + i * d;
|
140
|
-
const idx_t* shortlist = coarse_labels + k_coarse * i;
|
155
|
+
const idx_t* shortlist = coarse_labels.get() + k_coarse * i;
|
141
156
|
float* heap_sim = distances + k * i;
|
142
157
|
idx_t* heap_ids = labels + k * i;
|
143
158
|
maxheap_heapify(k, heap_sim, heap_ids);
|
@@ -155,7 +170,7 @@ void IndexIVFPQR::search_preassigned(
|
|
155
170
|
assert(ofs >= 0 && ofs < invlists->list_size(list_no));
|
156
171
|
|
157
172
|
// 1st level residual
|
158
|
-
quantizer->compute_residual(xq, residual_1, list_no);
|
173
|
+
quantizer->compute_residual(xq, residual_1.get(), list_no);
|
159
174
|
|
160
175
|
// 2nd level residual
|
161
176
|
const uint8_t* l2code = invlists->get_single_code(list_no, ofs);
|
@@ -168,9 +183,10 @@ void IndexIVFPQR::search_preassigned(
|
|
168
183
|
idx_t id = invlists->get_single_id(list_no, ofs);
|
169
184
|
assert(0 <= id && id < ntotal);
|
170
185
|
refine_pq.decode(
|
171
|
-
&refine_codes[id * refine_pq.code_size],
|
186
|
+
&refine_codes[id * refine_pq.code_size],
|
187
|
+
residual_1.get());
|
172
188
|
|
173
|
-
float dis = fvec_L2sqr(residual_1, residual_2, d);
|
189
|
+
float dis = fvec_L2sqr(residual_1.get(), residual_2, d);
|
174
190
|
|
175
191
|
if (dis < heap_sim[0]) {
|
176
192
|
idx_t id_or_pair = store_pairs ? sl : id;
|
@@ -37,7 +37,9 @@ struct IndexIVFPQR : IndexIVFPQ {
|
|
37
37
|
size_t remove_ids(const IDSelector& sel) override;
|
38
38
|
|
39
39
|
/// trains the two product quantizers
|
40
|
-
void
|
40
|
+
void train_encoder(idx_t n, const float* x, const idx_t* assign) override;
|
41
|
+
|
42
|
+
idx_t train_encoder_num_vectors() const override;
|
41
43
|
|
42
44
|
void add_with_ids(idx_t n, const float* x, const idx_t* xids) override;
|
43
45
|
|
@@ -46,7 +48,8 @@ struct IndexIVFPQR : IndexIVFPQ {
|
|
46
48
|
idx_t n,
|
47
49
|
const float* x,
|
48
50
|
const idx_t* xids,
|
49
|
-
const idx_t* precomputed_idx
|
51
|
+
const idx_t* precomputed_idx,
|
52
|
+
void* inverted_list_context = nullptr) override;
|
50
53
|
|
51
54
|
void reconstruct_from_offset(int64_t list_no, int64_t offset, float* recons)
|
52
55
|
const override;
|
@@ -9,8 +9,8 @@
|
|
9
9
|
|
10
10
|
#include <faiss/IndexIVFSpectralHash.h>
|
11
11
|
|
12
|
-
#include <stdint.h>
|
13
12
|
#include <algorithm>
|
13
|
+
#include <cstdint>
|
14
14
|
#include <memory>
|
15
15
|
|
16
16
|
#include <faiss/IndexLSH.h>
|
@@ -31,22 +31,17 @@ IndexIVFSpectralHash::IndexIVFSpectralHash(
|
|
31
31
|
float period)
|
32
32
|
: IndexIVF(quantizer, d, nlist, (nbit + 7) / 8, METRIC_L2),
|
33
33
|
nbit(nbit),
|
34
|
-
period(period)
|
35
|
-
threshold_type(Thresh_global) {
|
34
|
+
period(period) {
|
36
35
|
RandomRotationMatrix* rr = new RandomRotationMatrix(d, nbit);
|
37
36
|
rr->init(1234);
|
38
37
|
vt = rr;
|
39
|
-
own_fields = true;
|
40
38
|
is_trained = false;
|
39
|
+
by_residual = false;
|
41
40
|
}
|
42
41
|
|
43
|
-
IndexIVFSpectralHash::IndexIVFSpectralHash()
|
44
|
-
|
45
|
-
|
46
|
-
own_fields(false),
|
47
|
-
nbit(0),
|
48
|
-
period(0),
|
49
|
-
threshold_type(Thresh_global) {}
|
42
|
+
IndexIVFSpectralHash::IndexIVFSpectralHash() : IndexIVF() {
|
43
|
+
by_residual = false;
|
44
|
+
}
|
50
45
|
|
51
46
|
IndexIVFSpectralHash::~IndexIVFSpectralHash() {
|
52
47
|
if (own_fields) {
|
@@ -67,10 +62,14 @@ float median(size_t n, float* x) {
|
|
67
62
|
|
68
63
|
} // namespace
|
69
64
|
|
70
|
-
void IndexIVFSpectralHash::
|
65
|
+
void IndexIVFSpectralHash::train_encoder(
|
66
|
+
idx_t n,
|
67
|
+
const float* x,
|
68
|
+
const idx_t* assign) {
|
71
69
|
if (!vt->is_trained) {
|
72
70
|
vt->train(n, x);
|
73
71
|
}
|
72
|
+
FAISS_THROW_IF_NOT(!by_residual);
|
74
73
|
|
75
74
|
if (threshold_type == Thresh_global) {
|
76
75
|
// nothing to do
|
@@ -158,7 +157,7 @@ void binarize_with_freq(
|
|
158
157
|
}
|
159
158
|
}
|
160
159
|
|
161
|
-
}
|
160
|
+
} // namespace
|
162
161
|
|
163
162
|
void IndexIVFSpectralHash::encode_vectors(
|
164
163
|
idx_t n,
|
@@ -167,6 +166,7 @@ void IndexIVFSpectralHash::encode_vectors(
|
|
167
166
|
uint8_t* codes,
|
168
167
|
bool include_listnos) const {
|
169
168
|
FAISS_THROW_IF_NOT(is_trained);
|
169
|
+
FAISS_THROW_IF_NOT(!by_residual);
|
170
170
|
float freq = 2.0 / period;
|
171
171
|
size_t coarse_size = include_listnos ? coarse_code_size() : 0;
|
172
172
|
|
@@ -224,6 +224,7 @@ struct IVFScanner : InvertedListScanner {
|
|
224
224
|
hc(qcode.data(), index->code_size) {
|
225
225
|
this->store_pairs = store_pairs;
|
226
226
|
this->code_size = index->code_size;
|
227
|
+
this->keep_max = is_similarity_metric(index->metric_type);
|
227
228
|
}
|
228
229
|
|
229
230
|
void set_query(const float* query) override {
|
@@ -288,26 +289,23 @@ struct IVFScanner : InvertedListScanner {
|
|
288
289
|
}
|
289
290
|
};
|
290
291
|
|
292
|
+
struct BuildScanner {
|
293
|
+
using T = InvertedListScanner*;
|
294
|
+
|
295
|
+
template <class HammingComputer>
|
296
|
+
static T f(const IndexIVFSpectralHash* index, bool store_pairs) {
|
297
|
+
return new IVFScanner<HammingComputer>(index, store_pairs);
|
298
|
+
}
|
299
|
+
};
|
300
|
+
|
291
301
|
} // anonymous namespace
|
292
302
|
|
293
303
|
InvertedListScanner* IndexIVFSpectralHash::get_InvertedListScanner(
|
294
304
|
bool store_pairs,
|
295
305
|
const IDSelector* sel) const {
|
296
306
|
FAISS_THROW_IF_NOT(!sel);
|
297
|
-
|
298
|
-
|
299
|
-
case cs: \
|
300
|
-
return new IVFScanner<HammingComputer##cs>(this, store_pairs)
|
301
|
-
HANDLE_CODE_SIZE(4);
|
302
|
-
HANDLE_CODE_SIZE(8);
|
303
|
-
HANDLE_CODE_SIZE(16);
|
304
|
-
HANDLE_CODE_SIZE(20);
|
305
|
-
HANDLE_CODE_SIZE(32);
|
306
|
-
HANDLE_CODE_SIZE(64);
|
307
|
-
#undef HANDLE_CODE_SIZE
|
308
|
-
default:
|
309
|
-
return new IVFScanner<HammingComputerDefault>(this, store_pairs);
|
310
|
-
}
|
307
|
+
BuildScanner bs;
|
308
|
+
return dispatch_HammingComputer(code_size, bs, this, store_pairs);
|
311
309
|
}
|
312
310
|
|
313
311
|
void IndexIVFSpectralHash::replace_vt(VectorTransform* vt_in, bool own) {
|
@@ -30,14 +30,14 @@ struct IndexPreTransform;
|
|
30
30
|
*/
|
31
31
|
struct IndexIVFSpectralHash : IndexIVF {
|
32
32
|
/// transformation from d to nbit dim
|
33
|
-
VectorTransform* vt;
|
33
|
+
VectorTransform* vt = nullptr;
|
34
34
|
/// own the vt
|
35
|
-
bool own_fields;
|
35
|
+
bool own_fields = true;
|
36
36
|
|
37
37
|
/// nb of bits of the binary signature
|
38
|
-
int nbit;
|
38
|
+
int nbit = 0;
|
39
39
|
/// interval size for 0s and 1s
|
40
|
-
float period;
|
40
|
+
float period = 0;
|
41
41
|
|
42
42
|
enum ThresholdType {
|
43
43
|
Thresh_global, ///< global threshold at 0
|
@@ -45,7 +45,7 @@ struct IndexIVFSpectralHash : IndexIVF {
|
|
45
45
|
Thresh_centroid_half, ///< central interval around centroid
|
46
46
|
Thresh_median ///< median of training set
|
47
47
|
};
|
48
|
-
ThresholdType threshold_type;
|
48
|
+
ThresholdType threshold_type = Thresh_global;
|
49
49
|
|
50
50
|
/// Trained threshold.
|
51
51
|
/// size nlist * nbit or 0 if Thresh_global
|
@@ -60,7 +60,7 @@ struct IndexIVFSpectralHash : IndexIVF {
|
|
60
60
|
|
61
61
|
IndexIVFSpectralHash();
|
62
62
|
|
63
|
-
void
|
63
|
+
void train_encoder(idx_t n, const float* x, const idx_t* assign) override;
|
64
64
|
|
65
65
|
void encode_vectors(
|
66
66
|
idx_t n,
|
@@ -11,6 +11,7 @@
|
|
11
11
|
#include <cstring>
|
12
12
|
|
13
13
|
#include <algorithm>
|
14
|
+
#include <memory>
|
14
15
|
|
15
16
|
#include <faiss/impl/FaissAssert.h>
|
16
17
|
#include <faiss/utils/hamming.h>
|
@@ -56,7 +57,7 @@ const float* IndexLSH::apply_preprocess(idx_t n, const float* x) const {
|
|
56
57
|
}
|
57
58
|
|
58
59
|
if (train_thresholds) {
|
59
|
-
if (xt ==
|
60
|
+
if (xt == nullptr) {
|
60
61
|
xt = new float[nbits * n];
|
61
62
|
memcpy(xt, x, sizeof(*x) * n * nbits);
|
62
63
|
}
|
@@ -75,18 +76,17 @@ void IndexLSH::train(idx_t n, const float* x) {
|
|
75
76
|
thresholds.resize(nbits);
|
76
77
|
train_thresholds = false;
|
77
78
|
const float* xt = apply_preprocess(n, x);
|
78
|
-
|
79
|
+
std::unique_ptr<const float[]> del(xt == x ? nullptr : xt);
|
79
80
|
train_thresholds = true;
|
80
81
|
|
81
|
-
float
|
82
|
-
ScopeDeleter<float> del2(transposed_x);
|
82
|
+
std::unique_ptr<float[]> transposed_x(new float[n * nbits]);
|
83
83
|
|
84
84
|
for (idx_t i = 0; i < n; i++)
|
85
85
|
for (idx_t j = 0; j < nbits; j++)
|
86
86
|
transposed_x[j * n + i] = xt[i * nbits + j];
|
87
87
|
|
88
88
|
for (idx_t i = 0; i < nbits; i++) {
|
89
|
-
float* xi = transposed_x + i * n;
|
89
|
+
float* xi = transposed_x.get() + i * n;
|
90
90
|
// std::nth_element
|
91
91
|
std::sort(xi, xi + n);
|
92
92
|
if (n % 2 == 1)
|
@@ -110,19 +110,17 @@ void IndexLSH::search(
|
|
110
110
|
FAISS_THROW_IF_NOT(k > 0);
|
111
111
|
FAISS_THROW_IF_NOT(is_trained);
|
112
112
|
const float* xt = apply_preprocess(n, x);
|
113
|
-
|
113
|
+
std::unique_ptr<const float[]> del(xt == x ? nullptr : xt);
|
114
114
|
|
115
|
-
uint8_t
|
116
|
-
ScopeDeleter<uint8_t> del2(qcodes);
|
115
|
+
std::unique_ptr<uint8_t[]> qcodes(new uint8_t[n * code_size]);
|
117
116
|
|
118
|
-
fvecs2bitvecs(xt, qcodes, nbits, n);
|
117
|
+
fvecs2bitvecs(xt, qcodes.get(), nbits, n);
|
119
118
|
|
120
|
-
int
|
121
|
-
ScopeDeleter<int> del3(idistances);
|
119
|
+
std::unique_ptr<int[]> idistances(new int[n * k]);
|
122
120
|
|
123
|
-
int_maxheap_array_t res = {size_t(n), size_t(k), labels, idistances};
|
121
|
+
int_maxheap_array_t res = {size_t(n), size_t(k), labels, idistances.get()};
|
124
122
|
|
125
|
-
hammings_knn_hc(&res, qcodes, codes.data(), ntotal, code_size, true);
|
123
|
+
hammings_knn_hc(&res, qcodes.get(), codes.data(), ntotal, code_size, true);
|
126
124
|
|
127
125
|
// convert distances to floats
|
128
126
|
for (int i = 0; i < k * n; i++)
|
@@ -146,16 +144,16 @@ void IndexLSH::transfer_thresholds(LinearTransform* vt) {
|
|
146
144
|
void IndexLSH::sa_encode(idx_t n, const float* x, uint8_t* bytes) const {
|
147
145
|
FAISS_THROW_IF_NOT(is_trained);
|
148
146
|
const float* xt = apply_preprocess(n, x);
|
149
|
-
|
147
|
+
std::unique_ptr<const float[]> del(xt == x ? nullptr : xt);
|
150
148
|
fvecs2bitvecs(xt, bytes, nbits, n);
|
151
149
|
}
|
152
150
|
|
153
151
|
void IndexLSH::sa_decode(idx_t n, const uint8_t* bytes, float* x) const {
|
154
152
|
float* xt = x;
|
155
|
-
|
153
|
+
std::unique_ptr<float[]> del;
|
156
154
|
if (rotate_data || nbits != d) {
|
157
155
|
xt = new float[n * nbits];
|
158
|
-
del.
|
156
|
+
del.reset(xt);
|
159
157
|
}
|
160
158
|
bitvecs2fvecs(bytes, xt, nbits, n);
|
161
159
|
|
@@ -158,8 +158,8 @@ void IndexNNDescent::search(
|
|
158
158
|
{
|
159
159
|
VisitedTable vt(ntotal);
|
160
160
|
|
161
|
-
DistanceComputer
|
162
|
-
|
161
|
+
std::unique_ptr<DistanceComputer> dis(
|
162
|
+
storage_distance_computer(storage));
|
163
163
|
|
164
164
|
#pragma omp for
|
165
165
|
for (idx_t i = i0; i < i1; i++) {
|
@@ -197,8 +197,7 @@ void IndexNNDescent::add(idx_t n, const float* x) {
|
|
197
197
|
storage->add(n, x);
|
198
198
|
ntotal = storage->ntotal;
|
199
199
|
|
200
|
-
DistanceComputer
|
201
|
-
ScopeDeleter1<DistanceComputer> del(dis);
|
200
|
+
std::unique_ptr<DistanceComputer> dis(storage_distance_computer(storage));
|
202
201
|
nndescent.build(*dis, ntotal, verbose);
|
203
202
|
}
|
204
203
|
|
@@ -29,32 +29,16 @@ using namespace nsg;
|
|
29
29
|
* IndexNSG implementation
|
30
30
|
**************************************************************/
|
31
31
|
|
32
|
-
IndexNSG::IndexNSG(int d, int R, MetricType metric)
|
33
|
-
: Index(d, metric),
|
34
|
-
nsg(R),
|
35
|
-
own_fields(false),
|
36
|
-
storage(nullptr),
|
37
|
-
is_built(false),
|
38
|
-
GK(64),
|
39
|
-
build_type(0) {
|
40
|
-
nndescent_S = 10;
|
41
|
-
nndescent_R = 100;
|
32
|
+
IndexNSG::IndexNSG(int d, int R, MetricType metric) : Index(d, metric), nsg(R) {
|
42
33
|
nndescent_L = GK + 50;
|
43
|
-
nndescent_iter = 10;
|
44
34
|
}
|
45
35
|
|
46
36
|
IndexNSG::IndexNSG(Index* storage, int R)
|
47
37
|
: Index(storage->d, storage->metric_type),
|
48
38
|
nsg(R),
|
49
|
-
own_fields(false),
|
50
39
|
storage(storage),
|
51
|
-
is_built(false),
|
52
|
-
GK(64),
|
53
40
|
build_type(1) {
|
54
|
-
nndescent_S = 10;
|
55
|
-
nndescent_R = 100;
|
56
41
|
nndescent_L = GK + 50;
|
57
|
-
nndescent_iter = 10;
|
58
42
|
}
|
59
43
|
|
60
44
|
IndexNSG::~IndexNSG() {
|
@@ -95,8 +79,8 @@ void IndexNSG::search(
|
|
95
79
|
{
|
96
80
|
VisitedTable vt(ntotal);
|
97
81
|
|
98
|
-
DistanceComputer
|
99
|
-
|
82
|
+
std::unique_ptr<DistanceComputer> dis(
|
83
|
+
storage_distance_computer(storage));
|
100
84
|
|
101
85
|
#pragma omp for
|
102
86
|
for (idx_t i = i0; i < i1; i++) {
|
@@ -120,7 +104,7 @@ void IndexNSG::search(
|
|
120
104
|
}
|
121
105
|
}
|
122
106
|
|
123
|
-
void IndexNSG::build(idx_t n, const float* x, idx_t* knn_graph, int
|
107
|
+
void IndexNSG::build(idx_t n, const float* x, idx_t* knn_graph, int GK_2) {
|
124
108
|
FAISS_THROW_IF_NOT_MSG(
|
125
109
|
storage,
|
126
110
|
"Please use IndexNSGFlat (or variants) instead of IndexNSG directly");
|
@@ -131,9 +115,9 @@ void IndexNSG::build(idx_t n, const float* x, idx_t* knn_graph, int GK) {
|
|
131
115
|
ntotal = storage->ntotal;
|
132
116
|
|
133
117
|
// check the knn graph
|
134
|
-
check_knn_graph(knn_graph, n,
|
118
|
+
check_knn_graph(knn_graph, n, GK_2);
|
135
119
|
|
136
|
-
const nsg::Graph<idx_t> knng(knn_graph, n,
|
120
|
+
const nsg::Graph<idx_t> knng(knn_graph, n, GK_2);
|
137
121
|
nsg.build(storage, n, knng, verbose);
|
138
122
|
is_built = true;
|
139
123
|
}
|
@@ -302,10 +286,10 @@ IndexNSGFlat::IndexNSGFlat(int d, int R, MetricType metric)
|
|
302
286
|
* IndexNSGPQ implementation
|
303
287
|
**************************************************************/
|
304
288
|
|
305
|
-
IndexNSGPQ::IndexNSGPQ()
|
289
|
+
IndexNSGPQ::IndexNSGPQ() = default;
|
306
290
|
|
307
|
-
IndexNSGPQ::IndexNSGPQ(int d, int pq_m, int M)
|
308
|
-
: IndexNSG(new IndexPQ(d, pq_m,
|
291
|
+
IndexNSGPQ::IndexNSGPQ(int d, int pq_m, int M, int pq_nbits)
|
292
|
+
: IndexNSG(new IndexPQ(d, pq_m, pq_nbits), M) {
|
309
293
|
own_fields = true;
|
310
294
|
is_trained = false;
|
311
295
|
}
|
@@ -325,10 +309,10 @@ IndexNSGSQ::IndexNSGSQ(
|
|
325
309
|
int M,
|
326
310
|
MetricType metric)
|
327
311
|
: IndexNSG(new IndexScalarQuantizer(d, qtype, metric), M) {
|
328
|
-
is_trained =
|
312
|
+
is_trained = this->storage->is_trained;
|
329
313
|
own_fields = true;
|
330
314
|
}
|
331
315
|
|
332
|
-
IndexNSGSQ::IndexNSGSQ()
|
316
|
+
IndexNSGSQ::IndexNSGSQ() = default;
|
333
317
|
|
334
318
|
} // namespace faiss
|
@@ -28,25 +28,25 @@ struct IndexNSG : Index {
|
|
28
28
|
NSG nsg;
|
29
29
|
|
30
30
|
/// the sequential storage
|
31
|
-
bool own_fields;
|
32
|
-
Index* storage;
|
31
|
+
bool own_fields = false;
|
32
|
+
Index* storage = nullptr;
|
33
33
|
|
34
34
|
/// the index is built or not
|
35
|
-
bool is_built;
|
35
|
+
bool is_built = false;
|
36
36
|
|
37
37
|
/// K of KNN graph for building
|
38
|
-
int GK;
|
38
|
+
int GK = 64;
|
39
39
|
|
40
40
|
/// indicate how to build a knn graph
|
41
41
|
/// - 0: build NSG with brute force search
|
42
42
|
/// - 1: build NSG with NNDescent
|
43
|
-
char build_type;
|
43
|
+
char build_type = 0;
|
44
44
|
|
45
45
|
/// parameters for nndescent
|
46
|
-
int nndescent_S;
|
47
|
-
int nndescent_R;
|
48
|
-
int nndescent_L;
|
49
|
-
int nndescent_iter;
|
46
|
+
int nndescent_S = 10;
|
47
|
+
int nndescent_R = 100;
|
48
|
+
int nndescent_L; // set to GK + 50
|
49
|
+
int nndescent_iter = 10;
|
50
50
|
|
51
51
|
explicit IndexNSG(int d = 0, int R = 32, MetricType metric = METRIC_L2);
|
52
52
|
explicit IndexNSG(Index* storage, int R = 32);
|
@@ -90,7 +90,7 @@ struct IndexNSGFlat : IndexNSG {
|
|
90
90
|
*/
|
91
91
|
struct IndexNSGPQ : IndexNSG {
|
92
92
|
IndexNSGPQ();
|
93
|
-
IndexNSGPQ(int d, int pq_m, int M);
|
93
|
+
IndexNSGPQ(int d, int pq_m, int M, int pq_nbits = 8);
|
94
94
|
void train(idx_t n, const float* x) override;
|
95
95
|
};
|
96
96
|
|