Skip to content

Commit 1e7ef59

Browse files
Amir Sadoughifacebook-github-bot
Amir Sadoughi
authored andcommitted
demo: IndexPQ: separate codes from codebook (facebookresearch#3987)
Summary: Pull Request resolved: facebookresearch#3987 Created a new notebook demonstrating how to separate serializing and deserializing the PQ codebook (via faiss.write_index for IndexPQ) independently of the vector codes. For example, in the case where you have a few vector embeddings per user and want to shard the flat index by user you can re-use the same PQ method for all users but store each user's codes independently. Reviewed By: junjieqi Differential Revision: D64844978 fbshipit-source-id: ad6434101fbb3ef84999527a577ecb9b503e556c
1 parent 9c3cd77 commit 1e7ef59

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#!/usr/bin/env -S grimaldi --kernel bento_kernel_faiss
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
#
4+
# This source code is licensed under the MIT license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
# fmt: off
8+
# flake8: noqa
9+
10+
11+
""":md
12+
# IndexPQ: separate codes from codebook
13+
14+
This notebook demonstrates how to separate serializing and deserializing the PQ codebook
15+
(via faiss.write_index for IndexPQ) independently of the vector codes. For example, in the case
16+
where you have a few vector embeddings per user and want to shard the flat index by user you
17+
can re-use the same PQ method for all users but store each user's codes independently.
18+
19+
"""
20+
21+
""":py"""
22+
import faiss
23+
import numpy as np
24+
25+
""":py"""
26+
d = 768
27+
n = 10000
28+
ids = np.arange(n).astype('int64')
29+
training_data = np.random.rand(n, d).astype('float32')
30+
M = d//8
31+
nbits = 8
32+
33+
""":py"""
34+
def read_ids_codes():
35+
try:
36+
return np.load("/tmp/ids.npy"), np.load("/tmp/codes.npy")
37+
except FileNotFoundError:
38+
return None, None
39+
40+
41+
def write_ids_codes(ids, codes):
42+
# print(ids, codes)
43+
np.save("/tmp/ids.npy", ids)
44+
np.save("/tmp/codes.npy", codes.reshape(len(ids), -1))
45+
46+
47+
def write_template_index(template_index):
48+
faiss.write_index(template_index, "/tmp/template.index")
49+
50+
51+
def read_template_index_instance():
52+
pq_index = faiss.read_index("/tmp/template.index")
53+
return pq_index, faiss.IndexIDMap2(pq_index)
54+
55+
""":py"""
56+
# at train time
57+
58+
template_index = faiss.IndexPQ(d, M, nbits)
59+
template_index.train(training_data)
60+
write_template_index(template_index)
61+
62+
""":py"""
63+
# New database vector
64+
65+
template_instance_index, id_wrapper_index = read_template_index_instance()
66+
database_vector_id, database_vector_float32 = np.int64(
67+
np.random.rand() * 10000
68+
), np.random.rand(1, d).astype("float32")
69+
ids, codes = read_ids_codes()
70+
# print(ids, codes)
71+
code = template_instance_index.sa_encode(database_vector_float32)
72+
if ids is not None and codes is not None:
73+
ids = np.concatenate((ids, [database_vector_id]))
74+
codes = np.vstack((codes, code))
75+
else:
76+
ids = np.array([database_vector_id])
77+
codes = np.array([code])
78+
write_ids_codes(ids, codes)
79+
80+
""":py '1545041403561975'"""
81+
# then at query time
82+
query_vector_float32 = np.random.rand(1, d).astype("float32")
83+
template_index_instance, id_wrapper_index = read_template_index_instance()
84+
ids, codes = read_ids_codes()
85+
86+
for code in codes:
87+
for c in code:
88+
template_index_instance.codes.push_back(int(c))
89+
template_index_instance.ntotal = len(codes)
90+
for i in ids:
91+
id_wrapper_index.id_map.push_back(int(i))
92+
93+
id_wrapper_index.search(query_vector_float32, k=5)
94+
95+
""":py"""
96+
!rm /tmp/ids.npy /tmp/codes.npy /tmp/template.index

0 commit comments

Comments
 (0)