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
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
|