faiss 0.1.0 → 0.1.1
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 +103 -3
- data/ext/faiss/ext.cpp +99 -32
- data/ext/faiss/extconf.rb +12 -2
- data/lib/faiss/ext.bundle +0 -0
- data/lib/faiss/index.rb +3 -3
- data/lib/faiss/index_binary.rb +3 -3
- data/lib/faiss/kmeans.rb +1 -1
- data/lib/faiss/pca_matrix.rb +2 -2
- data/lib/faiss/product_quantizer.rb +3 -3
- data/lib/faiss/version.rb +1 -1
- data/vendor/faiss/AutoTune.cpp +719 -0
- data/vendor/faiss/AutoTune.h +212 -0
- data/vendor/faiss/Clustering.cpp +261 -0
- data/vendor/faiss/Clustering.h +101 -0
- data/vendor/faiss/IVFlib.cpp +339 -0
- data/vendor/faiss/IVFlib.h +132 -0
- data/vendor/faiss/Index.cpp +171 -0
- data/vendor/faiss/Index.h +261 -0
- data/vendor/faiss/Index2Layer.cpp +437 -0
- data/vendor/faiss/Index2Layer.h +85 -0
- data/vendor/faiss/IndexBinary.cpp +77 -0
- data/vendor/faiss/IndexBinary.h +163 -0
- data/vendor/faiss/IndexBinaryFlat.cpp +83 -0
- data/vendor/faiss/IndexBinaryFlat.h +54 -0
- data/vendor/faiss/IndexBinaryFromFloat.cpp +78 -0
- data/vendor/faiss/IndexBinaryFromFloat.h +52 -0
- data/vendor/faiss/IndexBinaryHNSW.cpp +325 -0
- data/vendor/faiss/IndexBinaryHNSW.h +56 -0
- data/vendor/faiss/IndexBinaryIVF.cpp +671 -0
- data/vendor/faiss/IndexBinaryIVF.h +211 -0
- data/vendor/faiss/IndexFlat.cpp +508 -0
- data/vendor/faiss/IndexFlat.h +175 -0
- data/vendor/faiss/IndexHNSW.cpp +1090 -0
- data/vendor/faiss/IndexHNSW.h +170 -0
- data/vendor/faiss/IndexIVF.cpp +909 -0
- data/vendor/faiss/IndexIVF.h +353 -0
- data/vendor/faiss/IndexIVFFlat.cpp +502 -0
- data/vendor/faiss/IndexIVFFlat.h +118 -0
- data/vendor/faiss/IndexIVFPQ.cpp +1207 -0
- data/vendor/faiss/IndexIVFPQ.h +161 -0
- data/vendor/faiss/IndexIVFPQR.cpp +219 -0
- data/vendor/faiss/IndexIVFPQR.h +65 -0
- data/vendor/faiss/IndexIVFSpectralHash.cpp +331 -0
- data/vendor/faiss/IndexIVFSpectralHash.h +75 -0
- data/vendor/faiss/IndexLSH.cpp +225 -0
- data/vendor/faiss/IndexLSH.h +87 -0
- data/vendor/faiss/IndexLattice.cpp +143 -0
- data/vendor/faiss/IndexLattice.h +68 -0
- data/vendor/faiss/IndexPQ.cpp +1188 -0
- data/vendor/faiss/IndexPQ.h +199 -0
- data/vendor/faiss/IndexPreTransform.cpp +288 -0
- data/vendor/faiss/IndexPreTransform.h +91 -0
- data/vendor/faiss/IndexReplicas.cpp +123 -0
- data/vendor/faiss/IndexReplicas.h +76 -0
- data/vendor/faiss/IndexScalarQuantizer.cpp +317 -0
- data/vendor/faiss/IndexScalarQuantizer.h +127 -0
- data/vendor/faiss/IndexShards.cpp +317 -0
- data/vendor/faiss/IndexShards.h +100 -0
- data/vendor/faiss/InvertedLists.cpp +623 -0
- data/vendor/faiss/InvertedLists.h +334 -0
- data/vendor/faiss/LICENSE +21 -0
- data/vendor/faiss/MatrixStats.cpp +252 -0
- data/vendor/faiss/MatrixStats.h +62 -0
- data/vendor/faiss/MetaIndexes.cpp +351 -0
- data/vendor/faiss/MetaIndexes.h +126 -0
- data/vendor/faiss/OnDiskInvertedLists.cpp +674 -0
- data/vendor/faiss/OnDiskInvertedLists.h +127 -0
- data/vendor/faiss/VectorTransform.cpp +1157 -0
- data/vendor/faiss/VectorTransform.h +322 -0
- data/vendor/faiss/c_api/AutoTune_c.cpp +83 -0
- data/vendor/faiss/c_api/AutoTune_c.h +64 -0
- data/vendor/faiss/c_api/Clustering_c.cpp +139 -0
- data/vendor/faiss/c_api/Clustering_c.h +117 -0
- data/vendor/faiss/c_api/IndexFlat_c.cpp +140 -0
- data/vendor/faiss/c_api/IndexFlat_c.h +115 -0
- data/vendor/faiss/c_api/IndexIVFFlat_c.cpp +64 -0
- data/vendor/faiss/c_api/IndexIVFFlat_c.h +58 -0
- data/vendor/faiss/c_api/IndexIVF_c.cpp +92 -0
- data/vendor/faiss/c_api/IndexIVF_c.h +135 -0
- data/vendor/faiss/c_api/IndexLSH_c.cpp +37 -0
- data/vendor/faiss/c_api/IndexLSH_c.h +40 -0
- data/vendor/faiss/c_api/IndexShards_c.cpp +44 -0
- data/vendor/faiss/c_api/IndexShards_c.h +42 -0
- data/vendor/faiss/c_api/Index_c.cpp +105 -0
- data/vendor/faiss/c_api/Index_c.h +183 -0
- data/vendor/faiss/c_api/MetaIndexes_c.cpp +49 -0
- data/vendor/faiss/c_api/MetaIndexes_c.h +49 -0
- data/vendor/faiss/c_api/clone_index_c.cpp +23 -0
- data/vendor/faiss/c_api/clone_index_c.h +32 -0
- data/vendor/faiss/c_api/error_c.h +42 -0
- data/vendor/faiss/c_api/error_impl.cpp +27 -0
- data/vendor/faiss/c_api/error_impl.h +16 -0
- data/vendor/faiss/c_api/faiss_c.h +58 -0
- data/vendor/faiss/c_api/gpu/GpuAutoTune_c.cpp +96 -0
- data/vendor/faiss/c_api/gpu/GpuAutoTune_c.h +56 -0
- data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.cpp +52 -0
- data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.h +68 -0
- data/vendor/faiss/c_api/gpu/GpuIndex_c.cpp +17 -0
- data/vendor/faiss/c_api/gpu/GpuIndex_c.h +30 -0
- data/vendor/faiss/c_api/gpu/GpuIndicesOptions_c.h +38 -0
- data/vendor/faiss/c_api/gpu/GpuResources_c.cpp +86 -0
- data/vendor/faiss/c_api/gpu/GpuResources_c.h +66 -0
- data/vendor/faiss/c_api/gpu/StandardGpuResources_c.cpp +54 -0
- data/vendor/faiss/c_api/gpu/StandardGpuResources_c.h +53 -0
- data/vendor/faiss/c_api/gpu/macros_impl.h +42 -0
- data/vendor/faiss/c_api/impl/AuxIndexStructures_c.cpp +220 -0
- data/vendor/faiss/c_api/impl/AuxIndexStructures_c.h +149 -0
- data/vendor/faiss/c_api/index_factory_c.cpp +26 -0
- data/vendor/faiss/c_api/index_factory_c.h +30 -0
- data/vendor/faiss/c_api/index_io_c.cpp +42 -0
- data/vendor/faiss/c_api/index_io_c.h +50 -0
- data/vendor/faiss/c_api/macros_impl.h +110 -0
- data/vendor/faiss/clone_index.cpp +147 -0
- data/vendor/faiss/clone_index.h +38 -0
- data/vendor/faiss/demos/demo_imi_flat.cpp +151 -0
- data/vendor/faiss/demos/demo_imi_pq.cpp +199 -0
- data/vendor/faiss/demos/demo_ivfpq_indexing.cpp +146 -0
- data/vendor/faiss/demos/demo_sift1M.cpp +252 -0
- data/vendor/faiss/gpu/GpuAutoTune.cpp +95 -0
- data/vendor/faiss/gpu/GpuAutoTune.h +27 -0
- data/vendor/faiss/gpu/GpuCloner.cpp +403 -0
- data/vendor/faiss/gpu/GpuCloner.h +82 -0
- data/vendor/faiss/gpu/GpuClonerOptions.cpp +28 -0
- data/vendor/faiss/gpu/GpuClonerOptions.h +53 -0
- data/vendor/faiss/gpu/GpuDistance.h +52 -0
- data/vendor/faiss/gpu/GpuFaissAssert.h +29 -0
- data/vendor/faiss/gpu/GpuIndex.h +148 -0
- data/vendor/faiss/gpu/GpuIndexBinaryFlat.h +89 -0
- data/vendor/faiss/gpu/GpuIndexFlat.h +190 -0
- data/vendor/faiss/gpu/GpuIndexIVF.h +89 -0
- data/vendor/faiss/gpu/GpuIndexIVFFlat.h +85 -0
- data/vendor/faiss/gpu/GpuIndexIVFPQ.h +143 -0
- data/vendor/faiss/gpu/GpuIndexIVFScalarQuantizer.h +100 -0
- data/vendor/faiss/gpu/GpuIndicesOptions.h +30 -0
- data/vendor/faiss/gpu/GpuResources.cpp +52 -0
- data/vendor/faiss/gpu/GpuResources.h +73 -0
- data/vendor/faiss/gpu/StandardGpuResources.cpp +295 -0
- data/vendor/faiss/gpu/StandardGpuResources.h +114 -0
- data/vendor/faiss/gpu/impl/RemapIndices.cpp +43 -0
- data/vendor/faiss/gpu/impl/RemapIndices.h +24 -0
- data/vendor/faiss/gpu/perf/IndexWrapper-inl.h +71 -0
- data/vendor/faiss/gpu/perf/IndexWrapper.h +39 -0
- data/vendor/faiss/gpu/perf/PerfClustering.cpp +115 -0
- data/vendor/faiss/gpu/perf/PerfIVFPQAdd.cpp +139 -0
- data/vendor/faiss/gpu/perf/WriteIndex.cpp +102 -0
- data/vendor/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +130 -0
- data/vendor/faiss/gpu/test/TestGpuIndexFlat.cpp +371 -0
- data/vendor/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +550 -0
- data/vendor/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +450 -0
- data/vendor/faiss/gpu/test/TestGpuMemoryException.cpp +84 -0
- data/vendor/faiss/gpu/test/TestUtils.cpp +315 -0
- data/vendor/faiss/gpu/test/TestUtils.h +93 -0
- data/vendor/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +159 -0
- data/vendor/faiss/gpu/utils/DeviceMemory.cpp +77 -0
- data/vendor/faiss/gpu/utils/DeviceMemory.h +71 -0
- data/vendor/faiss/gpu/utils/DeviceUtils.h +185 -0
- data/vendor/faiss/gpu/utils/MemorySpace.cpp +89 -0
- data/vendor/faiss/gpu/utils/MemorySpace.h +44 -0
- data/vendor/faiss/gpu/utils/StackDeviceMemory.cpp +239 -0
- data/vendor/faiss/gpu/utils/StackDeviceMemory.h +129 -0
- data/vendor/faiss/gpu/utils/StaticUtils.h +83 -0
- data/vendor/faiss/gpu/utils/Timer.cpp +60 -0
- data/vendor/faiss/gpu/utils/Timer.h +52 -0
- data/vendor/faiss/impl/AuxIndexStructures.cpp +305 -0
- data/vendor/faiss/impl/AuxIndexStructures.h +246 -0
- data/vendor/faiss/impl/FaissAssert.h +95 -0
- data/vendor/faiss/impl/FaissException.cpp +66 -0
- data/vendor/faiss/impl/FaissException.h +71 -0
- data/vendor/faiss/impl/HNSW.cpp +818 -0
- data/vendor/faiss/impl/HNSW.h +275 -0
- data/vendor/faiss/impl/PolysemousTraining.cpp +953 -0
- data/vendor/faiss/impl/PolysemousTraining.h +158 -0
- data/vendor/faiss/impl/ProductQuantizer.cpp +876 -0
- data/vendor/faiss/impl/ProductQuantizer.h +242 -0
- data/vendor/faiss/impl/ScalarQuantizer.cpp +1628 -0
- data/vendor/faiss/impl/ScalarQuantizer.h +120 -0
- data/vendor/faiss/impl/ThreadedIndex-inl.h +192 -0
- data/vendor/faiss/impl/ThreadedIndex.h +80 -0
- data/vendor/faiss/impl/index_read.cpp +793 -0
- data/vendor/faiss/impl/index_write.cpp +558 -0
- data/vendor/faiss/impl/io.cpp +142 -0
- data/vendor/faiss/impl/io.h +98 -0
- data/vendor/faiss/impl/lattice_Zn.cpp +712 -0
- data/vendor/faiss/impl/lattice_Zn.h +199 -0
- data/vendor/faiss/index_factory.cpp +392 -0
- data/vendor/faiss/index_factory.h +25 -0
- data/vendor/faiss/index_io.h +75 -0
- data/vendor/faiss/misc/test_blas.cpp +84 -0
- data/vendor/faiss/tests/test_binary_flat.cpp +64 -0
- data/vendor/faiss/tests/test_dealloc_invlists.cpp +183 -0
- data/vendor/faiss/tests/test_ivfpq_codec.cpp +67 -0
- data/vendor/faiss/tests/test_ivfpq_indexing.cpp +98 -0
- data/vendor/faiss/tests/test_lowlevel_ivf.cpp +566 -0
- data/vendor/faiss/tests/test_merge.cpp +258 -0
- data/vendor/faiss/tests/test_omp_threads.cpp +14 -0
- data/vendor/faiss/tests/test_ondisk_ivf.cpp +220 -0
- data/vendor/faiss/tests/test_pairs_decoding.cpp +189 -0
- data/vendor/faiss/tests/test_params_override.cpp +231 -0
- data/vendor/faiss/tests/test_pq_encoding.cpp +98 -0
- data/vendor/faiss/tests/test_sliding_ivf.cpp +240 -0
- data/vendor/faiss/tests/test_threaded_index.cpp +253 -0
- data/vendor/faiss/tests/test_transfer_invlists.cpp +159 -0
- data/vendor/faiss/tutorial/cpp/1-Flat.cpp +98 -0
- data/vendor/faiss/tutorial/cpp/2-IVFFlat.cpp +81 -0
- data/vendor/faiss/tutorial/cpp/3-IVFPQ.cpp +93 -0
- data/vendor/faiss/tutorial/cpp/4-GPU.cpp +119 -0
- data/vendor/faiss/tutorial/cpp/5-Multiple-GPUs.cpp +99 -0
- data/vendor/faiss/utils/Heap.cpp +122 -0
- data/vendor/faiss/utils/Heap.h +495 -0
- data/vendor/faiss/utils/WorkerThread.cpp +126 -0
- data/vendor/faiss/utils/WorkerThread.h +61 -0
- data/vendor/faiss/utils/distances.cpp +765 -0
- data/vendor/faiss/utils/distances.h +243 -0
- data/vendor/faiss/utils/distances_simd.cpp +809 -0
- data/vendor/faiss/utils/extra_distances.cpp +336 -0
- data/vendor/faiss/utils/extra_distances.h +54 -0
- data/vendor/faiss/utils/hamming-inl.h +472 -0
- data/vendor/faiss/utils/hamming.cpp +792 -0
- data/vendor/faiss/utils/hamming.h +220 -0
- data/vendor/faiss/utils/random.cpp +192 -0
- data/vendor/faiss/utils/random.h +60 -0
- data/vendor/faiss/utils/utils.cpp +783 -0
- data/vendor/faiss/utils/utils.h +181 -0
- metadata +216 -2
|
@@ -0,0 +1,252 @@
|
|
|
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
|
+
|
|
9
|
+
|
|
10
|
+
#include <cmath>
|
|
11
|
+
#include <cstdio>
|
|
12
|
+
#include <cstdlib>
|
|
13
|
+
#include <cassert>
|
|
14
|
+
#include <cstring>
|
|
15
|
+
|
|
16
|
+
#include <sys/types.h>
|
|
17
|
+
#include <sys/stat.h>
|
|
18
|
+
#include <unistd.h>
|
|
19
|
+
|
|
20
|
+
#include <sys/time.h>
|
|
21
|
+
|
|
22
|
+
#include <faiss/AutoTune.h>
|
|
23
|
+
#include <faiss/index_factory.h>
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* To run this demo, please download the ANN_SIFT1M dataset from
|
|
27
|
+
*
|
|
28
|
+
* http://corpus-texmex.irisa.fr/
|
|
29
|
+
*
|
|
30
|
+
* and unzip it to the sudirectory sift1M.
|
|
31
|
+
**/
|
|
32
|
+
|
|
33
|
+
/*****************************************************
|
|
34
|
+
* I/O functions for fvecs and ivecs
|
|
35
|
+
*****************************************************/
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
float * fvecs_read (const char *fname,
|
|
39
|
+
size_t *d_out, size_t *n_out)
|
|
40
|
+
{
|
|
41
|
+
FILE *f = fopen(fname, "r");
|
|
42
|
+
if(!f) {
|
|
43
|
+
fprintf(stderr, "could not open %s\n", fname);
|
|
44
|
+
perror("");
|
|
45
|
+
abort();
|
|
46
|
+
}
|
|
47
|
+
int d;
|
|
48
|
+
fread(&d, 1, sizeof(int), f);
|
|
49
|
+
assert((d > 0 && d < 1000000) || !"unreasonable dimension");
|
|
50
|
+
fseek(f, 0, SEEK_SET);
|
|
51
|
+
struct stat st;
|
|
52
|
+
fstat(fileno(f), &st);
|
|
53
|
+
size_t sz = st.st_size;
|
|
54
|
+
assert(sz % ((d + 1) * 4) == 0 || !"weird file size");
|
|
55
|
+
size_t n = sz / ((d + 1) * 4);
|
|
56
|
+
|
|
57
|
+
*d_out = d; *n_out = n;
|
|
58
|
+
float *x = new float[n * (d + 1)];
|
|
59
|
+
size_t nr = fread(x, sizeof(float), n * (d + 1), f);
|
|
60
|
+
assert(nr == n * (d + 1) || !"could not read whole file");
|
|
61
|
+
|
|
62
|
+
// shift array to remove row headers
|
|
63
|
+
for(size_t i = 0; i < n; i++)
|
|
64
|
+
memmove(x + i * d, x + 1 + i * (d + 1), d * sizeof(*x));
|
|
65
|
+
|
|
66
|
+
fclose(f);
|
|
67
|
+
return x;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// not very clean, but works as long as sizeof(int) == sizeof(float)
|
|
71
|
+
int *ivecs_read(const char *fname, size_t *d_out, size_t *n_out)
|
|
72
|
+
{
|
|
73
|
+
return (int*)fvecs_read(fname, d_out, n_out);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
double elapsed ()
|
|
77
|
+
{
|
|
78
|
+
struct timeval tv;
|
|
79
|
+
gettimeofday (&tv, nullptr);
|
|
80
|
+
return tv.tv_sec + tv.tv_usec * 1e-6;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
int main()
|
|
86
|
+
{
|
|
87
|
+
double t0 = elapsed();
|
|
88
|
+
|
|
89
|
+
// this is typically the fastest one.
|
|
90
|
+
const char *index_key = "IVF4096,Flat";
|
|
91
|
+
|
|
92
|
+
// these ones have better memory usage
|
|
93
|
+
// const char *index_key = "Flat";
|
|
94
|
+
// const char *index_key = "PQ32";
|
|
95
|
+
// const char *index_key = "PCA80,Flat";
|
|
96
|
+
// const char *index_key = "IVF4096,PQ8+16";
|
|
97
|
+
// const char *index_key = "IVF4096,PQ32";
|
|
98
|
+
// const char *index_key = "IMI2x8,PQ32";
|
|
99
|
+
// const char *index_key = "IMI2x8,PQ8+16";
|
|
100
|
+
// const char *index_key = "OPQ16_64,IMI2x8,PQ8+16";
|
|
101
|
+
|
|
102
|
+
faiss::Index * index;
|
|
103
|
+
|
|
104
|
+
size_t d;
|
|
105
|
+
|
|
106
|
+
{
|
|
107
|
+
printf ("[%.3f s] Loading train set\n", elapsed() - t0);
|
|
108
|
+
|
|
109
|
+
size_t nt;
|
|
110
|
+
float *xt = fvecs_read("sift1M/sift_learn.fvecs", &d, &nt);
|
|
111
|
+
|
|
112
|
+
printf ("[%.3f s] Preparing index \"%s\" d=%ld\n",
|
|
113
|
+
elapsed() - t0, index_key, d);
|
|
114
|
+
index = faiss::index_factory(d, index_key);
|
|
115
|
+
|
|
116
|
+
printf ("[%.3f s] Training on %ld vectors\n", elapsed() - t0, nt);
|
|
117
|
+
|
|
118
|
+
index->train(nt, xt);
|
|
119
|
+
delete [] xt;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
{
|
|
124
|
+
printf ("[%.3f s] Loading database\n", elapsed() - t0);
|
|
125
|
+
|
|
126
|
+
size_t nb, d2;
|
|
127
|
+
float *xb = fvecs_read("sift1M/sift_base.fvecs", &d2, &nb);
|
|
128
|
+
assert(d == d2 || !"dataset does not have same dimension as train set");
|
|
129
|
+
|
|
130
|
+
printf ("[%.3f s] Indexing database, size %ld*%ld\n",
|
|
131
|
+
elapsed() - t0, nb, d);
|
|
132
|
+
|
|
133
|
+
index->add(nb, xb);
|
|
134
|
+
|
|
135
|
+
delete [] xb;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
size_t nq;
|
|
139
|
+
float *xq;
|
|
140
|
+
|
|
141
|
+
{
|
|
142
|
+
printf ("[%.3f s] Loading queries\n", elapsed() - t0);
|
|
143
|
+
|
|
144
|
+
size_t d2;
|
|
145
|
+
xq = fvecs_read("sift1M/sift_query.fvecs", &d2, &nq);
|
|
146
|
+
assert(d == d2 || !"query does not have same dimension as train set");
|
|
147
|
+
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
size_t k; // nb of results per query in the GT
|
|
151
|
+
faiss::Index::idx_t *gt; // nq * k matrix of ground-truth nearest-neighbors
|
|
152
|
+
|
|
153
|
+
{
|
|
154
|
+
printf ("[%.3f s] Loading ground truth for %ld queries\n",
|
|
155
|
+
elapsed() - t0, nq);
|
|
156
|
+
|
|
157
|
+
// load ground-truth and convert int to long
|
|
158
|
+
size_t nq2;
|
|
159
|
+
int *gt_int = ivecs_read("sift1M/sift_groundtruth.ivecs", &k, &nq2);
|
|
160
|
+
assert(nq2 == nq || !"incorrect nb of ground truth entries");
|
|
161
|
+
|
|
162
|
+
gt = new faiss::Index::idx_t[k * nq];
|
|
163
|
+
for(int i = 0; i < k * nq; i++) {
|
|
164
|
+
gt[i] = gt_int[i];
|
|
165
|
+
}
|
|
166
|
+
delete [] gt_int;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Result of the auto-tuning
|
|
170
|
+
std::string selected_params;
|
|
171
|
+
|
|
172
|
+
{ // run auto-tuning
|
|
173
|
+
|
|
174
|
+
printf ("[%.3f s] Preparing auto-tune criterion 1-recall at 1 "
|
|
175
|
+
"criterion, with k=%ld nq=%ld\n", elapsed() - t0, k, nq);
|
|
176
|
+
|
|
177
|
+
faiss::OneRecallAtRCriterion crit(nq, 1);
|
|
178
|
+
crit.set_groundtruth (k, nullptr, gt);
|
|
179
|
+
crit.nnn = k; // by default, the criterion will request only 1 NN
|
|
180
|
+
|
|
181
|
+
printf ("[%.3f s] Preparing auto-tune parameters\n", elapsed() - t0);
|
|
182
|
+
|
|
183
|
+
faiss::ParameterSpace params;
|
|
184
|
+
params.initialize(index);
|
|
185
|
+
|
|
186
|
+
printf ("[%.3f s] Auto-tuning over %ld parameters (%ld combinations)\n",
|
|
187
|
+
elapsed() - t0, params.parameter_ranges.size(),
|
|
188
|
+
params.n_combinations());
|
|
189
|
+
|
|
190
|
+
faiss::OperatingPoints ops;
|
|
191
|
+
params.explore (index, nq, xq, crit, &ops);
|
|
192
|
+
|
|
193
|
+
printf ("[%.3f s] Found the following operating points: \n",
|
|
194
|
+
elapsed() - t0);
|
|
195
|
+
|
|
196
|
+
ops.display ();
|
|
197
|
+
|
|
198
|
+
// keep the first parameter that obtains > 0.5 1-recall@1
|
|
199
|
+
for (int i = 0; i < ops.optimal_pts.size(); i++) {
|
|
200
|
+
if (ops.optimal_pts[i].perf > 0.5) {
|
|
201
|
+
selected_params = ops.optimal_pts[i].key;
|
|
202
|
+
break;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
assert (selected_params.size() >= 0 ||
|
|
206
|
+
!"could not find good enough op point");
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
{ // Use the found configuration to perform a search
|
|
211
|
+
|
|
212
|
+
faiss::ParameterSpace params;
|
|
213
|
+
|
|
214
|
+
printf ("[%.3f s] Setting parameter configuration \"%s\" on index\n",
|
|
215
|
+
elapsed() - t0, selected_params.c_str());
|
|
216
|
+
|
|
217
|
+
params.set_index_parameters (index, selected_params.c_str());
|
|
218
|
+
|
|
219
|
+
printf ("[%.3f s] Perform a search on %ld queries\n",
|
|
220
|
+
elapsed() - t0, nq);
|
|
221
|
+
|
|
222
|
+
// output buffers
|
|
223
|
+
faiss::Index::idx_t *I = new faiss::Index::idx_t[nq * k];
|
|
224
|
+
float *D = new float[nq * k];
|
|
225
|
+
|
|
226
|
+
index->search(nq, xq, k, D, I);
|
|
227
|
+
|
|
228
|
+
printf ("[%.3f s] Compute recalls\n", elapsed() - t0);
|
|
229
|
+
|
|
230
|
+
// evaluate result by hand.
|
|
231
|
+
int n_1 = 0, n_10 = 0, n_100 = 0;
|
|
232
|
+
for(int i = 0; i < nq; i++) {
|
|
233
|
+
int gt_nn = gt[i * k];
|
|
234
|
+
for(int j = 0; j < k; j++) {
|
|
235
|
+
if (I[i * k + j] == gt_nn) {
|
|
236
|
+
if(j < 1) n_1++;
|
|
237
|
+
if(j < 10) n_10++;
|
|
238
|
+
if(j < 100) n_100++;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
printf("R@1 = %.4f\n", n_1 / float(nq));
|
|
243
|
+
printf("R@10 = %.4f\n", n_10 / float(nq));
|
|
244
|
+
printf("R@100 = %.4f\n", n_100 / float(nq));
|
|
245
|
+
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
delete [] xq;
|
|
249
|
+
delete [] gt;
|
|
250
|
+
delete index;
|
|
251
|
+
return 0;
|
|
252
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
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/gpu/GpuAutoTune.h>
|
|
9
|
+
#include <typeinfo>
|
|
10
|
+
|
|
11
|
+
#include <faiss/gpu/GpuIndex.h>
|
|
12
|
+
#include <faiss/IndexReplicas.h>
|
|
13
|
+
#include <faiss/IndexShards.h>
|
|
14
|
+
#include <faiss/IndexPreTransform.h>
|
|
15
|
+
#include <faiss/gpu/GpuIndexFlat.h>
|
|
16
|
+
#include <faiss/gpu/GpuIndexIVFFlat.h>
|
|
17
|
+
#include <faiss/gpu/GpuIndexIVFPQ.h>
|
|
18
|
+
#include <faiss/gpu/GpuIndexIVFScalarQuantizer.h>
|
|
19
|
+
#include <faiss/impl/FaissAssert.h>
|
|
20
|
+
#include <faiss/gpu/utils/DeviceUtils.h>
|
|
21
|
+
|
|
22
|
+
namespace faiss { namespace gpu {
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
using namespace ::faiss;
|
|
26
|
+
|
|
27
|
+
/**********************************************************
|
|
28
|
+
* Parameters to auto-tune on GpuIndex'es
|
|
29
|
+
**********************************************************/
|
|
30
|
+
|
|
31
|
+
#define DC(classname) auto ix = dynamic_cast<const classname *>(index)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
void GpuParameterSpace::initialize (const Index * index)
|
|
35
|
+
{
|
|
36
|
+
if (DC (IndexPreTransform)) {
|
|
37
|
+
index = ix->index;
|
|
38
|
+
}
|
|
39
|
+
if (DC (IndexReplicas)) {
|
|
40
|
+
if (ix->count() == 0) return;
|
|
41
|
+
index = ix->at(0);
|
|
42
|
+
}
|
|
43
|
+
if (DC (IndexShards)) {
|
|
44
|
+
if (ix->count() == 0) return;
|
|
45
|
+
index = ix->at(0);
|
|
46
|
+
}
|
|
47
|
+
if (DC (GpuIndexIVF)) {
|
|
48
|
+
ParameterRange & pr = add_range("nprobe");
|
|
49
|
+
for (int i = 0; i < 12; i++) {
|
|
50
|
+
size_t nprobe = 1 << i;
|
|
51
|
+
if (nprobe >= ix->getNumLists() ||
|
|
52
|
+
nprobe > getMaxKSelection()) break;
|
|
53
|
+
pr.values.push_back (nprobe);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// not sure we should call the parent initializer
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
#undef DC
|
|
62
|
+
// non-const version
|
|
63
|
+
#define DC(classname) auto *ix = dynamic_cast<classname *>(index)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
void GpuParameterSpace::set_index_parameter (
|
|
68
|
+
Index * index, const std::string & name, double val) const
|
|
69
|
+
{
|
|
70
|
+
if (DC (IndexReplicas)) {
|
|
71
|
+
for (int i = 0; i < ix->count(); i++)
|
|
72
|
+
set_index_parameter (ix->at(i), name, val);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (name == "nprobe") {
|
|
76
|
+
if (DC (GpuIndexIVF)) {
|
|
77
|
+
ix->setNumProbes (int (val));
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (name == "use_precomputed_table") {
|
|
82
|
+
if (DC (GpuIndexIVFPQ)) {
|
|
83
|
+
ix->setPrecomputedCodes(bool (val));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// maybe normal index parameters apply?
|
|
89
|
+
ParameterSpace::set_index_parameter (index, name, val);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
} } // namespace
|
|
@@ -0,0 +1,27 @@
|
|
|
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 <faiss/Index.h>
|
|
11
|
+
#include <faiss/AutoTune.h>
|
|
12
|
+
|
|
13
|
+
namespace faiss { namespace gpu {
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
/// parameter space and setters for GPU indexes
|
|
17
|
+
struct GpuParameterSpace: faiss::ParameterSpace {
|
|
18
|
+
/// initialize with reasonable parameters for the index
|
|
19
|
+
void initialize (const faiss::Index * index) override;
|
|
20
|
+
|
|
21
|
+
/// set a combination of parameters on an index
|
|
22
|
+
void set_index_parameter (
|
|
23
|
+
faiss::Index * index, const std::string & name,
|
|
24
|
+
double val) const override;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
} } // namespace
|
|
@@ -0,0 +1,403 @@
|
|
|
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
|
+
|
|
9
|
+
#include <faiss/gpu/GpuCloner.h>
|
|
10
|
+
#include <typeinfo>
|
|
11
|
+
|
|
12
|
+
#include <faiss/gpu/GpuIndex.h>
|
|
13
|
+
#include <faiss/impl/FaissAssert.h>
|
|
14
|
+
#include <faiss/index_io.h>
|
|
15
|
+
#include <faiss/IndexFlat.h>
|
|
16
|
+
#include <faiss/IndexIVF.h>
|
|
17
|
+
#include <faiss/IndexIVFFlat.h>
|
|
18
|
+
#include <faiss/IndexScalarQuantizer.h>
|
|
19
|
+
#include <faiss/IndexIVFPQ.h>
|
|
20
|
+
#include <faiss/IndexReplicas.h>
|
|
21
|
+
#include <faiss/IndexPreTransform.h>
|
|
22
|
+
#include <faiss/MetaIndexes.h>
|
|
23
|
+
#include <faiss/gpu/GpuIndexFlat.h>
|
|
24
|
+
#include <faiss/gpu/GpuIndexIVFFlat.h>
|
|
25
|
+
#include <faiss/gpu/GpuIndexIVFPQ.h>
|
|
26
|
+
#include <faiss/gpu/GpuIndexIVFScalarQuantizer.h>
|
|
27
|
+
#include <faiss/gpu/utils/DeviceUtils.h>
|
|
28
|
+
|
|
29
|
+
namespace faiss { namespace gpu {
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/**********************************************************
|
|
33
|
+
* Cloning to CPU
|
|
34
|
+
**********************************************************/
|
|
35
|
+
|
|
36
|
+
void ToCPUCloner::merge_index(Index *dst, Index *src, bool successive_ids)
|
|
37
|
+
{
|
|
38
|
+
if (auto ifl = dynamic_cast<IndexFlat *>(dst)) {
|
|
39
|
+
auto ifl2 = dynamic_cast<const IndexFlat *>(src);
|
|
40
|
+
FAISS_ASSERT(ifl2);
|
|
41
|
+
FAISS_ASSERT(successive_ids);
|
|
42
|
+
ifl->add(ifl2->ntotal, ifl2->xb.data());
|
|
43
|
+
} else if(auto ifl = dynamic_cast<IndexIVFFlat *>(dst)) {
|
|
44
|
+
auto ifl2 = dynamic_cast<IndexIVFFlat *>(src);
|
|
45
|
+
FAISS_ASSERT(ifl2);
|
|
46
|
+
ifl->merge_from(*ifl2, successive_ids ? ifl->ntotal : 0);
|
|
47
|
+
} else if(auto ifl = dynamic_cast<IndexIVFScalarQuantizer *>(dst)) {
|
|
48
|
+
auto ifl2 = dynamic_cast<IndexIVFScalarQuantizer *>(src);
|
|
49
|
+
FAISS_ASSERT(ifl2);
|
|
50
|
+
ifl->merge_from(*ifl2, successive_ids ? ifl->ntotal : 0);
|
|
51
|
+
} else if(auto ifl = dynamic_cast<IndexIVFPQ *>(dst)) {
|
|
52
|
+
auto ifl2 = dynamic_cast<IndexIVFPQ *>(src);
|
|
53
|
+
FAISS_ASSERT(ifl2);
|
|
54
|
+
ifl->merge_from(*ifl2, successive_ids ? ifl->ntotal : 0);
|
|
55
|
+
} else {
|
|
56
|
+
FAISS_ASSERT(!"merging not implemented for this type of class");
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
Index *ToCPUCloner::clone_Index(const Index *index)
|
|
62
|
+
{
|
|
63
|
+
if(auto ifl = dynamic_cast<const GpuIndexFlat *>(index)) {
|
|
64
|
+
IndexFlat *res = new IndexFlat();
|
|
65
|
+
ifl->copyTo(res);
|
|
66
|
+
return res;
|
|
67
|
+
} else if(auto ifl = dynamic_cast<const GpuIndexIVFFlat *>(index)) {
|
|
68
|
+
IndexIVFFlat *res = new IndexIVFFlat();
|
|
69
|
+
ifl->copyTo(res);
|
|
70
|
+
return res;
|
|
71
|
+
} else if(auto ifl =
|
|
72
|
+
dynamic_cast<const GpuIndexIVFScalarQuantizer *>(index)) {
|
|
73
|
+
IndexIVFScalarQuantizer *res = new IndexIVFScalarQuantizer();
|
|
74
|
+
ifl->copyTo(res);
|
|
75
|
+
return res;
|
|
76
|
+
} else if(auto ipq = dynamic_cast<const GpuIndexIVFPQ *>(index)) {
|
|
77
|
+
IndexIVFPQ *res = new IndexIVFPQ();
|
|
78
|
+
ipq->copyTo(res);
|
|
79
|
+
return res;
|
|
80
|
+
|
|
81
|
+
// for IndexShards and IndexReplicas we assume that the
|
|
82
|
+
// objective is to make a single component out of them
|
|
83
|
+
// (inverse op of ToGpuClonerMultiple)
|
|
84
|
+
|
|
85
|
+
} else if(auto ish = dynamic_cast<const IndexShards *>(index)) {
|
|
86
|
+
int nshard = ish->count();
|
|
87
|
+
FAISS_ASSERT(nshard > 0);
|
|
88
|
+
Index *res = clone_Index(ish->at(0));
|
|
89
|
+
for(int i = 1; i < ish->count(); i++) {
|
|
90
|
+
Index *res_i = clone_Index(ish->at(i));
|
|
91
|
+
merge_index(res, res_i, ish->successive_ids);
|
|
92
|
+
delete res_i;
|
|
93
|
+
}
|
|
94
|
+
return res;
|
|
95
|
+
} else if(auto ipr = dynamic_cast<const IndexReplicas *>(index)) {
|
|
96
|
+
// just clone one of the replicas
|
|
97
|
+
FAISS_ASSERT(ipr->count() > 0);
|
|
98
|
+
return clone_Index(ipr->at(0));
|
|
99
|
+
} else {
|
|
100
|
+
return Cloner::clone_Index(index);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
faiss::Index * index_gpu_to_cpu(const faiss::Index *gpu_index)
|
|
105
|
+
{
|
|
106
|
+
ToCPUCloner cl;
|
|
107
|
+
return cl.clone_Index(gpu_index);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
/**********************************************************
|
|
114
|
+
* Cloning to 1 GPU
|
|
115
|
+
**********************************************************/
|
|
116
|
+
|
|
117
|
+
ToGpuCloner::ToGpuCloner(GpuResources *resources, int device,
|
|
118
|
+
const GpuClonerOptions &options):
|
|
119
|
+
GpuClonerOptions(options), resources(resources), device(device)
|
|
120
|
+
{}
|
|
121
|
+
|
|
122
|
+
Index *ToGpuCloner::clone_Index(const Index *index)
|
|
123
|
+
{
|
|
124
|
+
if(auto ifl = dynamic_cast<const IndexFlat *>(index)) {
|
|
125
|
+
GpuIndexFlatConfig config;
|
|
126
|
+
config.device = device;
|
|
127
|
+
config.useFloat16 = useFloat16;
|
|
128
|
+
config.storeTransposed = storeTransposed;
|
|
129
|
+
|
|
130
|
+
return new GpuIndexFlat(resources, ifl, config);
|
|
131
|
+
} else if(auto ifl = dynamic_cast<const faiss::IndexIVFFlat *>(index)) {
|
|
132
|
+
GpuIndexIVFFlatConfig config;
|
|
133
|
+
config.device = device;
|
|
134
|
+
config.indicesOptions = indicesOptions;
|
|
135
|
+
config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
|
|
136
|
+
config.flatConfig.storeTransposed = storeTransposed;
|
|
137
|
+
|
|
138
|
+
GpuIndexIVFFlat *res =
|
|
139
|
+
new GpuIndexIVFFlat(resources,
|
|
140
|
+
ifl->d,
|
|
141
|
+
ifl->nlist,
|
|
142
|
+
ifl->metric_type,
|
|
143
|
+
config);
|
|
144
|
+
if(reserveVecs > 0 && ifl->ntotal == 0) {
|
|
145
|
+
res->reserveMemory(reserveVecs);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
res->copyFrom(ifl);
|
|
149
|
+
return res;
|
|
150
|
+
} else if(auto ifl =
|
|
151
|
+
dynamic_cast<const faiss::IndexIVFScalarQuantizer *>(index)) {
|
|
152
|
+
GpuIndexIVFScalarQuantizerConfig config;
|
|
153
|
+
config.device = device;
|
|
154
|
+
config.indicesOptions = indicesOptions;
|
|
155
|
+
config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
|
|
156
|
+
config.flatConfig.storeTransposed = storeTransposed;
|
|
157
|
+
|
|
158
|
+
GpuIndexIVFScalarQuantizer *res =
|
|
159
|
+
new GpuIndexIVFScalarQuantizer(resources,
|
|
160
|
+
ifl->d,
|
|
161
|
+
ifl->nlist,
|
|
162
|
+
ifl->sq.qtype,
|
|
163
|
+
ifl->metric_type,
|
|
164
|
+
ifl->by_residual,
|
|
165
|
+
config);
|
|
166
|
+
if(reserveVecs > 0 && ifl->ntotal == 0) {
|
|
167
|
+
res->reserveMemory(reserveVecs);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
res->copyFrom(ifl);
|
|
171
|
+
return res;
|
|
172
|
+
} else if(auto ipq = dynamic_cast<const faiss::IndexIVFPQ *>(index)) {
|
|
173
|
+
if(verbose)
|
|
174
|
+
printf(" IndexIVFPQ size %ld -> GpuIndexIVFPQ "
|
|
175
|
+
"indicesOptions=%d "
|
|
176
|
+
"usePrecomputed=%d useFloat16=%d reserveVecs=%ld\n",
|
|
177
|
+
ipq->ntotal, indicesOptions, usePrecomputed,
|
|
178
|
+
useFloat16, reserveVecs);
|
|
179
|
+
GpuIndexIVFPQConfig config;
|
|
180
|
+
config.device = device;
|
|
181
|
+
config.indicesOptions = indicesOptions;
|
|
182
|
+
config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
|
|
183
|
+
config.flatConfig.storeTransposed = storeTransposed;
|
|
184
|
+
config.useFloat16LookupTables = useFloat16;
|
|
185
|
+
config.usePrecomputedTables = usePrecomputed;
|
|
186
|
+
|
|
187
|
+
GpuIndexIVFPQ *res = new GpuIndexIVFPQ(resources, ipq, config);
|
|
188
|
+
|
|
189
|
+
if(reserveVecs > 0 && ipq->ntotal == 0) {
|
|
190
|
+
res->reserveMemory(reserveVecs);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return res;
|
|
194
|
+
} else {
|
|
195
|
+
return Cloner::clone_Index(index);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
faiss::Index * index_cpu_to_gpu(
|
|
201
|
+
GpuResources* resources, int device,
|
|
202
|
+
const faiss::Index *index,
|
|
203
|
+
const GpuClonerOptions *options)
|
|
204
|
+
{
|
|
205
|
+
GpuClonerOptions defaults;
|
|
206
|
+
ToGpuCloner cl(resources, device, options ? *options : defaults);
|
|
207
|
+
return cl.clone_Index(index);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
/**********************************************************
|
|
212
|
+
* Cloning to multiple GPUs
|
|
213
|
+
**********************************************************/
|
|
214
|
+
|
|
215
|
+
ToGpuClonerMultiple::ToGpuClonerMultiple(
|
|
216
|
+
std::vector<GpuResources *> & resources,
|
|
217
|
+
std::vector<int>& devices,
|
|
218
|
+
const GpuMultipleClonerOptions &options):
|
|
219
|
+
GpuMultipleClonerOptions(options)
|
|
220
|
+
{
|
|
221
|
+
FAISS_ASSERT(resources.size() == devices.size());
|
|
222
|
+
for(int i = 0; i < resources.size(); i++) {
|
|
223
|
+
sub_cloners.push_back(ToGpuCloner(resources[i], devices[i], options));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
ToGpuClonerMultiple::ToGpuClonerMultiple(
|
|
229
|
+
const std::vector<ToGpuCloner> & sub_cloners,
|
|
230
|
+
const GpuMultipleClonerOptions &options):
|
|
231
|
+
GpuMultipleClonerOptions(options),
|
|
232
|
+
sub_cloners(sub_cloners)
|
|
233
|
+
{}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
void ToGpuClonerMultiple::copy_ivf_shard (
|
|
237
|
+
const IndexIVF *index_ivf, IndexIVF *idx2,
|
|
238
|
+
long n, long i)
|
|
239
|
+
{
|
|
240
|
+
if (shard_type == 2) {
|
|
241
|
+
long i0 = i * index_ivf->ntotal / n;
|
|
242
|
+
long i1 = (i + 1) * index_ivf->ntotal / n;
|
|
243
|
+
|
|
244
|
+
if(verbose)
|
|
245
|
+
printf("IndexShards shard %ld indices %ld:%ld\n",
|
|
246
|
+
i, i0, i1);
|
|
247
|
+
index_ivf->copy_subset_to(*idx2, 2, i0, i1);
|
|
248
|
+
FAISS_ASSERT(idx2->ntotal == i1 - i0);
|
|
249
|
+
} else if (shard_type == 1) {
|
|
250
|
+
if(verbose)
|
|
251
|
+
printf("IndexShards shard %ld select modulo %ld = %ld\n",
|
|
252
|
+
i, n, i);
|
|
253
|
+
index_ivf->copy_subset_to(*idx2, 1, n, i);
|
|
254
|
+
} else {
|
|
255
|
+
FAISS_THROW_FMT ("shard_type %d not implemented", shard_type);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
Index * ToGpuClonerMultiple::clone_Index_to_shards (const Index *index)
|
|
261
|
+
{
|
|
262
|
+
long n = sub_cloners.size();
|
|
263
|
+
|
|
264
|
+
auto index_ivfpq =
|
|
265
|
+
dynamic_cast<const faiss::IndexIVFPQ *>(index);
|
|
266
|
+
auto index_ivfflat =
|
|
267
|
+
dynamic_cast<const faiss::IndexIVFFlat *>(index);
|
|
268
|
+
auto index_ivfsq =
|
|
269
|
+
dynamic_cast<const faiss::IndexIVFScalarQuantizer *>(index);
|
|
270
|
+
auto index_flat =
|
|
271
|
+
dynamic_cast<const faiss::IndexFlat *>(index);
|
|
272
|
+
FAISS_THROW_IF_NOT_MSG (
|
|
273
|
+
index_ivfpq || index_ivfflat || index_flat || index_ivfsq,
|
|
274
|
+
"IndexShards implemented only for "
|
|
275
|
+
"IndexIVFFlat, IndexIVFScalarQuantizer, "
|
|
276
|
+
"IndexFlat and IndexIVFPQ");
|
|
277
|
+
|
|
278
|
+
std::vector<faiss::Index*> shards(n);
|
|
279
|
+
|
|
280
|
+
for(long i = 0; i < n; i++) {
|
|
281
|
+
// make a shallow copy
|
|
282
|
+
if(reserveVecs)
|
|
283
|
+
sub_cloners[i].reserveVecs =
|
|
284
|
+
(reserveVecs + n - 1) / n;
|
|
285
|
+
|
|
286
|
+
if (index_ivfpq) {
|
|
287
|
+
faiss::IndexIVFPQ idx2(
|
|
288
|
+
index_ivfpq->quantizer, index_ivfpq->d,
|
|
289
|
+
index_ivfpq->nlist, index_ivfpq->code_size,
|
|
290
|
+
index_ivfpq->pq.nbits);
|
|
291
|
+
idx2.metric_type = index_ivfpq->metric_type;
|
|
292
|
+
idx2.pq = index_ivfpq->pq;
|
|
293
|
+
idx2.nprobe = index_ivfpq->nprobe;
|
|
294
|
+
idx2.use_precomputed_table = 0;
|
|
295
|
+
idx2.is_trained = index->is_trained;
|
|
296
|
+
copy_ivf_shard (index_ivfpq, &idx2, n, i);
|
|
297
|
+
shards[i] = sub_cloners[i].clone_Index(&idx2);
|
|
298
|
+
} else if (index_ivfflat) {
|
|
299
|
+
faiss::IndexIVFFlat idx2(
|
|
300
|
+
index_ivfflat->quantizer, index->d,
|
|
301
|
+
index_ivfflat->nlist, index_ivfflat->metric_type);
|
|
302
|
+
idx2.nprobe = index_ivfflat->nprobe;
|
|
303
|
+
copy_ivf_shard (index_ivfflat, &idx2, n, i);
|
|
304
|
+
shards[i] = sub_cloners[i].clone_Index(&idx2);
|
|
305
|
+
} else if (index_ivfsq) {
|
|
306
|
+
faiss::IndexIVFScalarQuantizer idx2(
|
|
307
|
+
index_ivfsq->quantizer, index->d, index_ivfsq->nlist,
|
|
308
|
+
index_ivfsq->sq.qtype,
|
|
309
|
+
index_ivfsq->metric_type,
|
|
310
|
+
index_ivfsq->by_residual);
|
|
311
|
+
idx2.nprobe = index_ivfsq->nprobe;
|
|
312
|
+
copy_ivf_shard (index_ivfsq, &idx2, n, i);
|
|
313
|
+
shards[i] = sub_cloners[i].clone_Index(&idx2);
|
|
314
|
+
} else if (index_flat) {
|
|
315
|
+
faiss::IndexFlat idx2 (
|
|
316
|
+
index->d, index->metric_type);
|
|
317
|
+
shards[i] = sub_cloners[i].clone_Index(&idx2);
|
|
318
|
+
if (index->ntotal > 0) {
|
|
319
|
+
long i0 = index->ntotal * i / n;
|
|
320
|
+
long i1 = index->ntotal * (i + 1) / n;
|
|
321
|
+
shards[i]->add (i1 - i0,
|
|
322
|
+
index_flat->xb.data() + i0 * index->d);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
bool successive_ids = index_flat != nullptr;
|
|
328
|
+
faiss::IndexShards *res =
|
|
329
|
+
new faiss::IndexShards(index->d, true,
|
|
330
|
+
successive_ids);
|
|
331
|
+
|
|
332
|
+
for (int i = 0; i < n; i++) {
|
|
333
|
+
res->add_shard(shards[i]);
|
|
334
|
+
}
|
|
335
|
+
res->own_fields = true;
|
|
336
|
+
FAISS_ASSERT(index->ntotal == res->ntotal);
|
|
337
|
+
return res;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
Index *ToGpuClonerMultiple::clone_Index(const Index *index)
|
|
341
|
+
{
|
|
342
|
+
long n = sub_cloners.size();
|
|
343
|
+
if (n == 1)
|
|
344
|
+
return sub_cloners[0].clone_Index(index);
|
|
345
|
+
|
|
346
|
+
if(dynamic_cast<const IndexFlat *>(index) ||
|
|
347
|
+
dynamic_cast<const faiss::IndexIVFFlat *>(index) ||
|
|
348
|
+
dynamic_cast<const faiss::IndexIVFScalarQuantizer *>(index) ||
|
|
349
|
+
dynamic_cast<const faiss::IndexIVFPQ *>(index)) {
|
|
350
|
+
if(!shard) {
|
|
351
|
+
IndexReplicas * res = new IndexReplicas();
|
|
352
|
+
for(auto & sub_cloner: sub_cloners) {
|
|
353
|
+
res->addIndex(sub_cloner.clone_Index(index));
|
|
354
|
+
}
|
|
355
|
+
res->own_fields = true;
|
|
356
|
+
return res;
|
|
357
|
+
} else {
|
|
358
|
+
return clone_Index_to_shards (index);
|
|
359
|
+
}
|
|
360
|
+
} else if(auto miq = dynamic_cast<const MultiIndexQuantizer *>(index)) {
|
|
361
|
+
if (verbose) {
|
|
362
|
+
printf("cloning MultiIndexQuantizer: "
|
|
363
|
+
"will be valid only for search k=1\n");
|
|
364
|
+
}
|
|
365
|
+
const ProductQuantizer & pq = miq->pq;
|
|
366
|
+
IndexSplitVectors *splitv = new IndexSplitVectors(pq.d, true);
|
|
367
|
+
splitv->own_fields = true;
|
|
368
|
+
|
|
369
|
+
for (int m = 0; m < pq.M; m++) {
|
|
370
|
+
// which GPU(s) will be assigned to this sub-quantizer
|
|
371
|
+
|
|
372
|
+
long i0 = m * n / pq.M;
|
|
373
|
+
long i1 = pq.M <= n ? (m + 1) * n / pq.M : i0 + 1;
|
|
374
|
+
std::vector<ToGpuCloner> sub_cloners_2;
|
|
375
|
+
sub_cloners_2.insert(
|
|
376
|
+
sub_cloners_2.begin(), sub_cloners.begin() + i0,
|
|
377
|
+
sub_cloners.begin() + i1);
|
|
378
|
+
ToGpuClonerMultiple cm(sub_cloners_2, *this);
|
|
379
|
+
IndexFlatL2 idxc (pq.dsub);
|
|
380
|
+
idxc.add (pq.ksub, pq.centroids.data() + m * pq.d * pq.ksub);
|
|
381
|
+
Index *idx2 = cm.clone_Index(&idxc);
|
|
382
|
+
splitv->add_sub_index(idx2);
|
|
383
|
+
}
|
|
384
|
+
return splitv;
|
|
385
|
+
} else {
|
|
386
|
+
return Cloner::clone_Index(index);
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
faiss::Index * index_cpu_to_gpu_multiple(
|
|
393
|
+
std::vector<GpuResources*> & resources,
|
|
394
|
+
std::vector<int> &devices,
|
|
395
|
+
const faiss::Index *index,
|
|
396
|
+
const GpuMultipleClonerOptions *options)
|
|
397
|
+
{
|
|
398
|
+
GpuMultipleClonerOptions defaults;
|
|
399
|
+
ToGpuClonerMultiple cl(resources, devices, options ? *options : defaults);
|
|
400
|
+
return cl.clone_Index(index);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
} } // namespace
|