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,102 @@
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/IndexIVFFlat.h>
10
+ #include <faiss/IndexIVFPQ.h>
11
+ #include <faiss/IndexFlat.h>
12
+ #include <faiss/index_io.h>
13
+ #include <faiss/gpu/test/TestUtils.h>
14
+ #include <vector>
15
+ #include <gflags/gflags.h>
16
+
17
+ // For IVFPQ:
18
+ DEFINE_bool(ivfpq, false, "use IVFPQ encoding");
19
+ DEFINE_int32(codes, 4, "number of PQ codes per vector");
20
+ DEFINE_int32(bits_per_code, 8, "number of bits per PQ code");
21
+
22
+ // For IVFFlat:
23
+ DEFINE_bool(l2, true, "use L2 metric (versus IP metric)");
24
+ DEFINE_bool(ivfflat, false, "use IVF flat encoding");
25
+
26
+ // For both:
27
+ DEFINE_string(out, "/home/jhj/local/index.out", "index file for output");
28
+ DEFINE_int32(dim, 128, "vector dimension");
29
+ DEFINE_int32(num_coarse, 100, "number of coarse centroids");
30
+ DEFINE_int32(num, 100000, "total database size");
31
+ DEFINE_int32(num_train, -1, "number of database vecs to train on");
32
+
33
+ template <typename T>
34
+ void fillAndSave(T& index, int numTrain, int num, int dim) {
35
+ auto trainVecs = faiss::gpu::randVecs(numTrain, dim);
36
+ index.train(numTrain, trainVecs.data());
37
+
38
+ constexpr int kAddChunk = 1000000;
39
+
40
+ for (int i = 0; i < num; i += kAddChunk) {
41
+ int numRemaining = (num - i) < kAddChunk ? (num - i) : kAddChunk;
42
+ auto vecs = faiss::gpu::randVecs(numRemaining, dim);
43
+
44
+ printf("adding at %d: %d\n", i, numRemaining);
45
+ index.add(numRemaining, vecs.data());
46
+ }
47
+
48
+ faiss::write_index(&index, FLAGS_out.c_str());
49
+ }
50
+
51
+ int main(int argc, char** argv) {
52
+ gflags::ParseCommandLineFlags(&argc, &argv, true);
53
+
54
+ // Either ivfpq or ivfflat must be set
55
+ if ((FLAGS_ivfpq && FLAGS_ivfflat) ||
56
+ (!FLAGS_ivfpq && !FLAGS_ivfflat)) {
57
+ printf("must specify either ivfpq or ivfflat\n");
58
+ return 1;
59
+ }
60
+
61
+ auto dim = FLAGS_dim;
62
+ auto numCentroids = FLAGS_num_coarse;
63
+ auto num = FLAGS_num;
64
+ auto numTrain = FLAGS_num_train;
65
+ numTrain = numTrain == -1 ? std::max((num / 4), 1) : numTrain;
66
+ numTrain = std::min(num, numTrain);
67
+
68
+ if (FLAGS_ivfpq) {
69
+ faiss::IndexFlatL2 quantizer(dim);
70
+ faiss::IndexIVFPQ index(&quantizer, dim, numCentroids,
71
+ FLAGS_codes, FLAGS_bits_per_code);
72
+ index.verbose = true;
73
+
74
+ printf("IVFPQ: codes %d bits per code %d\n",
75
+ FLAGS_codes, FLAGS_bits_per_code);
76
+ printf("Lists: %d\n", numCentroids);
77
+ printf("Database: dim %d num vecs %d trained on %d\n", dim, num, numTrain);
78
+ printf("output file: %s\n", FLAGS_out.c_str());
79
+
80
+ fillAndSave(index, numTrain, num, dim);
81
+ } else if (FLAGS_ivfflat) {
82
+ faiss::IndexFlatL2 quantizerL2(dim);
83
+ faiss::IndexFlatIP quantizerIP(dim);
84
+
85
+ faiss::IndexFlat* quantizer = FLAGS_l2 ?
86
+ (faiss::IndexFlat*) &quantizerL2 :
87
+ (faiss::IndexFlat*) &quantizerIP;
88
+
89
+ faiss::IndexIVFFlat index(quantizer, dim, numCentroids,
90
+ FLAGS_l2 ? faiss::METRIC_L2 :
91
+ faiss::METRIC_INNER_PRODUCT);
92
+
93
+ printf("IVFFlat: metric %s\n", FLAGS_l2 ? "L2" : "IP");
94
+ printf("Lists: %d\n", numCentroids);
95
+ printf("Database: dim %d num vecs %d trained on %d\n", dim, num, numTrain);
96
+ printf("output file: %s\n", FLAGS_out.c_str());
97
+
98
+ fillAndSave(index, numTrain, num, dim);
99
+ }
100
+
101
+ return 0;
102
+ }
@@ -0,0 +1,130 @@
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/IndexBinaryFlat.h>
10
+ #include <faiss/gpu/GpuIndexBinaryFlat.h>
11
+ #include <faiss/gpu/StandardGpuResources.h>
12
+ #include <faiss/gpu/utils/DeviceUtils.h>
13
+ #include <faiss/gpu/test/TestUtils.h>
14
+ #include <faiss/utils/utils.h>
15
+ #include <gtest/gtest.h>
16
+ #include <sstream>
17
+ #include <vector>
18
+
19
+ void compareBinaryDist(const std::vector<int>& cpuDist,
20
+ const std::vector<faiss::IndexBinary::idx_t>& cpuLabels,
21
+ const std::vector<int>& gpuDist,
22
+ const std::vector<faiss::IndexBinary::idx_t>& gpuLabels,
23
+ int numQuery,
24
+ int k) {
25
+ for (int i = 0; i < numQuery; ++i) {
26
+ // The index order can be permuted within a group that has the same
27
+ // distance, since this is based on the order in which the algorithm
28
+ // encounters the values. The last set of equivalent distances seen in the
29
+ // min-k might be truncated, so we can't check that set, but all others we
30
+ // can check.
31
+ std::set<faiss::IndexBinary::idx_t> cpuLabelSet;
32
+ std::set<faiss::IndexBinary::idx_t> gpuLabelSet;
33
+
34
+ int curDist = -1;
35
+
36
+ for (int j = 0; j < k; ++j) {
37
+ int idx = i * k + j;
38
+
39
+ if (curDist == -1) {
40
+ curDist = cpuDist[idx];
41
+ }
42
+
43
+ if (curDist != cpuDist[idx]) {
44
+ // Distances must be monotonically increasing
45
+ EXPECT_LT(curDist, cpuDist[idx]);
46
+
47
+ // This is a new set of distances
48
+ EXPECT_EQ(cpuLabelSet, gpuLabelSet);
49
+ curDist = cpuDist[idx];
50
+ cpuLabelSet.clear();
51
+ gpuLabelSet.clear();
52
+ }
53
+
54
+ cpuLabelSet.insert(cpuLabels[idx]);
55
+ gpuLabelSet.insert(gpuLabels[idx]);
56
+
57
+ // Because the distances are reproducible, they must be exactly the same
58
+ EXPECT_EQ(cpuDist[idx], gpuDist[idx]);
59
+ }
60
+ }
61
+ }
62
+
63
+ template <int DimMultiple>
64
+ void testGpuIndexBinaryFlat(int kOverride = -1) {
65
+ faiss::gpu::StandardGpuResources res;
66
+ res.noTempMemory();
67
+
68
+ faiss::gpu::GpuIndexBinaryFlatConfig config;
69
+ config.device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
70
+
71
+ // multiples of 8 and multiples of 32 use different implementations
72
+ int dims = faiss::gpu::randVal(1, 20) * DimMultiple;
73
+ faiss::gpu::GpuIndexBinaryFlat gpuIndex(&res, dims, config);
74
+
75
+ faiss::IndexBinaryFlat cpuIndex(dims);
76
+
77
+ int k = kOverride > 0 ?
78
+ kOverride : faiss::gpu::randVal(1, faiss::gpu::getMaxKSelection());
79
+ int numVecs = faiss::gpu::randVal(k + 1, 20000);
80
+ int numQuery = faiss::gpu::randVal(1, 1000);
81
+
82
+ auto data = faiss::gpu::randBinaryVecs(numVecs, dims);
83
+ gpuIndex.add(numVecs, data.data());
84
+ cpuIndex.add(numVecs, data.data());
85
+
86
+ auto query = faiss::gpu::randBinaryVecs(numQuery, dims);
87
+
88
+ std::vector<int> cpuDist(numQuery * k);
89
+ std::vector<faiss::IndexBinary::idx_t> cpuLabels(numQuery * k);
90
+
91
+ cpuIndex.search(numQuery,
92
+ query.data(),
93
+ k,
94
+ cpuDist.data(),
95
+ cpuLabels.data());
96
+
97
+ std::vector<int> gpuDist(numQuery * k);
98
+ std::vector<faiss::IndexBinary::idx_t> gpuLabels(numQuery * k);
99
+
100
+ gpuIndex.search(numQuery,
101
+ query.data(),
102
+ k,
103
+ gpuDist.data(),
104
+ gpuLabels.data());
105
+
106
+ compareBinaryDist(cpuDist, cpuLabels,
107
+ gpuDist, gpuLabels,
108
+ numQuery, k);
109
+ }
110
+
111
+ TEST(TestGpuIndexBinaryFlat, Test8) {
112
+ for (int tries = 0; tries < 4; ++tries) {
113
+ testGpuIndexBinaryFlat<8>();
114
+ }
115
+ }
116
+
117
+ TEST(TestGpuIndexBinaryFlat, Test32) {
118
+ for (int tries = 0; tries < 4; ++tries) {
119
+ testGpuIndexBinaryFlat<32>();
120
+ }
121
+ }
122
+
123
+ int main(int argc, char** argv) {
124
+ testing::InitGoogleTest(&argc, argv);
125
+
126
+ // just run with a fixed test seed
127
+ faiss::gpu::setTestSeed(100);
128
+
129
+ return RUN_ALL_TESTS();
130
+ }
@@ -0,0 +1,371 @@
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/gpu/GpuIndexFlat.h>
11
+ #include <faiss/gpu/StandardGpuResources.h>
12
+ #include <faiss/gpu/utils/DeviceUtils.h>
13
+ #include <faiss/gpu/test/TestUtils.h>
14
+ #include <gtest/gtest.h>
15
+ #include <sstream>
16
+ #include <vector>
17
+
18
+ // FIXME: figure out a better way to test fp16
19
+ constexpr float kF16MaxRelErr = 0.07f;
20
+ constexpr float kF32MaxRelErr = 6e-3f;
21
+
22
+ struct TestFlatOptions {
23
+ TestFlatOptions()
24
+ : useL2(true),
25
+ useFloat16(false),
26
+ useTransposed(false),
27
+ numVecsOverride(-1),
28
+ numQueriesOverride(-1),
29
+ kOverride(-1),
30
+ dimOverride(-1) {
31
+ }
32
+
33
+ bool useL2;
34
+ bool useFloat16;
35
+ bool useTransposed;
36
+ int numVecsOverride;
37
+ int numQueriesOverride;
38
+ int kOverride;
39
+ int dimOverride;
40
+ };
41
+
42
+ void testFlat(const TestFlatOptions& opt) {
43
+ int numVecs = opt.numVecsOverride > 0 ?
44
+ opt.numVecsOverride : faiss::gpu::randVal(1000, 20000);
45
+ int dim = opt.dimOverride > 0 ?
46
+ opt.dimOverride : faiss::gpu::randVal(50, 800);
47
+ int numQuery = opt.numQueriesOverride > 0 ?
48
+ opt.numQueriesOverride : faiss::gpu::randVal(1, 512);
49
+
50
+ // Due to loss of precision in a float16 accumulator, for large k,
51
+ // the number of differences is pretty huge. Restrict ourselves to a
52
+ // fairly small `k` for float16
53
+ int k = opt.useFloat16 ?
54
+ std::min(faiss::gpu::randVal(1, 50), numVecs) :
55
+ std::min(faiss::gpu::randVal(1, faiss::gpu::getMaxKSelection()), numVecs);
56
+ if (opt.kOverride > 0) {
57
+ k = opt.kOverride;
58
+ }
59
+
60
+ faiss::IndexFlatIP cpuIndexIP(dim);
61
+ faiss::IndexFlatL2 cpuIndexL2(dim);
62
+
63
+ faiss::IndexFlat* cpuIndex =
64
+ opt.useL2 ? (faiss::IndexFlat*) &cpuIndexL2 :
65
+ (faiss::IndexFlat*) &cpuIndexIP;
66
+
67
+ // Construct on a random device to test multi-device, if we have
68
+ // multiple devices
69
+ int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
70
+
71
+ faiss::gpu::StandardGpuResources res;
72
+ res.noTempMemory();
73
+
74
+
75
+ faiss::gpu::GpuIndexFlatConfig config;
76
+ config.device = device;
77
+ config.useFloat16 = opt.useFloat16;
78
+ config.storeTransposed = opt.useTransposed;
79
+
80
+ faiss::gpu::GpuIndexFlatIP gpuIndexIP(&res, dim, config);
81
+ faiss::gpu::GpuIndexFlatL2 gpuIndexL2(&res, dim, config);
82
+
83
+ faiss::gpu::GpuIndexFlat* gpuIndex =
84
+ opt.useL2 ? (faiss::gpu::GpuIndexFlat*) &gpuIndexL2 :
85
+ (faiss::gpu::GpuIndexFlat*) &gpuIndexIP;
86
+
87
+ std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
88
+ cpuIndex->add(numVecs, vecs.data());
89
+ gpuIndex->add(numVecs, vecs.data());
90
+
91
+ std::stringstream str;
92
+ str << (opt.useL2 ? "L2" : "IP") << " numVecs " << numVecs
93
+ << " dim " << dim
94
+ << " useFloat16 " << opt.useFloat16
95
+ << " transposed " << opt.useTransposed
96
+ << " numQuery " << numQuery
97
+ << " k " << k;
98
+
99
+ // To some extent, we depend upon the relative error for the test
100
+ // for float16
101
+ faiss::gpu::compareIndices(*cpuIndex, *gpuIndex, numQuery, dim, k, str.str(),
102
+ opt.useFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
103
+ // FIXME: the fp16 bounds are
104
+ // useless when math (the accumulator) is
105
+ // in fp16. Figure out another way to test
106
+ opt.useFloat16 ? 0.99f : 0.1f,
107
+ opt.useFloat16 ? 0.65f : 0.015f);
108
+ }
109
+
110
+ TEST(TestGpuIndexFlat, IP_Float32) {
111
+ for (int tries = 0; tries < 3; ++tries) {
112
+ TestFlatOptions opt;
113
+ opt.useL2 = false;
114
+ opt.useFloat16 = false;
115
+ opt.useTransposed = false;
116
+
117
+ testFlat(opt);
118
+
119
+ opt.useTransposed = true;
120
+ testFlat(opt);
121
+ }
122
+ }
123
+
124
+ TEST(TestGpuIndexFlat, L2_Float32) {
125
+ for (int tries = 0; tries < 3; ++tries) {
126
+ TestFlatOptions opt;
127
+ opt.useL2 = true;
128
+ opt.useFloat16 = false;
129
+ opt.useTransposed = false;
130
+
131
+ testFlat(opt);
132
+
133
+ opt.useTransposed = true;
134
+ testFlat(opt);
135
+ }
136
+ }
137
+
138
+ // test specialized k == 1 codepath
139
+ TEST(TestGpuIndexFlat, L2_Float32_K1) {
140
+ for (int tries = 0; tries < 3; ++tries) {
141
+ TestFlatOptions opt;
142
+ opt.useL2 = true;
143
+ opt.useFloat16 = false;
144
+ opt.useTransposed = false;
145
+ opt.kOverride = 1;
146
+
147
+ testFlat(opt);
148
+ }
149
+ }
150
+
151
+ TEST(TestGpuIndexFlat, IP_Float16) {
152
+ for (int tries = 0; tries < 3; ++tries) {
153
+ TestFlatOptions opt;
154
+ opt.useL2 = false;
155
+ opt.useFloat16 = true;
156
+ opt.useTransposed = false;
157
+
158
+ testFlat(opt);
159
+
160
+ opt.useTransposed = true;
161
+ testFlat(opt);
162
+ }
163
+ }
164
+
165
+ TEST(TestGpuIndexFlat, L2_Float16) {
166
+ for (int tries = 0; tries < 3; ++tries) {
167
+ TestFlatOptions opt;
168
+ opt.useL2 = true;
169
+ opt.useFloat16 = true;
170
+ opt.useTransposed = false;
171
+
172
+ testFlat(opt);
173
+
174
+ opt.useTransposed = true;
175
+ testFlat(opt);
176
+ }
177
+ }
178
+
179
+ // test specialized k == 1 codepath
180
+ TEST(TestGpuIndexFlat, L2_Float16_K1) {
181
+ for (int tries = 0; tries < 3; ++tries) {
182
+ TestFlatOptions opt;
183
+ opt.useL2 = true;
184
+ opt.useFloat16 = true;
185
+ opt.useTransposed = false;
186
+ opt.kOverride = 1;
187
+
188
+ testFlat(opt);
189
+ }
190
+ }
191
+
192
+ // test tiling along a huge vector set
193
+ TEST(TestGpuIndexFlat, L2_Tiling) {
194
+ for (int tries = 0; tries < 2; ++tries) {
195
+ TestFlatOptions opt;
196
+ opt.useL2 = true;
197
+ opt.useFloat16 = false;
198
+ opt.useTransposed = false;
199
+ opt.numVecsOverride = 1000000;
200
+
201
+ // keep the rest of the problem reasonably small
202
+ opt.numQueriesOverride = 4;
203
+ opt.dimOverride = 64;
204
+ opt.kOverride = 64;
205
+
206
+ testFlat(opt);
207
+ }
208
+ }
209
+
210
+ TEST(TestGpuIndexFlat, QueryEmpty) {
211
+ faiss::gpu::StandardGpuResources res;
212
+ res.noTempMemory();
213
+
214
+ faiss::gpu::GpuIndexFlatConfig config;
215
+ config.device = 0;
216
+ config.useFloat16 = false;
217
+ config.storeTransposed = false;
218
+
219
+ int dim = 128;
220
+ faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, dim, config);
221
+
222
+ // Querying an empty index should not blow up, and just return
223
+ // (FLT_MAX, -1)
224
+ int numQuery = 10;
225
+ int k = 50;
226
+ std::vector<float> queries(numQuery * dim, 1.0f);
227
+
228
+ std::vector<float> dist(numQuery * k, 0);
229
+ std::vector<faiss::Index::idx_t> ind(numQuery * k);
230
+
231
+ gpuIndex.search(numQuery, queries.data(), k, dist.data(), ind.data());
232
+
233
+ for (auto d : dist) {
234
+ EXPECT_EQ(d, std::numeric_limits<float>::max());
235
+ }
236
+
237
+ for (auto i : ind) {
238
+ EXPECT_EQ(i, -1);
239
+ }
240
+ }
241
+
242
+ TEST(TestGpuIndexFlat, CopyFrom) {
243
+ int numVecs = faiss::gpu::randVal(100, 200);
244
+ int dim = faiss::gpu::randVal(1, 1000);
245
+
246
+ faiss::IndexFlatL2 cpuIndex(dim);
247
+
248
+ std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
249
+ cpuIndex.add(numVecs, vecs.data());
250
+
251
+ faiss::gpu::StandardGpuResources res;
252
+ res.noTempMemory();
253
+
254
+ // Fill with garbage values
255
+ int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
256
+
257
+ faiss::gpu::GpuIndexFlatConfig config;
258
+ config.device = 0;
259
+ config.useFloat16 = false;
260
+ config.storeTransposed = false;
261
+
262
+ faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, 2000, config);
263
+ gpuIndex.copyFrom(&cpuIndex);
264
+
265
+ EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
266
+ EXPECT_EQ(gpuIndex.ntotal, numVecs);
267
+
268
+ EXPECT_EQ(cpuIndex.d, gpuIndex.d);
269
+ EXPECT_EQ(cpuIndex.d, dim);
270
+
271
+ int idx = faiss::gpu::randVal(0, numVecs - 1);
272
+
273
+ std::vector<float> gpuVals(dim);
274
+ gpuIndex.reconstruct(idx, gpuVals.data());
275
+
276
+ std::vector<float> cpuVals(dim);
277
+ cpuIndex.reconstruct(idx, cpuVals.data());
278
+
279
+ EXPECT_EQ(gpuVals, cpuVals);
280
+ }
281
+
282
+ TEST(TestGpuIndexFlat, CopyTo) {
283
+ faiss::gpu::StandardGpuResources res;
284
+ res.noTempMemory();
285
+
286
+ int numVecs = faiss::gpu::randVal(100, 200);
287
+ int dim = faiss::gpu::randVal(1, 1000);
288
+
289
+ int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
290
+
291
+ faiss::gpu::GpuIndexFlatConfig config;
292
+ config.device = device;
293
+ config.useFloat16 = false;
294
+ config.storeTransposed = false;
295
+
296
+ faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, dim, config);
297
+
298
+ std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
299
+ gpuIndex.add(numVecs, vecs.data());
300
+
301
+ // Fill with garbage values
302
+ faiss::IndexFlatL2 cpuIndex(2000);
303
+ gpuIndex.copyTo(&cpuIndex);
304
+
305
+ EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
306
+ EXPECT_EQ(gpuIndex.ntotal, numVecs);
307
+
308
+ EXPECT_EQ(cpuIndex.d, gpuIndex.d);
309
+ EXPECT_EQ(cpuIndex.d, dim);
310
+
311
+ int idx = faiss::gpu::randVal(0, numVecs - 1);
312
+
313
+ std::vector<float> gpuVals(dim);
314
+ gpuIndex.reconstruct(idx, gpuVals.data());
315
+
316
+ std::vector<float> cpuVals(dim);
317
+ cpuIndex.reconstruct(idx, cpuVals.data());
318
+
319
+ EXPECT_EQ(gpuVals, cpuVals);
320
+ }
321
+
322
+ TEST(TestGpuIndexFlat, UnifiedMemory) {
323
+ // Construct on a random device to test multi-device, if we have
324
+ // multiple devices
325
+ int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
326
+
327
+ if (!faiss::gpu::getFullUnifiedMemSupport(device)) {
328
+ return;
329
+ }
330
+
331
+ int dim = 256;
332
+
333
+ // FIXME: GpuIndexFlat doesn't support > 2^31 (vecs * dims) due to
334
+ // kernel indexing, so we can't test unified memory for memory
335
+ // oversubscription.
336
+ size_t numVecs = 50000;
337
+ int numQuery = 10;
338
+ int k = 10;
339
+
340
+ faiss::IndexFlatL2 cpuIndexL2(dim);
341
+
342
+ faiss::gpu::StandardGpuResources res;
343
+ res.noTempMemory();
344
+
345
+ faiss::gpu::GpuIndexFlatConfig config;
346
+ config.device = device;
347
+ config.memorySpace = faiss::gpu::MemorySpace::Unified;
348
+
349
+ faiss::gpu::GpuIndexFlatL2 gpuIndexL2(&res, dim, config);
350
+
351
+ std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
352
+ cpuIndexL2.add(numVecs, vecs.data());
353
+ gpuIndexL2.add(numVecs, vecs.data());
354
+
355
+ // To some extent, we depend upon the relative error for the test
356
+ // for float16
357
+ faiss::gpu::compareIndices(cpuIndexL2, gpuIndexL2,
358
+ numQuery, dim, k, "Unified Memory",
359
+ kF32MaxRelErr,
360
+ 0.1f,
361
+ 0.015f);
362
+ }
363
+
364
+ int main(int argc, char** argv) {
365
+ testing::InitGoogleTest(&argc, argv);
366
+
367
+ // just run with a fixed test seed
368
+ faiss::gpu::setTestSeed(100);
369
+
370
+ return RUN_ALL_TESTS();
371
+ }