faiss(2):理解product quantization算法

近幾年,深度學習技術被廣泛用於圖像識別、語音識別、自然語言處理等領域,能夠把每個實體(圖像、語音、文本)轉換爲對應的embedding向量。如這裏千人千面智能淘寶店鋪背後的算法研究登陸人工智能頂級會議AAAI 2017。而對於推薦、搜索或者廣告投放問題,都可以描述爲從大規模候選中給用戶提供有限的展現結果。那麼,這裏就會涉及到向量檢索的問題。

向量檢索最簡單的想法是暴力窮舉法,如果全部實體的個數是n,n是千萬量級甚至是上億的規模,檢索實體對應的向量是D,那麼當要從這個實體集合中尋找某個實體的相似實體,暴力窮舉的計算複雜度是O(n×D),這是一個非常大的計算量,該方法顯然不可取。所以對大數據量下高維度數據的相似搜索場景,我們就需要一些高效的相似搜索技術,而PQ就是其中一類方法。

1. Product Quantization算法原理

假設有50,000張圖片組成的圖片集,使用 CNN 提取特徵後,每張圖片可以由1024維的特徵表示。那麼整個圖片集由50000*1024的向量來表示。然後我們把1024維的向量平均分成m=8個子向量,每組子向量128維。如下圖:

對於這8組子向量的,使用 kmeans 方法聚成k=256類。也就是說,每個子向量有256箇中心點(centroids)。如下圖:

在product quantization方法中,這256箇中心點構成一個碼本。這些碼本的笛卡爾積就是原始D維向量對應的碼本。用qj表示第j組子向量,用[Cj表示其對應學習到的聚類中心碼本,那麼原始D維向量對應的碼本就是C=C1×C2×…×Cm,碼本大小爲km。 注意到每組子向量有其256箇中心點,我們可以用中心點的 ID 來表示每組子向量中的每個向量。中心點的 ID只需要 8位來保存即可。這樣,初始一個由32位浮點數組成的1,024維向量,可以轉化爲8個8位整數組成。

2. 最近鄰搜索

對向量壓縮後,有2種方法作相似搜索。一種是SDC(symmetric distance computation),另一種是ADC(asymmetric distance computation)。SDC算法和ADC算法的區別在於是否要對查詢向量x做量化。如下圖所示,x是查詢向量(query vector),y是數據集中的某個向量,目標是要在數據集中找到x的相似向量。

公式1:

SDC算法:先用PQ量化器對x和y表示爲對應的中心點q(x)和q(y),然後用公式1來近似d(x,y)。這裏 q 表示 PQ量化過程。

公式2:

ADC算法:只對y表示爲對應的中心點q(y),然後用下述公式2來近似d(x,y)。

3. python示例

  • 對初始向量按列平均分成 m 組,以每組作 kmeans 聚類:
vecs_sub = vecs[:, m * self.Ds : (m+1) * self.Ds]
self.codewords[m], _ = kmeans2(vecs_sub, self.Ks, iter=iter, minit='points')
  • 計算各分組子向量的每個向量的聚類的 ID 號。完成向量量化:

codes[:, m], _ = vq(vecs_sub, self.codewords[m])
  • 對於查詢向量q,將q按列也分成 m 組後,計算與聚類中心的距離:
for m in range(self.M):
            query_sub = query[m * self.Ds : (m+1) * self.Ds]
            dtable[m, :] = np.linalg.norm(self.codewords[m] - query_sub, axis=1) ** 2
  • 按組將其與聚類中心的距離求和後,取其距離之和最小值所對應的聚類中心。聚類中心所對應的初始向量,即最近鄰向量。
dists = np.sum(self.dtable[range(M), codes], axis=1)

4. 優化的PQ方法Optimized product quantization(OPQ)

Product Quantization的本質是將原始高維空間分解爲有限數量的低維子空間的笛卡爾積,然後分別量化。OPQ 試圖尋找一個正交矩陣,將原始矩陣旋轉後再行分解,以使量化後的向量重建後,其誤差最小。

原始的PQ:

改進的迭代式的ITQ:

優化的OPQ:

具體的解決方案,如何coupled R和 Ci:

方案1:

方案2(MSRA):

這裏作者提供了一個非常具有說服力的實驗:

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章