针对任何嵌入模型微调线性适配器

2023年09月07日 由 alex 发表 557 0

我们在LlamaIndex中添加了功能,允许你在任何模型(sentence_transformers、OpenAI等)生成的嵌入之上进行线性适配器的微调。


这使你可以将嵌入表示转化为一个新的潜在空间,该空间经过了针对你特定的数据和查询进行了优化的重新调整。这可能会导致检索性能的小幅提升,从而进一步提高RAG系统的性能。


一个好处是:使用这个适配器,你不需要重新嵌入文档!只需转换查询即可。


1


语境


微调嵌入模型的概念非常有用。实际上,我们受到了启发,添加了一个完整的示例存储库和博文,以及LlamaIndex中的本地抽象,展示了如何对任何非结构化文本语料库进行sentence_transformers模型的微调(使用我们的SentenceTransformersFinetuneEngine)。


然而,这种方法存在一些局限性:


1. SentenceTransformersFinetuneEngine仅限于对sentence_transformers模型进行微调。


2. 在微调嵌入模型之后,你需要重新嵌入文档语料库。


在一次Finetuning + RAG网络研讨会上,Jo(Vespa)提到了完全相同的问题:对嵌入模型进行微调需要重新索引文档。然而,他与Vespa的合作研究探讨了使用基础模型“冻结”文档嵌入的概念,而是在查询嵌入上训练一个转换。


这给我们提供了灵感,尝试一种类似的嵌入微调方法,既更加通用,又允许我们冻结现有的文档嵌入。


方法


我们全新的EmbeddingAdapterFinetuneEngine在任何模型生成的查询嵌入之上微调一个线性适配器。线性适配器只是一个线性变换,专门转换查询嵌入,同时保持文档嵌入不变。


线性适配器可以在任何现有的嵌入模型上使用: SBERT嵌入、OpenAI嵌入、Cohere嵌入等。因此,你可以将其直接连接到你已经使用的任何嵌入模型之上!


1-2


由于文档嵌入没有改变,这意味着在生成文档嵌入后,你始终可以对这个线性适配器进行微调。你可以选择任意在不同数据分布上重新训练这个适配器,而无需重新嵌入所有文档。


技术细节


如上所述,线性适配器只是在查询嵌入之上执行线性变换,同时保持文档嵌入固定(使用一个权重矩阵W和一个偏置项b):


                               1-3


就是这样!如果将文档嵌入表示为一个(nxd)矩阵D,其中n是文档数量,d是嵌入维度,那么嵌入相似度就可以通过以下方式进行衡量:


                  1-4


线性适配器使用了与sentence_transformers中的MultipleNegativesRankingLoss函数类似的损失项来进行训练。给定一批正样本(问题,上下文)例子,该函数在底层使用交叉熵损失来惩罚真实的(问题,上下文)对之间的距离远以及交换对之间的距离太近。


Notebook演示


在这个Notebook演示中,我们按照我们之前的关于嵌入微调的博文采取了类似的步骤:


1. 为训练和评估生成一个合成的问题-上下文数据集。


2. 在现有模型(例如SBERT)之上微调我们的线性适配器。


3. 获取嵌入模型,并进行评估。


生成用于训练和评估的综合数据集


我们使用我们的辅助函数generate_qa_embedding_pairs来生成我们的训练和评估数据集。该函数接受任何文本节点(块)的集合,并生成一个包含(问题,上下文)对的结构化数据集。


from llama_index.finetuning import (
    generate_qa_embedding_pairs,
    EmbeddingQAFinetuneDataset,
)
# generate
train_dataset = generate_qa_embedding_pairs(train_nodes)
val_dataset = generate_qa_embedding_pairs(val_nodes)
# save
train_dataset.save_json("train_dataset.json")
val_dataset.save_json("val_dataset.json")
# load 
train_dataset = EmbeddingQAFinetuneDataset.from_json("train_dataset.json")
val_dataset = EmbeddingQAFinetuneDataset.from_json("val_dataset.json")


微调我们的线性适配器


然后,我们在现有的嵌入模型上微调我们的线性适配器。我们导入我们的新的EmbeddingAdapterFinetuneEngine抽象,它接受一个现有的嵌入模型和一组训练参数。


在这个例子中,我们使用了bge-small-en sentence-transformers模型,但我们也可以使用LlamaIndex/LangChain中的任何嵌入模型。


from llama_index.finetuning import EmbeddingAdapterFinetuneEngine
from llama_index.embeddings import resolve_embed_model
import torch
base_embed_model = resolve_embed_model("local:BAAI/bge-small-en")
# alternative: use OpenAI
# from llama_index.embeddings import OpenAIEmbedding
# openai = OpenAIEmbedding()
finetune_engine = EmbeddingAdapterFinetuneEngine(
    train_dataset,
    base_embed_model,
    model_output_path="<model_output_path>",
    epochs=4,
    verbose=True,
    # can optionally pass along any parameters that go into `train_model`
    # optimizer_class=torch.optim.SGD,
    # optimizer_params={"lr": 0.01}
)


然后,我们可以调用fine-tune来启动微调任务。训练线性模型非常简单,不需要大量的计算资源 - 它可以在Macbook上轻松运行。


finetune_engine.finetune()


获取嵌入模型并对其进行评估


一旦微调任务完成,我们可以获取我们的嵌入模型。


我们可以直接从finetune_engine中获取,或者以更手动的方式导入我们的新的LinearAdapterEmbeddingModel并构建它。


选项1:


embed_model = finetune_engine.get_finetuned_model()


选项2:


from llama_index.embeddings import LinearAdapterEmbeddingModel
embed_model = LinearAdapterEmbeddingModel(base_embed_model, "<model_output_path>")


下一步是对其进行评估。我们将精调模型与基础模型以及text-embedding-ada-002进行比较。


我们使用两个排名指标进行评估:


1. 命中率指标: 对于每个(查询,上下文)对,我们检索具有查询的前k个文档。如果结果包含了正确的上下文,就算是命中。


2. 平均倒数排名(Mean Reciprocal Rank):一种稍微更精细的排名指标,它查看了在检索到的前k个文档集合中的正确上下文的“倒数排名”。倒数排名定义为1/排名。当然,如果结果中不包含上下文,则倒数排名为0。


结果


1-5


就命中率而言,基础模型在验证数据集上的命中率为78.7%,而微调模型为79.8%。与此同时,text-embedding-ada-002的命中率为87.0%。


就MRR而言,基础模型为64.3%,微调模型为66%,text-embedding-ada-002为68.4%。


微调模型在性能上有一些提升,尽管可以承认这个提升很小 - 它比直接在最新数据集上微调sentence_transformers获得的性能提升要小。


结论


我们在LlamaIndex中创建了一个全新的模块,可以让你在任何嵌入模型之上进行线性适配器的微调。


它可以帮助你在检索指标上获得一些微小的改进;重要的是,它允许你保持文档嵌入固定,只对查询进行转换。



文章来源:https://medium.com/llamaindex-blog/fine-tuning-a-linear-adapter-for-any-embedding-model-8dd0a142d383
欢迎关注ATYUN官方公众号
商务合作及内容投稿请联系邮箱:bd@atyun.com
评论 登录
热门职位
Maluuba
20000~40000/月
Cisco
25000~30000/月 深圳市
PilotAILabs
30000~60000/年 深圳市
写评论取消
回复取消