**
annoy是高維空間求近似最近鄰的乙個開源庫。
annoy構建一棵二叉樹,查詢時間為o(logn)。
annoy通過隨機挑選兩個點,並使用垂直於這個點的等距離超平面將集合劃分為兩部分。
如圖所示,圖中灰色線是連線兩個點,超平面是加粗的黑線。按照這個方法在每個子集上迭代進行劃分。
依此類推,直到每個集合最多剩餘k個點,下圖是乙個k = 10 的情況。
相應的完整二叉樹結構:
隨機投影森林。
乙個思想依據是:在原空間中相鄰的點,在樹結構上也表現出相互靠近的特點,也就是說,如果兩個點在空間上相互靠近,那麼他們很可能被樹結構劃分到一起。
如果要在空間中查詢臨近點,我們可以在這個二叉樹中搜尋。上圖中每個節點用超平面來定義,所以我們可以計算出該節點往哪個方向遍歷,搜尋時間 log n
如上圖,我們找到了七個最近鄰,但是假如我們想找到更多的最近鄰怎麼辦?有些最近鄰是在我們遍歷的葉子節點的外邊的。
技巧1:使用優先佇列
如果乙個劃分的兩邊「靠得足夠近」(量化方式在後面介紹),我們就兩邊都遍歷。這樣就不只是遍歷乙個節點的一邊,我們將遍歷更多的點
我們可以設定乙個閾值,用來表示是否願意搜尋劃分「錯」的一遍。如果設定為0,我們將總是遍歷「對」的一片。但是如果設定成0.5,就按照上面的搜尋路徑。
這個技巧實際上是利用優先順序佇列,依據兩邊的最大距離。好處是我們能夠設定比0大的閾值,逐漸增加搜尋範圍。
技巧2:構建乙個森林
我們能夠用乙個優先順序佇列,同時搜尋所有的樹。這樣有另外乙個好處,搜尋會聚焦到那些與已知點靠得最近的那些樹——能夠把距離最遠的空間劃分出去
每棵樹都包含所有的點,所以當我們搜尋多棵樹的時候,將找到多棵樹上的多個點。如果我們把所有的搜尋結果的葉子節點都合在一起,那麼得到的最近鄰就非常符合要求。
依照上述方法,我們找到乙個近鄰的集合,接下來就是計算所有的距離和對這些點進行排序,找到最近的k個點。
很明顯,我們會丟掉一些最近的點,這也是為什麼叫近似最近鄰的原因。
annoy在實際使用的時候,提供了一種機制可以調整(搜尋
k),你能夠根據它來權衡效能(時間)和準確度(質量)。
tips:
1.距離計算,採用歸一化的歐氏距離:vectors = sqrt(2-2*cos(u, v))
2.向量維度較小(<100),即使維度到達1000變現也不錯
3.記憶體占用小
4.索引建立與查詢分離(特別是一旦樹已經建立,就不能新增更多項)
5.有兩個引數可以用來調節annoy 樹的數量n_trees和搜尋期間檢查的節點數量search_k
n_trees在構建時提供,並影響構建時間和索引大小。 較大的值將給出更準確的結果,但更大的索引。
search_k在執行時提供,並影響搜尋效能。 較大的值將給出更準確的結果,但將需要更長的時間返回。
如果不提供search_k,它將預設為n *
n_trees,其中n是近似最近鄰的數目。
否則,search_k和n_tree大致是獨立的,即如果search_k保持不變,n_tree的值不會影響搜尋時間,反之亦然。
基本上,建議在可用負載量的情況下盡可能大地設定n_trees,並且考慮到查詢的時間限制,建議將search_k設定為盡可能大。
最近鄰搜尋和近似最近鄰搜尋(NN和ANN)和庫
這樣查詢返回的前k個向量並不一定是最相似的k個向量,衡量ann演算法好不好的乙個依據是召回,每次ann請求返回的k個結果與使用暴力查詢的k個結果去比較,如果完全一致,說明是最好的。因為省了搜尋時間卻沒有影響效果。目前的ann演算法有基於圖 hnswlib 的,基於樹 pysparnn 的,基於雜湊 ...
K最近鄰演算法
參考 所謂k最近鄰,就是k個最近的鄰居的意思,說的是每個樣本都可以用它最接近的k個鄰居來代表。cover和hart在1968年提出了最初的鄰近演算法。knn是一種分類 classification 演算法,它輸入基於例項的學習 instance based learning 屬於懶惰學習 lazy ...
K最近鄰演算法
一 原理 k最近鄰演算法 k nearest neighbor,knn 是最基本的分類演算法,其基本原理是 從最近的k個鄰居 樣本 中,選擇出現次數最多的類別作為判定類別。k最近鄰演算法可以理解為是乙個分類演算法,常用於標籤的 如性別。實現knn演算法核心的一般思路 相似度計算 計算未知樣本和每個訓...