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,... 同上。