增強 RAG:選擇最佳的嵌入和重排模型
對於如何選擇最佳的嵌入模型和重排模型,給出了詳細的步驟和代碼。
在構建檢索增強生成(RAG)管道時,關鍵組件之一是檢索器。我們有多種嵌入模型可供選擇,包括 OpenAI、CohereAI 和開源的 sentence transformers。此外,還有來自 CohereAI 和 sentence transformers 的幾種重排器可供選擇。
但是,在所有這些選項中,我們如何確定最佳組合以獲得頂級的檢索性能?我們如何知道哪個嵌入模型最適合我們的數據?或者哪個重排器最能提升我們的結果?
在這篇博客文章中,我們將使用 LlamaIndex 的 檢索評估
模塊迅速確定嵌入模型和重排器模型的最佳組合。讓我們開始吧!
讓我們首先了解 檢索評估
中可用的指標。
理解檢索評估中的指標
爲了衡量我們檢索系統的效率,我們主要依賴於兩個廣泛接受的指標:命中率和平均倒數排名(MRR)。讓我們深入這些指標,瞭解它們的重要性以及它們的工作原理。
命中率:
命中率計算在查詢中正確答案出現在檢索到的前 k 個文檔中的比例。簡單來說,它關乎我們的系統在前幾個猜測中正確答案出現的頻率。
平均倒數排名(MRR):
對於每個查詢,MRR 通過查看最相關文檔的最高排名來評估系統的準確性。具體來說,它是所有查詢中這些排名倒數的平均值。因此,如果第一個相關文檔是頂部結果,倒數排名就是 1;如果是第二個,倒數排名就是 1/2,以此類推。
現在我們已經確定了範圍並熟悉了這些指標,是時候深入實驗了。爲了獲得實踐經驗,您也可以通過我們的 Google Colab Notebook 進行操作。
設置環境
!pip install llama-index sentence-transformers cohere anthropic voyageai protobuf pypdf
設置 Keys
openai_api_key = 'YOUR OPENAI API KEY'
cohere_api_key = 'YOUR COHEREAI API KEY'
anthropic_api_key = 'YOUR ANTHROPIC API KEY'
openai.api_key = openai_api_key
下載數據
我們在此實驗中使用 Llama2 論文,我們下載這篇論文。
!wget --user-agent "Mozilla" "https://arxiv.org/pdf/2307.09288.pdf" -O "llama2.pdf"
加載數據
讓我們加載數據。我們將使用第 36 頁之前的內容進行實驗,這排除了目錄、參考文獻和附錄。
然後,這些數據被解析並轉換爲節點,這些節點代表我們想要檢索的數據塊。我們使用了 512 作爲塊大小。
documents = SimpleDirectoryReader(input_files=["llama2.pdf"]).load_data()
node_parser = SimpleNodeParser.from_defaults(chunk_size=512)
nodes = node_parser.get_nodes_from_documents(documents)
生成問題 - 上下文對
爲了評估目的,我們創建了一個問答對數據集。這個數據集可以被看作是我們數據中的一組問題及其相應的上下文。爲了在評估嵌入(OpenAI/CohereAI)和重排器(CohereAI)時消除偏見,我們使用 Anthropic LLM 生成問答對。
讓我們初始化一個提示模板來生成問答對。
# Prompt to generate questions
qa_generate_prompt_tmpl = """\
Context information is below.
---------------------
{context_str}
---------------------
Given the context information and not prior knowledge.
generate only questions based on the below query.
You are a Professor. Your task is to setup \
{num_questions_per_chunk} questions for an upcoming \
quiz/examination. The questions should be diverse in nature \
across the document. The questions should not contain options, not start with Q1/ Q2. \
Restrict the questions to the context information provided.\
"""
llm = Anthropic(api_key=anthropic_api_key)
qa_dataset = generate_question_context_pairs(
nodes, llm=llm, num_questions_per_chunk=2
)
過濾掉類似這樣的句子的函數— Here are 2 questions based on provided context
# function to clean the dataset
def filter_qa_dataset(qa_dataset):
"""
Filters out queries from the qa_dataset that contain certain phrases and the corresponding
entries in the relevant_docs, and creates a new EmbeddingQAFinetuneDataset object with
the filtered data.
:param qa_dataset: An object that has 'queries', 'corpus', and 'relevant_docs' attributes.
:return: An EmbeddingQAFinetuneDataset object with the filtered queries, corpus and relevant_docs.
"""
# Extract keys from queries and relevant_docs that need to be removed
queries_relevant_docs_keys_to_remove = {
k for k, v in qa_dataset.queries.items()
if 'Here are 2' in v or 'Here are two' in v
}
# Filter queries and relevant_docs using dictionary comprehensions
filtered_queries = {
k: v for k, v in qa_dataset.queries.items()
if k not in queries_relevant_docs_keys_to_remove
}
filtered_relevant_docs = {
k: v for k, v in qa_dataset.relevant_docs.items()
if k not in queries_relevant_docs_keys_to_remove
}
# Create a new instance of EmbeddingQAFinetuneDataset with the filtered data
return EmbeddingQAFinetuneDataset(
queries=filtered_queries,
corpus=qa_dataset.corpus,
relevant_docs=filtered_relevant_docs
)
# filter out pairs with phrases `Here are 2 questions based on provided context`
qa_dataset = filter_qa_dataset(qa_dataset)
自定義檢索器
爲了確定最優的檢索器,我們採用了嵌入模型和重排器的組合。最初,我們建立了一個基礎的 VectorIndexRetriever
。檢索節點後,我們引入了重排器來進一步優化結果。值得注意的是,在這個特定的實驗中,我們將 similarity_top_k
設置爲 10,並選擇了重排器的前 5 個結果。然而,您可以根據您特定實驗的需求自由調整此參數。我們在這裏展示了使用 OpenAIEmbedding
的代碼,請參考 notebook 中其他嵌入模型的代碼。
embed_model = OpenAIEmbedding()
service_context = ServiceContext.from_defaults(llm=None, embed_model = embed_model)
vector_index = VectorStoreIndex(nodes, service_context=service_context)
vector_retriever = VectorIndexRetriever(index=vector_index, similarity_top_k = 10)
class CustomRetriever(BaseRetriever):
"""Custom retriever that performs both Vector search and Knowledge Graph search"""
def __init__(
self,
vector_retriever: VectorIndexRetriever,
) -> None:
"""Init params."""
self._vector_retriever = vector_retriever
def _retrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
"""Retrieve nodes given query."""
retrieved_nodes = self._vector_retriever.retrieve(query_bundle)
if reranker != 'None':
retrieved_nodes = reranker.postprocess_nodes(retrieved_nodes, query_bundle)
else:
retrieved_nodes = retrieved_nodes[:5]
return retrieved_nodes
async def _aretrieve(self, query_bundle: QueryBundle) -> List[NodeWithScore]:
"""Asynchronously retrieve nodes given query.
Implemented by the user.
"""
return self._retrieve(query_bundle)
async def aretrieve(self, str_or_query_bundle: QueryType) -> List[NodeWithScore]:
if isinstance(str_or_query_bundle, str):
str_or_query_bundle = QueryBundle(str_or_query_bundle)
return await self._aretrieve(str_or_query_bundle)
custom_retriever = CustomRetriever(vector_retriever)
評估
爲了評估我們的檢索器,我們計算了平均倒數排名(MRR)和命中率這兩個指標:
retriever_evaluator = RetrieverEvaluator.from_metric_names(
["mrr", "hit_rate"], retriever=custom_retriever
)
eval_results = await retriever_evaluator.aevaluate_dataset(qa_dataset)
結果
我們將各種嵌入模型和重排器進行了測試。以下是我們考慮的模型:
嵌入模型:
-
OpenAI Embedding
-
Voyage Embedding
-
CohereAI Embedding (v2.0/ v3.0)
-
Jina Embeddings (small/ base)
-
BAAI/bge-large-en
-
Google PaLM Embedding
重排器::
-
CohereAI
-
bge-reranker-base
-
bge-reranker-large
值得一提的是,這些結果爲這個特定數據集和任務提供了深入的性能洞察。然而,實際結果可能會因數據特性、數據集大小以及其他變量(如 chunk_size、similarity_top_k 等)而有所不同。
下面的表格展示了基於命中率和平均倒數排名(MRR)指標的評估結果:
複製再試一次分享
分析:
按嵌入模型的性能:
-
OpenAI:展示了一流的性能,尤其是與
CohereRerank
結合使用時(命中率 0.926966,MRR 0.86573)和bge-reranker-large
結合使用時(命中率 0.910112,MRR 0.855805),表明與重排工具的兼容性很強。 -
bge-large:在使用重排器時體驗到顯著的性能提升,最佳結果來自
CohereRerank
(命中率 0.876404,MRR 0.822753)。 -
llm-embedder:從重排中獲益匪淺,尤其是與
CohereRerank
結合使用時(命中率 0.882022,MRR 0.830243),這提供了顯著的性能提升。 -
Cohere:Cohere 的最新 v3.0 嵌入性能優於 v2.0,並且與原生
CohereRerank
集成後,顯著提高了其指標,擁有 0.88764 的命中率和 0.836049 的 MRR。 -
Voyage:具有強大的初始性能,通過
CohereRerank
進一步增強(命中率 0.91573,MRR 0.851217),表明對重排有很高的響應性。 -
JinaAI:性能非常強,在使用
bge-reranker-large
(命中率 0.938202,MRR 0.868539)和CohereRerank
(命中率 0.932584,MRR 0.873689)時看到了顯著的增益,表明重排顯著提升了其性能。 -
Google-PaLM:該模型展示了強大的性能,在使用
CohereRerank
時有可衡量的增益(命中率 0.910112,MRR 0.855712)。這表明重排爲其整體結果提供了明確的提升。
重排器的影響:
-
無重排器:這爲每種嵌入模型提供了基線性能。
-
bge-reranker-base:普遍提高了所有嵌入模型的命中率和 MRR。
-
bge-reranker-large:這個重排器經常爲嵌入模型提供最高或接近最高的 MRR。對於幾種嵌入,它的性能與
CohereRerank
相媲美或超越了它。 -
CohereRerank:在所有嵌入模型中一致性地增強了性能,通常提供了最佳或接近最佳的結果。
重排器的必要性:
-
數據清楚地表明瞭重排器在優化搜索結果中的重要性。幾乎所有嵌入模型都從重排中受益,顯示出提高的命中率和 MRR 值。
-
特別是
CohereRerank
,重排器已經證明了它們將任何嵌入模型轉變爲具有競爭力的能力。
總體優勢:
-
當考慮到命中率和 MRR 時,
penAI + CohereRerank
和JinaAI-Base + bge-reranker-large/CohereRerank
的組合作爲頂級競爭者脫穎而出。 -
然而,
CohereRerank/bge-reranker-large
重排器在不同嵌入模型中帶來的持續改進使它們成爲提升搜索質量的突出選擇,無論使用哪種嵌入模型。
總結來說,爲了在命中率和 MRR 上達到最佳性能,OpenAI
或 JinaAI-Base
嵌入與 CohereRerank/bge-reranker-large
重排器的組合顯得尤爲突出。
請注意,我們的基準測試旨在爲你自己的數據提供一個可復現的腳本。儘管如此,請將這些數字視爲估計值,並在解釋它們時謹慎行事。
結論:
在這篇博客文章中,我們展示瞭如何使用不同的嵌入模型和重排器來評估和增強檢索器的性能。以下是我們的最終結論。
-
嵌入模型:
OpenAI
和JinaAI-Base
嵌入模型,特別是與CohereRerank/bge-reranker-large
重排器搭配使用時,爲命中率和 MRR 設定了黃金標準。 -
重排器:重排器的影響,尤其是
CohereRerank/bge-reranker-large
,怎麼強調都不爲過。它們在提高許多嵌入模型的 MRR 方面發揮了關鍵作用,顯示了它們在使搜索結果更好的重要性。 -
基礎是關鍵:選擇適合初始搜索的正確嵌入模型至關重要;即使是最好的重排器,如果基本搜索結果不佳,也難以提供太多幫助。
-
協同工作:要從檢索器中獲得最佳效果,重要的是找到嵌入模型和重排器的正確組合。這項研究表明,仔細測試並找到最佳配對的重要性。
這些結論強調了在構建高效的檢索系統時,嵌入模型和重排器選擇的重要性,以及它們如何協同工作以提供最佳的搜索結果。
原文:https://www.llamaindex.ai/blog/boosting-rag-picking-the-best-embedding-reranker-models-42d079022e83
作者:Ravi Theja
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/nqAqbYciJKkzL78RE4DhLA