Skip to content

Commit 70c4537

Browse files
simshifacebook-github-bot
authored andcommitted
fix: algorithm of spreading vectors over shards (#4299)
Summary: #3374 has a typo, my local repo has the correct fixing (find it when sync from recent v1.10), the intended fixing is: for example, if we have `n = 10`, and `nshards = 8` - the original buggy code ```c++ size_t shard_size = (n + nshards - 1) / nshards; // i.e. shard_size = (10 + 8 - 1) / 8 = 2 size_t i0 = idx * shard_size; // all i0: [0, 2, 4, 6, 8, 10, 12, 14], wrong!!! 14>n size_t ni = std::min(shard_size, n - i0); // all ni: [2, 2, 2, 2, 2, 0, -2, -4], wrong!!! ``` - should be: ```c++ size_t base_shard_size = n / nshards; // i.e. shard_size = 10 / 8 = 1 size_t i0 = idx * base_shard_size + std::min(size_t(idx), n % nshards); // all i0: [0, 2, 4, 5, 6, 7, 8, 9] size_t ni = base_shard_size; if (idx < n % nshards) { ++ni; } // all ni: [2, 2, 1, 1, 1, 1, 1, 1] ``` Pull Request resolved: #4299 Reviewed By: junjieqi Differential Revision: D73199869 Pulled By: mnorris11 fbshipit-source-id: 81cbb8284818212781978412262e91d7747f9b97
1 parent d4fa401 commit 70c4537

File tree

3 files changed

+114
-1
lines changed

3 files changed

+114
-1
lines changed

faiss/gpu/GpuIcmEncoder.cu

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ void GpuIcmEncoder::encode(
9696
auto fn = [=](int idx, IcmEncoderImpl* encoder) {
9797
size_t i0 = idx * base_shard_size + std::min(size_t(idx), n % nshards);
9898
size_t ni = base_shard_size;
99-
if (ni < n % nshards) {
99+
if (idx < n % nshards) {
100100
++ni;
101101
}
102102
if (ni <= 0) { // only if n < nshards

faiss/gpu/test/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ faiss_gpu_test(TestGpuIndexFlat.cpp)
4343
faiss_gpu_test(TestGpuIndexIVFFlat.cpp)
4444
faiss_gpu_test(TestGpuIndexBinaryFlat.cpp)
4545
faiss_gpu_test(TestGpuMemoryException.cpp)
46+
faiss_gpu_test(TestGpuIcmEncoder.cpp)
4647
faiss_gpu_test(TestGpuIndexIVFPQ.cpp)
4748
faiss_gpu_test(TestGpuIndexIVFScalarQuantizer.cpp)
4849
faiss_gpu_test(TestGpuResidualQuantizer.cpp)
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
#include <faiss/gpu/GpuIcmEncoder.h>
2+
#include <faiss/gpu/StandardGpuResources.h>
3+
#include <faiss/gpu/test/TestUtils.h>
4+
#include <faiss/impl/LocalSearchQuantizer.h>
5+
6+
#include <gtest/gtest.h>
7+
#include <tuple>
8+
#include <vector>
9+
10+
using faiss::LocalSearchQuantizer;
11+
using faiss::gpu::GpuIcmEncoder;
12+
using faiss::gpu::GpuResourcesProvider;
13+
using faiss::gpu::StandardGpuResources;
14+
15+
struct ShardingTestParams {
16+
size_t n;
17+
size_t nshards;
18+
};
19+
20+
class GpuIcmEncoderShardingTest
21+
: public ::testing::TestWithParam<ShardingTestParams> {
22+
protected:
23+
void SetUp() override {
24+
params = GetParam();
25+
26+
lsq.M = 4;
27+
lsq.K = 16;
28+
lsq.d = 32;
29+
30+
std::uniform_real_distribution<float> dist(-1.0f, 1.0f);
31+
lsq.codebooks.resize(lsq.M * lsq.K * lsq.d);
32+
for (auto& v : lsq.codebooks) {
33+
v = dist(gen);
34+
}
35+
36+
x.resize(params.n * lsq.d);
37+
codes.resize(params.n * lsq.M);
38+
39+
for (auto& v : x) {
40+
v = dist(gen);
41+
}
42+
43+
std::uniform_int_distribution<int32_t> codeDist(0, lsq.K - 1);
44+
for (auto& c : codes) {
45+
c = codeDist(gen);
46+
}
47+
}
48+
49+
LocalSearchQuantizer lsq;
50+
std::vector<float> x;
51+
std::vector<int32_t> codes;
52+
std::mt19937 gen;
53+
ShardingTestParams params;
54+
static constexpr size_t ils_iters = 4;
55+
};
56+
57+
TEST_P(GpuIcmEncoderShardingTest, DataShardingCorrectness) {
58+
std::vector<StandardGpuResources> resources(params.nshards);
59+
std::vector<GpuResourcesProvider*> provs;
60+
std::vector<int> devices;
61+
62+
for (size_t i = 0; i < params.nshards; ++i) {
63+
resources[i].noTempMemory();
64+
provs.push_back(&resources[i]);
65+
devices.push_back(0); // use GPU 0 for testing all shards
66+
}
67+
68+
GpuIcmEncoder encoder(&lsq, provs, devices);
69+
encoder.set_binary_term();
70+
71+
gen.seed(42);
72+
EXPECT_NO_THROW(
73+
encoder.encode(codes.data(), x.data(), gen, params.n, ils_iters));
74+
75+
for (auto c : codes) {
76+
EXPECT_GE(c, 0);
77+
EXPECT_LT(c, lsq.K);
78+
}
79+
}
80+
81+
std::vector<ShardingTestParams> GetShardingTestCases() {
82+
return {
83+
{1, 8},
84+
85+
{5, 4},
86+
87+
{10, 2},
88+
{10, 3},
89+
{10, 5},
90+
{10, 8},
91+
92+
{20, 8},
93+
};
94+
}
95+
96+
INSTANTIATE_TEST_SUITE_P(
97+
MultiGpuShardingTests,
98+
GpuIcmEncoderShardingTest,
99+
::testing::ValuesIn(GetShardingTestCases()),
100+
[](const ::testing::TestParamInfo<ShardingTestParams>& info) {
101+
return "n" + std::to_string(info.param.n) + "_shards" +
102+
std::to_string(info.param.nshards);
103+
});
104+
105+
int main(int argc, char** argv) {
106+
testing::InitGoogleTest(&argc, argv);
107+
108+
// just run with a fixed test seed
109+
faiss::gpu::setTestSeed(100);
110+
111+
return RUN_ALL_TESTS();
112+
}

0 commit comments

Comments
 (0)