最先进的检索增强型LLM:bge-large-en-v1.5

最先进的检索增强型LLM:bge-large-en-v1.5

简介

你对先进的检索增强型LLM“bge-large-en-v1.5”感兴趣吗?加入我们这篇博客,深入探索这个模型。你将了解嵌入模型的作用及其实际应用。我们将引导你通过代码部署“bge-large-en-v1.5”,进行微调,并将其无缝集成到LLM API中。准备好解锁嵌入模型与LLM交叉领域的新可能性!

什么是 bge-large-en-v1.5?

简而言之,bge-large-en-v1.5 是由 BAAI 创建的开源嵌入模型。

具体来说,“bge-large-en-v1.5”中的“bge”代表“BAAI General Embedding”。BAAI(在 GitHub 上也被称为“FlagEmbedding”)是一家专注于人工智能研究与开发的非营利组织。BAAI 专注于检索增强型大语言模型(LLM),并已启动了多个相关项目。这些项目包括长上下文 LLM(Activation Beacon)、LM 微调(LM-Cocktail)、密集检索(BGE-M3、LLM Embedder、BGE Embedding)、重排序模型(BGE Reranker)以及基准测试(C-MTEB)。Bge-large-en-v1.5 属于 BGE Embedding 模型系列,专门用于密集检索目的。

用于密集检索的嵌入模型有什么作用?

用于密集检索的嵌入模型将文本数据转换为密集的语义表示,这些表示捕获了输入的语义和上下文。密集检索器利用这些密集表示来高效地检索相关信息。以下是其工作原理和一些示例:

将文本转换为密集表示

嵌入模型接收句子、段落或整个文档作为输入,并将它们转换为固定长度的向量(嵌入)。这些向量编码了文本的语义信息,使得理解比简单的关键词匹配更加细致入微。

LLM 通常将嵌入模型作为其架构的一部分。例如,BERT 在通过其 Transformer 层处理输入序列之前使用嵌入技术来表示单词和输入序列。LLM 通过利用嵌入模型捕获语义关系和上下文细微差别的能力而受益,这对于在对话生成或机器翻译等任务中生成连贯且上下文适当的响应至关重要。

密集检索器的作用

密集检索器利用这些嵌入来执行检索任务。与依赖精确关键词匹配或索引的传统稀疏检索方法不同,密集检索器直接在查询嵌入和文档嵌入之间计算相似度分数。这种方法允许对从短句到长文档的各种长度文本输入进行更准确的检索。

应用示例

在信息检索任务中,例如搜索引擎或问答系统,这些密集表示能够高效且准确地检索相关文档或段落。

例如,一个查询如“COVID-19 的症状是什么?”可以转换为嵌入向量。同样,讨论 COVID-19 症状的文档也被转换为嵌入。通过比较查询嵌入和文档嵌入之间的相似度(使用余弦相似度等技术),可以快速识别并排名最相关的文档。

另一个示例是推荐系统。在这种情况下,嵌入通过理解用户偏好和内容相似性来帮助推荐产品、文章或视频。

总之,用于密集检索的嵌入模型与密集检索器相结合,在现代 AI 应用中发挥着关键作用,它们将文本转换为有意义的表示,并基于语义相似性高效地检索相关信息。

如何在代码中使用 bge-large-en-v1.5?

结合 Langchain 使用 bge-large-en-v1.5

你可以像这样在 langchain 中使用 bge

from langchain.embeddings import HuggingFaceBgeEmbeddings
model_name = "BAAI/bge-large-en-v1.5"
model_kwargs = {'device': 'cuda'}
encode_kwargs = {'normalize_embeddings': True} # set True to compute cosine similarity
model = HuggingFaceBgeEmbeddings(
    model_name=model_name,
    model_kwargs=model_kwargs,
    encode_kwargs=encode_kwargs,
    query_instruction="Generate a representation for this sentence to be used for retrieving relevant articles:"
)
model.query_instruction = "Generate a representation for this sentence to be used for retrieving relevant articles:"

结合 Huggingface Transformers 使用 bge-large-en-v1.5

使用 transformers 包,你可以像这样使用该模型:首先,将输入传递给 Transformer 模型,然后选择第一个 token(即 [CLS])的最后一个隐藏状态作为句子嵌入。

from transformers import AutoTokenizer, AutoModel
import torch
# Sentences we want sentence embeddings for
sentences = ["Sample Data-1", "Sample Data-2"]

# Load model from HuggingFace Hub
tokenizer = AutoTokenizer.from_pretrained('BAAI/bge-large-en-v1.5')
model = AutoModel.from_pretrained('BAAI/bge-large-en-v1.5')
model.eval()
# Tokenize sentences
encoded_input = tokenizer(sentences, padding=True, truncation=True, return_tensors='pt')
# for s2p(short query to long passage) retrieval task, add an instruction to query (not add instruction for passages)
# encoded_input = tokenizer([instruction + q for q in queries], padding=True, truncation=True, return_tensors='pt')
# Compute token embeddings
with torch.no_grad():
    model_output = model(**encoded_input)
    # Perform pooling. In this case, cls pooling.
    sentence_embeddings = model_output[0][:, 0]
