Faiss对一些基础算法提供了很是高效的实现:k-means、PCA、PQ编解码。算法
聚类
假设2维tensor x:app
ncentroids = 1024 niter = 20 verbose = True d = x.shape[1] kmeans = faiss.Kmeans(d, ncentroids, niter, verbose) kmeans.train(x)
中心点放在kmeans.centroids中,目标函数的值放在kmeans.obj中。返回查询数据最近的中心点:dom
D, I = kmeans.index.search(x, 1)
返回某个测试数据集中离各个中心点最近的15个点。函数
index = faiss.IndexFlatL2 (d) index.add (x) D, I = index.search (kmeans.centroids, 15)
经过调整索引能够放到GPU上运行。测试
PCA降维
从40维下降到10维度this
# random training data mt = np.random.rand(1000, 40).astype('float32') mat = faiss.PCAMatrix (40, 10) mat.train(mt) assert mat.is_trained tr = mat.apply_py(mt) # print this to show that the magnitude of tr's columns is decreasing print (tr ** 2).sum(0)
ProductQuantizer(PQ)
d = 32 # data dimension cs = 4 # code size (bytes) # train set nt = 10000 xt = np.random.rand(nt, d).astype('float32') # dataset to encode (could be same as train) n = 20000 x = np.random.rand(n, d).astype('float32') pq = faiss.ProductQuantizer(d, cs, 8) pq.train(xt) # encode codes = pq.compute_codes(x) # decode x2 = pq.decode(codes) # compute reconstruction error avg_relative_error = ((x - x2)**2).sum() / (x ** 2).sum()
标量量化器(每一维度量化)
d = 32 # data dimension # train set nt = 10000 xt = np.random.rand(nt, d).astype('float32') # dataset to encode (could be same as train) n = 20000 x = np.random.rand(n, d).astype('float32') # QT_8bit allocates 8 bits per dimension (QT_4bit also works) sq = faiss.ScalarQuantizer(d, faiss.ScalarQuantizer.QT_8bit) sq.train(xt) # encode codes = sq.compute_codes(x) # decode x2 = sq.decode(codes) # compute reconstruction error avg_relative_error = ((x - x2)**2).sum() / (x ** 2).sum()
选择索引的策略
推荐使用index_factory,经过参数建立索引。spa
- Flat 提供数据集的基准结果,不压缩向量,也不支持添加id;若是须要 add_with_ids,使用“IDMap,Flat”参数。 无需训练,支持GPU.
Faiss的索引都是放在RAM中的,因此也就要考虑到内存的占用。code
-
HNSWx 足够的内存,小的数据集。每一个向量的links数目x范围[4,64],经过efSearch参数折中速度和精度,每一个向量的内存占用为d4+x2*4个字节。 不支持add_with_ids(如须要添加IDMap),无需训练,不支持从索引中移除向量,不支持GPU索引
-
xxx,Flat xxx表示提早为数据作了聚类,如IVFFlat,经过nprobe这种速度和精度,支持GPU(聚类方法也支持的状况下)。内存
-
PCARx,...,SQ8 存储整改向量占用资源太多,能够PCA降到x维度;SQ每项用一个字节表示。这样每一个向量只占用x个字节的存储空间。不支持GPU。
-
OPQx_y,...,PQx PQx中x是字节数,一般<=64,若是更大采用SQ更为高效。OPQ是对数据作了线性变换更利于数据压缩,y表示:x的倍数、y<=d且y<4*x(推荐)。x表示OPQ中的分割参数,y才是最终切分结果。支持GPU。
从数据集大小的角度(数据量、训练数据大小):
-
少于1百万,使用...,IVFx,... 数据集大小为N,x为[4sqrt(N),16sqrt(N)]。使用K-menas进行聚类,咱们须要[30x,256x]个向量进行训练(固然越多越好)。支持GPU。
-
1百万 < N < 1千万,使用...,IMI2x10,... IMI在训练数据集中经过kmeans获得2^10个中心点。但它是对向量的先后两半分别进行的聚类,也就是获得的2^10^2=2^20个中心描述。咱们须要64*2^10个训练样本。不支持GPU。
-
1千万 < N < 1个亿,使用...,IMI2x12,... 同上,只是增长了聚类数。
-
1亿 < N < 10亿,使用...,IMI2x14,... 同上。