10 #include "../../IndexFlat.h"
11 #include "../../IndexIVFPQ.h"
12 #include "../GpuIndexIVFPQ.h"
13 #include "../StandardGpuResources.h"
14 #include "../utils/DeviceUtils.h"
15 #include "../test/TestUtils.h"
17 #include <gtest/gtest.h>
22 void pickEncoding(
int& codes,
int& dim) {
23 std::vector<int> codeSizes{
24 3, 4, 8, 12, 16, 20, 24,
25 28, 32, 40, 48, 56, 64, 96
29 std::vector<int> dimSizes{4, 8, 10, 12, 16, 20, 24, 28, 32};
32 codes = codeSizes[faiss::gpu::randVal(0, codeSizes.size() - 1)];
33 dim = codes * dimSizes[faiss::gpu::randVal(0, dimSizes.size() - 1)];
37 if (dim < 512 && dim >= 64) {
45 numAdd = faiss::gpu::randVal(10000, 30000);
46 numCentroids = std::sqrt((
float) numAdd);
47 numTrain = numCentroids * 40;
49 pickEncoding(codes, dim);
51 bitsPerCode = faiss::gpu::randVal(3, 8);
52 nprobe = std::min(faiss::gpu::randVal(40, 1000), numCentroids);
53 numQuery = faiss::gpu::randVal(32, 256);
54 k = std::min(faiss::gpu::randVal(10, 50), numAdd / 40);
55 usePrecomputed = faiss::gpu::randBool();
56 indicesOpt = faiss::gpu::randSelect({
57 faiss::gpu::INDICES_CPU,
58 faiss::gpu::INDICES_32_BIT,
59 faiss::gpu::INDICES_64_BIT});
64 useFloat16 = faiss::gpu::randBool();
67 device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
70 std::string toString()
const {
71 std::stringstream str;
72 str <<
"IVFPQ device " << device
73 <<
" numVecs " << numAdd
75 <<
" numCentroids " << numCentroids
77 <<
" bitsPerCode " << bitsPerCode
78 <<
" nprobe " << nprobe
79 <<
" numQuery " << numQuery
81 <<
" usePrecomputed " << usePrecomputed
82 <<
" indicesOpt " << indicesOpt
83 <<
" useFloat16 " << useFloat16;
88 float getCompareEpsilon()
const {
92 float getPctMaxDiff1()
const {
93 return useFloat16 ? 0.30f : 0.10f;
96 float getPctMaxDiffN()
const {
97 return useFloat16 ? 0.05f : 0.02f;
110 faiss::gpu::IndicesOptions indicesOpt;
115 TEST(TestGpuIndexIVFPQ, Query) {
116 for (
int tries = 0; tries < 5; ++tries) {
119 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
120 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
124 opt.codes, opt.bitsPerCode);
125 cpuIndex.nprobe = opt.nprobe;
126 cpuIndex.train(opt.numTrain, trainVecs.data());
127 cpuIndex.add(opt.numAdd, addVecs.data());
133 config.
device = opt.device;
139 gpuIndex.setNumProbes(opt.nprobe);
141 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
142 opt.numQuery, opt.dim, opt.k, opt.toString(),
143 opt.getCompareEpsilon(),
144 opt.getPctMaxDiff1(),
145 opt.getPctMaxDiffN());
149 TEST(TestGpuIndexIVFPQ, Add) {
150 for (
int tries = 0; tries < 5; ++tries) {
153 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
154 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
158 opt.codes, opt.bitsPerCode);
159 cpuIndex.nprobe = opt.nprobe;
160 cpuIndex.train(opt.numTrain, trainVecs.data());
166 config.
device = opt.device;
172 gpuIndex.setNumProbes(opt.nprobe);
174 gpuIndex.add(opt.numAdd, addVecs.data());
175 cpuIndex.add(opt.numAdd, addVecs.data());
177 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
178 opt.numQuery, opt.dim, opt.k, opt.toString(),
179 opt.getCompareEpsilon(),
180 opt.getPctMaxDiff1(),
181 opt.getPctMaxDiffN());
185 TEST(TestGpuIndexIVFPQ, CopyTo) {
187 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
188 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
194 config.
device = opt.device;
206 gpuIndex.setNumProbes(opt.nprobe);
207 gpuIndex.train(opt.numTrain, trainVecs.data());
208 gpuIndex.add(opt.numAdd, addVecs.data());
214 gpuIndex.copyTo(&cpuIndex);
216 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
217 EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
219 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
220 EXPECT_EQ(cpuIndex.d, opt.dim);
221 EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
222 EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
223 EXPECT_EQ(cpuIndex.pq.M, gpuIndex.getNumSubQuantizers());
224 EXPECT_EQ(gpuIndex.getNumSubQuantizers(), opt.codes);
225 EXPECT_EQ(cpuIndex.pq.nbits, gpuIndex.getBitsPerCode());
226 EXPECT_EQ(gpuIndex.getBitsPerCode(), opt.bitsPerCode);
229 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
230 opt.numQuery, opt.dim, opt.k, opt.toString(),
231 opt.getCompareEpsilon(),
232 opt.getPctMaxDiff1(),
233 opt.getPctMaxDiffN());
236 TEST(TestGpuIndexIVFPQ, CopyFrom) {
238 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
239 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
243 opt.codes, opt.bitsPerCode);
244 cpuIndex.nprobe = opt.nprobe;
245 cpuIndex.train(opt.numTrain, trainVecs.data());
246 cpuIndex.add(opt.numAdd, addVecs.data());
253 config.
device = opt.device;
259 gpuIndex(&res, 1, 1, 1, 1, faiss::METRIC_L2, config);
260 gpuIndex.setNumProbes(1);
262 gpuIndex.copyFrom(&cpuIndex);
265 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
266 EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
268 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
269 EXPECT_EQ(cpuIndex.d, opt.dim);
270 EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
271 EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
272 EXPECT_EQ(cpuIndex.pq.M, gpuIndex.getNumSubQuantizers());
273 EXPECT_EQ(gpuIndex.getNumSubQuantizers(), opt.codes);
274 EXPECT_EQ(cpuIndex.pq.nbits, gpuIndex.getBitsPerCode());
275 EXPECT_EQ(gpuIndex.getBitsPerCode(), opt.bitsPerCode);
278 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
279 opt.numQuery, opt.dim, opt.k, opt.toString(),
280 opt.getCompareEpsilon(),
281 opt.getPctMaxDiff1(),
282 opt.getPctMaxDiffN());
285 TEST(TestGpuIndexIVFPQ, QueryNaN) {
288 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
289 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
295 config.
device = opt.device;
308 gpuIndex.setNumProbes(opt.nprobe);
310 gpuIndex.train(opt.numTrain, trainVecs.data());
311 gpuIndex.add(opt.numAdd, addVecs.data());
314 std::vector<float> nans(numQuery * opt.dim,
315 std::numeric_limits<float>::quiet_NaN());
317 std::vector<float> distances(numQuery * opt.k, 0);
318 std::vector<faiss::Index::idx_t> indices(numQuery * opt.k, 0);
320 gpuIndex.search(numQuery,
326 for (
int q = 0; q < numQuery; ++q) {
327 for (
int k = 0; k < opt.k; ++k) {
328 EXPECT_EQ(indices[q * opt.k + k], -1);
329 EXPECT_EQ(distances[q * opt.k + k], std::numeric_limits<float>::max());
334 TEST(TestGpuIndexIVFPQ, AddNaN) {
341 config.
device = opt.device;
354 gpuIndex.setNumProbes(opt.nprobe);
357 std::vector<float> nans(numNans * opt.dim,
358 std::numeric_limits<float>::quiet_NaN());
361 for (
int i = 0; i < opt.dim; ++i) {
365 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
366 gpuIndex.train(opt.numTrain, trainVecs.data());
369 EXPECT_EQ(gpuIndex.ntotal, 0);
370 gpuIndex.add(numNans, nans.data());
373 EXPECT_EQ(gpuIndex.ntotal, 1);
375 std::vector<float> queryVecs = faiss::gpu::randVecs(opt.numQuery, opt.dim);
376 std::vector<float> distance(opt.numQuery * opt.k, 0);
377 std::vector<faiss::Index::idx_t> indices(opt.numQuery * opt.k, 0);
380 gpuIndex.search(opt.numQuery, queryVecs.data(), opt.k,
381 distance.data(), indices.data());
385 TEST(TestGpuIndexIVFPQ, UnifiedMemory) {
388 int device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
390 if (!faiss::gpu::getFullUnifiedMemSupport(device)) {
396 int numCentroids = 1024;
400 size_t numAdd = 100000;
401 size_t numTrain = numCentroids * 40;
408 std::vector<float> trainVecs = faiss::gpu::randVecs(numTrain, dim);
409 std::vector<float> addVecs = faiss::gpu::randVecs(numAdd, dim);
414 cpuIndex.train(numTrain, trainVecs.data());
415 cpuIndex.add(numAdd, addVecs.data());
416 cpuIndex.nprobe = nprobe;
423 config.
memorySpace = faiss::gpu::MemorySpace::Unified;
432 gpuIndex.copyFrom(&cpuIndex);
433 gpuIndex.setNumProbes(nprobe);
435 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
436 numQuery, dim, k,
"Unified Memory",
442 int main(
int argc,
char** argv) {
443 testing::InitGoogleTest(&argc, argv);
446 faiss::gpu::setTestSeed(100);
448 return RUN_ALL_TESTS();
bool usePrecomputedTables
bool useFloat16LookupTables
int device
GPU device on which the index is resident.
IndicesOptions indicesOptions
Index storage options for the GPU.