RAG開發新技術:利用語義相似度提升標簽過濾質量 原創
本文旨在介紹如何利用語義相似度改進標簽過濾以提升RAG應用開發質量。
要理解本文中的內容,你需要掌握Jaccard相似性和向量搜索等預備知識。本文算法的實現已在GitHub(https://github.com/atlantis-nova/simtag)上發布,并且是完全開源的。
簡介
多年來,我們已經發現了如何從諸如數字、原始文本、圖像和標簽等不同類型的模式數據中檢索信息。
隨著應用程序定制用戶接口的日益普及,標簽搜索系統已成為一種方便、準確的信息過濾方式。通常,使用標簽搜索的一些代表性場景包括檢索社交媒體帖子、文章、游戲、電影,甚至簡歷等領域。
然而,傳統的標簽搜索缺乏靈活性。如果我們要過濾完全包含給定標簽的樣本,可能會出現以下情況,特別是對于僅包含幾千個樣本的數據庫,可能沒有任何(或只有少數)與我們的查詢匹配的樣本。
缺乏有關信息時兩種搜索方案的搜索結果差異(作者本人提供圖片)
通過下面的內容,我將介紹幾種新的搜索算法。就我所知,目前我還沒有在網絡上找到與此相同的算法。
傳統標簽搜索是如何工作的?
傳統系統采用一種稱為Jaccard相似度的算法(通常通過Minhash算法執行),該算法能夠計算兩組元素之間的相似度(在我們的例子中,這些元素是標簽)。如前所述,這樣的搜索根本不靈活(無論集合中包含或是不包含查詢的標簽)。
一個簡單的AND位操作示例(盡管這里給出的并非是Jaccard相似性,但是能夠展示過濾方法的大致概念)(作者本人提供圖片)
我們能做得更好嗎?
如果我們不只是從匹配的標簽中過濾樣本,而是考慮樣本中所有其他不相同但與我們選擇的標簽相似的標簽,那么情況會怎么樣呢?我們可以使算法更加靈活,將結果擴展到非完美匹配,但仍然是良好的匹配。我們的思路是:直接將語義相似性應用于標簽,而不是文本。
語義標簽搜索算法
正如文章開頭提到的那樣,這種新方法試圖將語義搜索的功能與標簽過濾系統相結合。為了構建這個算法,我們只需要做一件事:
- 創建一個標記樣本的數據庫
在本文示例項目中,我將使用的參考數據是Steam游戲庫的開源集合(可從Kaggle下載:https://www.kaggle.com/datasets/fronkongames/steam-games-dataset,遵循MIT許可證)——大約有40000個樣本,這是用于測試我們算法的不錯的樣本。正如我們從顯示的數據幀中看到的,每個游戲都對應幾個已分配的標簽,我們的數據庫中共有400多個唯一的標簽。
示例源文件中提供的Steam數據幀截圖(作者本人提供圖片)
現在,我們已經準備好了初始數據,就可以繼續接下來的工作了。
我們的算法將通過以下步驟進行闡述:
- 提取標簽關系
- 對查詢和樣本進行編碼
- 使用向量檢索執行語義標簽搜索
- 驗證
在本文中,我將只分析這種新方法背后的數學原理(有關代碼的深入解釋和工作演示,請參閱本文示例工程源碼:https://github.com/atlantis-nova/simtag/blob/main/notebooks/steam_example.ipynb。有關如何使用simtag的說明,請參閱源碼工程根目錄下的README.md文件)。
1.提取標簽關系
首先想到的問題是,我們如何找到標簽之間的關系。請注意,目前已經存在幾種算法可用于獲得相同的結果:
- 使用統計方法
我們可以用來提取標簽關系的最簡單的方法稱為共現矩陣(co-occurrence matrix),這是我將在本文中使用的格式(出于其有效性和簡單性)。
- 使用深度學習
最先進的都是基于嵌入神經網絡(如過去使用的Word2Vec;現在通常使用轉換器,如LLM),可以提取樣本之間的語義關系。創建一個神經網絡來提取標簽關系(以自動編碼器的形式)是可能的,而且在面對某些情況時通常也是明智的方案。
- 使用預訓練模型
因為標簽是使用人類語言定義的,所以可以使用現有的預訓練模型來計算已經存在的相似性。這可能會更快,而且減少了麻煩。然而,每個數據集都有其獨特性。不足的一點是,使用預先訓練的模型將忽略客戶行為。
例如,我們稍后將看到2D與Fantasy有著密切的關系:但是,使用預先訓練的模型永遠不會發現這樣的匹配對。
算法的選擇可能取決于許多因素,特別是當我們必須處理龐大的數據池或有可擴展性問題時(如果我們擁有太多的標簽,那么我們需要使用機器學習來解決這個問題)。
a.使用Michelangiolo相似性構建共現矩陣
如前所述,我將使用共現矩陣作為提取這些關系的手段。我的目標是找到每對標簽之間的關系。為此,我將使用IoU(聯合上的交集)對所有樣本集(S)應用以下計數:
計算一對標簽之間相似度的公式(作者本人提供圖片)
該算法與Jaccard相似度非常相似。雖然這種算法針對樣本進行操作(而我介紹的那種算法針對元素進行操作),但是由于(據我所知)這個特定的應用程序尚未被編程實現過;因此,我們可以將其命名為Michelangiolo相似性。(公平地說,這個算法的使用以前在StackOverflow問題中已經提到過,但從未被編程實現過)。
Jaccard相似性和Michelangiolo相似性的差異(作者本人提供圖片)
對于40000個樣本,提取相似性矩陣大約需要一個小時,結果如下:
樣本列表S中所有唯一標簽的共現矩陣(作者本人提供圖片)
接下來,讓我們手動檢查前10個樣本中一些比較常見的標簽,看看結果是否有意義:
從共現矩陣中提取的樣本關系(作者本人提供圖片)
結果看起來很有希望!我們從簡單的分類數據(只能轉換為0和1)開始,但我們提取了標簽之間的語義關系(甚至沒有使用神經網絡)。
b.使用預訓練的神經網絡
同樣,我們可以使用預訓練的編碼器(https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2)提取樣本之間的現有關系。然而,這種解決方案忽略了只能從我們的數據中提取的關系,只關注人類語言的現有語義關系。注意,這種算法可能不是一個非常適合基于零售數據的工作解決方案。
另一方面,通過使用神經網絡,我們不再需要構建關系矩陣。因此,當關注可擴展性時,這是一種比較適當的解決方案。例如,如果我們必須分析大量的推特數據,我們會得到53.300個標簽。根據這個數量的標簽計算共現矩陣將得到大小為2500000000的稀疏矩陣(這是一個非常不切實際的壯舉)。相反,通過使用輸出向量長度為384的標準編碼器,得到的矩陣的總大小將為19200200。
使用預訓練編碼器對一組標簽進行編碼的快照數據
2.對查詢和樣本進行編碼
我們的目標是構建一個能夠支持語義標簽搜索的搜索引擎:根據我們一直在構建的格式,唯一能夠支持這種方案的技術是使用向量搜索。因此,我們需要找到一個合適的編碼算法,將樣本和查詢轉換為向量。
在大多數編碼算法中,我們都會使用相同的算法對查詢和樣本進行編碼。然而,每個樣本都包含多個標簽,而每個標簽都由一組不同的關系表示;因此,我們需要在單個向量中捕獲這些關系。
協變量編碼(作者本人提供圖片)
此外,我們需要解決上述可擴展性問題,我們將通過使用PCA模塊來實現(當我們使用共現矩陣時,我們可以跳過PCA,因為不需要壓縮我們的向量)。
當標簽的數量變得太大時,我們需要放棄計算共現矩陣的可能性,因為它以平方速率縮放。因此,我們可以使用預訓練的神經網絡提取每個現有標簽的向量(PCA模塊的第一步)。例如,all-MiniLM-L6-v2模型將每個標簽轉換為長度為384的向量。
然后,我們可以轉置獲得的矩陣,并對其進行壓縮:我們最初將使用1和0對可用標簽索引對查詢/樣本進行編碼,從而得到與初始矩陣(53300)長度相同的初始向量。此時,我們可以使用預先計算的PCA實例在大小為384的維度中壓縮相同的稀疏向量。
編碼樣本
就我們的樣本而言,該過程在PCA壓縮(激活時)后立即結束。
編碼查詢:協變量編碼
我們的查詢需要以不同的方式編碼:我們需要考慮與每個現有標簽相關的關系。這個過程是通過首先將壓縮向量與壓縮矩陣(所有現有關系的總和)相加來執行的。現在,我們已經獲得了一個矩陣(384x384),我們需要對其進行平均計算,從而獲得我們的查詢向量。
因為我們將使用歐幾里德搜索,它將首先優先搜索得分最高的特征(理想情況下,我們使用數字1激活的特征),但它也會考慮額外的次要得分情況。
加權搜索
因為我們將向量平均在一起,所以我們甚至可以對此計算應用權重,向量將受到與查詢標簽不同的影響。
3.使用向量檢索執行語義標簽搜索
你可能會問這樣的問題:為什么我們要經歷這個復雜的編碼過程,而不僅僅是將這對標簽輸入到函數f(query, sample)中并獲得一個分值?
如果你熟悉基于向量的搜索引擎,你已經知道答案了。通過成對執行計算,在只有40000個樣本的情況下,所需的計算能力是巨大的(單個查詢可能需要長達10秒):這不是一種可擴展的做法。然而,如果我們選擇對40000個樣本進行向量檢索,搜索將在0.1秒內完成:這是一種高度可擴展的做法,在我們的應用情況下這是非常完美的辦法。
4.驗證
為了使算法有效,需要對其進行驗證。目前,我們缺乏適當的數學驗證(乍一看,對M的相似性得分進行平均已經顯示出非常有希望的結果,但需要進一步的研究來獲得有證據支持的客觀指標)。
然而,當使用比較示例并可視化比較時,現有結果的優勢是非常直觀的。以下是兩種搜索方法的最靠近頂部的搜索結果比較(你看到的是分配給此游戲的標簽)。
傳統標簽搜索與語義標簽搜索的比較
- 傳統標簽搜索
我們可以看到傳統搜索可能會(在沒有額外規則的情況下,樣本會根據所有標簽的可用性進行過濾,而不是排序)返回具有更多標簽的樣本,但其中許多標簽可能并不相關。
- 語義標簽搜索
語義標簽搜索根據所有標簽的相關性對所有樣本進行排序。簡單來說,它取消了包含不相關標簽的樣本的資格。
這個新系統的真正優勢在于,當傳統搜索無法返回足夠的樣本時,我們可以使用語義標簽搜索來選擇任意數量的樣本。
兩次搜索結果稀缺前的差異(作者本人提供圖片)
在上面的例子中,使用傳統的標簽過濾不會從Steam庫中返回任何游戲。然而,通過使用語義標簽過濾,盡管我們仍然會得到不完美的結果,但會得到與我們的查詢最匹配的結果。你看到的是與我們的搜索匹配的前5個游戲的標簽。
結論
在此之前,如果不采用復雜的方法,如聚類、深度學習或多個K近鄰算法(KNN)搜索,就不可能在考慮標簽語義關系的情況下對標簽進行過濾。
本文中給出的算法提供的靈活性應允許與傳統的手動標記方法分離,后者迫使用戶在一組預定義的標簽之間進行選擇,并開辟了使用視覺語言模型的LLM自由地將標簽分配給文本或圖像的可能性,而不局限于預先存在的結構,從而為可擴展和改進的搜索方法開辟了新的選擇方案。
最后,我懷著最美好的祝愿決定向全世界開放這個算法,我也十分希望它能得到充分的利用。
譯者介紹
朱先忠,51CTO社區編輯,51CTO專家博客、講師,濰坊一所高校計算機教師,自由編程界老兵一枚。
原文標題:??Introducing Semantic Tag Filtering: Enhancing Retrieval with Tag Similarity??,作者:Michelangiolo Mazzeschi