# normalize embeddings
sentence_embeddings = torch.nn.functional.normalize(sentence_embeddings, p=2, dim=1)
print("Sentence embeddings:", sentence_embeddings)

有关 bge 模型使用的更多信息,你可以访问 GitHub 上的 FlagEmbedding。

如何微调 bge-large-en-v1.5?

步骤 1 安装

  • 使用 pip 安装:pip install -U FlagEmbedding
  • 或者克隆仓库后从源码安装并进入目录:pip install .
  • 为了开发,使用可编辑安装:pip install -e .

步骤 2 数据准备

  • 训练数据应为 JSON 格式,每一行是一个字典,包含 querypos(正例文本列表)和 neg(负例文本列表)。
  • 如果没有负例文本,可以从语料库中随机采样。

步骤 3 ** 挖掘难负例**

  • 使用脚本挖掘难负例以提高句子嵌入质量。
  • 你可以按照以下命令挖掘难负例:
python -m FlagEmbedding.baai_general_embedding.finetune.hn_mine \
--model_name_or_path BAAI/bge-base-en-v1.5 \
--input_file toy_finetune_data.jsonl \
--output_file toy_finetune_data_minedHN.jsonl \
--range_for_sampling 2-200 \
--negative_number 15 \
--use_gpu_for_searching
  • 输入文件:包含微调数据的 JSON 文件,脚本会为每个查询识别 top-k 文档,然后从这些 top-k 结果中随机选择负例,排除已经提供的正例。
  • 输出文件:存储新采样难负例的 JSON 文件的路径,供微调过程使用。
  • 负例数量:指定收集多少个负样本。
  • 采样范围:定义从中抽取负样本的范围。例如,范围 2–100 表示负例将取自 top 2 到 top 200 的文档。扩大此范围(例如到 60–300)会使负例选择不那么困难,因为考虑了更宽的文档集。
  • 检索池:脚本从中提取文档的来源。默认为输入文件中所有负例的集合,格式类似于预训练数据。如果指定了特定的检索池,脚本将使用该集合来查找负例。
  • 基于 GPU 的搜索:一个选项,指示是否应使用 GPU 加速的 faiss-gpu 来提高负例检索过程的效率。

步骤 4 训练

torchrun --nproc_per_node {number of gpus} \
-m FlagEmbedding.baai_general_embedding.finetune.run \
--output_dir {path to save model} \
--model_name_or_path BAAI/bge-large-en-v1.5 \
--train_data ./toy_finetune_data.jsonl \
--learning_rate 1e-5 \
--fp16 \
--num_train_epochs 5 \
--per_device_train_batch_size {large batch size; set 1 for toy data} \
--dataloader_drop_last True \
--normlized True \
--temperature 0.02 \
--query_max_len 64 \
--passage_max_len 256 \
--train_group_size 2 \
--negatives_cross_device \
--logging_steps 10 \
--save_steps 1000 \
--query_instruction_for_retrieval ""
  • 每个设备的训练批次大小:每个训练批次中处理的样本数量。通常,更大的批次大小会增强模型性能。你可以通过使用半精度训练(--fp16)、DeepSpeed 配置(--deepspeed ./df_config.json,其中 df_config.json 也可能称为 ds_config.json)和梯度检查点(--gradient_checkpointing)来增大此大小。
  • 训练组大小:训练时每个查询使用的总样本数量(包括正例和负例)。由于有一个保证的正例,此设置决定了负例数量(计算方式为 train_group_size - 1)。请注意,此数字不应超过数据 neg 列表中可用的负例数量。除了这些组内负例,批次中的其他负例也会被纳入微调过程。
  • 跨设备负例共享:允许在所有可用的 GPU 上分布负例,从而有效增加训练中使用的负例总数。
  • 学习率:选择适合你特定模型的值。对于大、基础或小规模模型,通常推荐 1e-5、2e-5 或 3e-5 等值。
  • 温度:影响相似度分数分布的分散程度。建议值范围为 0.01 到 0.1。
  • 最大查询长度:查询长度的上限,应与数据集中平均查询长度对应。
  • 最大段落长度:段落长度的上限,根据数据中平均段落长度设置。
  • 检索查询指令:可选的指令,附加到每个查询用于检索。如果不需要额外上下文,可以将其设置为空字符串。
  • 批内负例使用:一个标志,指示是否将同一批次中的段落视为训练中的负例。默认设置为启用(True)。
  • 检查点保存间隔:根据已完成的训练步数,定义保存模型检查点的频率。

步骤 5 模型加载

一旦 BGE 模型微调完成,你可以像示例中所示轻松加载它。如果在微调阶段为 --query_instruction_for_retrieval 超参数指定了唯一值,请确保相应地替换 query_instruction_for_retrieval

步骤 6 模型加载

对于模型评估,你可以运行 FlagEmbedding 提供的这个脚本

