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, bool useFloat16, int kOverride = -1) {
26 int numVecs = faiss::gpu::randVal(1000, 20000);
27 int dim = faiss::gpu::randVal(50, 800);
28 int numQuery = faiss::gpu::randVal(1, 512);
29
30 // Due to loss of precision in a float16 accumulator, for large k,
31 // the number of differences is pretty huge. Restrict ourselves to a
32 // fairly small `k` for float16
33 int k = useFloat16 ?
34 std::min(faiss::gpu::randVal(1, 50), numVecs) :
35 std::min(faiss::gpu::randVal(1, 1024), numVecs);
36 if (kOverride > 0) {
37 k = kOverride;
38 }
39
40 faiss::IndexFlatIP cpuIndexIP(dim);
41 faiss::IndexFlatL2 cpuIndexL2(dim);
42
43 faiss::IndexFlat* cpuIndex =
44 useL2 ? (faiss::IndexFlat*) &cpuIndexL2 : (faiss::IndexFlat*) &cpuIndexIP;
45
46 // Construct on a random device to test multi-device, if we have
47 // multiple devices
48 int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
49
50 faiss::gpu::StandardGpuResources res;
51 res.noTempMemory();
52 faiss::gpu::GpuIndexFlatIP gpuIndexIP(&res, device, dim, useFloat16);
53 faiss::gpu::GpuIndexFlatL2 gpuIndexL2(&res, device, dim, useFloat16);
54
55 faiss::gpu::GpuIndexFlat* gpuIndex =
56 useL2 ? (faiss::gpu::GpuIndexFlat*) &gpuIndexL2 :
57 (faiss::gpu::GpuIndexFlat*) &gpuIndexIP;
58
59 std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
60 cpuIndex->add(numVecs, vecs.data());
61 gpuIndex->add(numVecs, vecs.data());
62
63 std::stringstream str;
64 str << (useL2 ? "L2" : "IP") << " numVecs " << numVecs
65 << " dim " << dim
66 << " useFloat16 " << useFloat16
67 << " numQuery " << numQuery
68 << " k " << k;
69
70 // To some extent, we depend upon the relative error for the test
71 // for float16
72 faiss::gpu::compareIndices(*cpuIndex, *gpuIndex, numQuery, dim, k, str.str(),
73 useFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
74 // FIXME: the fp16 bounds are
75 // useless when math (the accumulator) is
76 // in fp16. Figure out another way to test
77 useFloat16 ? 0.99f : 0.1f,
78 useFloat16 ? 0.65f : 0.015f);
79 }
80
81 TEST(TestGpuIndexFlat, IP_Float32) {
82 for (int tries = 0; tries < 10; ++tries) {
83 faiss::gpu::newTestSeed();
84 testFlat(false, false);
85 }
86 }
87
88 TEST(TestGpuIndexFlat, L2_Float32) {
89 for (int tries = 0; tries < 10; ++tries) {
90 faiss::gpu::newTestSeed();
91 testFlat(true, false);
92 }
93 }
94
95 // test specialized k == 1 codepath
96 TEST(TestGpuIndexFlat, L2_Float32_K1) {
97 for (int tries = 0; tries < 5; ++tries) {
98 faiss::gpu::newTestSeed();
99 testFlat(true, false, 1);
100 }
101 }
102
103 TEST(TestGpuIndexFlat, IP_Float16) {
104 for (int tries = 0; tries < 10; ++tries) {
105 faiss::gpu::newTestSeed();
106 testFlat(false, true);
107 }
108 }
109
110 TEST(TestGpuIndexFlat, L2_Float16) {
111 for (int tries = 0; tries < 10; ++tries) {
112 faiss::gpu::newTestSeed();
113 testFlat(true, true);
114 }
115 }
116
117 // test specialized k == 1 codepath
118 TEST(TestGpuIndexFlat, L2_Float16_K1) {
119 for (int tries = 0; tries < 5; ++tries) {
120 faiss::gpu::newTestSeed();
121 testFlat(true, true, 1);
122 }
123 }
124
125 TEST(TestGpuIndexFlat, QueryEmpty) {
126 faiss::gpu::StandardGpuResources res;
127 res.noTempMemory();
128
129 int dim = 128;
130 faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, 0, dim, false);
131
132 // Querying an empty index should not blow up, and just return
133 // (FLT_MAX, -1)
134 int numQuery = 10;
135 int k = 50;
136 std::vector<float> queries(numQuery * dim, 1.0f);
137
138 std::vector<float> dist(numQuery * k, 0);
139 std::vector<faiss::Index::idx_t> ind(numQuery * k);
140
141 gpuIndex.search(numQuery, queries.data(), k, dist.data(), ind.data());
142
143 for (auto d : dist) {
144 EXPECT_EQ(d, std::numeric_limits<float>::max());
145 }
146
147 for (auto i : ind) {
148 EXPECT_EQ(i, -1);
149 }
150 }
151
152 TEST(TestGpuIndexFlat, CopyFrom) {
153 faiss::gpu::newTestSeed();
154
155 int numVecs = faiss::gpu::randVal(100, 200);
156 int dim = faiss::gpu::randVal(1, 1000);
157
158 faiss::IndexFlatL2 cpuIndex(dim);
159
160 std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
161 cpuIndex.add(numVecs, vecs.data());
162
163 faiss::gpu::StandardGpuResources res;
164 res.noTempMemory();
165
166 // Fill with garbage values
167 int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
168 faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, device, 2000, false);
169 gpuIndex.copyFrom(&cpuIndex);
170
171 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
172 EXPECT_EQ(gpuIndex.ntotal, numVecs);
173
174 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
175 EXPECT_EQ(cpuIndex.d, dim);
176
177 int idx = faiss::gpu::randVal(0, numVecs - 1);
178
179 std::vector<float> gpuVals(dim);
180 gpuIndex.reconstruct(idx, gpuVals.data());
181
182 std::vector<float> cpuVals(dim);
183 cpuIndex.reconstruct(idx, cpuVals.data());
184
185 EXPECT_EQ(gpuVals, cpuVals);
186 }
187
188 TEST(TestGpuIndexFlat, CopyTo) {
189 faiss::gpu::newTestSeed();
190
191 faiss::gpu::StandardGpuResources res;
192 res.noTempMemory();
193
194 int numVecs = faiss::gpu::randVal(100, 200);
195 int dim = faiss::gpu::randVal(1, 1000);
196
197 int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
198 faiss::gpu::GpuIndexFlatL2 gpuIndex(&res, device, dim, false);
199
200 std::vector<float> vecs = faiss::gpu::randVecs(numVecs, dim);
201 gpuIndex.add(numVecs, vecs.data());
202
203 // Fill with garbage values
204 faiss::IndexFlatL2 cpuIndex(2000);
205 gpuIndex.copyTo(&cpuIndex);
206
207 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
208 EXPECT_EQ(gpuIndex.ntotal, numVecs);
209
210 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
211 EXPECT_EQ(cpuIndex.d, dim);
212
213 int idx = faiss::gpu::randVal(0, numVecs - 1);
214
215 std::vector<float> gpuVals(dim);
216 gpuIndex.reconstruct(idx, gpuVals.data());
217
218 std::vector<float> cpuVals(dim);
219 cpuIndex.reconstruct(idx, cpuVals.data());
220
221 EXPECT_EQ(gpuVals, cpuVals);
222 }
faiss::IndexFlat
Definition: IndexFlat.h:24
faiss::gpu::GpuIndexFlat::copyTo
void copyTo(faiss::IndexFlat *index) const
Definition: GpuIndexFlat.cu:107
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::StandardGpuResources
Definition: StandardGpuResources.h:24
faiss::gpu::GpuIndexFlat::reconstruct
void reconstruct(faiss::Index::idx_t key, float *out) const override
Definition: GpuIndexFlat.cu:440
faiss::Index::ntotal
idx_t ntotal
total nb of indexed vectors
Definition: Index.h:67
faiss::IndexFlat::add
virtual void add(idx_t n, const float *x) override
Definition: IndexFlat.cpp:41
faiss::gpu::GpuIndexFlatIP
Definition: GpuIndexFlat.h:158
faiss::gpu::GpuIndexFlat::copyFrom
void copyFrom(const faiss::IndexFlat *index)
Definition: GpuIndexFlat.cu:81
faiss::gpu::GpuIndexFlat::add
void add(Index::idx_t n, const float *x) override
Definition: GpuIndexFlat.cu:149
faiss::gpu::GpuIndexFlatL2
Definition: GpuIndexFlat.h:131
faiss::gpu::GpuIndexFlat
Definition: GpuIndexFlat.h:31
faiss::gpu::GpuIndexFlat::search
void search(faiss::Index::idx_t n, const float *x, faiss::Index::idx_t k, float *distances, faiss::Index::idx_t *labels) const override
Definition: GpuIndexFlat.cu:167