faiss 0.2.4 → 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 +5 -0
- 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/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 +6 -2
- data/vendor/faiss/faiss/Index2Layer.h +6 -1
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.cpp +219 -16
- data/vendor/faiss/faiss/IndexAdditiveQuantizer.h +63 -5
- 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 +34 -21
- data/vendor/faiss/faiss/IndexFlat.h +7 -4
- data/vendor/faiss/faiss/IndexFlatCodes.cpp +35 -1
- data/vendor/faiss/faiss/IndexFlatCodes.h +12 -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 +121 -33
- data/vendor/faiss/faiss/IndexIVF.h +35 -16
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.cpp +84 -7
- data/vendor/faiss/faiss/IndexIVFAdditiveQuantizer.h +63 -1
- 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 +37 -17
- data/vendor/faiss/faiss/IndexIVFFlat.h +4 -2
- data/vendor/faiss/faiss/IndexIVFPQ.cpp +234 -50
- data/vendor/faiss/faiss/IndexIVFPQ.h +5 -1
- 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 +3 -1
- data/vendor/faiss/faiss/IndexIVFSpectralHash.h +2 -1
- data/vendor/faiss/faiss/IndexLSH.cpp +4 -2
- data/vendor/faiss/faiss/IndexLSH.h +2 -1
- data/vendor/faiss/faiss/IndexLattice.cpp +7 -1
- data/vendor/faiss/faiss/IndexLattice.h +3 -1
- data/vendor/faiss/faiss/IndexNNDescent.cpp +4 -3
- data/vendor/faiss/faiss/IndexNNDescent.h +2 -1
- data/vendor/faiss/faiss/IndexNSG.cpp +37 -3
- data/vendor/faiss/faiss/IndexNSG.h +25 -1
- data/vendor/faiss/faiss/IndexPQ.cpp +106 -69
- data/vendor/faiss/faiss/IndexPQ.h +19 -5
- 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 +8 -4
- data/vendor/faiss/faiss/IndexRefine.h +4 -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 +26 -15
- data/vendor/faiss/faiss/IndexScalarQuantizer.h +6 -7
- 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 +43 -0
- data/vendor/faiss/faiss/VectorTransform.h +22 -4
- data/vendor/faiss/faiss/clone_index.cpp +23 -1
- 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 +0 -4
- 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 +116 -47
- data/vendor/faiss/faiss/impl/AdditiveQuantizer.h +44 -13
- 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 +123 -27
- 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 +6 -28
- data/vendor/faiss/faiss/impl/LocalSearchQuantizer.h +6 -1
- 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 -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 +192 -36
- data/vendor/faiss/faiss/impl/ResidualQuantizer.h +40 -20
- data/vendor/faiss/faiss/impl/ResultHandler.h +96 -0
- data/vendor/faiss/faiss/impl/ScalarQuantizer.cpp +97 -173
- data/vendor/faiss/faiss/impl/ScalarQuantizer.h +18 -18
- data/vendor/faiss/faiss/impl/index_read.cpp +240 -9
- data/vendor/faiss/faiss/impl/index_write.cpp +237 -5
- data/vendor/faiss/faiss/impl/kmeans1d.cpp +6 -4
- 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 +196 -7
- 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 +380 -56
- data/vendor/faiss/faiss/utils/distances.h +113 -15
- data/vendor/faiss/faiss/utils/distances_simd.cpp +726 -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
- metadata +37 -3
|
@@ -0,0 +1,77 @@
|
|
|
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
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <cstdlib>
|
|
12
|
+
|
|
13
|
+
#include <faiss/utils/simdlib.h>
|
|
14
|
+
|
|
15
|
+
/*******************************************
|
|
16
|
+
* The Scaler objects are used to specialize the handling of the
|
|
17
|
+
* norm components in Additive quantizer fast-scan.
|
|
18
|
+
********************************************/
|
|
19
|
+
|
|
20
|
+
namespace faiss {
|
|
21
|
+
|
|
22
|
+
/// no-op handler
|
|
23
|
+
struct DummyScaler {
|
|
24
|
+
static constexpr int nscale = 0;
|
|
25
|
+
|
|
26
|
+
inline simd32uint8 lookup(const simd32uint8&, const simd32uint8&) const {
|
|
27
|
+
FAISS_THROW_MSG("DummyScaler::lookup should not be called.");
|
|
28
|
+
return simd32uint8(0);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
inline simd16uint16 scale_lo(const simd32uint8&) const {
|
|
32
|
+
FAISS_THROW_MSG("DummyScaler::scale_lo should not be called.");
|
|
33
|
+
return simd16uint16(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
inline simd16uint16 scale_hi(const simd32uint8&) const {
|
|
37
|
+
FAISS_THROW_MSG("DummyScaler::scale_hi should not be called.");
|
|
38
|
+
return simd16uint16(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
template <class dist_t>
|
|
42
|
+
inline dist_t scale_one(const dist_t&) const {
|
|
43
|
+
FAISS_THROW_MSG("DummyScaler::scale_one should not be called.");
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/// consumes 2x4 bits to encode a norm as a scalar additive quantizer
|
|
49
|
+
/// the norm is scaled because its range if larger than other components
|
|
50
|
+
struct NormTableScaler {
|
|
51
|
+
static constexpr int nscale = 2;
|
|
52
|
+
int scale_int;
|
|
53
|
+
simd16uint16 scale_simd;
|
|
54
|
+
|
|
55
|
+
explicit NormTableScaler(int scale) : scale_int(scale), scale_simd(scale) {}
|
|
56
|
+
|
|
57
|
+
inline simd32uint8 lookup(const simd32uint8& lut, const simd32uint8& c)
|
|
58
|
+
const {
|
|
59
|
+
return lut.lookup_2_lanes(c);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
inline simd16uint16 scale_lo(const simd32uint8& res) const {
|
|
63
|
+
return simd16uint16(res) * scale_simd;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
inline simd16uint16 scale_hi(const simd32uint8& res) const {
|
|
67
|
+
return (simd16uint16(res) >> 8) * scale_simd;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// for non-SIMD implem 2, 3, 4
|
|
71
|
+
template <class dist_t>
|
|
72
|
+
inline dist_t scale_one(const dist_t& x) const {
|
|
73
|
+
return x * scale_int;
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
} // namespace faiss
|
|
@@ -0,0 +1,383 @@
|
|
|
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/impl/ProductAdditiveQuantizer.h>
|
|
9
|
+
|
|
10
|
+
#include <cstddef>
|
|
11
|
+
#include <cstdio>
|
|
12
|
+
#include <cstring>
|
|
13
|
+
#include <memory>
|
|
14
|
+
#include <random>
|
|
15
|
+
|
|
16
|
+
#include <algorithm>
|
|
17
|
+
|
|
18
|
+
#include <faiss/clone_index.h>
|
|
19
|
+
#include <faiss/impl/AuxIndexStructures.h>
|
|
20
|
+
#include <faiss/impl/FaissAssert.h>
|
|
21
|
+
#include <faiss/utils/distances.h>
|
|
22
|
+
#include <faiss/utils/hamming.h>
|
|
23
|
+
#include <faiss/utils/utils.h>
|
|
24
|
+
|
|
25
|
+
extern "C" {
|
|
26
|
+
|
|
27
|
+
// general matrix multiplication
|
|
28
|
+
int sgemm_(
|
|
29
|
+
const char* transa,
|
|
30
|
+
const char* transb,
|
|
31
|
+
FINTEGER* m,
|
|
32
|
+
FINTEGER* n,
|
|
33
|
+
FINTEGER* k,
|
|
34
|
+
const float* alpha,
|
|
35
|
+
const float* a,
|
|
36
|
+
FINTEGER* lda,
|
|
37
|
+
const float* b,
|
|
38
|
+
FINTEGER* ldb,
|
|
39
|
+
float* beta,
|
|
40
|
+
float* c,
|
|
41
|
+
FINTEGER* ldc);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
namespace faiss {
|
|
45
|
+
|
|
46
|
+
ProductAdditiveQuantizer::ProductAdditiveQuantizer(
|
|
47
|
+
size_t d,
|
|
48
|
+
const std::vector<AdditiveQuantizer*>& aqs,
|
|
49
|
+
Search_type_t search_type) {
|
|
50
|
+
init(d, aqs, search_type);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
ProductAdditiveQuantizer::ProductAdditiveQuantizer()
|
|
54
|
+
: ProductAdditiveQuantizer(0, {}) {}
|
|
55
|
+
|
|
56
|
+
void ProductAdditiveQuantizer::init(
|
|
57
|
+
size_t d,
|
|
58
|
+
const std::vector<AdditiveQuantizer*>& aqs,
|
|
59
|
+
Search_type_t search_type) {
|
|
60
|
+
// AdditiveQuantizer constructor
|
|
61
|
+
this->d = d;
|
|
62
|
+
this->search_type = search_type;
|
|
63
|
+
M = 0;
|
|
64
|
+
for (const auto& q : aqs) {
|
|
65
|
+
M += q->M;
|
|
66
|
+
nbits.insert(nbits.end(), q->nbits.begin(), q->nbits.end());
|
|
67
|
+
}
|
|
68
|
+
verbose = false;
|
|
69
|
+
is_trained = false;
|
|
70
|
+
norm_max = norm_min = NAN;
|
|
71
|
+
code_size = 0;
|
|
72
|
+
tot_bits = 0;
|
|
73
|
+
total_codebook_size = 0;
|
|
74
|
+
only_8bit = false;
|
|
75
|
+
set_derived_values();
|
|
76
|
+
|
|
77
|
+
// ProductAdditiveQuantizer
|
|
78
|
+
nsplits = aqs.size();
|
|
79
|
+
|
|
80
|
+
FAISS_THROW_IF_NOT(quantizers.empty());
|
|
81
|
+
for (const auto& q : aqs) {
|
|
82
|
+
auto aq = dynamic_cast<AdditiveQuantizer*>(clone_Quantizer(q));
|
|
83
|
+
quantizers.push_back(aq);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
ProductAdditiveQuantizer::~ProductAdditiveQuantizer() {
|
|
88
|
+
for (auto& q : quantizers) {
|
|
89
|
+
delete q;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
AdditiveQuantizer* ProductAdditiveQuantizer::subquantizer(size_t s) const {
|
|
94
|
+
return quantizers[s];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
void ProductAdditiveQuantizer::train(size_t n, const float* x) {
|
|
98
|
+
if (is_trained) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// copy the subvectors into contiguous memory
|
|
103
|
+
size_t offset_d = 0;
|
|
104
|
+
std::vector<float> xt;
|
|
105
|
+
for (size_t s = 0; s < nsplits; s++) {
|
|
106
|
+
auto q = quantizers[s];
|
|
107
|
+
xt.resize(q->d * n);
|
|
108
|
+
|
|
109
|
+
#pragma omp parallel for if (n > 1000)
|
|
110
|
+
for (idx_t i = 0; i < n; i++) {
|
|
111
|
+
memcpy(xt.data() + i * q->d,
|
|
112
|
+
x + i * d + offset_d,
|
|
113
|
+
q->d * sizeof(*x));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
q->train(n, xt.data());
|
|
117
|
+
offset_d += q->d;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// compute codebook size
|
|
121
|
+
size_t codebook_size = 0;
|
|
122
|
+
for (const auto& q : quantizers) {
|
|
123
|
+
codebook_size += q->total_codebook_size * q->d;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// copy codebook from sub-quantizers
|
|
127
|
+
codebooks.resize(codebook_size); // size (M * ksub, dsub)
|
|
128
|
+
float* cb = codebooks.data();
|
|
129
|
+
for (size_t s = 0; s < nsplits; s++) {
|
|
130
|
+
auto q = quantizers[s];
|
|
131
|
+
size_t sub_codebook_size = q->total_codebook_size * q->d;
|
|
132
|
+
memcpy(cb, q->codebooks.data(), sub_codebook_size * sizeof(float));
|
|
133
|
+
cb += sub_codebook_size;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
is_trained = true;
|
|
137
|
+
|
|
138
|
+
// train norm
|
|
139
|
+
std::vector<int32_t> codes(n * M);
|
|
140
|
+
compute_unpacked_codes(x, codes.data(), n);
|
|
141
|
+
std::vector<float> x_recons(n * d);
|
|
142
|
+
std::vector<float> norms(n);
|
|
143
|
+
decode_unpacked(codes.data(), x_recons.data(), n);
|
|
144
|
+
fvec_norms_L2sqr(norms.data(), x_recons.data(), d, n);
|
|
145
|
+
train_norm(n, norms.data());
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
void ProductAdditiveQuantizer::compute_codes_add_centroids(
|
|
149
|
+
const float* x,
|
|
150
|
+
uint8_t* codes_out,
|
|
151
|
+
size_t n,
|
|
152
|
+
const float* centroids) const {
|
|
153
|
+
// size (n, M)
|
|
154
|
+
std::vector<int32_t> unpacked_codes(n * M);
|
|
155
|
+
compute_unpacked_codes(x, unpacked_codes.data(), n, centroids);
|
|
156
|
+
|
|
157
|
+
// pack
|
|
158
|
+
pack_codes(n, unpacked_codes.data(), codes_out, -1, nullptr, centroids);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
void ProductAdditiveQuantizer::compute_unpacked_codes(
|
|
162
|
+
const float* x,
|
|
163
|
+
int32_t* unpacked_codes,
|
|
164
|
+
size_t n,
|
|
165
|
+
const float* centroids) const {
|
|
166
|
+
/// TODO: actuallly we do not need to unpack and pack
|
|
167
|
+
size_t offset_d = 0, offset_m = 0;
|
|
168
|
+
std::vector<float> xsub;
|
|
169
|
+
std::vector<uint8_t> codes;
|
|
170
|
+
|
|
171
|
+
for (size_t s = 0; s < nsplits; s++) {
|
|
172
|
+
const auto q = quantizers[s];
|
|
173
|
+
xsub.resize(n * q->d);
|
|
174
|
+
codes.resize(n * q->code_size);
|
|
175
|
+
|
|
176
|
+
#pragma omp parallel for if (n > 1000)
|
|
177
|
+
for (idx_t i = 0; i < n; i++) {
|
|
178
|
+
memcpy(xsub.data() + i * q->d,
|
|
179
|
+
x + i * d + offset_d,
|
|
180
|
+
q->d * sizeof(float));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
q->compute_codes(xsub.data(), codes.data(), n);
|
|
184
|
+
|
|
185
|
+
// unpack
|
|
186
|
+
#pragma omp parallel for if (n > 1000)
|
|
187
|
+
for (idx_t i = 0; i < n; i++) {
|
|
188
|
+
uint8_t* code = codes.data() + i * q->code_size;
|
|
189
|
+
BitstringReader bsr(code, q->code_size);
|
|
190
|
+
|
|
191
|
+
// unpacked_codes[i][s][m] = codes[i][m]
|
|
192
|
+
for (size_t m = 0; m < q->M; m++) {
|
|
193
|
+
unpacked_codes[i * M + offset_m + m] = bsr.read(q->nbits[m]);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
offset_d += q->d;
|
|
198
|
+
offset_m += q->M;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
void ProductAdditiveQuantizer::decode_unpacked(
|
|
203
|
+
const int32_t* codes,
|
|
204
|
+
float* x,
|
|
205
|
+
size_t n,
|
|
206
|
+
int64_t ld_codes) const {
|
|
207
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
208
|
+
is_trained, "The product additive quantizer is not trained yet.");
|
|
209
|
+
|
|
210
|
+
if (ld_codes == -1) {
|
|
211
|
+
ld_codes = M;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// product additive quantizer decoding
|
|
215
|
+
#pragma omp parallel for if (n > 1000)
|
|
216
|
+
for (int64_t i = 0; i < n; i++) {
|
|
217
|
+
const int32_t* codesi = codes + i * ld_codes;
|
|
218
|
+
|
|
219
|
+
size_t offset_m = 0, offset_d = 0;
|
|
220
|
+
for (size_t s = 0; s < nsplits; s++) {
|
|
221
|
+
const auto q = quantizers[s];
|
|
222
|
+
float* xi = x + i * d + offset_d;
|
|
223
|
+
|
|
224
|
+
for (int m = 0; m < q->M; m++) {
|
|
225
|
+
int idx = codesi[offset_m + m];
|
|
226
|
+
const float* c = codebooks.data() +
|
|
227
|
+
q->d * (codebook_offsets[offset_m + m] + idx);
|
|
228
|
+
if (m == 0) {
|
|
229
|
+
memcpy(xi, c, sizeof(*x) * q->d);
|
|
230
|
+
} else {
|
|
231
|
+
fvec_add(q->d, xi, c, xi);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
offset_m += q->M;
|
|
236
|
+
offset_d += q->d;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
void ProductAdditiveQuantizer::decode(const uint8_t* codes, float* x, size_t n)
|
|
242
|
+
const {
|
|
243
|
+
FAISS_THROW_IF_NOT_MSG(
|
|
244
|
+
is_trained, "The product additive quantizer is not trained yet.");
|
|
245
|
+
|
|
246
|
+
#pragma omp parallel for if (n > 1000)
|
|
247
|
+
for (int64_t i = 0; i < n; i++) {
|
|
248
|
+
BitstringReader bsr(codes + i * code_size, code_size);
|
|
249
|
+
|
|
250
|
+
size_t offset_m = 0, offset_d = 0;
|
|
251
|
+
for (size_t s = 0; s < nsplits; s++) {
|
|
252
|
+
const auto q = quantizers[s];
|
|
253
|
+
float* xi = x + i * d + offset_d;
|
|
254
|
+
|
|
255
|
+
for (int m = 0; m < q->M; m++) {
|
|
256
|
+
int idx = bsr.read(q->nbits[m]);
|
|
257
|
+
const float* c = codebooks.data() +
|
|
258
|
+
q->d * (codebook_offsets[offset_m + m] + idx);
|
|
259
|
+
if (m == 0) {
|
|
260
|
+
memcpy(xi, c, sizeof(*x) * q->d);
|
|
261
|
+
} else {
|
|
262
|
+
fvec_add(q->d, xi, c, xi);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
offset_m += q->M;
|
|
267
|
+
offset_d += q->d;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
void ProductAdditiveQuantizer::compute_LUT(
|
|
273
|
+
size_t n,
|
|
274
|
+
const float* xq,
|
|
275
|
+
float* LUT,
|
|
276
|
+
float alpha,
|
|
277
|
+
long ld_lut) const {
|
|
278
|
+
// codebooks: size (M * ksub, dsub)
|
|
279
|
+
// xq: size (n, d)
|
|
280
|
+
// output LUT: size (n, M * ksub)
|
|
281
|
+
|
|
282
|
+
FINTEGER nqi = n;
|
|
283
|
+
// leading dimension of 'LUT' and 'xq'
|
|
284
|
+
FINTEGER ld_LUT = ld_lut > 0 ? ld_lut : total_codebook_size;
|
|
285
|
+
FINTEGER ld_xq = d;
|
|
286
|
+
|
|
287
|
+
float zero = 0;
|
|
288
|
+
size_t offset_d = 0;
|
|
289
|
+
size_t offset_cb = 0;
|
|
290
|
+
size_t offset_lut = 0;
|
|
291
|
+
|
|
292
|
+
for (size_t s = 0; s < nsplits; s++) {
|
|
293
|
+
const auto q = quantizers[s];
|
|
294
|
+
|
|
295
|
+
FINTEGER ncenti = q->total_codebook_size;
|
|
296
|
+
FINTEGER ld_cb = q->d; // leading dimension of 'codebooks'
|
|
297
|
+
|
|
298
|
+
auto codebooksi = codebooks.data() + offset_cb;
|
|
299
|
+
auto xqi = xq + offset_d;
|
|
300
|
+
auto LUTi = LUT + offset_lut;
|
|
301
|
+
|
|
302
|
+
sgemm_("Transposed",
|
|
303
|
+
"Not transposed",
|
|
304
|
+
&ncenti,
|
|
305
|
+
&nqi,
|
|
306
|
+
&ld_cb,
|
|
307
|
+
&alpha,
|
|
308
|
+
codebooksi,
|
|
309
|
+
&ld_cb,
|
|
310
|
+
xqi,
|
|
311
|
+
&ld_xq,
|
|
312
|
+
&zero,
|
|
313
|
+
LUTi,
|
|
314
|
+
&ld_LUT);
|
|
315
|
+
|
|
316
|
+
offset_d += q->d;
|
|
317
|
+
offset_cb += q->total_codebook_size * q->d;
|
|
318
|
+
offset_lut += q->total_codebook_size;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/*************************************
|
|
323
|
+
* Product Local Search Quantizer
|
|
324
|
+
************************************/
|
|
325
|
+
|
|
326
|
+
ProductLocalSearchQuantizer::ProductLocalSearchQuantizer(
|
|
327
|
+
size_t d,
|
|
328
|
+
size_t nsplits,
|
|
329
|
+
size_t Msub,
|
|
330
|
+
size_t nbits,
|
|
331
|
+
Search_type_t search_type) {
|
|
332
|
+
std::vector<AdditiveQuantizer*> aqs;
|
|
333
|
+
|
|
334
|
+
if (nsplits > 0) {
|
|
335
|
+
FAISS_THROW_IF_NOT(d % nsplits == 0);
|
|
336
|
+
size_t dsub = d / nsplits;
|
|
337
|
+
|
|
338
|
+
for (size_t i = 0; i < nsplits; i++) {
|
|
339
|
+
auto lsq =
|
|
340
|
+
new LocalSearchQuantizer(dsub, Msub, nbits, ST_decompress);
|
|
341
|
+
aqs.push_back(lsq);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
init(d, aqs, search_type);
|
|
345
|
+
for (auto& q : aqs) {
|
|
346
|
+
delete q;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
ProductLocalSearchQuantizer::ProductLocalSearchQuantizer()
|
|
351
|
+
: ProductLocalSearchQuantizer(0, 0, 0, 0) {}
|
|
352
|
+
|
|
353
|
+
/*************************************
|
|
354
|
+
* Product Residual Quantizer
|
|
355
|
+
************************************/
|
|
356
|
+
|
|
357
|
+
ProductResidualQuantizer::ProductResidualQuantizer(
|
|
358
|
+
size_t d,
|
|
359
|
+
size_t nsplits,
|
|
360
|
+
size_t Msub,
|
|
361
|
+
size_t nbits,
|
|
362
|
+
Search_type_t search_type) {
|
|
363
|
+
std::vector<AdditiveQuantizer*> aqs;
|
|
364
|
+
|
|
365
|
+
if (nsplits > 0) {
|
|
366
|
+
FAISS_THROW_IF_NOT(d % nsplits == 0);
|
|
367
|
+
size_t dsub = d / nsplits;
|
|
368
|
+
|
|
369
|
+
for (size_t i = 0; i < nsplits; i++) {
|
|
370
|
+
auto rq = new ResidualQuantizer(dsub, Msub, nbits, ST_decompress);
|
|
371
|
+
aqs.push_back(rq);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
init(d, aqs, search_type);
|
|
375
|
+
for (auto& q : aqs) {
|
|
376
|
+
delete q;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
ProductResidualQuantizer::ProductResidualQuantizer()
|
|
381
|
+
: ProductResidualQuantizer(0, 0, 0, 0) {}
|
|
382
|
+
|
|
383
|
+
} // namespace faiss
|
|
@@ -0,0 +1,154 @@
|
|
|
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
|
+
#pragma once
|
|
9
|
+
|
|
10
|
+
#include <cstdint>
|
|
11
|
+
#include <vector>
|
|
12
|
+
|
|
13
|
+
#include <faiss/Index.h>
|
|
14
|
+
#include <faiss/impl/AdditiveQuantizer.h>
|
|
15
|
+
#include <faiss/impl/LocalSearchQuantizer.h>
|
|
16
|
+
#include <faiss/impl/ResidualQuantizer.h>
|
|
17
|
+
|
|
18
|
+
namespace faiss {
|
|
19
|
+
|
|
20
|
+
/** Product Additive Quantizers
|
|
21
|
+
*
|
|
22
|
+
* The product additive quantizer is a variant of AQ and PQ.
|
|
23
|
+
* It first splits the vector space into multiple orthogonal sub-spaces
|
|
24
|
+
* just like PQ does. And then it quantizes each sub-space by an independent
|
|
25
|
+
* additive quantizer.
|
|
26
|
+
*
|
|
27
|
+
*/
|
|
28
|
+
struct ProductAdditiveQuantizer : AdditiveQuantizer {
|
|
29
|
+
size_t nsplits; ///< number of sub-vectors we split a vector into
|
|
30
|
+
|
|
31
|
+
std::vector<AdditiveQuantizer*> quantizers;
|
|
32
|
+
|
|
33
|
+
/** Construct a product additive quantizer.
|
|
34
|
+
*
|
|
35
|
+
* The additive quantizers passed in will be cloned into the
|
|
36
|
+
* ProductAdditiveQuantizer object.
|
|
37
|
+
*
|
|
38
|
+
* @param d dimensionality of the input vectors
|
|
39
|
+
* @param aqs sub-additive quantizers
|
|
40
|
+
* @param search_type AQ search type
|
|
41
|
+
*/
|
|
42
|
+
ProductAdditiveQuantizer(
|
|
43
|
+
size_t d,
|
|
44
|
+
const std::vector<AdditiveQuantizer*>& aqs,
|
|
45
|
+
Search_type_t search_type = ST_decompress);
|
|
46
|
+
|
|
47
|
+
ProductAdditiveQuantizer();
|
|
48
|
+
|
|
49
|
+
virtual ~ProductAdditiveQuantizer();
|
|
50
|
+
|
|
51
|
+
void init(
|
|
52
|
+
size_t d,
|
|
53
|
+
const std::vector<AdditiveQuantizer*>& aqs,
|
|
54
|
+
Search_type_t search_type);
|
|
55
|
+
|
|
56
|
+
AdditiveQuantizer* subquantizer(size_t m) const;
|
|
57
|
+
|
|
58
|
+
///< Train the product additive quantizer
|
|
59
|
+
void train(size_t n, const float* x) override;
|
|
60
|
+
|
|
61
|
+
/** Encode a set of vectors
|
|
62
|
+
*
|
|
63
|
+
* @param x vectors to encode, size n * d
|
|
64
|
+
* @param codes output codes, size n * code_size
|
|
65
|
+
* @param centroids centroids to be added to x, size n * d
|
|
66
|
+
*/
|
|
67
|
+
void compute_codes_add_centroids(
|
|
68
|
+
const float* x,
|
|
69
|
+
uint8_t* codes,
|
|
70
|
+
size_t n,
|
|
71
|
+
const float* centroids = nullptr) const override;
|
|
72
|
+
|
|
73
|
+
void compute_unpacked_codes(
|
|
74
|
+
const float* x,
|
|
75
|
+
int32_t* codes,
|
|
76
|
+
size_t n,
|
|
77
|
+
const float* centroids = nullptr) const;
|
|
78
|
+
|
|
79
|
+
/** Decode a set of vectors in non-packed format
|
|
80
|
+
*
|
|
81
|
+
* @param codes codes to decode, size n * ld_codes
|
|
82
|
+
* @param x output vectors, size n * d
|
|
83
|
+
*/
|
|
84
|
+
void decode_unpacked(
|
|
85
|
+
const int32_t* codes,
|
|
86
|
+
float* x,
|
|
87
|
+
size_t n,
|
|
88
|
+
int64_t ld_codes = -1) const override;
|
|
89
|
+
|
|
90
|
+
/** Decode a set of vectors
|
|
91
|
+
*
|
|
92
|
+
* @param codes codes to decode, size n * code_size
|
|
93
|
+
* @param x output vectors, size n * d
|
|
94
|
+
*/
|
|
95
|
+
void decode(const uint8_t* codes, float* x, size_t n) const override;
|
|
96
|
+
|
|
97
|
+
/** Compute inner-product look-up tables. Used in the search functions.
|
|
98
|
+
*
|
|
99
|
+
* @param xq query vector, size (n, d)
|
|
100
|
+
* @param LUT look-up table, size (n, total_codebook_size)
|
|
101
|
+
* @param alpha compute alpha * inner-product
|
|
102
|
+
* @param ld_lut leading dimension of LUT
|
|
103
|
+
*/
|
|
104
|
+
void compute_LUT(
|
|
105
|
+
size_t n,
|
|
106
|
+
const float* xq,
|
|
107
|
+
float* LUT,
|
|
108
|
+
float alpha = 1.0f,
|
|
109
|
+
long ld_lut = -1) const override;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/** Product Local Search Quantizer
|
|
113
|
+
*/
|
|
114
|
+
struct ProductLocalSearchQuantizer : ProductAdditiveQuantizer {
|
|
115
|
+
/** Construct a product LSQ object.
|
|
116
|
+
*
|
|
117
|
+
* @param d dimensionality of the input vectors
|
|
118
|
+
* @param nsplits number of sub-vectors we split a vector into
|
|
119
|
+
* @param Msub number of codebooks of each LSQ
|
|
120
|
+
* @param nbits bits for each step
|
|
121
|
+
* @param search_type AQ search type
|
|
122
|
+
*/
|
|
123
|
+
ProductLocalSearchQuantizer(
|
|
124
|
+
size_t d,
|
|
125
|
+
size_t nsplits,
|
|
126
|
+
size_t Msub,
|
|
127
|
+
size_t nbits,
|
|
128
|
+
Search_type_t search_type = ST_decompress);
|
|
129
|
+
|
|
130
|
+
ProductLocalSearchQuantizer();
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
/** Product Residual Quantizer
|
|
134
|
+
*/
|
|
135
|
+
struct ProductResidualQuantizer : ProductAdditiveQuantizer {
|
|
136
|
+
/** Construct a product RQ object.
|
|
137
|
+
*
|
|
138
|
+
* @param d dimensionality of the input vectors
|
|
139
|
+
* @param nsplits number of sub-vectors we split a vector into
|
|
140
|
+
* @param Msub number of codebooks of each RQ
|
|
141
|
+
* @param nbits bits for each step
|
|
142
|
+
* @param search_type AQ search type
|
|
143
|
+
*/
|
|
144
|
+
ProductResidualQuantizer(
|
|
145
|
+
size_t d,
|
|
146
|
+
size_t nsplits,
|
|
147
|
+
size_t Msub,
|
|
148
|
+
size_t nbits,
|
|
149
|
+
Search_type_t search_type = ST_decompress);
|
|
150
|
+
|
|
151
|
+
ProductResidualQuantizer();
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
}; // namespace faiss
|