通过微调调整基础 bge 模型可以导致更好的任务特定性能,但也可能导致模型在目标领域之外的整体有效性显著下降(例如,在 c-mteb 任务上性能下降)。有关解决方案(使用 LM-Cocktail)以及微调过程的更多信息,请查看 GitHub 上的 “FlagEmbedding/examples/finetune”。

如何将 bge-large-en-v1.5 与 LLM API 集成?

将嵌入模型与 LLM 集成可以增强 AI 的自然语言处理能力,实现更复杂的语义搜索、上下文理解和个性化交互。这种集成对于增强基于内容的推荐、文档聚类、异常检测、跨语言处理和知识图谱构建等任务特别有用。它还支持高级文本摘要和机器学习模型的特征增强,从而在情感分析和主题分类中取得更好的性能。

步骤 1:设置环境

首先,确保你拥有必要的 Python 环境,并安装了所需的软件包。

pip install openai
# 安装其他必要的软件包,例如 requests、numpy 等

步骤 2:初始化 Novita AI API 客户端

你已经提供了初始化 Novita AI API 客户端的代码。这里供参考:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.novita.ai/v3/openai",
    api_key="<YOUR Novita AI API Key>",  # 替换为你实际的 API 密钥
)
model = "nousresearch/nous-hermes-llama2-13b"

步骤 3:获取嵌入模型

假设你可以访问 bge-large-en-v1.5 模型,你将加载它。如果它是一个 Hugging Face 模型,你可以像这样使用 transformers 库:

from transformers import AutoModel, AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("BAAI/bge-large-en-v1.5")
model = AutoModel.from_pretrained("BAAI/bge-large-en-v1.5")

步骤 4:定义获取嵌入的函数

创建一个函数,从 bge-large-en-v1.5 模型获取嵌入。

def get_embeddings(text):
    inputs = tokenizer(text, return_tensors="pt")
    with torch.no_grad():
        embeddings = model(**inputs)[0].mean(dim=1)
    return embeddings.numpy()

步骤 5:与 Novita AI LLM API 集成

现在,将嵌入模型与 LLM API 集成,以增强 API 的响应或执行诸如语义搜索之类的任务。

def enhanced_llm_response(prompt):
    # 从 LLM 获取初始响应
    response = client.completions.create(
        model=model,
        prompt=prompt,
        stream=True,
        max_tokens=512,
    )
    
    # 处理响应(例如提取文本)
    # 这是实际响应处理的占位符
    response_text = next(response)['choices'][0]['text'].content
    
    # 获取响应的嵌入
    response_embeddings = get_embeddings(response_text)
    
    # 在这里,你可以将嵌入用于各种目的,
    # 例如语义搜索、过滤等。
    
    return response_text, response_embeddings

步骤 6:使用增强的函数

现在你可以使用 enhanced_llm_response 函数从 LLM 获取响应,并使用嵌入模型处理它们。

prompt = "A chat between a curious user and an artificial intelligence assistant"
response, embeddings = enhanced_llm_response(prompt)
print(response)
# 对嵌入进行处理,例如存储、搜索相似文本等

步骤 7:错误处理和日志记录

向代码中添加错误处理和日志记录,以管理 API 限制、请求失败和其他潜在问题。

步骤 8:测试和迭代

彻底测试集成,并根据结果进行迭代。你可能需要调整参数、处理更多边缘情况或优化性能。

请注意,实际实现细节可能因 Novita AI LLM API 和 bge-large-en-v1.5 模型的具体功能和需求而异。你可以联系 Novita AI 团队获取技术支持:support@novita.ai

结论

总之,我们对“bge-large-en-v1.5”的探索突出了它在密集检索任务中的核心作用,深入介绍了它的能力、应用和实际实现。从介绍模型及其在嵌入领域的重要性,到演示其在代码中的使用和微调过程,我们提供了一份全面的指南。此外,与 Novita AI LLM API 的集成展示了该模型在增强 LLM 语义理解和检索准确性方面的潜力。

敬请关注更多关于 LLM 的更新!

常见问题

1. BGE 重排序器是如何工作的?

通过将查询和段落输入重排序器,你可以获得一个相关性分数。该分数可以通过 sigmoid 函数转换为范围在 [0, 1] 内的浮点值。此过程旨在确保排名靠前的结果更相关且质量更高,从而提高整体系统性能。

2. BGE 的上下文长度是多少?

最新的模型 bge-m3 的上下文长度为 8kb。

3. bge m3 嵌入的大小是多少?

它可以处理不同长度的输入,从短句到包含多达 8192 个 token 的长文档。

Novita AI 是支持您 AI 抱负的一体化云平台。借助无缝集成的 API、无服务器计算和 GPU 加速,我们提供经济高效的工具,助您快速构建和扩展 AI 驱动业务。消除基础设施的烦恼,免费开始——Novita AI 让您的 AI 梦想成为现实。

推荐阅读

什么是 LLM 嵌入:你需要知道的一切

揭示 BGE Large 的力量:文本嵌入的未来