在自然語言處理領域,選擇合適的 embedding 模型對於下游任務至關重要。本文介紹如何使用 Ragas 和 LangChain 評估 OpenAI 的 embedding 模型,並探討如何利用 SentenceTransformer 進行句子相似度分析和模型微調。評估指標包含上下文實體召回率,並提供 Python 程式碼示範如何使用向量資料函式庫,例如 FAISS,進行相似度搜尋,以提升資訊檢索效率。同時,也提供使用 SentenceTransformer 進行模型微調的程式碼範例,以適應特定領域的資料。

Embedding 模型評估框架

評估不同 embedding 模型的效能是一個重要的步驟,以確保選擇最適合特定應用域的模型。一個良好的評估框架應該包括一系列的評估資料集和指標,以便能夠公平地比較不同的模型。

評估指標

在資訊檢索應用中,以下評估指標被廣泛使用:

  • Context Precision:評估檢索結果中是否包含了與輸入查詢相關的真實事實。
  • Context Entities Recall:評估檢索結果中包含了多少實體(entities)與真實事實相符。

Ragas 框架提供了這些評估指標,以及其他用於評估 RAG(Retrieval-Augmented Generation)模型的指標。

程式碼示例

以下程式碼示例使用 Ragas 和 LangChain 來評估不同 embedding 模型在 Context Entities Recall 指標上的效能。

安裝依賴函式庫

pip3 install ragas==0.1.13 datasets==2.20.0 langchain==0.2.12 openai==1.39.0 faiss-cpu==1.8.0.post1

評估程式碼

from ragas.metrics import context_entity_recall
from ragas import evaluate, RunConfig
from datasets import load_dataset, Dataset
from langchain_openai import ChatOpenAI, OpenAIEmbeddings
from langchain_text_splitters import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import FAISS
import os
from typing import List

# 載入 OpenAI API 金鑰
openai_api_key = os.getenv("OPENAI_API_KEY")

# 載入示例資料集
dataset = load_dataset("explodinggradients/amnesty_qa", split="eval")
sample_size = 100

# 取得示例查詢問題
sample_questions = dataset['question'][:sample_size]

執行評估

# 建立 Ragas 評估組態
run_config = RunConfig(
    # 指定評估指標
    metric=context_entity_recall,
    # 指定 embedding 模型
    embeddings=[OpenAIEmbeddings(model="text-embedding-ada-002"), OpenAIEmbeddings(model="text-embedding-3-large")],
    # 指定查詢問題
    queries=sample_questions,
    # 指定資料集
    dataset=dataset,
    # 指定批次大小
    batch_size=16,
)

# 執行評估
evaluation_results = evaluate(run_config)

結果分析

評估結果將包含每個 embedding 模型在 Context Entities Recall 指標上的效能。這些結果可以用來比較不同模型的效能,並選擇最適合特定應用域的模型。

圖表翻譯:

  flowchart TD
    A[載入資料集] --> B[建立 Ragas 評估組態]
    B --> C[執行評估]
    C --> D[分析結果]
    D --> E[選擇最佳模型]

內容解密:

上述程式碼示例展示瞭如何使用 Ragas 和 LangChain 來評估不同 embedding 模型的效能。首先,需要載入示例資料集和查詢問題。然後,需要建立 Ragas 評估組態,指定評估指標、embedding 模型、查詢問題和資料集。最後,需要執行評估並分析結果,以選擇最適合特定應用域的模型。

文字嵌入模型評估

在自然語言處理(NLP)中,文字嵌入模型扮演著至關重要的角色,它們能夠將文字轉換為數值向量,以便於電腦進行處理。在本文中,我們將探討如何評估不同的文字嵌入模型,特別是OpenAI的文字嵌入模型,並展示如何使用向量搜尋來檢索相關的上下文資訊。

文字預處理

為了評估文字嵌入模型,我們首先需要從樣本資料集中取得上下文資訊和真實標籤。這些資訊對於訓練和評估模型至關重要。

sample_contexts = [item for row in dataset["contexts"][:sample_size] for item in row]
sample_ground_truths = [item for row in dataset["ground_truths"][:sample_size] for item in row]

接下來,我們需要將樣本上下文分割成塊,以便於使用向量搜尋。這一步驟可以使用遞迴字元文字分割器(RecursiveCharacterTextSplitter)來實作。

