Faiss(三)索引的选择

从精确度、内存、数据集大小等几个方面考虑选择合适的索引

需要精确的结果吗?------IndexFlatL2或者IndexFlatIP

如果需要精确的结果,就只能选择IndexFlatL2或者IndexFlatIP,这是保证精确搜索的唯一索引,可以作为其他索引结果的参考基线。它不压缩向量,但也不会增加额外的开销,顺序添加id,不支持add_with_ids,除非使用"IDMap Flat"。该索引不需要训练,没有参数。

支持GPU

需要考虑内存吗?

所有的Faiss索引都是存储在RAM中的,如果RAM容量是一个限制因素,在选择索引时应该对精确度-速度进行权衡。

(1)内存完全不是问题------HNSWM或者IVF1024,PQNx4fs,RFlat

如果RAM很大或者数据集比较小的话,既快又准的HNSW是最佳选择。M(4~64之间)是每个节点连接的最大节点数,M越大搜索越精确,但需要的RAM越大。通过参数efSearch进行精确度-速度的权衡。

HNSW同样不支持add_with_ids,需要使用IDMap。不需要训练,不支持从索引中移除向量。

第二个索引比HNSW更快,但是需要一个re-ranking阶段,要调整两个参数:reranking的k_factor和IVF的nprobe。

不支持GPU

(2)内存有一点影响------"...,Flat"

"..."表示对数据库进行聚类的预处理操作。聚类之后,依然通过"Flat"的方式进行检索,如前所说,并不对向量进行压缩,所以存储容量和原始数据库一样。精确度-速度权衡参数的nprobe。

支持GPU

(3)节省内存还挺重要的------OPQ M_D,...,PQ M x4fsr

如果存储整个向量内存消耗太大,可以通过降维和压缩减少存储:OPQ将原始向量降到D维,PQ将D维向量量化成M个4bits的编码。

支持GPU

(4)内存很紧缺,节省内存相当重要------OPQ M_D,...,PQ M

PQ M通过乘积量化将向量压缩编码成M(通常M<=64)字节,对于较大的编码,SQ更准确更快。D应该是M的整数倍,最好D=4M。

支持GPU

数据集多大?

数据集的大小涉及聚类的选择(上面提到的"...")。数据集被聚类成nlist个子数据集,搜索时只有部分子数据集(nprobe个)被访问。聚类是在数据集向量的代表性样本上执行的,通常是数据集的一个样本。

1M以下------"...,IVF K,..."

其中4*sqrt(N) <= K <=16*sqrt(N),N是数据集的向量个数。聚类方法是k-means,需要30*K到256*K个向量进行训练,当然越多越好。

1M-10M------"...,IVF65536_HNSW32,..."

IVF与HNSW结合,使用HNSW进行聚类。需要30*65536到256*65536个向量来进行训练。

10M-100M------"...,IVF262144_HNSW32,..."

和上面一种情况一样,只是将65536换成了262144(2^18)。

这个时候训练过程会很慢,可以采取一些措施加快训练:

训练在GPU上进行,其他的过程在CPU上;

示例代码:

index = faiss.index_factory(128, "PCA64,IVF16384_HNSW32,Flat")    # 建立索引
index_ivf = faiss.extract_index_ivf(index)
clustering_index = faiss.index_cpu_to_all_gpus(faiss.IndexFlatL2(index_ivf.d))
index_ivf.clustering_index = clustering_index
# training with GPU
index.train(xt)   # xt是训练数据

采用两级聚类;

示例代码见demo_two_level_clustering.ipynb · GitHub

100M-1B------"...,IVF1048576_HNSW32,..."

将65536换成1048576(2^20),训练过程会更慢。

参考链接:https://github.com/facebookresearch/faiss/wiki/Guidelines-to-choose-an-index

你可能感兴趣的:(Faiss,python,聚类,算法)