faiss 0.1.0 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (226) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +103 -3
  4. data/ext/faiss/ext.cpp +99 -32
  5. data/ext/faiss/extconf.rb +12 -2
  6. data/lib/faiss/ext.bundle +0 -0
  7. data/lib/faiss/index.rb +3 -3
  8. data/lib/faiss/index_binary.rb +3 -3
  9. data/lib/faiss/kmeans.rb +1 -1
  10. data/lib/faiss/pca_matrix.rb +2 -2
  11. data/lib/faiss/product_quantizer.rb +3 -3
  12. data/lib/faiss/version.rb +1 -1
  13. data/vendor/faiss/AutoTune.cpp +719 -0
  14. data/vendor/faiss/AutoTune.h +212 -0
  15. data/vendor/faiss/Clustering.cpp +261 -0
  16. data/vendor/faiss/Clustering.h +101 -0
  17. data/vendor/faiss/IVFlib.cpp +339 -0
  18. data/vendor/faiss/IVFlib.h +132 -0
  19. data/vendor/faiss/Index.cpp +171 -0
  20. data/vendor/faiss/Index.h +261 -0
  21. data/vendor/faiss/Index2Layer.cpp +437 -0
  22. data/vendor/faiss/Index2Layer.h +85 -0
  23. data/vendor/faiss/IndexBinary.cpp +77 -0
  24. data/vendor/faiss/IndexBinary.h +163 -0
  25. data/vendor/faiss/IndexBinaryFlat.cpp +83 -0
  26. data/vendor/faiss/IndexBinaryFlat.h +54 -0
  27. data/vendor/faiss/IndexBinaryFromFloat.cpp +78 -0
  28. data/vendor/faiss/IndexBinaryFromFloat.h +52 -0
  29. data/vendor/faiss/IndexBinaryHNSW.cpp +325 -0
  30. data/vendor/faiss/IndexBinaryHNSW.h +56 -0
  31. data/vendor/faiss/IndexBinaryIVF.cpp +671 -0
  32. data/vendor/faiss/IndexBinaryIVF.h +211 -0
  33. data/vendor/faiss/IndexFlat.cpp +508 -0
  34. data/vendor/faiss/IndexFlat.h +175 -0
  35. data/vendor/faiss/IndexHNSW.cpp +1090 -0
  36. data/vendor/faiss/IndexHNSW.h +170 -0
  37. data/vendor/faiss/IndexIVF.cpp +909 -0
  38. data/vendor/faiss/IndexIVF.h +353 -0
  39. data/vendor/faiss/IndexIVFFlat.cpp +502 -0
  40. data/vendor/faiss/IndexIVFFlat.h +118 -0
  41. data/vendor/faiss/IndexIVFPQ.cpp +1207 -0
  42. data/vendor/faiss/IndexIVFPQ.h +161 -0
  43. data/vendor/faiss/IndexIVFPQR.cpp +219 -0
  44. data/vendor/faiss/IndexIVFPQR.h +65 -0
  45. data/vendor/faiss/IndexIVFSpectralHash.cpp +331 -0
  46. data/vendor/faiss/IndexIVFSpectralHash.h +75 -0
  47. data/vendor/faiss/IndexLSH.cpp +225 -0
  48. data/vendor/faiss/IndexLSH.h +87 -0
  49. data/vendor/faiss/IndexLattice.cpp +143 -0
  50. data/vendor/faiss/IndexLattice.h +68 -0
  51. data/vendor/faiss/IndexPQ.cpp +1188 -0
  52. data/vendor/faiss/IndexPQ.h +199 -0
  53. data/vendor/faiss/IndexPreTransform.cpp +288 -0
  54. data/vendor/faiss/IndexPreTransform.h +91 -0
  55. data/vendor/faiss/IndexReplicas.cpp +123 -0
  56. data/vendor/faiss/IndexReplicas.h +76 -0
  57. data/vendor/faiss/IndexScalarQuantizer.cpp +317 -0
  58. data/vendor/faiss/IndexScalarQuantizer.h +127 -0
  59. data/vendor/faiss/IndexShards.cpp +317 -0
  60. data/vendor/faiss/IndexShards.h +100 -0
  61. data/vendor/faiss/InvertedLists.cpp +623 -0
  62. data/vendor/faiss/InvertedLists.h +334 -0
  63. data/vendor/faiss/LICENSE +21 -0
  64. data/vendor/faiss/MatrixStats.cpp +252 -0
  65. data/vendor/faiss/MatrixStats.h +62 -0
  66. data/vendor/faiss/MetaIndexes.cpp +351 -0
  67. data/vendor/faiss/MetaIndexes.h +126 -0
  68. data/vendor/faiss/OnDiskInvertedLists.cpp +674 -0
  69. data/vendor/faiss/OnDiskInvertedLists.h +127 -0
  70. data/vendor/faiss/VectorTransform.cpp +1157 -0
  71. data/vendor/faiss/VectorTransform.h +322 -0
  72. data/vendor/faiss/c_api/AutoTune_c.cpp +83 -0
  73. data/vendor/faiss/c_api/AutoTune_c.h +64 -0
  74. data/vendor/faiss/c_api/Clustering_c.cpp +139 -0
  75. data/vendor/faiss/c_api/Clustering_c.h +117 -0
  76. data/vendor/faiss/c_api/IndexFlat_c.cpp +140 -0
  77. data/vendor/faiss/c_api/IndexFlat_c.h +115 -0
  78. data/vendor/faiss/c_api/IndexIVFFlat_c.cpp +64 -0
  79. data/vendor/faiss/c_api/IndexIVFFlat_c.h +58 -0
  80. data/vendor/faiss/c_api/IndexIVF_c.cpp +92 -0
  81. data/vendor/faiss/c_api/IndexIVF_c.h +135 -0
  82. data/vendor/faiss/c_api/IndexLSH_c.cpp +37 -0
  83. data/vendor/faiss/c_api/IndexLSH_c.h +40 -0
  84. data/vendor/faiss/c_api/IndexShards_c.cpp +44 -0
  85. data/vendor/faiss/c_api/IndexShards_c.h +42 -0
  86. data/vendor/faiss/c_api/Index_c.cpp +105 -0
  87. data/vendor/faiss/c_api/Index_c.h +183 -0
  88. data/vendor/faiss/c_api/MetaIndexes_c.cpp +49 -0
  89. data/vendor/faiss/c_api/MetaIndexes_c.h +49 -0
  90. data/vendor/faiss/c_api/clone_index_c.cpp +23 -0
  91. data/vendor/faiss/c_api/clone_index_c.h +32 -0
  92. data/vendor/faiss/c_api/error_c.h +42 -0
  93. data/vendor/faiss/c_api/error_impl.cpp +27 -0
  94. data/vendor/faiss/c_api/error_impl.h +16 -0
  95. data/vendor/faiss/c_api/faiss_c.h +58 -0
  96. data/vendor/faiss/c_api/gpu/GpuAutoTune_c.cpp +96 -0
  97. data/vendor/faiss/c_api/gpu/GpuAutoTune_c.h +56 -0
  98. data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.cpp +52 -0
  99. data/vendor/faiss/c_api/gpu/GpuClonerOptions_c.h +68 -0
  100. data/vendor/faiss/c_api/gpu/GpuIndex_c.cpp +17 -0
  101. data/vendor/faiss/c_api/gpu/GpuIndex_c.h +30 -0
  102. data/vendor/faiss/c_api/gpu/GpuIndicesOptions_c.h +38 -0
  103. data/vendor/faiss/c_api/gpu/GpuResources_c.cpp +86 -0
  104. data/vendor/faiss/c_api/gpu/GpuResources_c.h +66 -0
  105. data/vendor/faiss/c_api/gpu/StandardGpuResources_c.cpp +54 -0
  106. data/vendor/faiss/c_api/gpu/StandardGpuResources_c.h +53 -0
  107. data/vendor/faiss/c_api/gpu/macros_impl.h +42 -0
  108. data/vendor/faiss/c_api/impl/AuxIndexStructures_c.cpp +220 -0
  109. data/vendor/faiss/c_api/impl/AuxIndexStructures_c.h +149 -0
  110. data/vendor/faiss/c_api/index_factory_c.cpp +26 -0
  111. data/vendor/faiss/c_api/index_factory_c.h +30 -0
  112. data/vendor/faiss/c_api/index_io_c.cpp +42 -0
  113. data/vendor/faiss/c_api/index_io_c.h +50 -0
  114. data/vendor/faiss/c_api/macros_impl.h +110 -0
  115. data/vendor/faiss/clone_index.cpp +147 -0
  116. data/vendor/faiss/clone_index.h +38 -0
  117. data/vendor/faiss/demos/demo_imi_flat.cpp +151 -0
  118. data/vendor/faiss/demos/demo_imi_pq.cpp +199 -0
  119. data/vendor/faiss/demos/demo_ivfpq_indexing.cpp +146 -0
  120. data/vendor/faiss/demos/demo_sift1M.cpp +252 -0
  121. data/vendor/faiss/gpu/GpuAutoTune.cpp +95 -0
  122. data/vendor/faiss/gpu/GpuAutoTune.h +27 -0
  123. data/vendor/faiss/gpu/GpuCloner.cpp +403 -0
  124. data/vendor/faiss/gpu/GpuCloner.h +82 -0
  125. data/vendor/faiss/gpu/GpuClonerOptions.cpp +28 -0
  126. data/vendor/faiss/gpu/GpuClonerOptions.h +53 -0
  127. data/vendor/faiss/gpu/GpuDistance.h +52 -0
  128. data/vendor/faiss/gpu/GpuFaissAssert.h +29 -0
  129. data/vendor/faiss/gpu/GpuIndex.h +148 -0
  130. data/vendor/faiss/gpu/GpuIndexBinaryFlat.h +89 -0
  131. data/vendor/faiss/gpu/GpuIndexFlat.h +190 -0
  132. data/vendor/faiss/gpu/GpuIndexIVF.h +89 -0
  133. data/vendor/faiss/gpu/GpuIndexIVFFlat.h +85 -0
  134. data/vendor/faiss/gpu/GpuIndexIVFPQ.h +143 -0
  135. data/vendor/faiss/gpu/GpuIndexIVFScalarQuantizer.h +100 -0
  136. data/vendor/faiss/gpu/GpuIndicesOptions.h +30 -0
  137. data/vendor/faiss/gpu/GpuResources.cpp +52 -0
  138. data/vendor/faiss/gpu/GpuResources.h +73 -0
  139. data/vendor/faiss/gpu/StandardGpuResources.cpp +295 -0
  140. data/vendor/faiss/gpu/StandardGpuResources.h +114 -0
  141. data/vendor/faiss/gpu/impl/RemapIndices.cpp +43 -0
  142. data/vendor/faiss/gpu/impl/RemapIndices.h +24 -0
  143. data/vendor/faiss/gpu/perf/IndexWrapper-inl.h +71 -0
  144. data/vendor/faiss/gpu/perf/IndexWrapper.h +39 -0
  145. data/vendor/faiss/gpu/perf/PerfClustering.cpp +115 -0
  146. data/vendor/faiss/gpu/perf/PerfIVFPQAdd.cpp +139 -0
  147. data/vendor/faiss/gpu/perf/WriteIndex.cpp +102 -0
  148. data/vendor/faiss/gpu/test/TestGpuIndexBinaryFlat.cpp +130 -0
  149. data/vendor/faiss/gpu/test/TestGpuIndexFlat.cpp +371 -0
  150. data/vendor/faiss/gpu/test/TestGpuIndexIVFFlat.cpp +550 -0
  151. data/vendor/faiss/gpu/test/TestGpuIndexIVFPQ.cpp +450 -0
  152. data/vendor/faiss/gpu/test/TestGpuMemoryException.cpp +84 -0
  153. data/vendor/faiss/gpu/test/TestUtils.cpp +315 -0
  154. data/vendor/faiss/gpu/test/TestUtils.h +93 -0
  155. data/vendor/faiss/gpu/test/demo_ivfpq_indexing_gpu.cpp +159 -0
  156. data/vendor/faiss/gpu/utils/DeviceMemory.cpp +77 -0
  157. data/vendor/faiss/gpu/utils/DeviceMemory.h +71 -0
  158. data/vendor/faiss/gpu/utils/DeviceUtils.h +185 -0
  159. data/vendor/faiss/gpu/utils/MemorySpace.cpp +89 -0
  160. data/vendor/faiss/gpu/utils/MemorySpace.h +44 -0
  161. data/vendor/faiss/gpu/utils/StackDeviceMemory.cpp +239 -0
  162. data/vendor/faiss/gpu/utils/StackDeviceMemory.h +129 -0
  163. data/vendor/faiss/gpu/utils/StaticUtils.h +83 -0
  164. data/vendor/faiss/gpu/utils/Timer.cpp +60 -0
  165. data/vendor/faiss/gpu/utils/Timer.h +52 -0
  166. data/vendor/faiss/impl/AuxIndexStructures.cpp +305 -0
  167. data/vendor/faiss/impl/AuxIndexStructures.h +246 -0
  168. data/vendor/faiss/impl/FaissAssert.h +95 -0
  169. data/vendor/faiss/impl/FaissException.cpp +66 -0
  170. data/vendor/faiss/impl/FaissException.h +71 -0
  171. data/vendor/faiss/impl/HNSW.cpp +818 -0
  172. data/vendor/faiss/impl/HNSW.h +275 -0
  173. data/vendor/faiss/impl/PolysemousTraining.cpp +953 -0
  174. data/vendor/faiss/impl/PolysemousTraining.h +158 -0
  175. data/vendor/faiss/impl/ProductQuantizer.cpp +876 -0
  176. data/vendor/faiss/impl/ProductQuantizer.h +242 -0
  177. data/vendor/faiss/impl/ScalarQuantizer.cpp +1628 -0
  178. data/vendor/faiss/impl/ScalarQuantizer.h +120 -0
  179. data/vendor/faiss/impl/ThreadedIndex-inl.h +192 -0
  180. data/vendor/faiss/impl/ThreadedIndex.h +80 -0
  181. data/vendor/faiss/impl/index_read.cpp +793 -0
  182. data/vendor/faiss/impl/index_write.cpp +558 -0
  183. data/vendor/faiss/impl/io.cpp +142 -0
  184. data/vendor/faiss/impl/io.h +98 -0
  185. data/vendor/faiss/impl/lattice_Zn.cpp +712 -0
  186. data/vendor/faiss/impl/lattice_Zn.h +199 -0
  187. data/vendor/faiss/index_factory.cpp +392 -0
  188. data/vendor/faiss/index_factory.h +25 -0
  189. data/vendor/faiss/index_io.h +75 -0
  190. data/vendor/faiss/misc/test_blas.cpp +84 -0
  191. data/vendor/faiss/tests/test_binary_flat.cpp +64 -0
  192. data/vendor/faiss/tests/test_dealloc_invlists.cpp +183 -0
  193. data/vendor/faiss/tests/test_ivfpq_codec.cpp +67 -0
  194. data/vendor/faiss/tests/test_ivfpq_indexing.cpp +98 -0
  195. data/vendor/faiss/tests/test_lowlevel_ivf.cpp +566 -0
  196. data/vendor/faiss/tests/test_merge.cpp +258 -0
  197. data/vendor/faiss/tests/test_omp_threads.cpp +14 -0
  198. data/vendor/faiss/tests/test_ondisk_ivf.cpp +220 -0
  199. data/vendor/faiss/tests/test_pairs_decoding.cpp +189 -0
  200. data/vendor/faiss/tests/test_params_override.cpp +231 -0
  201. data/vendor/faiss/tests/test_pq_encoding.cpp +98 -0
  202. data/vendor/faiss/tests/test_sliding_ivf.cpp +240 -0
  203. data/vendor/faiss/tests/test_threaded_index.cpp +253 -0
  204. data/vendor/faiss/tests/test_transfer_invlists.cpp +159 -0
  205. data/vendor/faiss/tutorial/cpp/1-Flat.cpp +98 -0
  206. data/vendor/faiss/tutorial/cpp/2-IVFFlat.cpp +81 -0
  207. data/vendor/faiss/tutorial/cpp/3-IVFPQ.cpp +93 -0
  208. data/vendor/faiss/tutorial/cpp/4-GPU.cpp +119 -0
  209. data/vendor/faiss/tutorial/cpp/5-Multiple-GPUs.cpp +99 -0
  210. data/vendor/faiss/utils/Heap.cpp +122 -0
  211. data/vendor/faiss/utils/Heap.h +495 -0
  212. data/vendor/faiss/utils/WorkerThread.cpp +126 -0
  213. data/vendor/faiss/utils/WorkerThread.h +61 -0
  214. data/vendor/faiss/utils/distances.cpp +765 -0
  215. data/vendor/faiss/utils/distances.h +243 -0
  216. data/vendor/faiss/utils/distances_simd.cpp +809 -0
  217. data/vendor/faiss/utils/extra_distances.cpp +336 -0
  218. data/vendor/faiss/utils/extra_distances.h +54 -0
  219. data/vendor/faiss/utils/hamming-inl.h +472 -0
  220. data/vendor/faiss/utils/hamming.cpp +792 -0
  221. data/vendor/faiss/utils/hamming.h +220 -0
  222. data/vendor/faiss/utils/random.cpp +192 -0
  223. data/vendor/faiss/utils/random.h +60 -0
  224. data/vendor/faiss/utils/utils.cpp +783 -0
  225. data/vendor/faiss/utils/utils.h +181 -0
  226. metadata +216 -2
