本文由來自 Textkernel 的軟件與數據工程師 Eike Dehling 於2018年10月23日發佈與其Linkedin 的 pulse 上,已獲得翻譯授權。英文原文鏈接:
https://www.linkedin.com/pulse/searching-deep-learning-eike-dehling/
最近我在幫一個數據科學家同事工程化一個基於深度學習模型的搜索系統。他們的項目是關於在文檔嵌入應用深度學習模型,然後使用嵌入向量到我們的搜索系統中來查找相似文檔。
一個文檔嵌入本質上其實是一個(長的)數值數組,查找相似文檔就相當於查找其他與其較相近的(長的)數值數組;可以採用諸如歐氏距離等來衡量相似性。
可以藉此來查找相似文檔,但是因為不是直接基於關鍵詞而是基於“嵌入”,所以可以自動獲得與同義詞擴展相媲美的效果。它會查找相關文檔,即使它們使用不同的關鍵詞,因此能比關鍵詞檢索表現更好。
已經有解決這種問題的工具了,比如
facebook 的 FAISS 庫(https://github.com/facebookresearch/faiss)。這個類庫速度非常快,並且支持多種智能方法使用嵌入向量實現快速檢索。不過它不能友好地集成到類似 Elasticsearch 這樣的搜索引擎中。
對於 Elasticsearch 來說,也有一些插件(https://github.com/muhleder/elasticsearch-vector-scoring)提供了相似度計算功能,但是它們的速度並不怎麼樣,因為它們只計算了向量相似度而沒有做過濾。
所以我們自己動手實現了更好的解決方案。
Fast Nearest Neighbours
為了更快速檢索通常會使用各種“索引”,這種數據結構支持高效地過濾出相關的匹配,而無需單獨評估每一個匹配。基於關鍵詞的檢索一般使用“倒排索引”;基於地理位置的檢索,一般使用一種叫做 KD樹 的數據結構。我們也需要諸如此類的機制來快速過濾出最相關的匹配,因此我們只需要在這個較小的集合上計算精確得分。這一點非常重要,因為在一個高維向量的超大集合上計算距離,是代價非常高昂(慢)的操作。
上文提到的 FAISS 庫提供了多種方式來解決這個問題:
- PCA 降維
- K 均值聚類
- 局部敏感哈希
- 可能還有其他我不知道方法
這些方法中的每一種都能實現高效的索引方法,因此可以快速地篩選出較近鄰的文檔,然後通過計算精確的距離來查找最近鄰文檔。在降維以後就可以使用 KD樹,聚類或者局部敏感哈希後也可以使用倒排索引。
上圖揭示瞭如何通過過濾數據集來加速計算,需要計算精確距離的文檔數與計算時間之間是線性關係;同時也說明了高效地過濾掉不相似文檔多麼重要。
當然所有這些方法都是有可能在 Elasticsearch 裡得到實現的,其優點是便於和其他檢索系統集成。屆時就可以組合使用關鍵詞查詢或其他基於深度學習的查詢結果了。
實驗表明在我們的數據集上,結合了 PCA 降維後再使用 KD 樹索引,能帶給我們速度和精度的最佳y組合。
上圖揭示了縮小數據集是如何影響結果精確度的。能夠看到,過濾得太狠意味著我們會丟失一些最近鄰文檔;而如果過濾掉 50k 到 75k 的文檔,就可以找到所有的最近鄰文檔,同時計算時間只佔暴力計算所有距離的很小一部分。
Elasticsearch 插件
在 Lucene 即 Elasticsearch的底層類庫中,KD樹的數據結構已經實現了,但還沒有通過 Elasticsearch 的 API 暴露出來。已經有插件可以計算精確的向量距離,所以我們只需要開發一個小插件來支持使用這種索引結構即可。參見這裡:https://github.com/EikeDehling/vector-search-plugin
集成工作
現在集成工作只是相當於把拼圖圖片按照正確的順序拼到一起:
- 安裝 Elasticsearch 插件
- PCA降維(Python/sklearn 或者 Java/Smile)
- 索引降維後的完整向量到 Elasticsearch 中(以及其他必要屬性)
- 整裝待發!
安裝插件、創建索引以及添加文檔請參考這裡(https://github.com/EikeDehling/vector-search-plugin)。完成這些步驟後,現在就可以使用我們的嵌入向量了!請注意 pca_reduced_vector 上的範圍查詢,這才是我們新插件起到的作用。
POST my_index/_search
{
"query": {
"function_score": {
"query": {
"range": {
"pca_reduced_vector": {
"from": "-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5,-0.5",
"to": "0.5,0.5,0.5,0.5,0.5,0.5,0.5,0.5"
}
}
},
"functions": [
{
"script_score": {
"script": {
"inline": "vector_scoring",
"lang": "binary_vector_score",
"params": {
"vector_field": "full_vector",
"vector": [ 0.0, 0.0716, 0.1761, 0.0, 0.0779, 0.0, 0.1382, 0.3729 ]
}
}
}
}
],
"boost_mode": "replace"
}
},
"size": 10
}
(滑動查看)
結論
我們展示瞭如何應用深度學習向量來實現高效的搜索。這一方法適用於想要尋找相似文檔而普通關鍵詞查詢不夠好的任何應用場景。其中的嵌入向量,可以使用諸如 doc2vec 等來實現。
希望對你有所幫助,如果有任何反饋或疑問,請留言或私信給我!
原文發佈於微信公眾號 - vivo互聯網技術(vivoVMIC)
閱讀更多 機器不學習 的文章