在介紹騰訊詞向量時,用到了annoy,這里對annoy的用法詳細做一下介紹。
GitHub地址:https://github.com/spotify/annoy
Annoy是Erik Bernhardsson在Hack Week期間花了幾個下午寫的(github原話),全稱Approximate Nearest Neighbors Oh Yeah(這個Oh Yeah真是亮瞎眼)。這個包的優點就是快,內存占用也小,還可以靜態存儲索引用於更多任務。目前已經在音樂推薦系統Spotify中應用。
這個工具可以用來計算空間中點的距離,輸入某個點,返回最近的若干點。
這個包直接pip install annoy
就可以安裝,C++版本的直接下載后#include "annoylib.h"
。
使用方法:
from annoy import AnnoyIndex
import random
f = 40
t = AnnoyIndex(f, 'angular') # Length of item vector that will be indexed
for i in range(1000):
v = [random.gauss(0, 1) for z in range(f)]
t.add_item(i, v)
t.build(10) # 10 trees
t.save('test.ann')
# ...
u = AnnoyIndex(f, 'angular')
u.load('test.ann') # super fast, will just mmap the file
print(u.get_nns_by_item(0, 1000)) # will find the 1000 nearest neighbors
默認的索引是從0到n-1。
API:
AnnoyIndex(f, metric)
f 向量維度,metric 距離度量方式,取值 "angular", "euclidean", "manhattan", "hamming", or "dot". 計算angular是使用的sqrt(2(1-cos(u,v)))這個公式,用的歐幾里得距離。euc = sqrt(2(1-cos))。
a.add_item(i, v)
添加元素 i 和向量 v
a.build(n_trees, n_jobs=-1)
n_trees是森林的樹數目,值越大結果越精確,n_jobs 進程數,默認-1使用所有的CPU。build調用之后,就不能再添加元素了。
a.save(fn, prefault=False)
保存到本地
a.load(fn, prefault=False)
從本地讀取,prefault是預先讀入內存,默認為False.
a.unload()
清除加載內容
a.get_nns_by_item(i, n, search_k=-1, include_distances=False)
返回n個最近元素。在查詢過程中,它將檢查search_k個節點,如果沒有提供,默認為n_trees * n。search_k給了一個速度和准確率的折中。include_distances設為True,會提供一個由兩個列表組成的二元組,第二個列表包含所有相關的距離。
a.get_nns_by_vector(v, n, search_k=-1, include_distances=False)
結果一樣,不過是通過向量v來查詢。
a.get_item_vector(i)
返回索引i對應的向量
a.get_distance(i, j)
返回元素i和j的距離,squared distance
a.get_n_items()
返回元素數量
a.get_n_trees()
返回樹數目
a.on_disk_build(fn)
指定在除了RAM之外的其他文件上構建索引(在添加元素之前執行)
a.set_seed(seed)
在構建樹之前可以指定隨機數
這里面主要有兩個參數需要調,n_trees和search_k,一個是構建時的參數,一個是搜索時的參數。
下面這是qps和recall值之間的trade-off,使用時要綜合考慮准確率和速度。