@@ -0,0 +1,550 @@
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/IndexFlat.h>
10
+ #include <faiss/IndexIVFFlat.h>
11
+ #include <faiss/gpu/GpuIndexIVFFlat.h>
12
+ #include <faiss/gpu/StandardGpuResources.h>
13
+ #include <faiss/gpu/utils/DeviceUtils.h>
14
+ #include <faiss/gpu/test/TestUtils.h>
15
+ #include <cmath>
16
+ #include <gtest/gtest.h>
17
+ #include <sstream>
18
+ #include <vector>
19
+
20
+ // FIXME: figure out a better way to test fp16
21
+ constexpr float kF16MaxRelErr = 0.3f;
22
+ constexpr float kF32MaxRelErr = 0.03f;
23
+
24
+
25
+ struct Options {
26
+ Options() {
27
+ numAdd = 2 * faiss::gpu::randVal(2000, 5000);
28
+ dim = faiss::gpu::randVal(64, 200);
29
+
30
+ numCentroids = std::sqrt((float) numAdd / 2);
31
+ numTrain = numCentroids * 40;
32
+ nprobe = faiss::gpu::randVal(std::min(10, numCentroids), numCentroids);
33
+ numQuery = faiss::gpu::randVal(32, 100);
34
+
35
+ // Due to the approximate nature of the query and of floating point
36
+ // differences between GPU and CPU, to stay within our error bounds, only
37
+ // use a small k
38
+ k = std::min(faiss::gpu::randVal(10, 30), numAdd / 40);
39
+ indicesOpt = faiss::gpu::randSelect({
40
+ faiss::gpu::INDICES_CPU,
41
+ faiss::gpu::INDICES_32_BIT,
42
+ faiss::gpu::INDICES_64_BIT});
43
+
44
+ device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
45
+ }
46
+
47
+ std::string toString() const {
48
+ std::stringstream str;
49
+ str << "IVFFlat device " << device
50
+ << " numVecs " << numAdd
51
+ << " dim " << dim
52
+ << " numCentroids " << numCentroids
53
+ << " nprobe " << nprobe
54
+ << " numQuery " << numQuery
55
+ << " k " << k
56
+ << " indicesOpt " << indicesOpt;
57
+
58
+ return str.str();
59
+ }
60
+
61
+ int numAdd;
62
+ int dim;
63
+ int numCentroids;
64
+ int numTrain;
65
+ int nprobe;
66
+ int numQuery;
67
+ int k;
68
+ int device;
69
+ faiss::gpu::IndicesOptions indicesOpt;
70
+ };
71
+
72
+ void queryTest(faiss::MetricType metricType,
73
+ bool useFloat16CoarseQuantizer,
74
+ int dimOverride = -1) {
75
+ for (int tries = 0; tries < 2; ++tries) {
76
+ Options opt;
77
+ opt.dim = dimOverride != -1 ? dimOverride : opt.dim;
78
+
79
+ std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
80
+ std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
81
+
82
+ faiss::IndexFlatL2 quantizerL2(opt.dim);
83
+ faiss::IndexFlatIP quantizerIP(opt.dim);
84
+ faiss::Index* quantizer =
85
+ metricType == faiss::METRIC_L2 ?
86
+ (faiss::Index*) &quantizerL2 : (faiss::Index*) &quantizerIP;
87
+
88
+ faiss::IndexIVFFlat cpuIndex(quantizer,
89
+ opt.dim, opt.numCentroids, metricType);
90
+ cpuIndex.train(opt.numTrain, trainVecs.data());
91
+ cpuIndex.add(opt.numAdd, addVecs.data());
92
+ cpuIndex.nprobe = opt.nprobe;
93
+
94
+ faiss::gpu::StandardGpuResources res;
95
+ res.noTempMemory();
96
+
97
+ faiss::gpu::GpuIndexIVFFlatConfig config;
98
+ config.device = opt.device;
99
+ config.indicesOptions = opt.indicesOpt;
100
+ config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
101
+
102
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(&res,
103
+ cpuIndex.d,
104
+ cpuIndex.nlist,
105
+ cpuIndex.metric_type,
106
+ config);
107
+ gpuIndex.copyFrom(&cpuIndex);
108
+ gpuIndex.setNumProbes(opt.nprobe);
109
+
110
+ bool compFloat16 = useFloat16CoarseQuantizer;
111
+ faiss::gpu::compareIndices(cpuIndex, gpuIndex,
112
+ opt.numQuery, opt.dim, opt.k, opt.toString(),
113
+ compFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
114
+ // FIXME: the fp16 bounds are
115
+ // useless when math (the accumulator) is
116
+ // in fp16. Figure out another way to test
117
+ compFloat16 ? 0.70f : 0.1f,
118
+ compFloat16 ? 0.65f : 0.015f);
119
+ }
120
+ }
121
+
122
+ void addTest(faiss::MetricType metricType,
123
+ bool useFloat16CoarseQuantizer) {
124
+ for (int tries = 0; tries < 2; ++tries) {
125
+ Options opt;
126
+
127
+ std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
128
+ std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
129
+
130
+ faiss::IndexFlatL2 quantizerL2(opt.dim);
131
+ faiss::IndexFlatIP quantizerIP(opt.dim);
132
+ faiss::Index* quantizer =
133
+ metricType == faiss::METRIC_L2 ?
134
+ (faiss::Index*) &quantizerL2 : (faiss::Index*) &quantizerIP;
135
+
136
+ faiss::IndexIVFFlat cpuIndex(quantizer,
137
+ opt.dim,
138
+ opt.numCentroids,
139
+ metricType);
140
+ cpuIndex.train(opt.numTrain, trainVecs.data());
141
+ cpuIndex.nprobe = opt.nprobe;
142
+
143
+ faiss::gpu::StandardGpuResources res;
144
+ res.noTempMemory();
145
+
146
+ faiss::gpu::GpuIndexIVFFlatConfig config;
147
+ config.device = opt.device;
148
+ config.indicesOptions = opt.indicesOpt;
149
+ config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
150
+
151
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(&res,
152
+ cpuIndex.d,
153
+ cpuIndex.nlist,
154
+ cpuIndex.metric_type,
155
+ config);
156
+ gpuIndex.copyFrom(&cpuIndex);
157
+ gpuIndex.setNumProbes(opt.nprobe);
158
+
159
+ cpuIndex.add(opt.numAdd, addVecs.data());
160
+ gpuIndex.add(opt.numAdd, addVecs.data());
161
+
162
+ bool compFloat16 = useFloat16CoarseQuantizer;
163
+ faiss::gpu::compareIndices(cpuIndex, gpuIndex,
164
+ opt.numQuery, opt.dim, opt.k, opt.toString(),
165
+ compFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
166
+ compFloat16 ? 0.70f : 0.1f,
167
+ compFloat16 ? 0.30f : 0.015f);
168
+ }
169
+ }
170
+
171
+ void copyToTest(bool useFloat16CoarseQuantizer) {
172
+ Options opt;
173
+ std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
174
+ std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
175
+
176
+ faiss::gpu::StandardGpuResources res;
177
+ res.noTempMemory();
178
+
179
+ faiss::gpu::GpuIndexIVFFlatConfig config;
180
+ config.device = opt.device;
181
+ config.indicesOptions = opt.indicesOpt;
182
+ config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
183
+
184
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(&res,
185
+ opt.dim,
186
+ opt.numCentroids,
187
+ faiss::METRIC_L2,
188
+ config);
189
+ gpuIndex.train(opt.numTrain, trainVecs.data());
190
+ gpuIndex.add(opt.numAdd, addVecs.data());
191
+ gpuIndex.setNumProbes(opt.nprobe);
192
+
193
+ // use garbage values to see if we overwrite then
194
+ faiss::IndexFlatL2 cpuQuantizer(1);
195
+ faiss::IndexIVFFlat cpuIndex(&cpuQuantizer, 1, 1, faiss::METRIC_L2);
196
+ cpuIndex.nprobe = 1;
197
+
198
+ gpuIndex.copyTo(&cpuIndex);
199
+
200
+ EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
201
+ EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
202
+
203
+ EXPECT_EQ(cpuIndex.d, gpuIndex.d);
204
+ EXPECT_EQ(cpuIndex.quantizer->d, gpuIndex.quantizer->d);
205
+ EXPECT_EQ(cpuIndex.d, opt.dim);
206
+ EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
207
+ EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
208
+
209
+ // Query both objects; results should be equivalent
210
+ bool compFloat16 = useFloat16CoarseQuantizer;
211
+ faiss::gpu::compareIndices(cpuIndex, gpuIndex,
212
+ opt.numQuery, opt.dim, opt.k, opt.toString(),
213
+ compFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
214
+ compFloat16 ? 0.70f : 0.1f,
215
+ compFloat16 ? 0.30f : 0.015f);
216
+ }
217
+
218
+ void copyFromTest(bool useFloat16CoarseQuantizer) {
219
+ Options opt;
220
+ std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
221
+ std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
222
+
223
+ faiss::IndexFlatL2 cpuQuantizer(opt.dim);
224
+ faiss::IndexIVFFlat cpuIndex(&cpuQuantizer,
225
+ opt.dim,
226
+ opt.numCentroids,
227
+ faiss::METRIC_L2);
228
+ cpuIndex.nprobe = opt.nprobe;
229
+ cpuIndex.train(opt.numTrain, trainVecs.data());
230
+ cpuIndex.add(opt.numAdd, addVecs.data());
231
+
232
+ // use garbage values to see if we overwrite then
233
+ faiss::gpu::StandardGpuResources res;
234
+ res.noTempMemory();
235
+
236
+ faiss::gpu::GpuIndexIVFFlatConfig config;
237
+ config.device = opt.device;
238
+ config.indicesOptions = opt.indicesOpt;
239
+ config.flatConfig.useFloat16 = useFloat16CoarseQuantizer;
240
+
241
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(&res,
242
+ 1,
243
+ 1,
244
+ faiss::METRIC_L2,
245
+ config);
246
+ gpuIndex.setNumProbes(1);
247
+
248
+ gpuIndex.copyFrom(&cpuIndex);
249
+
250
+ EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
251
+ EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
252
+
253
+ EXPECT_EQ(cpuIndex.d, gpuIndex.d);
254
+ EXPECT_EQ(cpuIndex.d, opt.dim);
255
+ EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
256
+ EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
257
+
258
+ // Query both objects; results should be equivalent
259
+ bool compFloat16 = useFloat16CoarseQuantizer;
260
+ faiss::gpu::compareIndices(cpuIndex, gpuIndex,
261
+ opt.numQuery, opt.dim, opt.k, opt.toString(),
262
+ compFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
263
+ compFloat16 ? 0.70f : 0.1f,
264
+ compFloat16 ? 0.30f : 0.015f);
265
+ }
266
+
267
+ TEST(TestGpuIndexIVFFlat, Float32_32_Add_L2) {
268
+ addTest(faiss::METRIC_L2, false);
269
+ }
270
+
271
+ TEST(TestGpuIndexIVFFlat, Float32_32_Add_IP) {
272
+ addTest(faiss::METRIC_INNER_PRODUCT, false);
273
+ }
274
+
275
+ TEST(TestGpuIndexIVFFlat, Float16_32_Add_L2) {
276
+ addTest(faiss::METRIC_L2, true);
277
+ }
278
+
279
+ TEST(TestGpuIndexIVFFlat, Float16_32_Add_IP) {
280
+ addTest(faiss::METRIC_INNER_PRODUCT, true);
281
+ }
282
+
283
+ //
284
+ // General query tests
285
+ //
286
+
287
+ TEST(TestGpuIndexIVFFlat, Float32_Query_L2) {
288
+ queryTest(faiss::METRIC_L2, false);
289
+ }
290
+
291
+ TEST(TestGpuIndexIVFFlat, Float32_Query_IP) {
292
+ queryTest(faiss::METRIC_INNER_PRODUCT, false);
293
+ }
294
+
295
+ // float16 coarse quantizer
296
+
297
+ TEST(TestGpuIndexIVFFlat, Float16_32_Query_L2) {
298
+ queryTest(faiss::METRIC_L2, true);
299
+ }
300
+
301
+ TEST(TestGpuIndexIVFFlat, Float16_32_Query_IP) {
302
+ queryTest(faiss::METRIC_INNER_PRODUCT, true);
303
+ }
304
+
305
+ //
306
+ // There are IVF list scanning specializations for 64-d and 128-d that we
307
+ // make sure we explicitly test here
308
+ //
309
+
310
+ TEST(TestGpuIndexIVFFlat, Float32_Query_L2_64) {
311
+ queryTest(faiss::METRIC_L2, false, 64);
312
+ }
313
+
314
+ TEST(TestGpuIndexIVFFlat, Float32_Query_IP_64) {
315
+ queryTest(faiss::METRIC_INNER_PRODUCT, false, 64);
316
+ }
317
+
318
+ TEST(TestGpuIndexIVFFlat, Float32_Query_L2_128) {
319
+ queryTest(faiss::METRIC_L2, false, 128);
320
+ }
321
+
322
+ TEST(TestGpuIndexIVFFlat, Float32_Query_IP_128) {
323
+ queryTest(faiss::METRIC_INNER_PRODUCT, false, 128);
324
+ }
325
+
326
+ //
327
+ // Copy tests
328
+ //
329
+
330
+ TEST(TestGpuIndexIVFFlat, Float32_32_CopyTo) {
331
+ copyToTest(false);
332
+ }
333
+
334
+ TEST(TestGpuIndexIVFFlat, Float32_32_CopyFrom) {
335
+ copyFromTest(false);
336
+ }
337
+
338
+ TEST(TestGpuIndexIVFFlat, Float32_negative) {
339
+ Options opt;
340
+
341
+ auto trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
342
+ auto addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
343
+
344
+ // Put all vecs on negative side
345
+ for (auto& f : trainVecs) {
346
+ f = std::abs(f) * -1.0f;
347
+ }
348
+
349
+ for (auto& f : addVecs) {
350
+ f *= std::abs(f) * -1.0f;
351
+ }
352
+
353
+ faiss::IndexFlatIP quantizerIP(opt.dim);
354
+ faiss::Index* quantizer = (faiss::Index*) &quantizerIP;
355
+
356
+ faiss::IndexIVFFlat cpuIndex(quantizer,
357
+ opt.dim, opt.numCentroids,
358
+ faiss::METRIC_INNER_PRODUCT);
359
+ cpuIndex.train(opt.numTrain, trainVecs.data());
360
+ cpuIndex.add(opt.numAdd, addVecs.data());
361
+ cpuIndex.nprobe = opt.nprobe;
362
+
363
+ faiss::gpu::StandardGpuResources res;
364
+ res.noTempMemory();
365
+
366
+ faiss::gpu::GpuIndexIVFFlatConfig config;
367
+ config.device = opt.device;
368
+ config.indicesOptions = opt.indicesOpt;
369
+
370
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(&res,
371
+ cpuIndex.d,
372
+ cpuIndex.nlist,
373
+ cpuIndex.metric_type,
374
+ config);
375
+ gpuIndex.copyFrom(&cpuIndex);
376
+ gpuIndex.setNumProbes(opt.nprobe);
377
+
378
+ // Construct a positive test set
379
+ auto queryVecs = faiss::gpu::randVecs(opt.numQuery, opt.dim);
380
+
381
+ // Put all vecs on positive size
382
+ for (auto& f : queryVecs) {
383
+ f = std::abs(f);
384
+ }
385
+
386
+ bool compFloat16 = false;
387
+ faiss::gpu::compareIndices(queryVecs,
388
+ cpuIndex, gpuIndex,
389
+ opt.numQuery, opt.dim, opt.k, opt.toString(),
390
+ compFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
391
+ // FIXME: the fp16 bounds are
392
+ // useless when math (the accumulator) is
393
+ // in fp16. Figure out another way to test
394
+ compFloat16 ? 0.99f : 0.1f,
395
+ compFloat16 ? 0.65f : 0.015f);
396
+ }
397
+
398
+ //
399
+ // NaN tests
400
+ //
401
+
402
+ TEST(TestGpuIndexIVFFlat, QueryNaN) {
403
+ Options opt;
404
+
405
+ std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
406
+ std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
407
+
408
+ faiss::gpu::StandardGpuResources res;
409
+ res.noTempMemory();
410
+
411
+ faiss::gpu::GpuIndexIVFFlatConfig config;
412
+ config.device = opt.device;
413
+ config.indicesOptions = opt.indicesOpt;
414
+ config.flatConfig.useFloat16 = faiss::gpu::randBool();
415
+
416
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(&res,
417
+ opt.dim,
418
+ opt.numCentroids,
419
+ faiss::METRIC_L2,
420
+ config);
421
+ gpuIndex.setNumProbes(opt.nprobe);
422
+
423
+ gpuIndex.train(opt.numTrain, trainVecs.data());
424
+ gpuIndex.add(opt.numAdd, addVecs.data());
425
+
426
+ int numQuery = 10;
427
+ std::vector<float> nans(numQuery * opt.dim,
428
+ std::numeric_limits<float>::quiet_NaN());
429
+
430
+ std::vector<float> distances(numQuery * opt.k, 0);
431
+ std::vector<faiss::Index::idx_t> indices(numQuery * opt.k, 0);
432
+
433
+ gpuIndex.search(numQuery,
434
+ nans.data(),
435
+ opt.k,
436
+ distances.data(),
437
+ indices.data());
438
+
439
+ for (int q = 0; q < numQuery; ++q) {
440
+ for (int k = 0; k < opt.k; ++k) {
441
+ EXPECT_EQ(indices[q * opt.k + k], -1);
442
+ EXPECT_EQ(distances[q * opt.k + k], std::numeric_limits<float>::max());
443
+ }
444
+ }
445
+ }
446
+
447
+ TEST(TestGpuIndexIVFFlat, AddNaN) {
448
+ Options opt;
449
+
450
+ faiss::gpu::StandardGpuResources res;
451
+ res.noTempMemory();
452
+
453
+ faiss::gpu::GpuIndexIVFFlatConfig config;
454
+ config.device = opt.device;
455
+ config.indicesOptions = opt.indicesOpt;
456
+ config.flatConfig.useFloat16 = faiss::gpu::randBool();
457
+
458
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(&res,
459
+ opt.dim,
460
+ opt.numCentroids,
461
+ faiss::METRIC_L2,
462
+ config);
463
+ gpuIndex.setNumProbes(opt.nprobe);
464
+
465
+ int numNans = 10;
466
+ std::vector<float> nans(numNans * opt.dim,
467
+ std::numeric_limits<float>::quiet_NaN());
468
+
469
+ // Make one vector valid, which should actually add
470
+ for (int i = 0; i < opt.dim; ++i) {
471
+ nans[i] = 0.0f;
472
+ }
473
+
474
+ std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
475
+ gpuIndex.train(opt.numTrain, trainVecs.data());
476
+
477
+ // should not crash
478
+ EXPECT_EQ(gpuIndex.ntotal, 0);
479
+ gpuIndex.add(numNans, nans.data());
480
+
481
+ std::vector<float> queryVecs = faiss::gpu::randVecs(opt.numQuery, opt.dim);
482
+ std::vector<float> distance(opt.numQuery * opt.k, 0);
483
+ std::vector<faiss::Index::idx_t> indices(opt.numQuery * opt.k, 0);
484
+
485
+ // should not crash
486
+ gpuIndex.search(opt.numQuery, queryVecs.data(), opt.k,
487
+ distance.data(), indices.data());
488
+ }
489
+
490
+ TEST(TestGpuIndexIVFFlat, UnifiedMemory) {
491
+ // Construct on a random device to test multi-device, if we have
492
+ // multiple devices
493
+ int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
494
+
495
+ if (!faiss::gpu::getFullUnifiedMemSupport(device)) {
496
+ return;
497
+ }
498
+
499
+ int dim = 128;
500
+
501
+ int numCentroids = 256;
502
+ // Unfortunately it would take forever to add 24 GB in IVFPQ data,
503
+ // so just perform a small test with data allocated in the unified
504
+ // memory address space
505
+ size_t numAdd = 10000;
506
+ size_t numTrain = numCentroids * 40;
507
+ int numQuery = 10;
508
+ int k = 10;
509
+ int nprobe = 8;
510
+
511
+ std::vector<float> trainVecs = faiss::gpu::randVecs(numTrain, dim);
512
+ std::vector<float> addVecs = faiss::gpu::randVecs(numAdd, dim);
513
+
514
+ faiss::IndexFlatL2 quantizer(dim);
515
+ faiss::IndexIVFFlat cpuIndex(&quantizer, dim, numCentroids, faiss::METRIC_L2);
516
+
517
+ cpuIndex.train(numTrain, trainVecs.data());
518
+ cpuIndex.add(numAdd, addVecs.data());
519
+ cpuIndex.nprobe = nprobe;
520
+
521
+ faiss::gpu::StandardGpuResources res;
522
+ res.noTempMemory();
523
+
524
+ faiss::gpu::GpuIndexIVFFlatConfig config;
525
+ config.device = device;
526
+ config.memorySpace = faiss::gpu::MemorySpace::Unified;
527
+
528
+ faiss::gpu::GpuIndexIVFFlat gpuIndex(&res,
529
+ dim,
530
+ numCentroids,
531
+ faiss::METRIC_L2,
532
+ config);
533
+ gpuIndex.copyFrom(&cpuIndex);
534
+ gpuIndex.setNumProbes(nprobe);
535
+
536
+ faiss::gpu::compareIndices(cpuIndex, gpuIndex,
537
+ numQuery, dim, k, "Unified Memory",
538
+ kF32MaxRelErr,
539
+ 0.1f,
540
+ 0.015f);
541
+ }
542
+
543
+ int main(int argc, char** argv) {
544
+ testing::InitGoogleTest(&argc, argv);
545
+
546
+ // just run with a fixed test seed
547
+ faiss::gpu::setTestSeed(100);
548
+
549
+ return RUN_ALL_TESTS();
550
+ }