【finetuning】交叉编码器微调案例

本案例演示如何使用LlamaIndex微调交叉编码器,以提高检索系统的重排序效果。通过使用QASPER数据集,我们将展示从数据准备、模型微调到评估的完整流程。

1. 案例目标

本案例的主要目标是:

  1. 学习交叉编码器微调:了解如何使用LlamaIndex对交叉编码器进行微调,以适应特定领域的重排序任务。
  2. 提高检索效果:通过微调交叉编码器,提升检索系统的重排序能力,从而提高检索结果的准确性。
  3. 评估微调效果:学习如何使用多种评估方法(如Hits指标、pairwise比较)来量化微调前后模型性能的差异。

2. 技术栈与核心依赖

  • LlamaIndex:用于构建检索增强生成(RAG)系统的核心框架
  • llama-index-finetuning-cross-encoders:LlamaIndex的交叉编码器微调模块
  • sentence-transformers:用于加载和使用预训练的句子嵌入模型
  • datasets:Hugging Face数据集库,用于加载和处理QASPER数据集
  • OpenAI API:用于生成评估数据
  • Hugging Face Hub:用于保存和分享微调后的模型

3. 环境配置

在开始之前,需要安装以下依赖包:

!pip install llama-index-finetuning-cross-encoders !pip install datasets !pip install sentence-transformers !pip install openai !pip install huggingface_hub

此外,还需要设置以下环境变量:

import os os.environ["OPENAI_API_KEY"] = "YOUR_API_KEY"

4. 案例实现

4.1 数据准备

本案例使用QASPER数据集,这是一个包含学术论文及其相关问答的数据集。我们首先加载数据集并进行预处理:

from datasets import load_dataset # 加载QASPER数据集 qasper_dataset = load_dataset("allenai/qasper") # 抽取部分数据用于训练和测试 train_dataset = qasper_dataset["train"].shuffle(seed=42).select(range(800)) test_dataset = qasper_dataset["test"].shuffle(seed=42).select(range(80))

接下来,我们定义一些辅助函数来处理论文文本和问题提取:

def get_full_text(paper): """获取论文的全文""" full_text = "" if "title" in paper: full_text += paper["title"] + "\n\n" if "abstract" in paper: full_text += paper["abstract"] + "\n\n" # 添加全文内容 for section in paper["full_text"]: section_name = section["section_name"] section_text = " ".join(section["paragraphs"]) full_text += f"{section_name}\n{section_text}\n\n" return full_text def get_questions(paper): """获取论文中的所有问题""" return [q["question"] for q in paper["qas"]]

4.2 生成微调数据

我们使用LlamaIndex的generate_finetuning_dataset函数来生成微调数据:

from llama_index.finetuning.cross_encoders import generate_finetuning_dataset # 生成微调数据 finetuning_dataset = generate_finetuning_dataset( train_dataset, get_full_text, get_questions, max_chunk_length=256, top_k=5, output_path="fine_tuning.csv" )

这个过程会生成11674条微调样本,每条样本包含一个查询和相关文档的片段,以及它们的相关性标签。

4.3 微调交叉编码器

接下来,我们使用生成的微调数据来微调交叉编码器:

from llama_index.finetuning.cross_encoders import CrossEncoderFinetuneEngine # 初始化微调引擎 finetune_engine = CrossEncoderFinetuneEngine( model_name="cross-encoder/ms-marco-MiniLM-L-12-v2", train_dataset_path="fine_tuning.csv", model_output_path="finetuned_cross_encoder", epochs=3, batch_size=16, learning_rate=2e-5, warmup_steps=50, save_steps=200, eval_steps=200, logging_steps=50, ) # 开始微调 finetune_engine.finetune()

微调完成后,我们可以将模型推送到Hugging Face Hub:

from huggingface_hub import HfApi, notebook_login # 登录Hugging Face notebook_login() # 推送模型 finetune_engine.push_to_hub("your-username/finetuned-cross-encoder")

4.4 评估微调效果

我们使用多种方法来评估微调后的交叉编码器效果:

