faiss 0.2.3 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/LICENSE.txt +1 -1
- data/README.md +23 -21
- data/ext/faiss/extconf.rb +11 -0
- data/ext/faiss/index.cpp +4 -4
- data/ext/faiss/index_binary.cpp +6 -6
- data/ext/faiss/product_quantizer.cpp +4 -4
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/faiss/AutoTune.cpp +13 -0
- data/vendor/faiss/faiss/Clustering.cpp +32 -0
- data/vendor/faiss/faiss/Clustering.h +14 -0
- data/vendor/faiss/faiss/IVFlib.cpp +101 -2
- data/vendor/faiss/faiss/IVFlib.h +26 -2
- data/vendor/faiss/faiss/Index.cpp +36 -3
- data/vendor/faiss/faiss/Index.h +43 -6
- data/vendor/faiss/faiss/Index2Layer.cpp +24 -93
- data/vendor/faiss/faiss/Index2Layer.h +8 -17
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +610 -0
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +253 -0
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.cpp +299 -0
- data/vendor/faiss/faiss/IndexAdditiveQuantizerFastScan.h +199 -0
- data/vendor/faiss/faiss/IndexBinary.cpp +20 -4
- data/vendor/faiss/faiss/IndexBinary.h +18 -3
- data/vendor/faiss/faiss/IndexBinaryFlat.cpp +9 -2
- data/vendor/faiss/faiss/IndexBinaryFlat.h +4 -2
- data/vendor/faiss/faiss/IndexBinaryFromFloat.cpp +4 -1
- data/vendor/faiss/faiss/IndexBinaryFromFloat.h +2 -1
- data/vendor/faiss/faiss/IndexBinaryHNSW.cpp +5 -1
- data/vendor/faiss/faiss/IndexBinaryHNSW.h +2 -1
- data/vendor/faiss/faiss/IndexBinaryHash.cpp +17 -4
- data/vendor/faiss/faiss/IndexBinaryHash.h +8 -4
- data/vendor/faiss/faiss/IndexBinaryIVF.cpp +28 -13
- data/vendor/faiss/faiss/IndexBinaryIVF.h +10 -7
- data/vendor/faiss/faiss/IndexFastScan.cpp +626 -0
- data/vendor/faiss/faiss/IndexFastScan.h +145 -0
- data/vendor/faiss/faiss/IndexFlat.cpp +52 -69
- data/vendor/faiss/faiss/IndexFlat.h +16 -19
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +101 -0
- data/vendor/faiss/faiss/IndexFlatCodes.h +59 -0
- data/vendor/faiss/faiss/IndexHNSW.cpp +66 -138
- data/vendor/faiss/faiss/IndexHNSW.h +4 -2
- data/vendor/faiss/faiss/IndexIDMap.cpp +247 -0
- data/vendor/faiss/faiss/IndexIDMap.h +107 -0
- data/vendor/faiss/faiss/IndexIVF.cpp +200 -40
- data/vendor/faiss/faiss/IndexIVF.h +59 -22
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +393 -0
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +183 -0
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.cpp +590 -0
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizerFastScan.h +171 -0
- data/vendor/faiss/faiss/IndexIVFFastScan.cpp +1290 -0
- data/vendor/faiss/faiss/IndexIVFFastScan.h +213 -0
- data/vendor/faiss/faiss/IndexIVFFlat.cpp +43 -26
- data/vendor/faiss/faiss/IndexIVFFlat.h +4 -2
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +238 -53
- data/vendor/faiss/faiss/IndexIVFPQ.h +6 -2
- data/vendor/faiss/faiss/IndexIVFPQFastScan.cpp +23 -852
- data/vendor/faiss/faiss/IndexIVFPQFastScan.h +7 -112
- data/vendor/faiss/faiss/IndexIVFPQR.cpp +3 -3
- data/vendor/faiss/faiss/IndexIVFPQR.h +1 -1
- data/vendor/faiss/faiss/IndexIVFSpectralHash.cpp +63 -40
- data/vendor/faiss/faiss/IndexIVFSpectralHash.h +23 -7
- data/vendor/faiss/faiss/IndexLSH.cpp +8 -32
- data/vendor/faiss/faiss/IndexLSH.h +4 -16
- data/vendor/faiss/faiss/IndexLattice.cpp +7 -1
- data/vendor/faiss/faiss/IndexLattice.h +3 -1
- data/vendor/faiss/faiss/IndexNNDescent.cpp +4 -5
- data/vendor/faiss/faiss/IndexNNDescent.h +2 -1
- data/vendor/faiss/faiss/IndexNSG.cpp +37 -5
- data/vendor/faiss/faiss/IndexNSG.h +25 -1
- data/vendor/faiss/faiss/IndexPQ.cpp +108 -120
- data/vendor/faiss/faiss/IndexPQ.h +21 -22
- data/vendor/faiss/faiss/IndexPQFastScan.cpp +15 -450
- data/vendor/faiss/faiss/IndexPQFastScan.h +15 -78
- data/vendor/faiss/faiss/IndexPreTransform.cpp +47 -8
- data/vendor/faiss/faiss/IndexPreTransform.h +15 -3
- data/vendor/faiss/faiss/IndexRefine.cpp +36 -4
- data/vendor/faiss/faiss/IndexRefine.h +14 -2
- data/vendor/faiss/faiss/IndexReplicas.cpp +4 -2
- data/vendor/faiss/faiss/IndexReplicas.h +2 -1
- data/vendor/faiss/faiss/IndexRowwiseMinMax.cpp +438 -0
- data/vendor/faiss/faiss/IndexRowwiseMinMax.h +92 -0
- data/vendor/faiss/faiss/IndexScalarQuantizer.cpp +28 -43
- data/vendor/faiss/faiss/IndexScalarQuantizer.h +8 -23
- data/vendor/faiss/faiss/IndexShards.cpp +4 -1
- data/vendor/faiss/faiss/IndexShards.h +2 -1
- data/vendor/faiss/faiss/MetaIndexes.cpp +5 -178
- data/vendor/faiss/faiss/MetaIndexes.h +3 -81
- data/vendor/faiss/faiss/VectorTransform.cpp +45 -1
- data/vendor/faiss/faiss/VectorTransform.h +25 -4
- data/vendor/faiss/faiss/clone_index.cpp +26 -3
- data/vendor/faiss/faiss/clone_index.h +3 -0
- data/vendor/faiss/faiss/cppcontrib/SaDecodeKernels.h +300 -0
- data/vendor/faiss/faiss/cppcontrib/detail/CoarseBitType.h +24 -0
- data/vendor/faiss/faiss/cppcontrib/detail/UintReader.h +195 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-avx2-inl.h +2058 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-inl.h +408 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/Level2-neon-inl.h +2147 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMax-inl.h +460 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/MinMaxFP16-inl.h +465 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-avx2-inl.h +1618 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-inl.h +251 -0
- data/vendor/faiss/faiss/cppcontrib/sa_decode/PQ-neon-inl.h +1452 -0
- data/vendor/faiss/faiss/gpu/GpuAutoTune.cpp +1 -0
- data/vendor/faiss/faiss/gpu/GpuCloner.cpp +2 -6
- data/vendor/faiss/faiss/gpu/GpuIcmEncoder.h +60 -0
- data/vendor/faiss/faiss/gpu/GpuIndex.h +28 -4
- data/vendor/faiss/faiss/gpu/GpuIndexBinaryFlat.h +2 -1
- data/vendor/faiss/faiss/gpu/GpuIndexFlat.h +10 -8
- data/vendor/faiss/faiss/gpu/GpuIndexIVF.h +75 -14
- data/vendor/faiss/faiss/gpu/GpuIndexIVFFlat.h +19 -32
- data/vendor/faiss/faiss/gpu/GpuIndexIVFPQ.h +22 -31
- data/vendor/faiss/faiss/gpu/GpuIndexIVFScalarQuantizer.h +22 -28
- data/vendor/faiss/faiss/gpu/GpuResources.cpp +14 -0
- data/vendor/faiss/faiss/gpu/GpuResources.h +16 -3
- data/vendor/faiss/faiss/gpu/StandardGpuResources.cpp +3 -3
- data/vendor/faiss/faiss/gpu/impl/IndexUtils.h +32 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +1 -0
- data/vendor/faiss/faiss/gpu/test/TestGpuIndexFlat.cpp +311 -75
- data/vendor/faiss/faiss/gpu/test/TestUtils.cpp +10 -0
- data/vendor/faiss/faiss/gpu/test/TestUtils.h +3 -0
- data/vendor/faiss/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +2 -2
- data/vendor/faiss/faiss/gpu/utils/DeviceUtils.h +5 -4
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.cpp +331 -29
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +110 -19
- data/vendor/faiss/faiss/impl/AuxIndexStructures.cpp +0 -54
- data/vendor/faiss/faiss/impl/AuxIndexStructures.h +0 -76
- data/vendor/faiss/faiss/impl/DistanceComputer.h +64 -0
- data/vendor/faiss/faiss/impl/HNSW.cpp +133 -32
- data/vendor/faiss/faiss/impl/HNSW.h +19 -16
- data/vendor/faiss/faiss/impl/IDSelector.cpp +125 -0
- data/vendor/faiss/faiss/impl/IDSelector.h +135 -0
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.cpp +378 -217
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +106 -29
- data/vendor/faiss/faiss/impl/LookupTableScaler.h +77 -0
- data/vendor/faiss/faiss/impl/NNDescent.cpp +1 -0
- data/vendor/faiss/faiss/impl/NSG.cpp +1 -4
- data/vendor/faiss/faiss/impl/NSG.h +1 -1
- data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.cpp +383 -0
- data/vendor/faiss/faiss/impl/ProductAdditiveQuantizer.h +154 -0
- data/vendor/faiss/faiss/impl/ProductQuantizer.cpp +225 -145
- data/vendor/faiss/faiss/impl/ProductQuantizer.h +29 -10
- data/vendor/faiss/faiss/impl/Quantizer.h +43 -0
- data/vendor/faiss/faiss/impl/ResidualQuantizer.cpp +521 -55
- data/vendor/faiss/faiss/impl/ResidualQuantizer.h +94 -16
- data/vendor/faiss/faiss/impl/ResultHandler.h +96 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +108 -191
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +18 -18
- data/vendor/faiss/faiss/impl/index_read.cpp +338 -24
- data/vendor/faiss/faiss/impl/index_write.cpp +300 -18
- data/vendor/faiss/faiss/impl/io.cpp +1 -1
- data/vendor/faiss/faiss/impl/io_macros.h +20 -0
- data/vendor/faiss/faiss/impl/kmeans1d.cpp +303 -0
- data/vendor/faiss/faiss/impl/kmeans1d.h +48 -0
- data/vendor/faiss/faiss/impl/pq4_fast_scan.cpp +56 -16
- data/vendor/faiss/faiss/impl/pq4_fast_scan.h +25 -8
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_1.cpp +66 -25
- data/vendor/faiss/faiss/impl/pq4_fast_scan_search_qbs.cpp +75 -27
- data/vendor/faiss/faiss/index_factory.cpp +772 -412
- data/vendor/faiss/faiss/index_factory.h +3 -0
- data/vendor/faiss/faiss/index_io.h +5 -0
- data/vendor/faiss/faiss/invlists/DirectMap.cpp +1 -0
- data/vendor/faiss/faiss/invlists/InvertedLists.cpp +4 -1
- data/vendor/faiss/faiss/invlists/OnDiskInvertedLists.cpp +2 -1
- data/vendor/faiss/faiss/python/python_callbacks.cpp +27 -0
- data/vendor/faiss/faiss/python/python_callbacks.h +15 -0
- data/vendor/faiss/faiss/utils/Heap.h +31 -15
- data/vendor/faiss/faiss/utils/distances.cpp +384 -58
- data/vendor/faiss/faiss/utils/distances.h +149 -18
- data/vendor/faiss/faiss/utils/distances_simd.cpp +776 -6
- data/vendor/faiss/faiss/utils/extra_distances.cpp +12 -7
- data/vendor/faiss/faiss/utils/extra_distances.h +3 -1
- data/vendor/faiss/faiss/utils/fp16-fp16c.h +21 -0
- data/vendor/faiss/faiss/utils/fp16-inl.h +101 -0
- data/vendor/faiss/faiss/utils/fp16.h +11 -0
- data/vendor/faiss/faiss/utils/hamming-inl.h +54 -0
- data/vendor/faiss/faiss/utils/hamming.cpp +0 -48
- data/vendor/faiss/faiss/utils/ordered_key_value.h +10 -0
- data/vendor/faiss/faiss/utils/quantize_lut.cpp +62 -0
- data/vendor/faiss/faiss/utils/quantize_lut.h +20 -0
- data/vendor/faiss/faiss/utils/random.cpp +53 -0
- data/vendor/faiss/faiss/utils/random.h +5 -0
- data/vendor/faiss/faiss/utils/simdlib_avx2.h +4 -0
- data/vendor/faiss/faiss/utils/simdlib_emulated.h +6 -1
- data/vendor/faiss/faiss/utils/simdlib_neon.h +7 -2
- data/vendor/faiss/faiss/utils/utils.h +1 -1
- metadata +46 -5
- data/vendor/faiss/faiss/IndexResidual.cpp +0 -291
- data/vendor/faiss/faiss/IndexResidual.h +0 -152
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include <faiss/IndexIVFAdditiveQuantizer.h>
|
|
9
|
+
|
|
10
|
+
#include <algorithm>
|
|
11
|
+
#include <cmath>
|
|
12
|
+
#include <cstring>
|
|
13
|
+
|
|
14
|
+
#include <faiss/impl/FaissAssert.h>
|
|
15
|
+
#include <faiss/impl/ResidualQuantizer.h>
|
|
16
|
+
#include <faiss/impl/ResultHandler.h>
|
|
17
|
+
#include <faiss/utils/distances.h>
|
|
18
|
+
#include <faiss/utils/extra_distances.h>
|
|
19
|
+
#include <faiss/utils/utils.h>
|
|
20
|
+
|
|
21
|
+
namespace faiss {
|
|
22
|
+
|
|
23
|
+
/**************************************************************************************
|
|
24
|
+
* IndexIVFAdditiveQuantizer
|
|
25
|
+
**************************************************************************************/
|
|
26
|
+
|
|
27
|
+
IndexIVFAdditiveQuantizer::IndexIVFAdditiveQuantizer(
|
|
28
|
+
AdditiveQuantizer* aq,
|
|
29
|
+
Index* quantizer,
|
|
30
|
+
size_t d,
|
|
31
|
+
size_t nlist,
|
|
32
|
+
MetricType metric)
|
|
33
|
+
: IndexIVF(quantizer, d, nlist, 0, metric), aq(aq) {
|
|
34
|
+
by_residual = true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
IndexIVFAdditiveQuantizer::IndexIVFAdditiveQuantizer(AdditiveQuantizer* aq)
|
|
38
|
+
: IndexIVF(), aq(aq) {}
|
|
39
|
+
|
|
40
|
+
void IndexIVFAdditiveQuantizer::train_residual(idx_t n, const float* x) {
|
|
41
|
+
const float* x_in = x;
|
|
42
|
+
|
|
43
|
+
size_t max_train_points = 1024 * ((size_t)1 << aq->nbits[0]);
|
|
44
|
+
// we need more data to train LSQ
|
|
45
|
+
if (dynamic_cast<LocalSearchQuantizer*>(aq)) {
|
|
46
|
+
max_train_points = 1024 * aq->M * ((size_t)1 << aq->nbits[0]);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
x = fvecs_maybe_subsample(
|
|
50
|
+
d, (size_t*)&n, max_train_points, x, verbose, 1234);
|
|
51
|
+
ScopeDeleter<float> del_x(x_in == x ? nullptr : x);
|
|
52
|
+
|
|
53
|
+
if (by_residual) {
|
|
54
|
+
std::vector<Index::idx_t> idx(n);
|
|
55
|
+
quantizer->assign(n, x, idx.data());
|
|
56
|
+
|
|
57
|
+
std::vector<float> residuals(n * d);
|
|
58
|
+
quantizer->compute_residual_n(n, x, residuals.data(), idx.data());
|
|
59
|
+
|
|
60
|
+
aq->train(n, residuals.data());
|
|
61
|
+
} else {
|
|
62
|
+
aq->train(n, x);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
void IndexIVFAdditiveQuantizer::encode_vectors(
|
|
67
|
+
idx_t n,
|
|
68
|
+
const float* x,
|
|
69
|
+
const idx_t* list_nos,
|
|
70
|
+
uint8_t* codes,
|
|
71
|
+
bool include_listnos) const {
|
|
72
|
+
FAISS_THROW_IF_NOT(is_trained);
|
|
73
|
+
|
|
74
|
+
// first encode then possibly add listnos
|
|
75
|
+
|
|
76
|
+
if (by_residual) {
|
|
77
|
+
// subtract centroids
|
|
78
|
+
std::vector<float> residuals(n * d);
|
|
79
|
+
|
|
80
|
+
#pragma omp parallel for if (n > 10000)
|
|
81
|
+
for (idx_t i = 0; i < n; i++) {
|
|
82
|
+
quantizer->compute_residual(
|
|
83
|
+
x + i * d,
|
|
84
|
+
residuals.data() + i * d,
|
|
85
|
+
list_nos[i] >= 0 ? list_nos[i] : 0);
|
|
86
|
+
}
|
|
87
|
+
aq->compute_codes(residuals.data(), codes, n);
|
|
88
|
+
} else {
|
|
89
|
+
aq->compute_codes(x, codes, n);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (include_listnos) {
|
|
93
|
+
// write back from the end, where there is enough space
|
|
94
|
+
size_t coarse_size = coarse_code_size();
|
|
95
|
+
for (idx_t i = n - 1; i >= 0; i--) {
|
|
96
|
+
uint8_t* code = codes + i * (code_size + coarse_size);
|
|
97
|
+
memmove(code + coarse_size, codes + i * code_size, code_size);
|
|
98
|
+
encode_listno(list_nos[i], code);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
void IndexIVFAdditiveQuantizer::sa_decode(
|
|
104
|
+
idx_t n,
|
|
105
|
+
const uint8_t* codes,
|
|
106
|
+
float* x) const {
|
|
107
|
+
const size_t coarse_size = coarse_code_size();
|
|
108
|
+
|
|
109
|
+
#pragma omp parallel if (n > 1000)
|
|
110
|
+
{
|
|
111
|
+
std::vector<float> residual(d);
|
|
112
|
+
|
|
113
|
+
#pragma omp for
|
|
114
|
+
for (idx_t i = 0; i < n; i++) {
|
|
115
|
+
const uint8_t* code = codes + i * (code_size + coarse_size);
|
|
116
|
+
int64_t list_no = decode_listno(code);
|
|
117
|
+
float* xi = x + i * d;
|
|
118
|
+
aq->decode(code + coarse_size, xi, 1);
|
|
119
|
+
if (by_residual) {
|
|
120
|
+
quantizer->reconstruct(list_no, residual.data());
|
|
121
|
+
for (size_t j = 0; j < d; j++) {
|
|
122
|
+
xi[j] += residual[j];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
IndexIVFAdditiveQuantizer::~IndexIVFAdditiveQuantizer() {}
|
|
130
|
+
|
|
131
|
+
/*********************************************
|
|
132
|
+
* AQInvertedListScanner
|
|
133
|
+
*********************************************/
|
|
134
|
+
|
|
135
|
+
namespace {
|
|
136
|
+
|
|
137
|
+
using Search_type_t = AdditiveQuantizer::Search_type_t;
|
|
138
|
+
|
|
139
|
+
struct AQInvertedListScanner : InvertedListScanner {
|
|
140
|
+
const IndexIVFAdditiveQuantizer& ia;
|
|
141
|
+
const AdditiveQuantizer& aq;
|
|
142
|
+
std::vector<float> tmp;
|
|
143
|
+
|
|
144
|
+
AQInvertedListScanner(const IndexIVFAdditiveQuantizer& ia, bool store_pairs)
|
|
145
|
+
: ia(ia), aq(*ia.aq) {
|
|
146
|
+
this->store_pairs = store_pairs;
|
|
147
|
+
this->code_size = ia.code_size;
|
|
148
|
+
keep_max = ia.metric_type == METRIC_INNER_PRODUCT;
|
|
149
|
+
tmp.resize(ia.d);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const float* q0;
|
|
153
|
+
|
|
154
|
+
/// from now on we handle this query.
|
|
155
|
+
void set_query(const float* query_vector) override {
|
|
156
|
+
q0 = query_vector;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const float* q;
|
|
160
|
+
/// following codes come from this inverted list
|
|
161
|
+
void set_list(idx_t list_no, float coarse_dis) override {
|
|
162
|
+
if (ia.metric_type == METRIC_L2 && ia.by_residual) {
|
|
163
|
+
ia.quantizer->compute_residual(q0, tmp.data(), list_no);
|
|
164
|
+
q = tmp.data();
|
|
165
|
+
} else {
|
|
166
|
+
q = q0;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
~AQInvertedListScanner() {}
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
template <bool is_IP>
|
|
174
|
+
struct AQInvertedListScannerDecompress : AQInvertedListScanner {
|
|
175
|
+
AQInvertedListScannerDecompress(
|
|
176
|
+
const IndexIVFAdditiveQuantizer& ia,
|
|
177
|
+
bool store_pairs)
|
|
178
|
+
: AQInvertedListScanner(ia, store_pairs) {}
|
|
179
|
+
|
|
180
|
+
float coarse_dis = 0;
|
|
181
|
+
|
|
182
|
+
/// following codes come from this inverted list
|
|
183
|
+
void set_list(idx_t list_no, float coarse_dis) override {
|
|
184
|
+
AQInvertedListScanner::set_list(list_no, coarse_dis);
|
|
185
|
+
if (ia.by_residual) {
|
|
186
|
+
this->coarse_dis = coarse_dis;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/// compute a single query-to-code distance
|
|
191
|
+
float distance_to_code(const uint8_t* code) const final {
|
|
192
|
+
std::vector<float> b(aq.d);
|
|
193
|
+
aq.decode(code, b.data(), 1);
|
|
194
|
+
FAISS_ASSERT(q);
|
|
195
|
+
FAISS_ASSERT(b.data());
|
|
196
|
+
|
|
197
|
+
return is_IP ? coarse_dis + fvec_inner_product(q, b.data(), aq.d)
|
|
198
|
+
: fvec_L2sqr(q, b.data(), aq.d);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
~AQInvertedListScannerDecompress() override {}
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
template <bool is_IP, Search_type_t search_type>
|
|
205
|
+
struct AQInvertedListScannerLUT : AQInvertedListScanner {
|
|
206
|
+
std::vector<float> LUT, tmp;
|
|
207
|
+
float distance_bias;
|
|
208
|
+
|
|
209
|
+
AQInvertedListScannerLUT(
|
|
210
|
+
const IndexIVFAdditiveQuantizer& ia,
|
|
211
|
+
bool store_pairs)
|
|
212
|
+
: AQInvertedListScanner(ia, store_pairs) {
|
|
213
|
+
LUT.resize(aq.total_codebook_size);
|
|
214
|
+
tmp.resize(ia.d);
|
|
215
|
+
distance_bias = 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/// from now on we handle this query.
|
|
219
|
+
void set_query(const float* query_vector) override {
|
|
220
|
+
AQInvertedListScanner::set_query(query_vector);
|
|
221
|
+
if (!is_IP && !ia.by_residual) {
|
|
222
|
+
distance_bias = fvec_norm_L2sqr(query_vector, ia.d);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/// following codes come from this inverted list
|
|
227
|
+
void set_list(idx_t list_no, float coarse_dis) override {
|
|
228
|
+
AQInvertedListScanner::set_list(list_no, coarse_dis);
|
|
229
|
+
// TODO find a way to provide the nprobes together to do a matmul
|
|
230
|
+
// + precompute tables
|
|
231
|
+
aq.compute_LUT(1, q, LUT.data());
|
|
232
|
+
|
|
233
|
+
if (ia.by_residual) {
|
|
234
|
+
distance_bias = coarse_dis;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/// compute a single query-to-code distance
|
|
239
|
+
float distance_to_code(const uint8_t* code) const final {
|
|
240
|
+
return distance_bias +
|
|
241
|
+
aq.compute_1_distance_LUT<is_IP, search_type>(code, LUT.data());
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
~AQInvertedListScannerLUT() override {}
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
} // anonymous namespace
|
|
248
|
+
|
|
249
|
+
InvertedListScanner* IndexIVFAdditiveQuantizer::get_InvertedListScanner(
|
|
250
|
+
bool store_pairs,
|
|
251
|
+
const IDSelector* sel) const {
|
|
252
|
+
FAISS_THROW_IF_NOT(!sel);
|
|
253
|
+
if (metric_type == METRIC_INNER_PRODUCT) {
|
|
254
|
+
if (aq->search_type == AdditiveQuantizer::ST_decompress) {
|
|
255
|
+
return new AQInvertedListScannerDecompress<true>(
|
|
256
|
+
*this, store_pairs);
|
|
257
|
+
} else {
|
|
258
|
+
return new AQInvertedListScannerLUT<
|
|
259
|
+
true,
|
|
260
|
+
AdditiveQuantizer::ST_LUT_nonorm>(*this, store_pairs);
|
|
261
|
+
}
|
|
262
|
+
} else {
|
|
263
|
+
switch (aq->search_type) {
|
|
264
|
+
case AdditiveQuantizer::ST_decompress:
|
|
265
|
+
return new AQInvertedListScannerDecompress<false>(
|
|
266
|
+
*this, store_pairs);
|
|
267
|
+
#define A(st) \
|
|
268
|
+
case AdditiveQuantizer::st: \
|
|
269
|
+
return new AQInvertedListScannerLUT<false, AdditiveQuantizer::st>( \
|
|
270
|
+
*this, store_pairs);
|
|
271
|
+
A(ST_LUT_nonorm)
|
|
272
|
+
// A(ST_norm_from_LUT)
|
|
273
|
+
A(ST_norm_float)
|
|
274
|
+
A(ST_norm_qint8)
|
|
275
|
+
A(ST_norm_qint4)
|
|
276
|
+
A(ST_norm_cqint4)
|
|
277
|
+
case AdditiveQuantizer::ST_norm_lsq2x4:
|
|
278
|
+
case AdditiveQuantizer::ST_norm_rq2x4:
|
|
279
|
+
A(ST_norm_cqint8)
|
|
280
|
+
#undef A
|
|
281
|
+
default:
|
|
282
|
+
FAISS_THROW_FMT(
|
|
283
|
+
"search type %d not supported", aq->search_type);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**************************************************************************************
|
|
289
|
+
* IndexIVFResidualQuantizer
|
|
290
|
+
**************************************************************************************/
|
|
291
|
+
|
|
292
|
+
IndexIVFResidualQuantizer::IndexIVFResidualQuantizer(
|
|
293
|
+
Index* quantizer,
|
|
294
|
+
size_t d,
|
|
295
|
+
size_t nlist,
|
|
296
|
+
const std::vector<size_t>& nbits,
|
|
297
|
+
MetricType metric,
|
|
298
|
+
Search_type_t search_type)
|
|
299
|
+
: IndexIVFAdditiveQuantizer(&rq, quantizer, d, nlist, metric),
|
|
300
|
+
rq(d, nbits, search_type) {
|
|
301
|
+
code_size = invlists->code_size = rq.code_size;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
IndexIVFResidualQuantizer::IndexIVFResidualQuantizer()
|
|
305
|
+
: IndexIVFAdditiveQuantizer(&rq) {}
|
|
306
|
+
|
|
307
|
+
IndexIVFResidualQuantizer::IndexIVFResidualQuantizer(
|
|
308
|
+
Index* quantizer,
|
|
309
|
+
size_t d,
|
|
310
|
+
size_t nlist,
|
|
311
|
+
size_t M, /* number of subquantizers */
|
|
312
|
+
size_t nbits, /* number of bit per subvector index */
|
|
313
|
+
MetricType metric,
|
|
314
|
+
Search_type_t search_type)
|
|
315
|
+
: IndexIVFResidualQuantizer(
|
|
316
|
+
quantizer,
|
|
317
|
+
d,
|
|
318
|
+
nlist,
|
|
319
|
+
std::vector<size_t>(M, nbits),
|
|
320
|
+
metric,
|
|
321
|
+
search_type) {}
|
|
322
|
+
|
|
323
|
+
IndexIVFResidualQuantizer::~IndexIVFResidualQuantizer() {}
|
|
324
|
+
|
|
325
|
+
/**************************************************************************************
|
|
326
|
+
* IndexIVFLocalSearchQuantizer
|
|
327
|
+
**************************************************************************************/
|
|
328
|
+
|
|
329
|
+
IndexIVFLocalSearchQuantizer::IndexIVFLocalSearchQuantizer(
|
|
330
|
+
Index* quantizer,
|
|
331
|
+
size_t d,
|
|
332
|
+
size_t nlist,
|
|
333
|
+
size_t M, /* number of subquantizers */
|
|
334
|
+
size_t nbits, /* number of bit per subvector index */
|
|
335
|
+
MetricType metric,
|
|
336
|
+
Search_type_t search_type)
|
|
337
|
+
: IndexIVFAdditiveQuantizer(&lsq, quantizer, d, nlist, metric),
|
|
338
|
+
lsq(d, M, nbits, search_type) {
|
|
339
|
+
code_size = invlists->code_size = lsq.code_size;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
IndexIVFLocalSearchQuantizer::IndexIVFLocalSearchQuantizer()
|
|
343
|
+
: IndexIVFAdditiveQuantizer(&lsq) {}
|
|
344
|
+
|
|
345
|
+
IndexIVFLocalSearchQuantizer::~IndexIVFLocalSearchQuantizer() {}
|
|
346
|
+
|
|
347
|
+
/**************************************************************************************
|
|
348
|
+
* IndexIVFProductResidualQuantizer
|
|
349
|
+
**************************************************************************************/
|
|
350
|
+
|
|
351
|
+
IndexIVFProductResidualQuantizer::IndexIVFProductResidualQuantizer(
|
|
352
|
+
Index* quantizer,
|
|
353
|
+
size_t d,
|
|
354
|
+
size_t nlist,
|
|
355
|
+
size_t nsplits,
|
|
356
|
+
size_t Msub,
|
|
357
|
+
size_t nbits,
|
|
358
|
+
MetricType metric,
|
|
359
|
+
Search_type_t search_type)
|
|
360
|
+
: IndexIVFAdditiveQuantizer(&prq, quantizer, d, nlist, metric),
|
|
361
|
+
prq(d, nsplits, Msub, nbits, search_type) {
|
|
362
|
+
code_size = invlists->code_size = prq.code_size;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
IndexIVFProductResidualQuantizer::IndexIVFProductResidualQuantizer()
|
|
366
|
+
: IndexIVFAdditiveQuantizer(&prq) {}
|
|
367
|
+
|
|
368
|
+
IndexIVFProductResidualQuantizer::~IndexIVFProductResidualQuantizer() {}
|
|
369
|
+
|
|
370
|
+
/**************************************************************************************
|
|
371
|
+
* IndexIVFProductLocalSearchQuantizer
|
|
372
|
+
**************************************************************************************/
|
|
373
|
+
|
|
374
|
+
IndexIVFProductLocalSearchQuantizer::IndexIVFProductLocalSearchQuantizer(
|
|
375
|
+
Index* quantizer,
|
|
376
|
+
size_t d,
|
|
377
|
+
size_t nlist,
|
|
378
|
+
size_t nsplits,
|
|
379
|
+
size_t Msub,
|
|
380
|
+
size_t nbits,
|
|
381
|
+
MetricType metric,
|
|
382
|
+
Search_type_t search_type)
|
|
383
|
+
: IndexIVFAdditiveQuantizer(&plsq, quantizer, d, nlist, metric),
|
|
384
|
+
plsq(d, nsplits, Msub, nbits, search_type) {
|
|
385
|
+
code_size = invlists->code_size = plsq.code_size;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
IndexIVFProductLocalSearchQuantizer::IndexIVFProductLocalSearchQuantizer()
|
|
389
|
+
: IndexIVFAdditiveQuantizer(&plsq) {}
|
|
390
|
+
|
|
391
|
+
IndexIVFProductLocalSearchQuantizer::~IndexIVFProductLocalSearchQuantizer() {}
|
|
392
|
+
|
|
393
|
+
} // namespace faiss
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#ifndef FAISS_INDEX_IVF_ADDITIVE_QUANTIZER_H
|
|
9
|
+
#define FAISS_INDEX_IVF_ADDITIVE_QUANTIZER_H
|
|
10
|
+
|
|
11
|
+
#include <faiss/impl/AdditiveQuantizer.h>
|
|
12
|
+
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
#include <vector>
|
|
15
|
+
|
|
16
|
+
#include <faiss/IndexIVF.h>
|
|
17
|
+
#include <faiss/impl/LocalSearchQuantizer.h>
|
|
18
|
+
#include <faiss/impl/ProductAdditiveQuantizer.h>
|
|
19
|
+
#include <faiss/impl/ResidualQuantizer.h>
|
|
20
|
+
#include <faiss/impl/platform_macros.h>
|
|
21
|
+
|
|
22
|
+
namespace faiss {
|
|
23
|
+
|
|
24
|
+
/// Abstract class for IVF additive quantizers.
|
|
25
|
+
/// The search functions are in common.
|
|
26
|
+
struct IndexIVFAdditiveQuantizer : IndexIVF {
|
|
27
|
+
// the quantizer
|
|
28
|
+
AdditiveQuantizer* aq;
|
|
29
|
+
bool by_residual = true;
|
|
30
|
+
int use_precomputed_table = 0; // for future use
|
|
31
|
+
|
|
32
|
+
using Search_type_t = AdditiveQuantizer::Search_type_t;
|
|
33
|
+
|
|
34
|
+
IndexIVFAdditiveQuantizer(
|
|
35
|
+
AdditiveQuantizer* aq,
|
|
36
|
+
Index* quantizer,
|
|
37
|
+
size_t d,
|
|
38
|
+
size_t nlist,
|
|
39
|
+
MetricType metric = METRIC_L2);
|
|
40
|
+
|
|
41
|
+
explicit IndexIVFAdditiveQuantizer(AdditiveQuantizer* aq);
|
|
42
|
+
|
|
43
|
+
void train_residual(idx_t n, const float* x) override;
|
|
44
|
+
|
|
45
|
+
void encode_vectors(
|
|
46
|
+
idx_t n,
|
|
47
|
+
const float* x,
|
|
48
|
+
const idx_t* list_nos,
|
|
49
|
+
uint8_t* codes,
|
|
50
|
+
bool include_listnos = false) const override;
|
|
51
|
+
|
|
52
|
+
InvertedListScanner* get_InvertedListScanner(
|
|
53
|
+
bool store_pairs,
|
|
54
|
+
const IDSelector* sel) const override;
|
|
55
|
+
|
|
56
|
+
void sa_decode(idx_t n, const uint8_t* codes, float* x) const override;
|
|
57
|
+
|
|
58
|
+
~IndexIVFAdditiveQuantizer() override;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/** IndexIVF based on a residual quantizer. Stored vectors are
|
|
62
|
+
* approximated by residual quantization codes.
|
|
63
|
+
*/
|
|
64
|
+
struct IndexIVFResidualQuantizer : IndexIVFAdditiveQuantizer {
|
|
65
|
+
/// The residual quantizer used to encode the vectors
|
|
66
|
+
ResidualQuantizer rq;
|
|
67
|
+
|
|
68
|
+
/** Constructor.
|
|
69
|
+
*
|
|
70
|
+
* @param d dimensionality of the input vectors
|
|
71
|
+
* @param M number of subquantizers
|
|
72
|
+
* @param nbits number of bit per subvector index
|
|
73
|
+
*/
|
|
74
|
+
IndexIVFResidualQuantizer(
|
|
75
|
+
Index* quantizer,
|
|
76
|
+
size_t d,
|
|
77
|
+
size_t nlist,
|
|
78
|
+
const std::vector<size_t>& nbits,
|
|
79
|
+
MetricType metric = METRIC_L2,
|
|
80
|
+
Search_type_t search_type = AdditiveQuantizer::ST_decompress);
|
|
81
|
+
|
|
82
|
+
IndexIVFResidualQuantizer(
|
|
83
|
+
Index* quantizer,
|
|
84
|
+
size_t d,
|
|
85
|
+
size_t nlist,
|
|
86
|
+
size_t M, /* number of subquantizers */
|
|
87
|
+
size_t nbits, /* number of bit per subvector index */
|
|
88
|
+
MetricType metric = METRIC_L2,
|
|
89
|
+
Search_type_t search_type = AdditiveQuantizer::ST_decompress);
|
|
90
|
+
|
|
91
|
+
IndexIVFResidualQuantizer();
|
|
92
|
+
|
|
93
|
+
virtual ~IndexIVFResidualQuantizer();
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/** IndexIVF based on a residual quantizer. Stored vectors are
|
|
97
|
+
* approximated by residual quantization codes.
|
|
98
|
+
*/
|
|
99
|
+
struct IndexIVFLocalSearchQuantizer : IndexIVFAdditiveQuantizer {
|
|
100
|
+
/// The LSQ quantizer used to encode the vectors
|
|
101
|
+
LocalSearchQuantizer lsq;
|
|
102
|
+
|
|
103
|
+
/** Constructor.
|
|
104
|
+
*
|
|
105
|
+
* @param d dimensionality of the input vectors
|
|
106
|
+
* @param M number of subquantizers
|
|
107
|
+
* @param nbits number of bit per subvector index
|
|
108
|
+
*/
|
|
109
|
+
IndexIVFLocalSearchQuantizer(
|
|
110
|
+
Index* quantizer,
|
|
111
|
+
size_t d,
|
|
112
|
+
size_t nlist,
|
|
113
|
+
size_t M, /* number of subquantizers */
|
|
114
|
+
size_t nbits, /* number of bit per subvector index */
|
|
115
|
+
MetricType metric = METRIC_L2,
|
|
116
|
+
Search_type_t search_type = AdditiveQuantizer::ST_decompress);
|
|
117
|
+
|
|
118
|
+
IndexIVFLocalSearchQuantizer();
|
|
119
|
+
|
|
120
|
+
virtual ~IndexIVFLocalSearchQuantizer();
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/** IndexIVF based on a product residual quantizer. Stored vectors are
|
|
124
|
+
* approximated by product residual quantization codes.
|
|
125
|
+
*/
|
|
126
|
+
struct IndexIVFProductResidualQuantizer : IndexIVFAdditiveQuantizer {
|
|
127
|
+
/// The product residual quantizer used to encode the vectors
|
|
128
|
+
ProductResidualQuantizer prq;
|
|
129
|
+
|
|
130
|
+
/** Constructor.
|
|
131
|
+
*
|
|
132
|
+
* @param d dimensionality of the input vectors
|
|
133
|
+
* @param nsplits number of residual quantizers
|
|
134
|
+
* @param Msub number of subquantizers per RQ
|
|
135
|
+
* @param nbits number of bit per subvector index
|
|
136
|
+
*/
|
|
137
|
+
IndexIVFProductResidualQuantizer(
|
|
138
|
+
Index* quantizer,
|
|
139
|
+
size_t d,
|
|
140
|
+
size_t nlist,
|
|
141
|
+
size_t nsplits,
|
|
142
|
+
size_t Msub,
|
|
143
|
+
size_t nbits,
|
|
144
|
+
MetricType metric = METRIC_L2,
|
|
145
|
+
Search_type_t search_type = AdditiveQuantizer::ST_decompress);
|
|
146
|
+
|
|
147
|
+
IndexIVFProductResidualQuantizer();
|
|
148
|
+
|
|
149
|
+
virtual ~IndexIVFProductResidualQuantizer();
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/** IndexIVF based on a product local search quantizer. Stored vectors are
|
|
153
|
+
* approximated by product local search quantization codes.
|
|
154
|
+
*/
|
|
155
|
+
struct IndexIVFProductLocalSearchQuantizer : IndexIVFAdditiveQuantizer {
|
|
156
|
+
/// The product local search quantizer used to encode the vectors
|
|
157
|
+
ProductLocalSearchQuantizer plsq;
|
|
158
|
+
|
|
159
|
+
/** Constructor.
|
|
160
|
+
*
|
|
161
|
+
* @param d dimensionality of the input vectors
|
|
162
|
+
* @param nsplits number of local search quantizers
|
|
163
|
+
* @param Msub number of subquantizers per LSQ
|
|
164
|
+
* @param nbits number of bit per subvector index
|
|
165
|
+
*/
|
|
166
|
+
IndexIVFProductLocalSearchQuantizer(
|
|
167
|
+
Index* quantizer,
|
|
168
|
+
size_t d,
|
|
169
|
+
size_t nlist,
|
|
170
|
+
size_t nsplits,
|
|
171
|
+
size_t Msub,
|
|
172
|
+
size_t nbits,
|
|
173
|
+
MetricType metric = METRIC_L2,
|
|
174
|
+
Search_type_t search_type = AdditiveQuantizer::ST_decompress);
|
|
175
|
+
|
|
176
|
+
IndexIVFProductLocalSearchQuantizer();
|
|
177
|
+
|
|
178
|
+
virtual ~IndexIVFProductLocalSearchQuantizer();
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
} // namespace faiss
|
|
182
|
+
|
|
183
|
+
#endif
|