1. 程式人生 > >【4】facebook大數據搜索庫faiss使用——Faiss索引介紹

【4】facebook大數據搜索庫faiss使用——Faiss索引介紹

source http 哈希函數 位數 對象 兩個 目的 ebo rank

基礎索引如下所示:

  • 精確索引(IndexFlatL2): 主要參數d;占用字節4d;是否窮盡式搜索:是;
  • 內積精確檢索(IndexFlatIP):d;4d;是;
  • 級聯式圖搜索(IndexHNSWFlat):d,M; 4d+8M; 否;
  • 倒置文件與精確後檢驗(IndexIVFFlat):quantizer,d,nlists,metric; 4d;否
  • 局部感應哈希(iNDEXlsh): d,nbits; nbits/8; 是
  • 標量量化(IndexScalarQuantizer):d; d; 是
  • PQ(IndexPQ): d, M, nbits; M(nbits=8); 是
  • 倒排文件+標量量化(IndexIVFScalarQuantizer):quantizer, d, nlists, qtype; d或d/2; 否
  • IVFADC粗量化+PQ+殘差(IndexIVFPQ):quantizer,d, nlists, M, nbits; M+4或M+8;否
  • IVFADC+R即為IVFADC+基於code的rerank(IndexIVFPQR):quantizer,d, nlists, M, nbits, M_refine, nbits_refine; M+M_refine+4或M+M_refine+8; 否

單元捕獲方法

常用的一種加速檢索過程,但以一定找到最近鄰為代價的方法是是使用例如k-means的分割技術,對應的算法有時稱之為 單元捕獲方法

  • 特征空間分割為ncells單元。
  • 數據集向量根據哈希函數賦值到其中的一個單元,存儲在ncells個倒置列表的倒置文件系統中(在k-means中,查詢向量會賦值到離它最近的中心點)。
  • 查詢時,選擇nprobe個倒置列表;
  • 查詢向量和每個列表中的每個庫向量比較。

通過上述方法,只有部分數據庫向量與查詢向量比較:初步估計,這個比例大約是nprobe/ncells,但是需要註意的是,這個估計通常是偏低的,因為各個倒置列表並不是等長的。當給定查詢向量的最近鄰所在單元未被選中時,就會查詢失敗。
Faiss C++對應的index是IndexIVFFlat。構造函數將index作為參數,用於倒置列表的賦值,查詢操作在這個index中進行,返回倒置列表中向量ID。

使用帶有Flat Index單元捕獲方法作為粗分類量化器

通常,我們使用Flat Index作為粗分類量化器。IndexIVF的訓練方法給這些flat index添加中心點。nprobe在查詢時確定(對於衡量速度和精確度很有用)。
註意:n表示索引的點數,選擇這個中心點數的常用方法:賦值到中心點的花費 和 當解析倒置列表時需要計算的距離次數。中心點的數目大致為:ncentroids=C*sqrt(n).
註意 IndexIVFKmeans

IndexIVFSphericalKmeans不是對象,而是返回IndexIVFFlat對象的函數。
警告:分割方法容易遭遇維度詛咒,對於及其高維的數據,要得到好的召回率需要很大數目的probe值。

和LSH的關系

最有名的單元捕獲方法就是技術分享圖片,但是這個方法和它的演變方法有兩個缺點:

  1. 需要很多哈希函數獲得較好的結果,導致占用內存很多;
  2. 哈希函數不適用於輸入數據,容易導致次優選擇。

二值code

在C++,一個LSH index聲明:

IndexLSH* index = new faiss::IndexLSH(d, nbits);

其中d是輸入向量維度,nbits是每個存儲向量的比特位數目。
而python的(改進的)LSH index構建和檢索如下:

n_bits = 2*d
lsh = faiss.IndexLSH(d, n_bits)
lsh.tracin(x_train)
lsh.add(x_vase)
D, I = lsh.search(x_query, k)

註意: 該算法使用的不是vanilla-LSH,而是更好的選擇。

基於量化的方法

在C++,基於量化的index由關鍵字PQ定義。其中n_bits必須等於8,12或者16.維度d必須是m的倍數。

倒置文件系統與PQ

倒置文件系統+PQ可能對於大規模檢索最有用。通常如下使用:

coarse_quantizer = faiss.IndexFlatL2(d)
index = faiss.IndexIVFPQ(coarse_quantizer, d, ncentroids, code_size, 8)
index.nprobe = 5

可以查看IndexIVFFlat那章設置ncentroids,code_size通常是2^4~2^64。和IndexPQ一樣,d是m的倍數。

【4】facebook大數據搜索庫faiss使用——Faiss索引介紹