12 #include "../../IndexFlat.h"
13 #include "../../IndexIVF.h"
14 #include "../GpuIndexIVFFlat.h"
15 #include "../StandardGpuResources.h"
16 #include "../utils/DeviceUtils.h"
17 #include "../test/TestUtils.h"
18 #include <gtest/gtest.h>
23 constexpr
float kF16MaxRelErr = 0.3f;
24 constexpr
float kF32MaxRelErr = 0.03f;
29 numAdd = faiss::gpu::randVal(4000, 20000);
30 dim = faiss::gpu::randVal(64, 200);
32 numCentroids = std::sqrt((
float) numAdd);
33 numTrain = numCentroids * 40;
34 nprobe = faiss::gpu::randVal(10, numCentroids);
35 numQuery = faiss::gpu::randVal(32, 100);
36 k = std::min(faiss::gpu::randVal(10, 30), numAdd / 40);
37 indicesOpt = faiss::gpu::randSelect({
38 faiss::gpu::INDICES_CPU,
39 faiss::gpu::INDICES_32_BIT,
40 faiss::gpu::INDICES_64_BIT});
42 device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
45 std::string toString()
const {
46 std::stringstream str;
47 str <<
"IVFFlat device " << device
48 <<
" numVecs " << numAdd
50 <<
" numCentroids " << numCentroids
51 <<
" nprobe " << nprobe
52 <<
" numQuery " << numQuery
54 <<
" indicesOpt " << indicesOpt;
67 faiss::gpu::IndicesOptions indicesOpt;
71 bool useFloat16CoarseQuantizer,
73 int dimOverride = -1) {
74 for (
int tries = 0; tries < 3; ++tries) {
75 faiss::gpu::newTestSeed();
78 opt.dim = dimOverride != -1 ? dimOverride : opt.dim;
80 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
81 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
86 metricType == faiss::METRIC_L2 ?
90 opt.dim, opt.numCentroids, metricType);
91 cpuIndex.train(opt.numTrain, trainVecs.data());
92 cpuIndex.add(opt.numAdd, addVecs.data());
93 cpuIndex.nprobe = opt.nprobe;
100 useFloat16CoarseQuantizer,
105 cpuIndex.metric_type);
106 gpuIndex.copyFrom(&cpuIndex);
107 gpuIndex.setNumProbes(opt.nprobe);
109 bool compFloat16 = useFloat16CoarseQuantizer || useFloat16;
110 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
111 opt.numQuery, opt.dim, opt.k, opt.toString(),
112 compFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
116 compFloat16 ? 0.99f : 0.1f,
117 compFloat16 ? 0.65f : 0.015f);
122 bool useFloat16CoarseQuantizer,
124 for (
int tries = 0; tries < 5; ++tries) {
125 faiss::gpu::newTestSeed();
129 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
130 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
135 metricType == faiss::METRIC_L2 ?
142 cpuIndex.train(opt.numTrain, trainVecs.data());
143 cpuIndex.nprobe = opt.nprobe;
150 useFloat16CoarseQuantizer,
155 cpuIndex.metric_type);
156 gpuIndex.copyFrom(&cpuIndex);
157 gpuIndex.setNumProbes(opt.nprobe);
159 cpuIndex.add(opt.numAdd, addVecs.data());
160 gpuIndex.add(opt.numAdd, addVecs.data());
162 bool compFloat16 = useFloat16CoarseQuantizer || useFloat16;
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);
171 void copyToTest(
bool useFloat16CoarseQuantizer,
173 faiss::gpu::newTestSeed();
176 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
177 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
184 useFloat16CoarseQuantizer,
190 gpuIndex.train(opt.numTrain, trainVecs.data());
191 gpuIndex.add(opt.numAdd, addVecs.data());
192 gpuIndex.setNumProbes(opt.nprobe);
199 gpuIndex.copyTo(&cpuIndex);
201 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
202 EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
204 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
205 EXPECT_EQ(cpuIndex.d, opt.dim);
206 EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
207 EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
210 bool compFloat16 = useFloat16CoarseQuantizer || useFloat16;
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);
218 void copyFromTest(
bool useFloat16CoarseQuantizer,
220 faiss::gpu::newTestSeed();
223 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
224 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
231 cpuIndex.nprobe = opt.nprobe;
232 cpuIndex.train(opt.numTrain, trainVecs.data());
233 cpuIndex.add(opt.numAdd, addVecs.data());
241 useFloat16CoarseQuantizer,
247 gpuIndex.setNumProbes(1);
249 gpuIndex.copyFrom(&cpuIndex);
251 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
252 EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
254 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
255 EXPECT_EQ(cpuIndex.d, opt.dim);
256 EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
257 EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
260 bool compFloat16 = useFloat16CoarseQuantizer || useFloat16;
261 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
262 opt.numQuery, opt.dim, opt.k, opt.toString(),
263 compFloat16 ? kF16MaxRelErr : kF32MaxRelErr,
264 compFloat16 ? 0.70f : 0.1f,
265 compFloat16 ? 0.30f : 0.015f);
268 TEST(TestGpuIndexIVFFlat, Float32_32_Add_L2) {
269 addTest(faiss::METRIC_L2,
false,
false);
272 TEST(TestGpuIndexIVFFlat, Float32_32_Add_IP) {
273 addTest(faiss::METRIC_INNER_PRODUCT,
false,
false);
276 TEST(TestGpuIndexIVFFlat, Float32_16_Add_L2) {
277 addTest(faiss::METRIC_L2,
false,
true);
280 TEST(TestGpuIndexIVFFlat, Float32_16_Add_IP) {
281 addTest(faiss::METRIC_INNER_PRODUCT,
false,
true);
284 TEST(TestGpuIndexIVFFlat, Float16_32_Add_L2) {
285 addTest(faiss::METRIC_L2,
true,
false);
288 TEST(TestGpuIndexIVFFlat, Float16_32_Add_IP) {
289 addTest(faiss::METRIC_INNER_PRODUCT,
true,
false);
296 TEST(TestGpuIndexIVFFlat, Float32_Query_L2) {
297 queryTest(faiss::METRIC_L2,
false,
false);
300 TEST(TestGpuIndexIVFFlat, Float32_Query_IP) {
301 queryTest(faiss::METRIC_INNER_PRODUCT,
false,
false);
304 TEST(TestGpuIndexIVFFlat, Float16_Query_L2) {
305 queryTest(faiss::METRIC_L2,
false,
true);
308 TEST(TestGpuIndexIVFFlat, Float16_Query_IP) {
309 queryTest(faiss::METRIC_INNER_PRODUCT,
false,
true);
314 TEST(TestGpuIndexIVFFlat, Float16_32_Query_L2) {
315 queryTest(faiss::METRIC_L2,
true,
false);
318 TEST(TestGpuIndexIVFFlat, Float16_32_Query_IP) {
319 queryTest(faiss::METRIC_INNER_PRODUCT,
true,
false);
327 TEST(TestGpuIndexIVFFlat, Float32_Query_L2_64) {
328 queryTest(faiss::METRIC_L2,
false,
false, 64);
331 TEST(TestGpuIndexIVFFlat, Float32_Query_IP_64) {
332 queryTest(faiss::METRIC_INNER_PRODUCT,
false,
false, 64);
335 TEST(TestGpuIndexIVFFlat, Float16_Query_L2_64) {
336 queryTest(faiss::METRIC_L2,
false,
true, 64);
339 TEST(TestGpuIndexIVFFlat, Float16_Query_IP_64) {
340 queryTest(faiss::METRIC_INNER_PRODUCT,
false,
true, 64);
343 TEST(TestGpuIndexIVFFlat, Float32_Query_L2_128) {
344 queryTest(faiss::METRIC_L2,
false,
false, 128);
347 TEST(TestGpuIndexIVFFlat, Float32_Query_IP_128) {
348 queryTest(faiss::METRIC_INNER_PRODUCT,
false,
false, 128);
351 TEST(TestGpuIndexIVFFlat, Float16_Query_L2_128) {
352 queryTest(faiss::METRIC_L2,
false,
true, 128);
355 TEST(TestGpuIndexIVFFlat, Float16_Query_IP_128) {
356 queryTest(faiss::METRIC_INNER_PRODUCT,
false,
true, 128);
361 TEST(TestGpuIndexIVFFlat, Float16_Query_L2_256) {
362 queryTest(faiss::METRIC_L2,
false,
true, 256);
365 TEST(TestGpuIndexIVFFlat, Float16_Query_IP_256) {
366 queryTest(faiss::METRIC_INNER_PRODUCT,
false,
true, 256);
373 TEST(TestGpuIndexIVFFlat, Float32_16_CopyTo) {
374 copyToTest(
false,
true);
377 TEST(TestGpuIndexIVFFlat, Float32_32_CopyTo) {
378 copyToTest(
false,
false);
385 TEST(TestGpuIndexIVFFlat, QueryNaN) {
386 faiss::gpu::newTestSeed();
390 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
391 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
398 faiss::gpu::randBool(),
399 faiss::gpu::randBool(),
404 gpuIndex.setNumProbes(opt.nprobe);
406 gpuIndex.train(opt.numTrain, trainVecs.data());
407 gpuIndex.add(opt.numAdd, addVecs.data());
410 std::vector<float> nans(numQuery * opt.dim,
411 std::numeric_limits<float>::quiet_NaN());
413 std::vector<float> distances(numQuery * opt.k, 0);
414 std::vector<faiss::Index::idx_t> indices(numQuery * opt.k, 0);
416 gpuIndex.search(numQuery,
422 for (
int q = 0; q < numQuery; ++q) {
423 for (
int k = 0; k < opt.k; ++k) {
424 EXPECT_EQ(indices[q * opt.k + k], -1);
425 EXPECT_EQ(distances[q * opt.k + k], std::numeric_limits<float>::max());
430 TEST(TestGpuIndexIVFFlat, AddNaN) {
431 faiss::gpu::newTestSeed();
440 faiss::gpu::randBool(),
441 faiss::gpu::randBool(),
446 gpuIndex.setNumProbes(opt.nprobe);
449 std::vector<float> nans(numNans * opt.dim,
450 std::numeric_limits<float>::quiet_NaN());
453 for (
int i = 0; i < opt.dim; ++i) {
457 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
458 gpuIndex.train(opt.numTrain, trainVecs.data());
461 EXPECT_EQ(gpuIndex.ntotal, 0);
462 gpuIndex.add(numNans, nans.data());
465 EXPECT_EQ(gpuIndex.ntotal, 1);
467 std::vector<float> queryVecs = faiss::gpu::randVecs(opt.numQuery, opt.dim);
468 std::vector<float> distance(opt.numQuery * opt.k, 0);
469 std::vector<faiss::Index::idx_t> indices(opt.numQuery * opt.k, 0);
472 gpuIndex.search(opt.numQuery, queryVecs.data(), opt.k,
473 distance.data(), indices.data());
MetricType
Some algorithms support both an inner product vetsion and a L2 search version.