【finetuning】在黑盒嵌入模型上微调适配器分析

发布时间:2026/7/17 5:37:40

【finetuning】在黑盒嵌入模型上微调适配器分析 案例目标本案例展示了如何在任何黑盒嵌入模型如sentence_transformers、OpenAI等之上微调适配器。通过将嵌入表示转换为针对特定数据和查询优化的新潜在空间可以提高检索性能进而提升RAG系统的整体表现。该案例实现了三种类型的适配器微调线性适配器Linear Adapter两层神经网络适配器2-Layer NN Adapter自定义神经网络适配器Custom NN Adapter技术栈与核心依赖LlamaIndex: 提供EmbeddingAdapterFinetuneEngine等核心微调功能llama-index-embeddings-openai: 提供OpenAI嵌入模型支持llama-index-embeddings-adapter: 提供适配器嵌入模型支持llama-index-finetuning: 提供微调引擎和工具PyTorch: 用于构建自定义神经网络适配器BAAI/bge-small-en: 作为基础嵌入模型进行微调OpenAI Embedding (text-embedding-ada-002): 作为对比基准环境配置安装必要的依赖包%pip install llama-index-embeddings-openai %pip install llama-index-embeddings-adapter %pip install llama-index-finetuning案例实现数据准备与加载使用Lyft 2021年10K报告作为训练数据Uber 2021年10K报告作为验证数据TRAIN_FILES [./data/10k/lyft_2021.pdf] VAL_FILES [./data/10k/uber_2021.pdf]定义加载和解析文档的函数def load_corpus(files, verboseFalse): if verbose: print(fLoading files {files}) reader SimpleDirectoryReader(input_filesfiles) docs reader.load_data() if verbose: print(fLoaded {len(docs)} docs) parser SentenceSplitter() nodes parser.get_nodes_from_documents(docs, show_progressverbose) if verbose: print(fParsed {len(nodes)} nodes) return nodes生成合成查询使用LLMgpt-3.5-turbo为每个文本块生成问题构建问题上下文对作为微调数据from llama_index.finetuning import generate_qa_embedding_pairs from llama_index.core.evaluation import EmbeddingQAFinetuneDataset train_dataset generate_qa_embedding_pairs(train_nodes) val_dataset generate_qa_embedding_pairs(val_nodes)线性适配器微调使用EmbeddingAdapterFinetuneEngine对BAAI/bge-small-en模型进行线性适配器微调from llama_index.finetuning import EmbeddingAdapterFinetuneEngine from llama_index.core.embeddings import resolve_embed_model import torch base_embed_model resolve_embed_model(local:BAAI/bge-small-en) finetune_engine EmbeddingAdapterFinetuneEngine( train_dataset, base_embed_model, model_output_pathmodel_output_test, epochs4, verboseTrue, ) finetune_engine.finetune() embed_model finetune_engine.get_finetuned_model()两层神经网络适配器微调定义并使用两层神经网络适配器进行微调from llama_index.core.embeddings.adapter_utils import TwoLayerNN base_embed_model resolve_embed_model(local:BAAI/bge-small-en) adapter_model TwoLayerNN( 384, # input dimension 1024, # hidden dimension 384, # output dimension biasTrue, ) finetune_engine EmbeddingAdapterFinetuneEngine( train_dataset, base_embed_model, model_output_pathmodel5_output_test, model_checkpoint_pathmodel5_ck, adapter_modeladapter_model, epochs25, verboseTrue, ) finetune_engine.finetune() embed_model_2layer finetune_engine.get_finetuned_model(adapter_clsTwoLayerNN)自定义神经网络适配器微调通过继承BaseAdapter类创建自定义神经网络适配器from llama_index.core.embeddings.adapter_utils import BaseAdapter import torch.nn.functional as F from torch import nn, Tensor from typing import Dict class CustomNN(BaseAdapter): Custom NN transformation. Is a copy of our TwoLayerNN, showing it here for notebook purposes. Args: in_features (int): Input features hidden_features (int): Hidden features out_features (int): Output features bias (bool): Whether to use bias add_residual (bool): Whether to add residual connection def __init__( self, in_features: int, hidden_features: int, out_features: int, bias: bool True, add_residual: bool True, ): super().__init__() self.in_features in_features self.hidden_features hidden_features self.out_features out_features self.bias bias self._add_residual add_residual self.linear1 nn.Linear(in_features, hidden_features, biasbias) self.linear2 nn.Linear(hidden_features, out_features, biasbias) self.residual_weight nn.Parameter(torch.ones(1)) def forward(self, embed: Tensor) - Tensor: output1 self.linear1(embed) output1 F.relu(output1) output2 self.linear2(output1) if self._add_residual: output2 self.residual_weight * output2 embed return output2 def get_config_dict(self) - Dict: Get config dict. return { in_features: self.in_features, hidden_features: self.hidden_features, out_features: self.out_features, bias: self.bias, add_residual: self._add_residual, }模型评估使用命中率(Hit-rate)和平均倒数排名(MRR)指标评估模型性能from llama_index.embeddings.openai import OpenAIEmbedding from llama_index.core import VectorStoreIndex from llama_index.core.schema import TextNode from tqdm.notebook import tqdm import pandas as pd from eval_utils import evaluate, display_results # 评估OpenAI ada模型 ada OpenAIEmbedding() ada_val_results evaluate(val_dataset, ada) # 评估基础BGE模型 bge local:BAAI/bge-small-en bge_val_results evaluate(val_dataset, bge) # 评估微调后的模型 ft_val_results evaluate(val_dataset, embed_model)案例效果通过对比实验评估了不同模型的检索性能模型命中率(Hit-rate)平均倒数排名(MRR)OpenAI ada0.8708860.72884BGE基础模型0.7873420.643038线性适配器微调模型0.7987340.662152两层神经网络适配器微调模型0.7987340.662848自定义神经网络适配器微调模型0.7898730.645127关键发现OpenAI的ada模型表现最佳但需要API调用且成本较高微调后的适配器模型相比基础BGE模型有显著提升线性适配器和两层神经网络适配器性能相近适配器微调提供了一种在保持基础模型不变的情况下提升性能的方法案例实现思路本案例的核心实现思路是数据准备使用金融文档(Lyft和Uber的10K报告)构建训练和验证语料库合成查询生成利用LLM为每个文本块生成相关问题构建(问题,上下文)对适配器微调在基础嵌入模型之上添加可训练的适配器层只训练适配器参数而不修改基础模型多类型适配器实现线性、两层神经网络和自定义神经网络三种适配器结构性能评估使用命中率和MRR指标评估微调效果并与OpenAI和基础模型对比适配器微调的优势在于不需要修改基础嵌入模型适用于任何黑盒模型训练参数量少计算资源需求低可以针对特定领域数据进行定制化优化支持多种适配器结构可根据需求选择扩展建议更多适配器结构尝试更复杂的神经网络结构如注意力机制、Transformer等领域特定优化针对特定领域(如医疗、法律等)设计专门的适配器结构多模态适配器扩展到多模态嵌入模型支持文本、图像等多种数据类型动态适配器根据查询内容动态选择或组合不同的适配器适配器压缩研究如何压缩适配器模型减少存储和计算开销适配器共享探索在多个任务或领域间共享适配器参数的方法增量微调支持在新数据上增量更新适配器而不需要重新训练总结本案例详细介绍了如何在黑盒嵌入模型上微调适配器通过将嵌入表示转换为针对特定数据和查询优化的新潜在空间提高了检索性能。案例实现了线性、两层神经网络和自定义神经网络三种适配器结构并通过实验验证了微调后模型相比基础模型的性能提升。适配器微调方法具有不修改基础模型、训练参数少、计算资源需求低等优势为优化现有嵌入模型提供了一种灵活高效的途径。这种方法特别适用于需要在保持基础模型不变的情况下针对特定领域或任务进行定制化优化的场景。

相关新闻