Faiss

- Main Page
- Namespaces
- Classes
- Files

- File List

All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends
TestGpuIndexFlat.cpp
1
2 /**
3 * Copyright (c) 2015-present, Facebook, Inc.
4 * All rights reserved.
5 *
6 * This source code is licensed under the CC-by-NC license found in the
7 * LICENSE file in the root directory of this source tree.
8 */
9
10 // Copyright 2004-present Facebook. All Rights Reserved.
11
12 #include "../../IndexFlat.h"
13 #include "../GpuIndexFlat.h"
14 #include "../StandardGpuResources.h"
15 #include "../utils/DeviceUtils.h"
16 #include "../test/TestUtils.h"
17 #include <gtest/gtest.h>
18 #include <sstream>
19 #include <vector>
20
21 // FIXME: figure out a better way to test fp16
22 constexpr float kF16MaxRelErr = 0.07f;
23 constexpr float kF32MaxRelErr = 6e-3f;
24
25 void testFlat(bool useL2,
26 bool useFloat16,
27 bool useTransposed,
28 int kOverride = -1) {
29 int numVecs = faiss::gpu::randVal(1000, 20000);
30 int dim = faiss::gpu::randVal(50, 800);
31 int numQuery = faiss::gpu::randVal(1, 512);
32
33 // Due to loss of precision in a float16 accumulator, for large k,
34 // the number of differences is pretty huge. Restrict ourselves to a
35 // fairly small `k` for float16
36 int k = useFloat16 ?
37 std::min(faiss::gpu::randVal(1, 50), numVecs) :
38 std::min(faiss::gpu::randVal(1, 1024), numVecs);
39 if (kOverride > 0) {
40 k = kOverride;
41 }
42
43 faiss::IndexFlatIP cpuIndexIP(dim);
44 faiss::IndexFlatL2 cpuIndexL2(dim);
45
46 faiss::IndexFlat* cpuIndex =
47 useL2 ? (faiss::IndexFlat*) &cpuIndexL2 : (faiss::IndexFlat*) &cpuIndexIP;
48
49 // Construct on a random device to test multi-device, if we have
50 // multiple devices
51 int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
52
53 faiss::gpu::StandardGpuResources res;
54 res.noTempMemory();
55
56
57 faiss::gpu::GpuIndexFlatConfig config;
58 config.device = device;
59 config.useFloat16 = useFloat16;
60 config.storeTransposed = useTransposed;
61
62 faiss::gpu::GpuIndexFlatIP gpuIndexIP(&res, dim, config);
63 faiss::gpu::GpuIndexFlatL2 gpuIndexL2(&res, dim, config);
64
65 faiss::gpu::GpuIndexFlat* gpuIndex =
66 useL2 ? (faiss::gpu::GpuIndexFlat*) &gpuIndexL2 :
67 (faiss::gpu::GpuIndexFlat*) &gpuIndexIP;
68
69 std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
70 cpuIndex->add(numVecs, vecs.data());
71 gpuIndex->add(numVecs, vecs.data());
72
73 std::stringstream str;
74 str << (useL2 ? "L2" : "IP") << " numVecs " << numVecs
75 << " dim " << dim
76 << " useFloat16 " << useFloat16
77 << " transposed " << useTransposed
78 << " numQuery " << numQuery
79 << " k " << k;
80
81 // To some extent, we depend upon the relative error for the test
82 // for float16
83 faiss::gpu::compareIndices(*cpuIndex, *gpuIndex, numQuery, dim, k, str.str(),
84 useFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
85 // FIXME: the fp16 bounds are
86 // useless when math (the accumulator) is
87 // in fp16. Figure out another way to test
88 useFloat16 ? 0.99f : 0.1f,
89 useFloat16 ? 0.65f : 0.015f);
90 }
91
92 TEST(TestGpuIndexFlat, IP_Float32) {
93 for (int tries = 0; tries < 5; ++tries) {
94 faiss::gpu::newTestSeed();
95 testFlat(false, false, false);
96 testFlat(false, false, true);
97 }
98 }
99
100 TEST(TestGpuIndexFlat, L2_Float32) {
101 for (int tries = 0; tries < 5; ++tries) {
102 faiss::gpu::newTestSeed();
103 testFlat(true, false, false);
104 testFlat(true, false, true);
105 }
106 }
107
108 // test specialized k == 1 codepath
109 TEST(TestGpuIndexFlat, L2_Float32_K1) {
110 for (int tries = 0; tries < 5; ++tries) {
111 faiss::gpu::newTestSeed();
112 testFlat(true, false, false, 1);
113 testFlat(true, false, true, 1);
114 }
115 }
116
117 TEST(TestGpuIndexFlat, IP_Float16) {
118 for (int tries = 0; tries < 5; ++tries) {
119 faiss::gpu::newTestSeed();
120 testFlat(false, true, false);
121 testFlat(false, true, false);
122 }
123 }
124
125 TEST(TestGpuIndexFlat, L2_Float16) {
126 for (int tries = 0; tries < 5; ++tries) {
127 faiss::gpu::newTestSeed();
128 testFlat(true, true, false);
129 testFlat(true, true, true);
130 }
131 }
132
133 // test specialized k == 1 codepath
134 TEST(TestGpuIndexFlat, L2_Float16_K1) {
135 for (int tries = 0; tries < 5; ++tries) {
136 faiss::gpu::newTestSeed();
137 testFlat(true, true, false, 1);
138 testFlat(true, true, true, 1);
139 }
140 }
141
142 TEST(TestGpuIndexFlat, QueryEmpty) {
143 faiss::gpu::StandardGpuResources res;
144 res.noTempMemory();
145
146 faiss::gpu::GpuIndexFlatConfig config;
147 config.device = 0;
148 config.useFloat16 = false;
149 config.storeTransposed = false;
150
151 int dim = 128;
152 faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, dim, config);
153
154 // Querying an empty index should not blow up, and just return
155 // (FLT_MAX, -1)
156 int numQuery = 10;
157 int k = 50;
158 std::vector<float> queries(numQuery * dim, 1.0f);
159
160 std::vector<float> dist(numQuery * k, 0);
161 std::vector<faiss::Index::idx_t> ind(numQuery * k);
162
163 gpuIndex.search(numQuery, queries.data(), k, dist.data(), ind.data());
164
165 for (auto d : dist) {
166 EXPECT_EQ(d, std::numeric_limits<float>::max());
167 }
168
169 for (auto i : ind) {
170 EXPECT_EQ(i, -1);
171 }
172 }
173
174 TEST(TestGpuIndexFlat, CopyFrom) {
175 faiss::gpu::newTestSeed();
176
177 int numVecs = faiss::gpu::randVal(100, 200);
178 int dim = faiss::gpu::randVal(1, 1000);
179
180 faiss::IndexFlatL2 cpuIndex(dim);
181
182 std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
183 cpuIndex.add(numVecs, vecs.data());
184
185 faiss::gpu::StandardGpuResources res;
186 res.noTempMemory();
187
188 // Fill with garbage values
189 int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
190
191 faiss::gpu::GpuIndexFlatConfig config;
192 config.device = 0;
193 config.useFloat16 = false;
194 config.storeTransposed = false;
195
196 faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, 2000, config);
197 gpuIndex.copyFrom(&cpuIndex);
198
199 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
200 EXPECT_EQ(gpuIndex.ntotal, numVecs);
201
202 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
203 EXPECT_EQ(cpuIndex.d, dim);
204
205 int idx = faiss::gpu::randVal(0, numVecs - 1);
206
207 std::vector<float> gpuVals(dim);
208 gpuIndex.reconstruct(idx, gpuVals.data());
209
210 std::vector<float> cpuVals(dim);
211 cpuIndex.reconstruct(idx, cpuVals.data());
212
213 EXPECT_EQ(gpuVals, cpuVals);
214 }
215
216 TEST(TestGpuIndexFlat, CopyTo) {
217 faiss::gpu::newTestSeed();
218
219 faiss::gpu::StandardGpuResources res;
220 res.noTempMemory();
221
222 int numVecs = faiss::gpu::randVal(100, 200);
223 int dim = faiss::gpu::randVal(1, 1000);
224
225 int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
226
227 faiss::gpu::GpuIndexFlatConfig config;
228 config.device = device;
229 config.useFloat16 = false;
230 config.storeTransposed = false;
231
232 faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, dim, config);
233
234 std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
235 gpuIndex.add(numVecs, vecs.data());
236
237 // Fill with garbage values
238 faiss::IndexFlatL2 cpuIndex(2000);
239 gpuIndex.copyTo(&cpuIndex);
240
241 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
242 EXPECT_EQ(gpuIndex.ntotal, numVecs);
243
244 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
245 EXPECT_EQ(cpuIndex.d, dim);
246
247 int idx = faiss::gpu::randVal(0, numVecs - 1);
248
249 std::vector<float> gpuVals(dim);
250 gpuIndex.reconstruct(idx, gpuVals.data());
251
252 std::vector<float> cpuVals(dim);
253 cpuIndex.reconstruct(idx, cpuVals.data());
254
255 EXPECT_EQ(gpuVals, cpuVals);
256 }
faiss::IndexFlat
Definition: IndexFlat.h:24
faiss::gpu::GpuIndexFlat::copyTo
void copyTo(faiss::IndexFlat *index) const
Definition: GpuIndexFlat.cu:111
faiss::gpu::StandardGpuResources::noTempMemory
void noTempMemory()
Definition: StandardGpuResources.cpp:72
faiss::IndexFlatL2
Definition: IndexFlat.h:81
faiss::IndexFlat::reconstruct
virtual void reconstruct(idx_t key, float *recons) const override
Definition: IndexFlat.cpp:109
faiss::IndexFlatIP
Definition: IndexFlat.h:75
faiss::Index::d
int d
vector dimension
Definition: Index.h:66
faiss::gpu::GpuIndexFlatConfig
Definition: GpuIndexFlat.h:28
faiss::gpu::StandardGpuResources
Definition: StandardGpuResources.h:24
faiss::gpu::GpuIndexFlat::search
virtual void search(faiss::Index::idx_t n, const float *x, faiss::Index::idx_t k, float *distances, faiss::Index::idx_t *labels) const
Definition: GpuIndexFlat.cu:176
faiss::Index::ntotal
idx_t ntotal
total nb of indexed vectors
Definition: Index.h:67
faiss::gpu::GpuIndex::add
virtual void add(faiss::Index::idx_t, const float *x)
Definition: GpuIndex.cu:37
faiss::IndexFlat::add
virtual void add(idx_t n, const float *x) override
Definition: IndexFlat.cpp:41
faiss::gpu::GpuIndexFlatIP
Definition: GpuIndexFlat.h:176
faiss::gpu::GpuIndexFlat::copyFrom
void copyFrom(const faiss::IndexFlat *index)
Definition: GpuIndexFlat.cu:84
faiss::gpu::GpuIndexFlatL2
Definition: GpuIndexFlat.h:151
faiss::gpu::GpuIndexFlat::reconstruct
virtual void reconstruct(faiss::Index::idx_t key, float *out) const
Definition: GpuIndexFlat.cu:458
faiss::gpu::GpuIndexFlat
Definition: GpuIndexFlat.h:43