faiss 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +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
data/lib/faiss/kmeans.rb
CHANGED
data/lib/faiss/pca_matrix.rb
CHANGED
@@ -2,13 +2,13 @@ module Faiss
|
|
2
2
|
class PCAMatrix
|
3
3
|
def train(objects)
|
4
4
|
objects = Numo::SFloat.cast(objects) unless objects.is_a?(Numo::SFloat)
|
5
|
-
_train(objects.shape[0], objects
|
5
|
+
_train(objects.shape[0], objects)
|
6
6
|
end
|
7
7
|
|
8
8
|
def apply(objects)
|
9
9
|
objects = Numo::SFloat.cast(objects) unless objects.is_a?(Numo::SFloat)
|
10
10
|
n = objects.shape[0]
|
11
|
-
res = _apply(n, objects
|
11
|
+
res = _apply(n, objects)
|
12
12
|
Numo::SFloat.from_binary(res).reshape(n, d_out)
|
13
13
|
end
|
14
14
|
end
|
@@ -2,20 +2,20 @@ module Faiss
|
|
2
2
|
class ProductQuantizer
|
3
3
|
def train(objects)
|
4
4
|
objects = Numo::SFloat.cast(objects) unless objects.is_a?(Numo::SFloat)
|
5
|
-
_train(objects.shape[0], objects
|
5
|
+
_train(objects.shape[0], objects)
|
6
6
|
end
|
7
7
|
|
8
8
|
def compute_codes(objects)
|
9
9
|
objects = Numo::SFloat.cast(objects) unless objects.is_a?(Numo::SFloat)
|
10
10
|
n = objects.shape[0]
|
11
|
-
res = _compute_codes(n, objects
|
11
|
+
res = _compute_codes(n, objects)
|
12
12
|
Numo::UInt8.from_binary(res).reshape(n, m)
|
13
13
|
end
|
14
14
|
|
15
15
|
def decode(objects)
|
16
16
|
objects = Numo::UInt8.cast(objects) unless objects.is_a?(Numo::UInt8)
|
17
17
|
n = objects.shape[0]
|
18
|
-
res = _decode(n, objects
|
18
|
+
res = _decode(n, objects)
|
19
19
|
Numo::SFloat.from_binary(res).reshape(n, d)
|
20
20
|
end
|
21
21
|
end
|
data/lib/faiss/version.rb
CHANGED
@@ -0,0 +1,719 @@
|
|
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
|
+
// -*- c++ -*-
|
9
|
+
|
10
|
+
/*
|
11
|
+
* implementation of Hyper-parameter auto-tuning
|
12
|
+
*/
|
13
|
+
|
14
|
+
#include <faiss/AutoTune.h>
|
15
|
+
|
16
|
+
#include <cmath>
|
17
|
+
|
18
|
+
#include <faiss/impl/FaissAssert.h>
|
19
|
+
#include <faiss/utils/utils.h>
|
20
|
+
#include <faiss/utils/random.h>
|
21
|
+
|
22
|
+
#include <faiss/IndexFlat.h>
|
23
|
+
#include <faiss/VectorTransform.h>
|
24
|
+
#include <faiss/IndexPreTransform.h>
|
25
|
+
#include <faiss/IndexLSH.h>
|
26
|
+
#include <faiss/IndexPQ.h>
|
27
|
+
#include <faiss/IndexIVF.h>
|
28
|
+
#include <faiss/IndexIVFPQ.h>
|
29
|
+
#include <faiss/IndexIVFPQR.h>
|
30
|
+
#include <faiss/IndexIVFFlat.h>
|
31
|
+
#include <faiss/MetaIndexes.h>
|
32
|
+
#include <faiss/IndexScalarQuantizer.h>
|
33
|
+
#include <faiss/IndexHNSW.h>
|
34
|
+
|
35
|
+
#include <faiss/IndexBinaryFlat.h>
|
36
|
+
#include <faiss/IndexBinaryHNSW.h>
|
37
|
+
#include <faiss/IndexBinaryIVF.h>
|
38
|
+
|
39
|
+
namespace faiss {
|
40
|
+
|
41
|
+
|
42
|
+
AutoTuneCriterion::AutoTuneCriterion (idx_t nq, idx_t nnn):
|
43
|
+
nq (nq), nnn (nnn), gt_nnn (0)
|
44
|
+
{}
|
45
|
+
|
46
|
+
|
47
|
+
void AutoTuneCriterion::set_groundtruth (
|
48
|
+
int gt_nnn, const float *gt_D_in, const idx_t *gt_I_in)
|
49
|
+
{
|
50
|
+
this->gt_nnn = gt_nnn;
|
51
|
+
if (gt_D_in) { // allow null for this, as it is often not used
|
52
|
+
gt_D.resize (nq * gt_nnn);
|
53
|
+
memcpy (gt_D.data(), gt_D_in, sizeof (gt_D[0]) * nq * gt_nnn);
|
54
|
+
}
|
55
|
+
gt_I.resize (nq * gt_nnn);
|
56
|
+
memcpy (gt_I.data(), gt_I_in, sizeof (gt_I[0]) * nq * gt_nnn);
|
57
|
+
}
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
OneRecallAtRCriterion::OneRecallAtRCriterion (idx_t nq, idx_t R):
|
62
|
+
AutoTuneCriterion(nq, R), R(R)
|
63
|
+
{}
|
64
|
+
|
65
|
+
double OneRecallAtRCriterion::evaluate(const float* /*D*/, const idx_t* I)
|
66
|
+
const {
|
67
|
+
FAISS_THROW_IF_NOT_MSG(
|
68
|
+
(gt_I.size() == gt_nnn * nq && gt_nnn >= 1 && nnn >= R),
|
69
|
+
"ground truth not initialized");
|
70
|
+
idx_t n_ok = 0;
|
71
|
+
for (idx_t q = 0; q < nq; q++) {
|
72
|
+
idx_t gt_nn = gt_I[q * gt_nnn];
|
73
|
+
const idx_t* I_line = I + q * nnn;
|
74
|
+
for (int i = 0; i < R; i++) {
|
75
|
+
if (I_line[i] == gt_nn) {
|
76
|
+
n_ok++;
|
77
|
+
break;
|
78
|
+
}
|
79
|
+
}
|
80
|
+
}
|
81
|
+
return n_ok / double(nq);
|
82
|
+
}
|
83
|
+
|
84
|
+
|
85
|
+
IntersectionCriterion::IntersectionCriterion (idx_t nq, idx_t R):
|
86
|
+
AutoTuneCriterion(nq, R), R(R)
|
87
|
+
{}
|
88
|
+
|
89
|
+
double IntersectionCriterion::evaluate(const float* /*D*/, const idx_t* I)
|
90
|
+
const {
|
91
|
+
FAISS_THROW_IF_NOT_MSG(
|
92
|
+
(gt_I.size() == gt_nnn * nq && gt_nnn >= R && nnn >= R),
|
93
|
+
"ground truth not initialized");
|
94
|
+
int64_t n_ok = 0;
|
95
|
+
#pragma omp parallel for reduction(+: n_ok)
|
96
|
+
for (idx_t q = 0; q < nq; q++) {
|
97
|
+
n_ok += ranklist_intersection_size (
|
98
|
+
R, >_I [q * gt_nnn],
|
99
|
+
R, I + q * nnn);
|
100
|
+
}
|
101
|
+
return n_ok / double (nq * R);
|
102
|
+
}
|
103
|
+
|
104
|
+
/***************************************************************
|
105
|
+
* OperatingPoints
|
106
|
+
***************************************************************/
|
107
|
+
|
108
|
+
OperatingPoints::OperatingPoints ()
|
109
|
+
{
|
110
|
+
clear();
|
111
|
+
}
|
112
|
+
|
113
|
+
void OperatingPoints::clear ()
|
114
|
+
{
|
115
|
+
all_pts.clear();
|
116
|
+
optimal_pts.clear();
|
117
|
+
/// default point: doing nothing gives 0 performance and takes 0 time
|
118
|
+
OperatingPoint op = {0, 0, "", -1};
|
119
|
+
optimal_pts.push_back(op);
|
120
|
+
}
|
121
|
+
|
122
|
+
/// add a performance measure
|
123
|
+
bool OperatingPoints::add (double perf, double t, const std::string & key,
|
124
|
+
size_t cno)
|
125
|
+
{
|
126
|
+
OperatingPoint op = {perf, t, key, int64_t(cno)};
|
127
|
+
all_pts.push_back (op);
|
128
|
+
if (perf == 0) {
|
129
|
+
return false; // no method for 0 accuracy is faster than doing nothing
|
130
|
+
}
|
131
|
+
std::vector<OperatingPoint> & a = optimal_pts;
|
132
|
+
if (perf > a.back().perf) {
|
133
|
+
// keep unconditionally
|
134
|
+
a.push_back (op);
|
135
|
+
} else if (perf == a.back().perf) {
|
136
|
+
if (t < a.back ().t) {
|
137
|
+
a.back() = op;
|
138
|
+
} else {
|
139
|
+
return false;
|
140
|
+
}
|
141
|
+
} else {
|
142
|
+
int i;
|
143
|
+
// stricto sensu this should be a bissection
|
144
|
+
for (i = 0; i < a.size(); i++) {
|
145
|
+
if (a[i].perf >= perf) break;
|
146
|
+
}
|
147
|
+
assert (i < a.size());
|
148
|
+
if (t < a[i].t) {
|
149
|
+
if (a[i].perf == perf) {
|
150
|
+
a[i] = op;
|
151
|
+
} else {
|
152
|
+
a.insert (a.begin() + i, op);
|
153
|
+
}
|
154
|
+
} else {
|
155
|
+
return false;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
{ // remove non-optimal points from array
|
159
|
+
int i = a.size() - 1;
|
160
|
+
while (i > 0) {
|
161
|
+
if (a[i].t < a[i - 1].t)
|
162
|
+
a.erase (a.begin() + (i - 1));
|
163
|
+
i--;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
return true;
|
167
|
+
}
|
168
|
+
|
169
|
+
|
170
|
+
int OperatingPoints::merge_with (const OperatingPoints &other,
|
171
|
+
const std::string & prefix)
|
172
|
+
{
|
173
|
+
int n_add = 0;
|
174
|
+
for (int i = 0; i < other.all_pts.size(); i++) {
|
175
|
+
const OperatingPoint & op = other.all_pts[i];
|
176
|
+
if (add (op.perf, op.t, prefix + op.key, op.cno))
|
177
|
+
n_add++;
|
178
|
+
}
|
179
|
+
return n_add;
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
|
184
|
+
/// get time required to obtain a given performance measure
|
185
|
+
double OperatingPoints::t_for_perf (double perf) const
|
186
|
+
{
|
187
|
+
const std::vector<OperatingPoint> & a = optimal_pts;
|
188
|
+
if (perf > a.back().perf) return 1e50;
|
189
|
+
int i0 = -1, i1 = a.size() - 1;
|
190
|
+
while (i0 + 1 < i1) {
|
191
|
+
int imed = (i0 + i1 + 1) / 2;
|
192
|
+
if (a[imed].perf < perf) i0 = imed;
|
193
|
+
else i1 = imed;
|
194
|
+
}
|
195
|
+
return a[i1].t;
|
196
|
+
}
|
197
|
+
|
198
|
+
|
199
|
+
void OperatingPoints::all_to_gnuplot (const char *fname) const
|
200
|
+
{
|
201
|
+
FILE *f = fopen(fname, "w");
|
202
|
+
if (!f) {
|
203
|
+
fprintf (stderr, "cannot open %s", fname);
|
204
|
+
perror("");
|
205
|
+
abort();
|
206
|
+
}
|
207
|
+
for (int i = 0; i < all_pts.size(); i++) {
|
208
|
+
const OperatingPoint & op = all_pts[i];
|
209
|
+
fprintf (f, "%g %g %s\n", op.perf, op.t, op.key.c_str());
|
210
|
+
}
|
211
|
+
fclose(f);
|
212
|
+
}
|
213
|
+
|
214
|
+
void OperatingPoints::optimal_to_gnuplot (const char *fname) const
|
215
|
+
{
|
216
|
+
FILE *f = fopen(fname, "w");
|
217
|
+
if (!f) {
|
218
|
+
fprintf (stderr, "cannot open %s", fname);
|
219
|
+
perror("");
|
220
|
+
abort();
|
221
|
+
}
|
222
|
+
double prev_perf = 0.0;
|
223
|
+
for (int i = 0; i < optimal_pts.size(); i++) {
|
224
|
+
const OperatingPoint & op = optimal_pts[i];
|
225
|
+
fprintf (f, "%g %g\n", prev_perf, op.t);
|
226
|
+
fprintf (f, "%g %g %s\n", op.perf, op.t, op.key.c_str());
|
227
|
+
prev_perf = op.perf;
|
228
|
+
}
|
229
|
+
fclose(f);
|
230
|
+
}
|
231
|
+
|
232
|
+
void OperatingPoints::display (bool only_optimal) const
|
233
|
+
{
|
234
|
+
const std::vector<OperatingPoint> &pts =
|
235
|
+
only_optimal ? optimal_pts : all_pts;
|
236
|
+
printf("Tested %ld operating points, %ld ones are optimal:\n",
|
237
|
+
all_pts.size(), optimal_pts.size());
|
238
|
+
|
239
|
+
for (int i = 0; i < pts.size(); i++) {
|
240
|
+
const OperatingPoint & op = pts[i];
|
241
|
+
const char *star = "";
|
242
|
+
if (!only_optimal) {
|
243
|
+
for (int j = 0; j < optimal_pts.size(); j++) {
|
244
|
+
if (op.cno == optimal_pts[j].cno) {
|
245
|
+
star = "*";
|
246
|
+
break;
|
247
|
+
}
|
248
|
+
}
|
249
|
+
}
|
250
|
+
printf ("cno=%ld key=%s perf=%.4f t=%.3f %s\n",
|
251
|
+
op.cno, op.key.c_str(), op.perf, op.t, star);
|
252
|
+
}
|
253
|
+
|
254
|
+
}
|
255
|
+
|
256
|
+
/***************************************************************
|
257
|
+
* ParameterSpace
|
258
|
+
***************************************************************/
|
259
|
+
|
260
|
+
ParameterSpace::ParameterSpace ():
|
261
|
+
verbose (1), n_experiments (500),
|
262
|
+
batchsize (1<<30), thread_over_batches (false),
|
263
|
+
min_test_duration (0)
|
264
|
+
{
|
265
|
+
}
|
266
|
+
|
267
|
+
/* not keeping this constructor as inheritors will call the parent
|
268
|
+
initialize()
|
269
|
+
*/
|
270
|
+
|
271
|
+
#if 0
|
272
|
+
ParameterSpace::ParameterSpace (Index *index):
|
273
|
+
verbose (1), n_experiments (500),
|
274
|
+
batchsize (1<<30), thread_over_batches (false)
|
275
|
+
|
276
|
+
{
|
277
|
+
initialize(index);
|
278
|
+
}
|
279
|
+
#endif
|
280
|
+
|
281
|
+
size_t ParameterSpace::n_combinations () const
|
282
|
+
{
|
283
|
+
size_t n = 1;
|
284
|
+
for (int i = 0; i < parameter_ranges.size(); i++)
|
285
|
+
n *= parameter_ranges[i].values.size();
|
286
|
+
return n;
|
287
|
+
}
|
288
|
+
|
289
|
+
/// get string representation of the combination
|
290
|
+
std::string ParameterSpace::combination_name (size_t cno) const {
|
291
|
+
char buf[1000], *wp = buf;
|
292
|
+
*wp = 0;
|
293
|
+
for (int i = 0; i < parameter_ranges.size(); i++) {
|
294
|
+
const ParameterRange & pr = parameter_ranges[i];
|
295
|
+
size_t j = cno % pr.values.size();
|
296
|
+
cno /= pr.values.size();
|
297
|
+
wp += snprintf (
|
298
|
+
wp, buf + 1000 - wp, "%s%s=%g", i == 0 ? "" : ",",
|
299
|
+
pr.name.c_str(), pr.values[j]);
|
300
|
+
}
|
301
|
+
return std::string (buf);
|
302
|
+
}
|
303
|
+
|
304
|
+
|
305
|
+
bool ParameterSpace::combination_ge (size_t c1, size_t c2) const
|
306
|
+
{
|
307
|
+
for (int i = 0; i < parameter_ranges.size(); i++) {
|
308
|
+
int nval = parameter_ranges[i].values.size();
|
309
|
+
size_t j1 = c1 % nval;
|
310
|
+
size_t j2 = c2 % nval;
|
311
|
+
if (!(j1 >= j2)) return false;
|
312
|
+
c1 /= nval;
|
313
|
+
c2 /= nval;
|
314
|
+
}
|
315
|
+
return true;
|
316
|
+
}
|
317
|
+
|
318
|
+
|
319
|
+
|
320
|
+
#define DC(classname) \
|
321
|
+
const classname *ix = dynamic_cast<const classname *>(index)
|
322
|
+
|
323
|
+
static void init_pq_ParameterRange (const ProductQuantizer & pq,
|
324
|
+
ParameterRange & pr)
|
325
|
+
{
|
326
|
+
if (pq.code_size % 4 == 0) {
|
327
|
+
// Polysemous not supported for code sizes that are not a
|
328
|
+
// multiple of 4
|
329
|
+
for (int i = 2; i <= pq.code_size * 8 / 2; i+= 2)
|
330
|
+
pr.values.push_back(i);
|
331
|
+
}
|
332
|
+
pr.values.push_back (pq.code_size * 8);
|
333
|
+
}
|
334
|
+
|
335
|
+
ParameterRange &ParameterSpace::add_range(const char * name)
|
336
|
+
{
|
337
|
+
for (auto & pr : parameter_ranges) {
|
338
|
+
if (pr.name == name) {
|
339
|
+
return pr;
|
340
|
+
}
|
341
|
+
}
|
342
|
+
parameter_ranges.push_back (ParameterRange ());
|
343
|
+
parameter_ranges.back ().name = name;
|
344
|
+
return parameter_ranges.back ();
|
345
|
+
}
|
346
|
+
|
347
|
+
|
348
|
+
/// initialize with reasonable parameters for the index
|
349
|
+
void ParameterSpace::initialize (const Index * index)
|
350
|
+
{
|
351
|
+
if (DC (IndexPreTransform)) {
|
352
|
+
index = ix->index;
|
353
|
+
}
|
354
|
+
if (DC (IndexRefineFlat)) {
|
355
|
+
ParameterRange & pr = add_range("k_factor_rf");
|
356
|
+
for (int i = 0; i <= 6; i++) {
|
357
|
+
pr.values.push_back (1 << i);
|
358
|
+
}
|
359
|
+
index = ix->base_index;
|
360
|
+
}
|
361
|
+
if (DC (IndexPreTransform)) {
|
362
|
+
index = ix->index;
|
363
|
+
}
|
364
|
+
|
365
|
+
if (DC (IndexIVF)) {
|
366
|
+
{
|
367
|
+
ParameterRange & pr = add_range("nprobe");
|
368
|
+
for (int i = 0; i < 13; i++) {
|
369
|
+
size_t nprobe = 1 << i;
|
370
|
+
if (nprobe >= ix->nlist) break;
|
371
|
+
pr.values.push_back (nprobe);
|
372
|
+
}
|
373
|
+
}
|
374
|
+
if (dynamic_cast<const IndexHNSW*>(ix->quantizer)) {
|
375
|
+
ParameterRange & pr = add_range("efSearch");
|
376
|
+
for (int i = 2; i <= 9; i++) {
|
377
|
+
pr.values.push_back (1 << i);
|
378
|
+
}
|
379
|
+
}
|
380
|
+
}
|
381
|
+
if (DC (IndexPQ)) {
|
382
|
+
ParameterRange & pr = add_range("ht");
|
383
|
+
init_pq_ParameterRange (ix->pq, pr);
|
384
|
+
}
|
385
|
+
if (DC (IndexIVFPQ)) {
|
386
|
+
ParameterRange & pr = add_range("ht");
|
387
|
+
init_pq_ParameterRange (ix->pq, pr);
|
388
|
+
}
|
389
|
+
|
390
|
+
if (DC (IndexIVF)) {
|
391
|
+
const MultiIndexQuantizer *miq =
|
392
|
+
dynamic_cast<const MultiIndexQuantizer *> (ix->quantizer);
|
393
|
+
if (miq) {
|
394
|
+
ParameterRange & pr_max_codes = add_range("max_codes");
|
395
|
+
for (int i = 8; i < 20; i++) {
|
396
|
+
pr_max_codes.values.push_back (1 << i);
|
397
|
+
}
|
398
|
+
pr_max_codes.values.push_back (
|
399
|
+
std::numeric_limits<double>::infinity()
|
400
|
+
);
|
401
|
+
}
|
402
|
+
}
|
403
|
+
if (DC (IndexIVFPQR)) {
|
404
|
+
ParameterRange & pr = add_range("k_factor");
|
405
|
+
for (int i = 0; i <= 6; i++) {
|
406
|
+
pr.values.push_back (1 << i);
|
407
|
+
}
|
408
|
+
}
|
409
|
+
if (dynamic_cast<const IndexHNSW*>(index)) {
|
410
|
+
ParameterRange & pr = add_range("efSearch");
|
411
|
+
for (int i = 2; i <= 9; i++) {
|
412
|
+
pr.values.push_back (1 << i);
|
413
|
+
}
|
414
|
+
}
|
415
|
+
}
|
416
|
+
|
417
|
+
#undef DC
|
418
|
+
|
419
|
+
// non-const version
|
420
|
+
#define DC(classname) classname *ix = dynamic_cast<classname *>(index)
|
421
|
+
|
422
|
+
|
423
|
+
/// set a combination of parameters on an index
|
424
|
+
void ParameterSpace::set_index_parameters (Index *index, size_t cno) const
|
425
|
+
{
|
426
|
+
|
427
|
+
for (int i = 0; i < parameter_ranges.size(); i++) {
|
428
|
+
const ParameterRange & pr = parameter_ranges[i];
|
429
|
+
size_t j = cno % pr.values.size();
|
430
|
+
cno /= pr.values.size();
|
431
|
+
double val = pr.values [j];
|
432
|
+
set_index_parameter (index, pr.name, val);
|
433
|
+
}
|
434
|
+
}
|
435
|
+
|
436
|
+
/// set a combination of parameters on an index
|
437
|
+
void ParameterSpace::set_index_parameters (
|
438
|
+
Index *index, const char *description_in) const
|
439
|
+
{
|
440
|
+
char description[strlen(description_in) + 1];
|
441
|
+
char *ptr;
|
442
|
+
memcpy (description, description_in, strlen(description_in) + 1);
|
443
|
+
|
444
|
+
for (char *tok = strtok_r (description, " ,", &ptr);
|
445
|
+
tok;
|
446
|
+
tok = strtok_r (nullptr, " ,", &ptr)) {
|
447
|
+
char name[100];
|
448
|
+
double val;
|
449
|
+
int ret = sscanf (tok, "%100[^=]=%lf", name, &val);
|
450
|
+
FAISS_THROW_IF_NOT_FMT (
|
451
|
+
ret == 2, "could not interpret parameters %s", tok);
|
452
|
+
set_index_parameter (index, name, val);
|
453
|
+
}
|
454
|
+
|
455
|
+
}
|
456
|
+
|
457
|
+
void ParameterSpace::set_index_parameter (
|
458
|
+
Index * index, const std::string & name, double val) const
|
459
|
+
{
|
460
|
+
if (verbose > 1)
|
461
|
+
printf(" set %s=%g\n", name.c_str(), val);
|
462
|
+
|
463
|
+
if (name == "verbose") {
|
464
|
+
index->verbose = int(val);
|
465
|
+
// and fall through to also enable it on sub-indexes
|
466
|
+
}
|
467
|
+
if (DC (IndexPreTransform)) {
|
468
|
+
set_index_parameter (ix->index, name, val);
|
469
|
+
return;
|
470
|
+
}
|
471
|
+
if (DC (IndexShards)) {
|
472
|
+
// call on all sub-indexes
|
473
|
+
auto fn =
|
474
|
+
[this, name, val](int, Index* subIndex) {
|
475
|
+
set_index_parameter(subIndex, name, val);
|
476
|
+
};
|
477
|
+
|
478
|
+
ix->runOnIndex(fn);
|
479
|
+
return;
|
480
|
+
}
|
481
|
+
if (DC (IndexReplicas)) {
|
482
|
+
// call on all sub-indexes
|
483
|
+
auto fn =
|
484
|
+
[this, name, val](int, Index* subIndex) {
|
485
|
+
set_index_parameter(subIndex, name, val);
|
486
|
+
};
|
487
|
+
|
488
|
+
ix->runOnIndex(fn);
|
489
|
+
return;
|
490
|
+
}
|
491
|
+
if (DC (IndexRefineFlat)) {
|
492
|
+
if (name == "k_factor_rf") {
|
493
|
+
ix->k_factor = int(val);
|
494
|
+
return;
|
495
|
+
}
|
496
|
+
// otherwise it is for the sub-index
|
497
|
+
set_index_parameter (&ix->refine_index, name, val);
|
498
|
+
return;
|
499
|
+
}
|
500
|
+
|
501
|
+
if (name == "verbose") {
|
502
|
+
index->verbose = int(val);
|
503
|
+
return; // last verbose that we could find
|
504
|
+
}
|
505
|
+
|
506
|
+
if (name == "nprobe") {
|
507
|
+
if (DC (IndexIDMap)) {
|
508
|
+
set_index_parameter (ix->index, name, val);
|
509
|
+
return;
|
510
|
+
} else if (DC (IndexIVF)) {
|
511
|
+
ix->nprobe = int(val);
|
512
|
+
return;
|
513
|
+
}
|
514
|
+
}
|
515
|
+
|
516
|
+
if (name == "ht") {
|
517
|
+
if (DC (IndexPQ)) {
|
518
|
+
if (val >= ix->pq.code_size * 8) {
|
519
|
+
ix->search_type = IndexPQ::ST_PQ;
|
520
|
+
} else {
|
521
|
+
ix->search_type = IndexPQ::ST_polysemous;
|
522
|
+
ix->polysemous_ht = int(val);
|
523
|
+
}
|
524
|
+
return;
|
525
|
+
} else if (DC (IndexIVFPQ)) {
|
526
|
+
if (val >= ix->pq.code_size * 8) {
|
527
|
+
ix->polysemous_ht = 0;
|
528
|
+
} else {
|
529
|
+
ix->polysemous_ht = int(val);
|
530
|
+
}
|
531
|
+
return;
|
532
|
+
}
|
533
|
+
}
|
534
|
+
|
535
|
+
if (name == "k_factor") {
|
536
|
+
if (DC (IndexIVFPQR)) {
|
537
|
+
ix->k_factor = val;
|
538
|
+
return;
|
539
|
+
}
|
540
|
+
}
|
541
|
+
if (name == "max_codes") {
|
542
|
+
if (DC (IndexIVF)) {
|
543
|
+
ix->max_codes = std::isfinite(val) ? size_t(val) : 0;
|
544
|
+
return;
|
545
|
+
}
|
546
|
+
}
|
547
|
+
|
548
|
+
if (name == "efSearch") {
|
549
|
+
if (DC (IndexHNSW)) {
|
550
|
+
ix->hnsw.efSearch = int(val);
|
551
|
+
return;
|
552
|
+
}
|
553
|
+
if (DC (IndexIVF)) {
|
554
|
+
if (IndexHNSW *cq =
|
555
|
+
dynamic_cast<IndexHNSW *>(ix->quantizer)) {
|
556
|
+
cq->hnsw.efSearch = int(val);
|
557
|
+
return;
|
558
|
+
}
|
559
|
+
}
|
560
|
+
}
|
561
|
+
|
562
|
+
FAISS_THROW_FMT ("ParameterSpace::set_index_parameter:"
|
563
|
+
"could not set parameter %s",
|
564
|
+
name.c_str());
|
565
|
+
}
|
566
|
+
|
567
|
+
void ParameterSpace::display () const
|
568
|
+
{
|
569
|
+
printf ("ParameterSpace, %ld parameters, %ld combinations:\n",
|
570
|
+
parameter_ranges.size (), n_combinations ());
|
571
|
+
for (int i = 0; i < parameter_ranges.size(); i++) {
|
572
|
+
const ParameterRange & pr = parameter_ranges[i];
|
573
|
+
printf (" %s: ", pr.name.c_str ());
|
574
|
+
char sep = '[';
|
575
|
+
for (int j = 0; j < pr.values.size(); j++) {
|
576
|
+
printf ("%c %g", sep, pr.values [j]);
|
577
|
+
sep = ',';
|
578
|
+
}
|
579
|
+
printf ("]\n");
|
580
|
+
}
|
581
|
+
}
|
582
|
+
|
583
|
+
|
584
|
+
|
585
|
+
void ParameterSpace::update_bounds (size_t cno, const OperatingPoint & op,
|
586
|
+
double *upper_bound_perf,
|
587
|
+
double *lower_bound_t) const
|
588
|
+
{
|
589
|
+
if (combination_ge (cno, op.cno)) {
|
590
|
+
if (op.t > *lower_bound_t) *lower_bound_t = op.t;
|
591
|
+
}
|
592
|
+
if (combination_ge (op.cno, cno)) {
|
593
|
+
if (op.perf < *upper_bound_perf) *upper_bound_perf = op.perf;
|
594
|
+
}
|
595
|
+
}
|
596
|
+
|
597
|
+
|
598
|
+
|
599
|
+
void ParameterSpace::explore (Index *index,
|
600
|
+
size_t nq, const float *xq,
|
601
|
+
const AutoTuneCriterion & crit,
|
602
|
+
OperatingPoints * ops) const
|
603
|
+
{
|
604
|
+
FAISS_THROW_IF_NOT_MSG (nq == crit.nq,
|
605
|
+
"criterion does not have the same nb of queries");
|
606
|
+
|
607
|
+
size_t n_comb = n_combinations ();
|
608
|
+
|
609
|
+
if (n_experiments == 0) {
|
610
|
+
|
611
|
+
for (size_t cno = 0; cno < n_comb; cno++) {
|
612
|
+
set_index_parameters (index, cno);
|
613
|
+
std::vector<Index::idx_t> I(nq * crit.nnn);
|
614
|
+
std::vector<float> D(nq * crit.nnn);
|
615
|
+
|
616
|
+
double t0 = getmillisecs ();
|
617
|
+
index->search (nq, xq, crit.nnn, D.data(), I.data());
|
618
|
+
double t_search = (getmillisecs() - t0) / 1e3;
|
619
|
+
|
620
|
+
double perf = crit.evaluate (D.data(), I.data());
|
621
|
+
|
622
|
+
bool keep = ops->add (perf, t_search, combination_name (cno), cno);
|
623
|
+
|
624
|
+
if (verbose)
|
625
|
+
printf(" %ld/%ld: %s perf=%.3f t=%.3f s %s\n", cno, n_comb,
|
626
|
+
combination_name (cno).c_str(), perf, t_search,
|
627
|
+
keep ? "*" : "");
|
628
|
+
}
|
629
|
+
return;
|
630
|
+
}
|
631
|
+
|
632
|
+
int n_exp = n_experiments;
|
633
|
+
|
634
|
+
if (n_exp > n_comb) n_exp = n_comb;
|
635
|
+
FAISS_THROW_IF_NOT (n_comb == 1 || n_exp > 2);
|
636
|
+
std::vector<int> perm (n_comb);
|
637
|
+
// make sure the slowest and fastest experiment are run
|
638
|
+
perm[0] = 0;
|
639
|
+
if (n_comb > 1) {
|
640
|
+
perm[1] = n_comb - 1;
|
641
|
+
rand_perm (&perm[2], n_comb - 2, 1234);
|
642
|
+
for (int i = 2; i < perm.size(); i++) perm[i] ++;
|
643
|
+
}
|
644
|
+
|
645
|
+
for (size_t xp = 0; xp < n_exp; xp++) {
|
646
|
+
size_t cno = perm[xp];
|
647
|
+
|
648
|
+
if (verbose)
|
649
|
+
printf(" %ld/%d: cno=%ld %s ", xp, n_exp, cno,
|
650
|
+
combination_name (cno).c_str());
|
651
|
+
|
652
|
+
{
|
653
|
+
double lower_bound_t = 0.0;
|
654
|
+
double upper_bound_perf = 1.0;
|
655
|
+
for (int i = 0; i < ops->all_pts.size(); i++) {
|
656
|
+
update_bounds (cno, ops->all_pts[i],
|
657
|
+
&upper_bound_perf, &lower_bound_t);
|
658
|
+
}
|
659
|
+
double best_t = ops->t_for_perf (upper_bound_perf);
|
660
|
+
if (verbose)
|
661
|
+
printf ("bounds [perf<=%.3f t>=%.3f] %s",
|
662
|
+
upper_bound_perf, lower_bound_t,
|
663
|
+
best_t <= lower_bound_t ? "skip\n" : "");
|
664
|
+
if (best_t <= lower_bound_t) continue;
|
665
|
+
}
|
666
|
+
|
667
|
+
set_index_parameters (index, cno);
|
668
|
+
std::vector<Index::idx_t> I(nq * crit.nnn);
|
669
|
+
std::vector<float> D(nq * crit.nnn);
|
670
|
+
|
671
|
+
double t0 = getmillisecs ();
|
672
|
+
|
673
|
+
int nrun = 0;
|
674
|
+
double t_search;
|
675
|
+
|
676
|
+
do {
|
677
|
+
|
678
|
+
if (thread_over_batches) {
|
679
|
+
#pragma omp parallel for
|
680
|
+
for (size_t q0 = 0; q0 < nq; q0 += batchsize) {
|
681
|
+
size_t q1 = q0 + batchsize;
|
682
|
+
if (q1 > nq) q1 = nq;
|
683
|
+
index->search (q1 - q0, xq + q0 * index->d,
|
684
|
+
crit.nnn,
|
685
|
+
D.data() + q0 * crit.nnn,
|
686
|
+
I.data() + q0 * crit.nnn);
|
687
|
+
}
|
688
|
+
} else {
|
689
|
+
for (size_t q0 = 0; q0 < nq; q0 += batchsize) {
|
690
|
+
size_t q1 = q0 + batchsize;
|
691
|
+
if (q1 > nq) q1 = nq;
|
692
|
+
index->search (q1 - q0, xq + q0 * index->d,
|
693
|
+
crit.nnn,
|
694
|
+
D.data() + q0 * crit.nnn,
|
695
|
+
I.data() + q0 * crit.nnn);
|
696
|
+
}
|
697
|
+
}
|
698
|
+
nrun ++;
|
699
|
+
t_search = (getmillisecs() - t0) / 1e3;
|
700
|
+
|
701
|
+
} while (t_search < min_test_duration);
|
702
|
+
|
703
|
+
t_search /= nrun;
|
704
|
+
|
705
|
+
double perf = crit.evaluate (D.data(), I.data());
|
706
|
+
|
707
|
+
bool keep = ops->add (perf, t_search, combination_name (cno), cno);
|
708
|
+
|
709
|
+
if (verbose)
|
710
|
+
printf(" perf %.3f t %.3f (%d runs) %s\n",
|
711
|
+
perf, t_search, nrun,
|
712
|
+
keep ? "*" : "");
|
713
|
+
}
|
714
|
+
}
|
715
|
+
|
716
|
+
|
717
|
+
|
718
|
+
|
719
|
+
} // namespace faiss
|