亞馬遜云創(chuàng)新「神經(jīng)稀疏檢索」:僅需要文本匹配就能實(shí)現(xiàn)語(yǔ)義搜索
本文作者是來(lái)自 OpenSearch 中國(guó)研發(fā)團(tuán)隊(duì)的機(jī)器學(xué)習(xí)負(fù)責(zé)人楊揚(yáng)博士以及機(jī)器學(xué)習(xí)工程師耿志超和管聰。OpenSearch 是一個(gè)由亞馬遜云科技發(fā)起的純開(kāi)源搜索和實(shí)時(shí)分析引擎項(xiàng)目。目前軟件超過(guò) 5 億下載量,社區(qū)在全球擁有 70 個(gè)以上的企業(yè)合作伙伴。
自從大模型爆火以來(lái),語(yǔ)義檢索也逐漸成為一項(xiàng)熱門技術(shù)。尤其是在 RAG(retrieval augmented generation)應(yīng)用中,檢索結(jié)果的相關(guān)性直接決定了 AI 生成的最終效果。
目前市面上絕大部分的語(yǔ)義檢索實(shí)現(xiàn)方案,都是利用語(yǔ)言模型(Language Model)將一串文本編碼為一個(gè)高維向量,并利用近似 k - 鄰近搜索(k-NN)進(jìn)行檢索。面對(duì) VectorDB 和語(yǔ)言模型部署(需要 GPU)高昂的費(fèi)用,很多人望而卻步。
近日,亞馬遜 OpenSearch 連同亞馬遜上海人工智能研究院,在 OpenSearch NeuralSearch 插件中推出了 Neural Sparse 功能,解決了當(dāng)前語(yǔ)義檢索正在面臨的以下三個(gè)挑戰(zhàn):
- 相關(guān)性表現(xiàn)在不同查詢上的穩(wěn)定性:zero-shot 語(yǔ)義檢索要求語(yǔ)義編碼模型在不同背景的數(shù)據(jù)集上都有不錯(cuò)的相關(guān)性表現(xiàn),即要求語(yǔ)言模型即開(kāi)即用,無(wú)需用戶在自己的數(shù)據(jù)集上 fine-tune。利用稀疏編碼與詞向量(Term Vector)同源的特性,Neural Sparse 可以在遇到陌生文字表述(行業(yè)專有詞、縮寫等等)的時(shí)候向文本匹配降級(jí),從而避免離譜的檢索結(jié)果。
- 在線搜索的時(shí)間效率:低時(shí)延對(duì)于實(shí)時(shí)檢索應(yīng)用的意義是顯而易見(jiàn)的。目前流行的語(yǔ)義檢索方法一般都會(huì)包含語(yǔ)義編碼以及索引兩個(gè)過(guò)程,這兩者的速度決定了一個(gè)檢索應(yīng)用端到端的檢索效率。Neural Sparse 獨(dú)特的 doc-only 模式,無(wú)需在線編碼,即能在與文本匹配相近的時(shí)延情況下,達(dá)成與一流語(yǔ)言模型相媲美的語(yǔ)義檢索的精度。
- 索引的存儲(chǔ)資源消耗:商業(yè)化的檢索應(yīng)用對(duì)存儲(chǔ)資源的消耗是非常敏感的。在對(duì)海量數(shù)據(jù)進(jìn)行索引時(shí),搜索引擎的運(yùn)行成本與存儲(chǔ)資源的消耗強(qiáng)相關(guān)。在相關(guān)實(shí)驗(yàn)中,索引相同規(guī)模的數(shù)據(jù),Neural Sparse 僅需要 k-NN 索引的 1/10。同時(shí)內(nèi)存消耗也大大小于 k-NN 索引。
Relevance Demo
- 文檔主頁(yè):https://opensearch.org/docs/latest/search-plugins/neural-sparse-search/
- 項(xiàng)目 Github 地址:https://github.com/opensearch-project/neural-search
技術(shù)亮點(diǎn)
稀疏編碼與原生 Lucene 索引結(jié)合
當(dāng)前語(yǔ)義檢索的主要方法來(lái)自于稠密編碼(Dense Encoding),待檢索的文檔以及查詢文本都會(huì)被語(yǔ)言編碼模型轉(zhuǎn)換為一個(gè)高維空間中的向量。例如 Sentence-BERT 中的 TASB 模型會(huì)生成 768 維的向量,All-MiniLM-L6 則會(huì)將文本轉(zhuǎn)化為 384 維的向量。這一類高維向量的索引需要用到特殊的 k-NN 搜索引擎,例如最早基于樹(shù)結(jié)構(gòu)的 FLANN、基于哈希的 LSH、還有后來(lái)出現(xiàn)基于鄰近圖與跳表的 HNSW 以及最新基于量化的 FAISS 引擎。
而稀疏編碼(Sparse Encoding)則會(huì)將文本轉(zhuǎn)化為一組 token 與權(quán)值的組合。這里的 token 是語(yǔ)言編碼模型采用分割器對(duì)文本進(jìn)行切割后產(chǎn)生的文字單元。例如使用 WordPiece 分割器,token 可以在一定程度上理解為「單詞」,但也會(huì)出現(xiàn)單詞過(guò)長(zhǎng)而被切分為兩個(gè) token 的情況。
稀疏編碼與稠密編碼對(duì)比
由于稀疏編碼所產(chǎn)生的 token - 權(quán)值組合,與傳統(tǒng)文本匹配方法采用的 term-vector 非常類似,所以在 OpenSearch 中可以采用原生的 Lucene 索引去存儲(chǔ)文檔稀疏編碼。相較于 k-NN 搜索引擎,原生的 Luence 引擎會(huì)更加輕便,占用的資源也較少。
下表展示了采用 Lucene 進(jìn)行文本匹配,采用 k-NN 引擎存儲(chǔ)稠密編碼以及采用 Lucene 存儲(chǔ)稀疏編碼的磁盤消耗以及運(yùn)行時(shí)內(nèi)存(runtime RAM)消耗的比較。
*整個(gè)系統(tǒng)在只運(yùn)行 OpenSearch 時(shí)的內(nèi)存,包括 JVM 的堆內(nèi)和堆外內(nèi)存
在陌生數(shù)據(jù)集上的自適應(yīng)性
根據(jù) BEIR 文章中提及的,由于目前絕大部分的稠密編碼模型都是基于 MSMARCO 數(shù)據(jù)集上精調(diào)(fine-tune)得到,模型在該數(shù)據(jù)集上表現(xiàn)非常優(yōu)越。然而在其他的 BEIR 的數(shù)據(jù)集上進(jìn)行 zero-shot 的測(cè)試時(shí),稠密編碼模型在大約有 60%~70% 的數(shù)據(jù)集上的相關(guān)性無(wú)法超越 BM25。這一點(diǎn)也可以從我們自己復(fù)現(xiàn)的對(duì)比實(shí)驗(yàn)中間看出(見(jiàn)下表)。
部分?jǐn)?shù)據(jù)集上幾個(gè)方法的相關(guān)性表現(xiàn)比較
我們?cè)趯?shí)驗(yàn)中發(fā)現(xiàn)稀疏編碼在陌生數(shù)據(jù)集上的表現(xiàn)要優(yōu)于稠密編碼。雖然目前還沒(méi)有更加詳細(xì)的量化數(shù)據(jù)來(lái)印證,但根據(jù)在部分樣本上的分析,其優(yōu)勢(shì)主要在兩點(diǎn):1)稀疏編碼在近義詞的聯(lián)想方面更加突出,2)在遇到完全陌生的文本表述,例如一些專業(yè)術(shù)語(yǔ),稀疏編碼會(huì)更傾向于增強(qiáng)這些術(shù)語(yǔ) token 的權(quán)值而弱化聯(lián)想出的 token 的權(quán)值,使得檢索過(guò)程向關(guān)鍵詞匹配退化,追求的一個(gè)穩(wěn)定的相關(guān)性表現(xiàn)。
在 BEIR 基準(zhǔn)上的實(shí)驗(yàn)中我們可以看到,Neural Sparse 的兩個(gè)方法相較于稠密編碼模型以及 BM25,相關(guān)性得分更高。
極致速度:僅文檔編碼模式
Neural Search 同時(shí)提供了一種能夠提供極致線上檢索速度的模式。在這種模式下,僅有待檢索的文檔會(huì)進(jìn)行稀疏編碼。相反,在在線檢索的過(guò)程中,查詢文本并不會(huì)調(diào)用語(yǔ)言編碼模型進(jìn)行編碼。而僅僅使用分割器(tokenizer)對(duì)查詢文本進(jìn)行分割。由于省去了對(duì)深度學(xué)習(xí)模型的調(diào)用過(guò)程,不但大大降低了在線檢索的時(shí)延,也節(jié)省了模型推理所需要的大量計(jì)算資源,例如 GPU 算力等。
下表比較了文本匹配檢索方法 BM25、稠密編碼檢索 BERT-TASB 模型、稀疏編碼檢索帶查詢編碼 bi-encoder 方式以及稀疏編碼檢索僅文檔編碼 doc-only 在 MSMARCO v2 一百萬(wàn)量級(jí)數(shù)據(jù)集上的速度對(duì)比。我們可以清楚地看到僅文擋編碼模式具有和 BM25 相近的速度表現(xiàn),而且從上一節(jié)的表格中我們可以看到僅文檔編碼模式的相關(guān)性表現(xiàn),并沒(méi)有與帶查詢稀疏編碼的方法差太多。可以說(shuō),僅文檔編碼模式是一個(gè)非常具有性價(jià)比的選擇。
還要更快:使用兩段式搜索進(jìn)行加速
前文中提到,在稀疏編碼的過(guò)程中,文本被轉(zhuǎn)化為一組 token 與權(quán)值的組合。這種轉(zhuǎn)化產(chǎn)生了大量權(quán)值較低的 token,這些 token 雖然在搜索過(guò)程中占用了大部分時(shí)間,但對(duì)最終搜索結(jié)果的貢獻(xiàn)并不顯著。
因此,我們提出了一種新的搜索策略,首先在第一次搜索中過(guò)濾掉這些低權(quán)值 token,僅依賴高權(quán)值 token 來(lái)定位排名較高的文檔。隨后在這些精選的文檔上,重新引入之前被過(guò)濾的低權(quán)值 token 進(jìn)行第二次詳細(xì)評(píng)分,從而獲取最終得分。
通過(guò)這種方法,我們顯著減少了兩部分的延時(shí):首先,在第一階段搜索中,僅通過(guò)高權(quán)值 token 在倒排索引中進(jìn)行匹配,大幅減少了不必要的計(jì)算時(shí)間。其次,在精確的小范圍結(jié)果文檔內(nèi)再次評(píng)分時(shí),我們僅對(duì)具有潛在相關(guān)性的文檔計(jì)算低權(quán)值 token 的分?jǐn)?shù),進(jìn)一步優(yōu)化了處理時(shí)間。
最終,這種改進(jìn)的方法在僅文檔編碼模式(doc-only)上實(shí)現(xiàn)了與 BM25 搜索接近的延時(shí)表現(xiàn),在帶查詢編碼模式 (bi-encoder) 上則加快了 5 到 8 倍,極大地提升了 Neural Search 的延時(shí)表現(xiàn)和吞吐量。以下是在四個(gè)典型 BEIR 數(shù)據(jù)集上標(biāo)準(zhǔn) neural sparse、兩階段 neural sparse、BM25 的時(shí)延對(duì)比:
兩階段式搜索速度對(duì)比
用 5 步在 OpenSearch 中搭建 Neural Sparse 語(yǔ)義檢索應(yīng)用
1. 設(shè)置啟用 Neural Search
首先設(shè)置集群配置來(lái)使得模型可以在本地集群上運(yùn)行。
PUT /_cluster/settings
{
"transient" : {
"plugins.ml_commons.allow_registering_model_via_url" : true,
"plugins.ml_commons.only_run_on_ml_node" : false,
"plugins.ml_commons.native_memory_threshold" : 99
}
}
2. 部署編碼器
Opensearch 目前開(kāi)源了 3 個(gè)模型。相關(guān)注冊(cè)信息都可以在官方文檔中獲取。我們以 amazon/neural-sparse/opensearch-neural-sparse-encoding-v1 為例,首先使用 register API 來(lái)注冊(cè):
POST /_plugins/_ml/models/_register?deploy=true
{
"name": "amazon/neural-sparse/opensearch-neural-sparse-encoding-v1",
"version": "1.0.1",
"model_format": "TORCH_SCRIPT"
}
在集群的返回中,可以看到 task_id
{
"task_id": "<task_id>",
"status": "CREATED"
}
用 task_id 來(lái)得到詳細(xì)的注冊(cè)信息:
GET /_plugins/_ml/tasks/
在 API 返回中,我們可以拿到具體的 model_id:
{
"model_id": "<model_id>",
"task_type": "REGISTER_MODEL",
"function_name": "SPARSE_TOKENIZE",
"state": "COMPLETED",
"worker_node": [
"wubXZX7xTIC7RW2z8nzhzw"
],
"create_time": 1701390988405,
"last_update_time": 1701390993724,
"is_async": true
}
3. 設(shè)置預(yù)處理管線
在索引之前,每個(gè)文檔需要被編碼的文本字段需要被轉(zhuǎn)變成稀疏向量。在 OpenSearch 中,這一過(guò)程是通過(guò)預(yù)處理器來(lái)自動(dòng)實(shí)現(xiàn)的。你可以使用以下 API 來(lái)創(chuàng)建離線索引時(shí)的處理器管線:
PUT /_ingest/pipeline/neural-sparse-pipeline
{
"description": "An example neural sparse encoding pipeline",
"processors" : [
{
"sparse_encoding": {
"model_id": "<model_id>",
"field_map": {
"passage_text": "passage_embedding"
}
}
}
]
}
如果需要開(kāi)啟兩階段加速功能 (非必需功能),則需要建立一個(gè)兩階段搜索管線,并在索引建立之后設(shè)置為默認(rèn)的搜索管線。
建立一個(gè)默認(rèn)參數(shù)的兩階段加速搜索管線方式如下,更詳細(xì)的參數(shù)設(shè)置和意義請(qǐng)參考 2.15 及以后版本的 OpenSearch 官方文檔。
PUT /_search/pipeline/two_phase_search_pipeline
{
"request_processors": [
{
"neural_sparse_two_phase_processor": {
"tag": "neural-sparse",
"description": "This processor is making two-phase processor."
}
}
]
}
4. 設(shè)置索引
神經(jīng)稀疏搜索利用 rank_features 字段類型來(lái)存儲(chǔ)編碼得到的詞元和相對(duì)應(yīng)的權(quán)重。索引將使用上述預(yù)處理器來(lái)編碼文本。我們可以按以下方式創(chuàng)建索一個(gè)包含兩階段搜索加速管線的索引(如果不想開(kāi)啟此功能,可把 `two_phase_search_pipeline` 替換為 `_none` 或刪除 `settings.search` 這一配置單元)。
PUT /my-neural-sparse-index
{
"settings": {
"ingest":{
"default_pipeline":"neural-sparse-pipeline"
},
"search":{
"default_pipeline":"two_phase_search_pipeline"
}
},
"mappings": {
"properties": {
"passage_embedding": {
"type": "rank_features"
},
"passage_text": {
"type": "text"
}
}
}
}
5. 使用預(yù)處理器導(dǎo)入文檔并搜索
在設(shè)置索引之后,客戶可以提交文檔。客戶提供文本字段,而攝取進(jìn)程將自動(dòng)將文本內(nèi)容轉(zhuǎn)換為稀疏向量,并根據(jù)預(yù)處理器中的字段映射 field_map 將其放入 rank_features 字段:
PUT /my-neural-sparse-index/_doc/
{
"passage_text": "Hello world"
}
在索引中進(jìn)行稀疏語(yǔ)義搜索的接口如下,將 <model_id> 替換為第二步中注冊(cè)的 model_id:
GET my-neural-sparse-index/_search
{
"query": {
"neural_sparse": {
"passage_embedding": {
"query_text": "Hi world",
"model_id": <model_id>
}
}
}
}
關(guān)于 OpenSearch
OpenSearch 是一種分布式、由社區(qū)驅(qū)動(dòng)并取得 Apache 2.0 許可的 100% 開(kāi)源搜索和分析套件,可用于一組廣泛的使用案例,如實(shí)時(shí)應(yīng)用程序監(jiān)控、日志分析和網(wǎng)站搜索。OpenSearch 提供了一個(gè)高度可擴(kuò)展的系統(tǒng),通過(guò)集成的可視化工具 OpenSearch 控制面板為大量數(shù)據(jù)提供快速訪問(wèn)和響應(yīng),使用戶可以輕松地探索他們的數(shù)據(jù)。
OpenSearch 由 Apache Lucene 搜索庫(kù)提供技術(shù)支持,它支持一系列搜索及分析功能,如 k - 最近鄰(KNN)搜索、SQL、異常檢測(cè)、Machine Learning Commons、Trace Analytics、全文搜索等。
本文轉(zhuǎn)自 機(jī)器之心 ,作者:機(jī)器之心