text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=400, chunk_overlap=100, add_start_index=True
)
chunks: List[str] = []
for context in sample_contexts:
    split_chunks = text_splitter.split_text(context)
    chunks.extend(split_chunks)

嵌入模型評估

我們將評估兩個OpenAI的文字嵌入模型:text-embedding-ada-002text-embedding-3-large。為了進行評估,我們需要建立一個記憶體中的向量儲存,並使用OpenAI嵌入模型對塊進行嵌入。

openai_embedding_models = ["text-embedding-ada-002", "text-embedding-3-large"]
for embedding_model in openai_embedding_models:
    db = FAISS.from_texts(
        chunks, OpenAIEmbeddings(openai_api_key=openai_api_key, model=embedding_model)
    )

相似性搜尋

使用嵌入模型後,我們可以進行相似性搜尋來檢索相關的上下文資訊。這一步驟可以使用向量儲存中的搜尋功能來實作。

retrieval_contexts: List[str] = []
for question in sample_questions:
    # 進行相似性搜尋並檢索相關上下文
    pass

內容解密:

在上述程式碼中,我們使用遞迴字元文字分割器將樣本上下文分割成塊。這一步驟是為了使得向量搜尋能夠更有效地工作。接下來,我們建立了一個記憶體中的向量儲存,並使用OpenAI嵌入模型對塊進行嵌入。最後,我們進行相似性搜尋來檢索相關的上下文資訊。

圖表翻譯:

以下是使用Mermaid語法繪製的程式邏輯流程圖:

  flowchart TD
    A[取得樣本上下文] --> B[分割上下文]
    B --> C[建立向量儲存]
    C --> D[進行嵌入]
    D --> E[相似性搜尋]
    E --> F[檢索相關上下文]

在這個流程圖中,我們可以看到程式的邏輯流程:從取得樣本上下文開始,到分割上下文、建立向量儲存、進行嵌入、相似性搜尋,最後到檢索相關上下文。這個流程圖有助於我們更好地理解程式的邏輯結構。

執行評估和微調嵌入模型

在上一節中,我們已經瞭解瞭如何使用預先訓練好的嵌入模型來進行相似度搜尋。現在,我們將更深入地探討如何評估和微調這些模型,以便它們能夠更好地適應您的特定使用案例。

評估嵌入模型

評估嵌入模型的效能是確保它們能夠有效地捕捉您資料中的語義關係的關鍵步驟。以下是一個簡單的例子,展示瞭如何使用 evaluate 函式來評估嵌入模型的效能:

search_results = db.similarity_search(question)
retrieval_contexts.append(list(map(lambda result: result.page_content, search_results)))

result = evaluate(
    dataset=Dataset.from_dict({
        "question": sample_questions,
        "contexts": retrieval_contexts,
        "ground_truth": sample_ground_truths
    }),
    metrics=[context_entity_recall],
    run_config=ragas_run_config,
    raise_exceptions=False,
    llm=ChatOpenAI(openai_api_key=openai_api_key, model_name="gpt-4o-mini")
)

print(f"Results for embedding model '{embedding_model}':")
print(result)

這段程式碼會輸出評估結果,例如:

Results for embedding model 'text-embedding-ada-002': {'context_entity_recall': 0.5687}
Results for embedding model 'text-embedding-3-large': {'context_entity_recall': 0.5973}

如您所見,text-embedding-3-large 在這個評估中取得了更高的上下文實體召回率。上下文相關性評分被標準化在 0 到 1 之間。

微調嵌入模型

除了嘗試不同的預先訓練模型外,您還可以微調預先訓練好的嵌入模型,以最佳化它們以適應您的特定使用案例。微調嵌入模型在以下情況下可能是有益的:

  1. 領域特定資料:如果您的應用程式涉及領域特定資料,可能不會被現成的模型很好地捕捉,例如具有專門術語的法律檔案或醫學記錄,微調可以幫助模型更好地理解和表示領域特定概念。
  2. 避免不想要的匹配:在似乎相似的概念應該被區分的情況下,微調可以幫助模型之間進行區分。例如,您可以微調模型以區分蘋果公司和蘋果水果。

