12 #include "../../IndexFlat.h"
13 #include "../../IndexIVFPQ.h"
14 #include "../GpuIndexIVFPQ.h"
15 #include "../StandardGpuResources.h"
16 #include "../utils/DeviceUtils.h"
17 #include "../test/TestUtils.h"
19 #include <gtest/gtest.h>
24 void pickEncoding(
int& codes,
int& dim) {
25 std::vector<int> codeSizes{
26 3, 4, 8, 12, 16, 20, 24,
27 28, 32, 40, 48, 56, 64, 96
30 std::vector<int> dimSizes{4, 8, 16, 32};
32 codes = codeSizes[faiss::gpu::randVal(0, codeSizes.size() - 1)];
35 dim = codes * dimSizes[faiss::gpu::randVal(0, dimSizes.size() - 1)];
39 if (dim < 512 && dim >= 64) {
47 numAdd = faiss::gpu::randVal(10000, 30000);
48 numCentroids = std::sqrt((
float) numAdd);
49 numTrain = numCentroids * 40;
51 pickEncoding(codes, dim);
53 bitsPerCode = faiss::gpu::randVal(3, 8);
54 nprobe = std::min(faiss::gpu::randVal(40, 1000), numCentroids);
55 numQuery = faiss::gpu::randVal(32, 256);
56 k = std::min(faiss::gpu::randVal(10, 50), numAdd / 40);
57 usePrecomputed = faiss::gpu::randBool();
58 indicesOpt = faiss::gpu::randSelect({
59 faiss::gpu::INDICES_CPU,
60 faiss::gpu::INDICES_32_BIT,
61 faiss::gpu::INDICES_64_BIT});
66 useFloat16 = faiss::gpu::randBool();
69 device = faiss::gpu::randVal(0, faiss::gpu::getNumDevices() - 1);
72 std::string toString()
const {
73 std::stringstream str;
74 str <<
"IVFPQ device " << device
75 <<
" numVecs " << numAdd
77 <<
" numCentroids " << numCentroids
79 <<
" bitsPerCode " << bitsPerCode
80 <<
" nprobe " << nprobe
81 <<
" numQuery " << numQuery
83 <<
" usePrecomputed " << usePrecomputed
84 <<
" indicesOpt " << indicesOpt
85 <<
" useFloat16 " << useFloat16;
90 float getCompareEpsilon()
const {
94 float getPctMaxDiff1()
const {
95 return useFloat16 ? 0.30f : 0.10f;
98 float getPctMaxDiffN()
const {
99 return useFloat16 ? 0.05f : 0.015f;
112 faiss::gpu::IndicesOptions indicesOpt;
117 TEST(TestGpuIndexIVFPQ, Query) {
118 for (
int tries = 0; tries < 5; ++tries) {
119 faiss::gpu::newTestSeed();
123 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
124 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
128 opt.codes, opt.bitsPerCode);
129 cpuIndex.nprobe = opt.nprobe;
130 cpuIndex.train(opt.numTrain, trainVecs.data());
131 cpuIndex.add(opt.numAdd, addVecs.data());
140 gpuIndex.setPrecomputedCodes(opt.usePrecomputed);
141 gpuIndex.setNumProbes(opt.nprobe);
143 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
144 opt.numQuery, opt.dim, opt.k, opt.toString(),
145 opt.getCompareEpsilon(),
146 opt.getPctMaxDiff1(),
147 opt.getPctMaxDiffN());
151 TEST(TestGpuIndexIVFPQ, Add) {
152 for (
int tries = 0; tries < 5; ++tries) {
153 faiss::gpu::newTestSeed();
157 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
158 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
162 opt.codes, opt.bitsPerCode);
163 cpuIndex.nprobe = opt.nprobe;
164 cpuIndex.train(opt.numTrain, trainVecs.data());
173 gpuIndex.setPrecomputedCodes(opt.usePrecomputed);
174 gpuIndex.setNumProbes(opt.nprobe);
176 gpuIndex.add(opt.numAdd, addVecs.data());
177 cpuIndex.add(opt.numAdd, addVecs.data());
179 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
180 opt.numQuery, opt.dim, opt.k, opt.toString(),
181 opt.getCompareEpsilon(),
182 opt.getPctMaxDiff1(),
183 opt.getPctMaxDiffN());
187 TEST(TestGpuIndexIVFPQ, CopyTo) {
188 faiss::gpu::newTestSeed();
191 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
192 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
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) {
237 faiss::gpu::newTestSeed();
240 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
241 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
245 opt.codes, opt.bitsPerCode);
246 cpuIndex.nprobe = opt.nprobe;
247 cpuIndex.train(opt.numTrain, trainVecs.data());
248 cpuIndex.add(opt.numAdd, addVecs.data());
255 1, 1, 1, 1,
false, opt.indicesOpt,
256 opt.useFloat16, faiss::METRIC_L2);
257 gpuIndex.setNumProbes(1);
259 gpuIndex.copyFrom(&cpuIndex);
262 EXPECT_EQ(cpuIndex.ntotal, gpuIndex.ntotal);
263 EXPECT_EQ(gpuIndex.ntotal, opt.numAdd);
265 EXPECT_EQ(cpuIndex.d, gpuIndex.d);
266 EXPECT_EQ(cpuIndex.d, opt.dim);
267 EXPECT_EQ(cpuIndex.nlist, gpuIndex.getNumLists());
268 EXPECT_EQ(cpuIndex.nprobe, gpuIndex.getNumProbes());
269 EXPECT_EQ(cpuIndex.pq.M, gpuIndex.getNumSubQuantizers());
270 EXPECT_EQ(gpuIndex.getNumSubQuantizers(), opt.codes);
271 EXPECT_EQ(cpuIndex.pq.nbits, gpuIndex.getBitsPerCode());
272 EXPECT_EQ(gpuIndex.getBitsPerCode(), opt.bitsPerCode);
275 faiss::gpu::compareIndices(cpuIndex, gpuIndex,
276 opt.numQuery, opt.dim, opt.k, opt.toString(),
277 opt.getCompareEpsilon(),
278 opt.getPctMaxDiff1(),
279 opt.getPctMaxDiffN());
282 TEST(TestGpuIndexIVFPQ, QueryNaN) {
283 faiss::gpu::newTestSeed();
287 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
288 std::vector<float> addVecs = faiss::gpu::randVecs(opt.numAdd, opt.dim);
303 gpuIndex.setPrecomputedCodes(opt.usePrecomputed);
304 gpuIndex.setNumProbes(opt.nprobe);
306 gpuIndex.train(opt.numTrain, trainVecs.data());
307 gpuIndex.add(opt.numAdd, addVecs.data());
310 std::vector<float> nans(numQuery * opt.dim,
311 std::numeric_limits<float>::quiet_NaN());
313 std::vector<float> distances(numQuery * opt.k, 0);
314 std::vector<faiss::Index::idx_t> indices(numQuery * opt.k, 0);
316 gpuIndex.search(numQuery,
322 for (
int q = 0; q < numQuery; ++q) {
323 for (
int k = 0; k < opt.k; ++k) {
324 EXPECT_EQ(indices[q * opt.k + k], -1);
325 EXPECT_EQ(distances[q * opt.k + k], std::numeric_limits<float>::max());
330 TEST(TestGpuIndexIVFPQ, AddNaN) {
331 faiss::gpu::newTestSeed();
348 gpuIndex.setPrecomputedCodes(opt.usePrecomputed);
349 gpuIndex.setNumProbes(opt.nprobe);
352 std::vector<float> nans(numNans * opt.dim,
353 std::numeric_limits<float>::quiet_NaN());
356 for (
int i = 0; i < opt.dim; ++i) {
360 std::vector<float> trainVecs = faiss::gpu::randVecs(opt.numTrain, opt.dim);
361 gpuIndex.train(opt.numTrain, trainVecs.data());
364 EXPECT_EQ(gpuIndex.ntotal, 0);
365 gpuIndex.add(numNans, nans.data());
368 EXPECT_EQ(gpuIndex.ntotal, 1);
370 std::vector<float> queryVecs = faiss::gpu::randVecs(opt.numQuery, opt.dim);
371 std::vector<float> distance(opt.numQuery * opt.k, 0);
372 std::vector<faiss::Index::idx_t> indices(opt.numQuery * opt.k, 0);
375 gpuIndex.search(opt.numQuery, queryVecs.data(), opt.k,
376 distance.data(), indices.data());