4.4.1 使用Hits指标评估
from llama_index.core.evaluation import RetrieverEvaluator from llama_index.core.schema import TextNode, NodeWithScore # 创建评估数据 eval_data = [] for paper in test_dataset: full_text = get_full_text(paper) questions = get_questions(paper) # 创建节点 node = TextNode(text=full_text) # 为每个问题创建查询和期望结果 for question in questions: eval_data.append({ "query": question, "expected_ids": [node.id], "mode": "default" }) # 评估原始模型 original_retriever = VectorIndexRetriever(index=index, similarity_top_k=5) original_evaluator = RetrieverEvaluator.from_metric_names( ["hit_rate"], retriever=original_retriever ) original_results = original_evaluator.evaluate(eval_data) # 评估微调后的模型 finetuned_retriever = VectorIndexRetriever( index=index, similarity_top_k=5, reranker=CrossEncoderReranker(model_name="your-username/finetuned-cross-encoder") ) finetuned_evaluator = RetrieverEvaluator.from_metric_names( ["hit_rate"], retriever=finetuned_retriever ) finetuned_results = finetuned_evaluator.evaluate(eval_data)
4.4.2 使用Pairwise比较评估
from llama_index.core.evaluation import PairwiseComparisonEvaluator # 创建比较评估器 pairwise_evaluator = PairwiseComparisonEvaluator( llm=OpenAI(model="gpt-4") ) # 比较原始模型和微调后模型的结果 pairwise_results = [] for query in test_queries: # 获取原始模型结果 original_response = original_query_engine.query(query) # 获取微调后模型结果 finetuned_response = finetuned_query_engine.query(query) # 进行比较评估 result = pairwise_evaluator.evaluate( query=query, response=original_response, reference=finetuned_response ) pairwise_results.append(result)

5. 案例效果

通过实验,我们观察到以下结果:

5.1 Hits指标对比

  • 无重排序器:Hits@5 = 30
  • 基础交叉编码器:Hits@5 = 34
  • 微调交叉编码器:Hits@5 = 37

5.2 Pairwise比较结果

  • 无重排序器:平均pairwise得分 = 0.553788
  • 基础交叉编码器:平均pairwise得分 = 0.556818
  • 微调交叉编码器:平均pairwise得分 = 0.6

这些结果表明,微调后的交叉编码器在重排序任务上表现更好,能够更准确地识别与查询最相关的文档。

6. 案例实现思路

6.1 数据准备

我们选择QASPER数据集是因为它包含了学术论文及其相关问题,非常适合用于学术检索系统的微调。通过提取论文全文和问题,我们创建了高质量的查询-文档对。

6.2 微调策略

我们选择了"cross-encoder/ms-marco-MiniLM-L-12-v2"作为基础模型,因为它在重排序任务上表现良好且模型大小适中。微调过程中,我们使用了较小的学习率(2e-5)和适当的批次大小(16),以确保模型能够稳定学习。

6.3 评估方法

我们采用了多种评估方法来全面衡量模型性能:

  • Hits指标:衡量正确答案出现在前K个结果中的频率
  • Pairwise比较:使用GPT-4作为评估器,比较不同模型的响应质量

7. 扩展建议

  • 使用更大的数据集:增加训练数据量可能会进一步提升模型性能
  • 尝试不同的基础模型:实验不同的预训练交叉编码器作为基础模型
  • 调整超参数:优化学习率、批次大小等超参数
  • 领域自适应微调:针对特定领域(如医学、法律)进行微调
  • 集成到RAG系统:将微调后的交叉编码器集成到完整的RAG系统中

8. 总结

本案例展示了如何使用LlamaIndex微调交叉编码器,以提高检索系统的重排序效果。通过QASPER数据集的实验,我们证明了微调后的交叉编码器在Hits指标和Pairwise比较上都优于基础模型。这种方法可以应用于各种领域,以提升检索系统的性能。

交叉编码器微调的关键在于:

  1. 高质量的数据:需要准备与目标领域相关的查询-文档对
  2. 合适的微调策略:选择适当的基础模型和超参数
  3. 全面的评估:使用多种评估方法来衡量模型性能

通过本案例的学习,您应该能够掌握交叉编码器微调的基本流程,并将其应用到自己的检索系统中。