11 #include "../../IndexFlat.h"
12 #include "../../IndexIVFPQ.h"
13 #include "../GpuIndexIVFPQ.h"
14 #include "../StandardGpuResources.h"
15 #include "../utils/DeviceUtils.h"
16 #include "../test/TestUtils.h"
18 #include <gtest/gtest.h>
23 void pickEncoding(
int& codes,
int& dim) {
24 std::vector<int> codeSizes{
25 3, 4, 8, 12, 16, 20, 24,
26 28, 32, 40, 48, 56, 64, 96
29 std::vector<int> dimSizes{4, 8, 16, 32};
31 codes = codeSizes[faiss::gpu::randVal(0, codeSizes.size() - 1)];
34 dim = codes * dimSizes[faiss::gpu::randVal(0, dimSizes.size() - 1)];
38 if (dim < 512 && dim >= 64) {
46 numAdd = faiss::gpu::randVal(10000, 30000);
47 numCentroids = std::sqrt((
float) numAdd);
48 numTrain = numCentroids * 40;
50 pickEncoding(codes, dim);
52 bitsPerCode = faiss::gpu::randVal(3, 8);
53 nprobe = std::min(faiss::gpu::randVal(40, 1000), numCentroids);
54 numQuery = faiss::gpu::randVal(32, 256);
55 k = std::min(faiss::gpu::randVal(10, 50), numAdd / 40);
56 usePrecomputed = faiss::gpu::randBool();
57 indicesOpt = faiss::gpu::randSelect({
58 faiss::gpu::INDICES_CPU,
59 faiss::gpu::INDICES_32_BIT,
60 faiss::gpu::INDICES_64_BIT});
65 useFloat16 = faiss::gpu::randBool();
68 device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
71 std::string toString()
const {
72 std::stringstream str;
73 str <<
"IVFPQ device " << device
74 <<
" numVecs " << numAdd
76 <<
" numCentroids " << numCentroids
78 <<
" bitsPerCode " << bitsPerCode
79 <<
" nprobe " << nprobe
80 <<
" numQuery " << numQuery
82 <<
" usePrecomputed " << usePrecomputed
83 <<
" indicesOpt " << indicesOpt
84 <<
" useFloat16 " << useFloat16;
89 float getCompareEpsilon()
const {
93 float getPctMaxDiff1()
const {
94 return useFloat16 ? 0.30f : 0.10f;
97 float getPctMaxDiffN()
const {
98 return useFloat16 ? 0.05f : 0.015f;
111 faiss::gpu::IndicesOptions indicesOpt;
116 TEST(TestGpuIndexIVFPQ, Query) {
117 for (
int tries = 0; tries < 5; ++tries) {
118 faiss::gpu::newTestSeed();
122 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
123 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
127 opt.codes, opt.bitsPerCode);
128 cpuIndex.nprobe = opt.nprobe;
129 cpuIndex.train(opt.numTrain, trainVecs.data());
130 cpuIndex.add(opt.numAdd, addVecs.data());
136 config.
device = opt.device;
142 gpuIndex.setNumProbes(opt.nprobe);
144 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
145 opt.numQuery, opt.dim, opt.k, opt.toString(),
146 opt.getCompareEpsilon(),
147 opt.getPctMaxDiff1(),
148 opt.getPctMaxDiffN());
152 TEST(TestGpuIndexIVFPQ, Add) {
153 for (
int tries = 0; tries < 5; ++tries) {
154 faiss::gpu::newTestSeed();
158 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
159 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
163 opt.codes, opt.bitsPerCode);
164 cpuIndex.nprobe = opt.nprobe;
165 cpuIndex.train(opt.numTrain, trainVecs.data());
171 config.
device = opt.device;
177 gpuIndex.setNumProbes(opt.nprobe);
179 gpuIndex.add(opt.numAdd, addVecs.data());
180 cpuIndex.add(opt.numAdd, addVecs.data());
182 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
183 opt.numQuery, opt.dim, opt.k, opt.toString(),
184 opt.getCompareEpsilon(),
185 opt.getPctMaxDiff1(),
186 opt.getPctMaxDiffN());
190 TEST(TestGpuIndexIVFPQ, CopyTo) {
191 faiss::gpu::newTestSeed();
194 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
195 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
201 config.
device = opt.device;
213 gpuIndex.setNumProbes(opt.nprobe);
214 gpuIndex.train(opt.numTrain, trainVecs.data());
215 gpuIndex.add(opt.numAdd, addVecs.data());
221 gpuIndex.copyTo(&cpuIndex);
223 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
224 EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
226 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
227 EXPECT_EQ(cpuIndex.d, opt.dim);
228 EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
229 EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
230 EXPECT_EQ(cpuIndex.pq.M, gpuIndex.getNumSubQuantizers());
231 EXPECT_EQ(gpuIndex.getNumSubQuantizers(), opt.codes);
232 EXPECT_EQ(cpuIndex.pq.nbits, gpuIndex.getBitsPerCode());
233 EXPECT_EQ(gpuIndex.getBitsPerCode(), opt.bitsPerCode);
236 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
237 opt.numQuery, opt.dim, opt.k, opt.toString(),
238 opt.getCompareEpsilon(),
239 opt.getPctMaxDiff1(),
240 opt.getPctMaxDiffN());
243 TEST(TestGpuIndexIVFPQ, CopyFrom) {
244 faiss::gpu::newTestSeed();
247 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
248 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
252 opt.codes, opt.bitsPerCode);
253 cpuIndex.nprobe = opt.nprobe;
254 cpuIndex.train(opt.numTrain, trainVecs.data());
255 cpuIndex.add(opt.numAdd, addVecs.data());
262 config.
device = opt.device;
268 gpuIndex(&res, 1, 1, 1, 1, faiss::METRIC_L2, config);
269 gpuIndex.setNumProbes(1);
271 gpuIndex.copyFrom(&cpuIndex);
274 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
275 EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
277 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
278 EXPECT_EQ(cpuIndex.d, opt.dim);
279 EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
280 EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
281 EXPECT_EQ(cpuIndex.pq.M, gpuIndex.getNumSubQuantizers());
282 EXPECT_EQ(gpuIndex.getNumSubQuantizers(), opt.codes);
283 EXPECT_EQ(cpuIndex.pq.nbits, gpuIndex.getBitsPerCode());
284 EXPECT_EQ(gpuIndex.getBitsPerCode(), opt.bitsPerCode);
287 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
288 opt.numQuery, opt.dim, opt.k, opt.toString(),
289 opt.getCompareEpsilon(),
290 opt.getPctMaxDiff1(),
291 opt.getPctMaxDiffN());
294 TEST(TestGpuIndexIVFPQ, QueryNaN) {
295 faiss::gpu::newTestSeed();
299 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
300 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
306 config.
device = opt.device;
319 gpuIndex.setNumProbes(opt.nprobe);
321 gpuIndex.train(opt.numTrain, trainVecs.data());
322 gpuIndex.add(opt.numAdd, addVecs.data());
325 std::vector<float> nans(numQuery * opt.dim,
326 std::numeric_limits<float>::quiet_NaN());
328 std::vector<float> distances(numQuery * opt.k, 0);
329 std::vector<faiss::Index::idx_t> indices(numQuery * opt.k, 0);
331 gpuIndex.search(numQuery,
337 for (
int q = 0; q < numQuery; ++q) {
338 for (
int k = 0; k < opt.k; ++k) {
339 EXPECT_EQ(indices[q * opt.k + k], -1);
340 EXPECT_EQ(distances[q * opt.k + k], std::numeric_limits<float>::max());
345 TEST(TestGpuIndexIVFPQ, AddNaN) {
346 faiss::gpu::newTestSeed();
354 config.
device = opt.device;
367 gpuIndex.setNumProbes(opt.nprobe);
370 std::vector<float> nans(numNans * opt.dim,
371 std::numeric_limits<float>::quiet_NaN());
374 for (
int i = 0; i < opt.dim; ++i) {
378 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
379 gpuIndex.train(opt.numTrain, trainVecs.data());
382 EXPECT_EQ(gpuIndex.ntotal, 0);
383 gpuIndex.add(numNans, nans.data());
386 EXPECT_EQ(gpuIndex.ntotal, 1);
388 std::vector<float> queryVecs = faiss::gpu::randVecs(opt.numQuery, opt.dim);
389 std::vector<float> distance(opt.numQuery * opt.k, 0);
390 std::vector<faiss::Index::idx_t> indices(opt.numQuery * opt.k, 0);
393 gpuIndex.search(opt.numQuery, queryVecs.data(), opt.k,
394 distance.data(), indices.data());
398 TEST(TestGpuIndexIVFPQ, UnifiedMemory) {
401 int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
403 if (!faiss::gpu::getFullUnifiedMemSupport(device)) {
409 int numCentroids = 1024;
413 size_t numAdd = 100000;
414 size_t numTrain = numCentroids * 40;
421 std::vector<float> trainVecs = faiss::gpu::randVecs(numTrain, dim);
422 std::vector<float> addVecs = faiss::gpu::randVecs(numAdd, dim);
427 cpuIndex.train(numTrain, trainVecs.data());
428 cpuIndex.add(numAdd, addVecs.data());
429 cpuIndex.nprobe = nprobe;
436 config.
memorySpace = faiss::gpu::MemorySpace::Unified;
445 gpuIndex.copyFrom(&cpuIndex);
446 gpuIndex.setNumProbes(nprobe);
448 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
449 numQuery, dim, k,
"Unified Memory",
bool usePrecomputedTables
bool useFloat16LookupTables
int device
GPU device on which the index is resident.
IndicesOptions indicesOptions
Index storage options for the GPU.