然而,現成的嵌入模型通常對於許多工都具有很高的效能,特別是當它們與後面章節中討論的其他最佳化方法結合使用時。

微調嵌入模型的可用選項可能會根據模型及其主機而有所不同。託管模型主機提供商可能只暴露其模型的某些方法,而使用開源模型可以提供更多的靈活性。

SentenceTransformers 通常涉及提供類別似句子的對,以及可選地包含相似度的量度。或者,可以提供錨點、正面和負面示例來指導微調過程。以下是一個簡單的示例,展示瞭如何使用 SentenceTransformers 和 PyTorch 函式庫來微調開源嵌入模型 gte-base-en-v1.5

from sentence_transformers import SentenceTransformer, InputExample, losses, util
from torch.utils.data import DataLoader

# 安裝依賴項
pip3 install sentence-transformers==3.0.1 torch==2.2.2

# 載入模型和資料
model = SentenceTransformer('gte-base-en-v1.5')

# 定義錨點、正面和負面示例
anchor = "I love eating apples."
positive = "Apples are my favorite fruit."
negative = "Apple is a tech company."

# 建立輸入示例
input_example = InputExample(texts=[anchor, positive, negative])

# 建立資料載入器
data_loader = DataLoader([input_example], batch_size=1)

# 定義損失函式
loss = losses.MultipleNegativesRankingLoss(model)

# 執行微調
model.fit(data_loader, epochs=1, loss=loss)

這個簡單的示例展示瞭如何使用 SentenceTransformers 和 PyTorch 來微調嵌入模型。您需要根據您的具體需求和資料來調整錨點、正面和負面示例,以及其他引數。

使用 SentenceTransformer 進行句子相似度分析

SentenceTransformer 是一個強大的函式庫,能夠將句子轉換為向量,並計算不同句子之間的相似度。以下是使用 SentenceTransformer 進行句子相似度分析的範例程式碼:

from sentence_transformers import SentenceTransformer, util

# 初始化 SentenceTransformer 模型 (使用 all-mpnet-base-v2 模型)
model = SentenceTransformer('all-mpnet-base-v2')

# 範例句子
sentences = [
    "This framework generates embeddings for each input sentence",
    "Sentences are converted to vectors",
    "Embeddings are generated by the framework",
    "This is an embedding generation framework",
    "Apple is a tech company",
    "I love eating apples"
]

# 將句子轉換成嵌入向量
embeddings = model.encode(sentences)

# 計算句子相似度
for i in range(len(sentences)):
    for j in range(i + 1, len(sentences)):
        similarity = util.cos_sim(embeddings[i], embeddings[j])
        print(f"Similarity between '{sentences[i]}' and '{sentences[j]}': {similarity[0][0]}")


# 使用相似度進行搜尋
query = "Generate embeddings for sentences"
query_embedding = model.encode(query)

# 計算查詢與所有句子的相似度
similarities = util.cos_sim(query_embedding, embeddings)

# 找出最相似的句子
most_similar_index = similarities.argmax()
most_similar_sentence = sentences[most_similar_index]

print(f"Most similar sentence to '{query}': '{most_similar_sentence}'")


# 根據相似度排序句子
sorted_indices = similarities.argsort(descending=True)
sorted_sentences = [sentences[i] for i in sorted_indices[0]]

print(f"Sentences sorted by similarity to '{query}': {sorted_sentences}")

結論

本文深入探討了評估和微調嵌入模型的最佳實務。從使用Ragas框架進行評估,到利用SentenceTransformers微調模型以適應特定領域,我們提供了全面的。我們強調了上下文實體召回率等關鍵指標的重要性,並闡明瞭如何利用這些指標來比較不同模型的效能。此外,我們還探討了微調嵌入模型的優勢,特別是在處理特定領域資料和避免不必要的匹配時。雖然現成的嵌入模型通常表現良好,但微調可以進一步提升其在特定應用場景下的效能。展望未來,隨著嵌入技術的持續發展,預期將出現更多精密的評估和微調技術,從而進一步提升自然語言處理應用的準確性和效率。對於臺灣的開發者而言,掌握這些技術至關重要,以便在日益競爭的全球市場中保持領先地位。我們建議技術團隊持續關注最新的研究成果,並積極探索如何將這些技術應用於實際專案中,以最大化其商業價值。