Faiss: 入門導讀

引言

Faiss是Facebook於2017年開源的一個相似度檢索工具。

相似度檢索是啥?搜索、廣告、推薦都需要用到相似度的檢索。因為無論是網頁、廣告抑或推薦博文一定要符合你的查詢意圖才能帶來更好的用戶體驗。

Faiss支持的不止是文本的相似檢索,它支持多媒體文檔。圖片,視頻都可以,只要把它們向量化就行。

本文主要是解讀一下Faiss的官方Get Started文檔中的Demo代碼:

https://github.com/facebookresearch/faiss/wiki/Getting-started

雖然代碼只有潦潦數行,但對於初學者也值得玩味。另外注意本文對demo代碼有微調。

正文

片段一

import numpy as np
d = 64 # dimension
nb = 100000 # database size
nq = 10000 # nb of queries
np.random.seed(1234) # make reproducible
xb = np.random.random((nb, d)).astype('float32')
xb[:, 0] += np.arange(nb) / 1000.

numpy 隨機數

np.random.random((nb, d)) 使用numpy隨機數生成二維數組(矩陣)。其中nb表示矩陣的行數,d表示矩陣的列數。

隨機數的數值範圍在 [0.0, 1.0)區間,本來就是浮點型,貌似可以不用再astype了。

numpy.array

np.random.random((nb, d)) 生成的數據類型是numpy.array。

python3雖然也有array類型,但是隻支持一維。普通的list雖然可以二維,但是性能太差。所以numpy有自己的array類型,並且有更豐富的api。

numpy.array 切片

xb 就是一個numpy.array了。然後 xb[:, 0] 表示的是對二維數組切片。

這個方括號裡冒號逗號分隔,可以視作三個參數:

  • 參數1和參數2表示的選擇的行範圍。用法類型list的切片,只是這裡選擇的是行。
  • 參數3表示在選擇完行之後,要選擇的列的下標。


所以xb[:, 0]表示的是選擇所有行的第一列。

悄悄告訴你:別試了,即使是二維的list不支持這個寫法哦。


片段二

import faiss # make faiss available
index = faiss.IndexFlatL2(d) # build the index
print(index.is_trained)
print(index.ntotal)
index.add(xb) # add vectors to the index
print(index.ntotal)

這個算是進入正題了,導入faiss包(需要事先安裝哦,建議使用conda安裝)

faiss.IndexFlatL2(d)

faiss.IndexFlatL2(d)創建了一個IndexFlatL2類型的索引。faiss支持豐富的索引類型,這裡創建的只是最簡單的索引,它進行暴力的L2距離搜索。

基於向量空間計算相似度,主要有兩種方法,一種就是L2(即歐幾里得距離),另外一種是計算夾角cosin(即餘弦相似度),本文這裡不做展開,後續會有文章單獨介紹。

另外創建索引一定要指定維度,也就是參數d。

index.is_trained

index.is_trained 表示是否訓練完成。大部分索引需要訓練,而IndexFlatL2不需要,所以這裡會直接返回True。

index.add(xb)

xb是前面用numpy生成的隨機二維數組(一組向量),將其添加到索引中。

或者可以說成是給xb構建了一個索引。

index.ntotal

這個表示被索引數據的數目,在執行index.add之前ntotal是0,在index.add之後ntotal為100000,也就是nb的值。


片段三

k = 4 # we want to see 4 nearest neighbors
D, I = index.search(xb[:5], k) # sanity check
print(I)
print(D)

index.search

index.search就是在進行相似性檢索了。參數1是輸入數據,參數2是個數。

k = 4,表示要搜索4個近鄰(NN)。也就是通常說的KNN,K-means的K。

xb[:5]是xb的0 - 4行共5組向量,在xb中找到與輸入的5個向量最相似的4個向量。

返回值:I

I表示的是id。輸出如下:

[[ 0 393 363 78]

[ 1 555 277 364]

[ 2 304 101 13]

[ 3 173 18 182]

[ 4 288 370 531]]

因為輸入數據xb[:5]含有5個向量,所以返回的結果也是5個(5行)。

每一行有4個元素(因為k=4)。從左到右表示距離從近到遠。元素的值是xb中的向量的id。

返回值:D

D表示的就是計算出來的距離。輸出如下:

[[0. 7.1751738 7.20763 7.2511625]

[0. 6.3235645 6.684581 6.799946 ]

[0. 5.7964087 6.391736 7.2815123]

[0. 7.2779055 7.527987 7.6628466]

[0. 6.7638035 7.2951202 7.3688145]]

也就是I的矩陣中,返回的向量id和輸入向量之間的距離。

從結果可以驗證,確實從左到右其距離越來越遠。


片段四

xq = np.random.random((nq, d)).astype('float32')
xq[:, 0] += np.arange(nq) / 1000.
D, I = index.search(xq, k) # actual search
print(I[:5]) # neighbors of the 5 first queries
print(I[-5:]) # neighbors of the 5 last queries
print(D)

這個代碼片段其實和上一個類似的,只是這個是在模擬真實的檢索。

因為真實的相似檢索過程,輸入數據可不是文檔集合的xb[:5],而是另外一組向量。

比如用戶看完一篇文章,要推薦其他文章給用戶。那麼xq就是將看完的這篇文章的特徵向量化,然後去所有候選的文章集合中去找最與之相似的幾篇。

這個過程也就是『召回』。在信息檢索和推薦領域都有召回的概念。

Faiss: 入門導讀


分享到:


相關文章: