BGE-M3 一个多功能、多语言、多粒度的语言向量模型

BGE-M3 是一个多功能、多语言、多粒度的嵌入模型,具有以下特点:

多功能性 (Multi-Functionality): BGE-M3 同时支持三种常见的检索功能,包括密集检索、多向量检索和稀疏检索。

多语言性 (Multi-Linguality): 支持100多种语言,具有广泛的应用场景。

多粒度性 (Multi-Granularity): 能够处理从短句到8192个token的长文档输入,满足不同任务的需求。

检索流程的建议:

我们建议使用“混合检索+重排序”的方式进行检索。

混合检索 (Hybrid Retrieval) 利用多种方法的优势,提升检索准确率和泛化能力。经典的混合检索方案包括结合嵌入检索与BM25算法,现在你可以使用支持密集与稀疏检索的 BGE-M3,在生成密集嵌入的同时获得类似 BM25 的词元权重。可以参考 Vespa 和 Milvus 实现混合检索。

重排序 (Re-Ranking) 模型通过交叉编码器的方式,比双编码器模型具有更高的准确率。例如,在检索后使用 bge-reranker 或 bge-reranker-v2 进一步筛选文本。

最新动态

  • 2024年7月1日: 更新了 BGE-M3 在 MIRACL 评测中的结果,并发布了bge-m3_miracl_2cr代码复现指南。
  • 2024年3月20日: Milvus团队帮助实现了 BGE-M3 在 Milvus 中的混合检索,相关代码可以参考 pymilvus/examples/hello_hybrid_sparse_dense.py
  • 2024年3月8日: 在最新的基准测试中,BGE-M3 在英语及多种语言中表现优异,超越了诸如 OpenAI 的模型。
  • 2024年2月6日: 发布了MLDR(覆盖13种语言的长文档检索数据集)和评测流程。

技术规格

模型名 维度 序列长度 介绍
BAAI/bge-m3 1024 8192 多语言,基于统一的微调(密集、稀疏、ColBERT)
BAAI/bge-m3-unsupervised 1024 8192 对比学习训练,来自 bge-m3-retromae
BAAI/bge-large-en-v1.5 1024 512 英文模型
BAAI/bge-base-en-v1.5 768 512 英文模型
BAAI/bge-small-en-v1.5 384 512 英文模型

不同检索方法的介绍

  1. 密集检索: 通过将文本映射到单一嵌入向量进行检索,例如 DPR、BGE-v1.5。
  2. 稀疏检索(词汇匹配): 通过计算文本中出现的词元权重,常用模型如 BM25、unicoil、splade。
  3. 多向量检索: 使用多个向量来表示文本,例如 ColBERT。

如何在其他项目中使用 BGE-M3

  • 对于嵌入检索,可以按照 BGE 的用法使用 BGE-M3,只是 BGE-M3 不再需要为查询添加指令。
  • 对于混合检索,可以使用 Vespa 和 Milvus。

BGE-M3 使用教程

  1. 安装:

    git clone https://github.com/FlagOpen/FlagEmbedding.git
    cd FlagEmbedding
    pip install -e .
    

    或直接安装:

    pip install -U FlagEmbedding
    
  2. 生成密集嵌入:

    from FlagEmbedding import BGEM3FlagModel
    model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
    sentences = ["What is BGE M3?", "Definition of BM25"]
    embeddings = model.encode(sentences, batch_size=12, max_length=8192)['dense_vecs']
    
  3. 生成稀疏嵌入:

    from FlagEmbedding import BGEM3FlagModel
    model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
    output = model.encode(sentences, return_dense=True, return_sparse=True)
    lexical_weights = output['lexical_weights']
    print(model.convert_id_to_token(lexical_weights))
    
  4. 生成多向量嵌入:

    from FlagEmbedding import BGEM3FlagModel
    model = BGEM3FlagModel('BAAI/bge-m3', use_fp16=True)
    output = model.encode(sentences, return_dense=True, return_sparse=True, return_colbert_vecs=True)
    print(model.colbert_score(output['colbert_vecs'][0], output['colbert_vecs'][1]))
    
  5. 文本对评分:

    sentence_pairs = [[i,j] for i in sentences_1 for j in sentences_2]
    scores = model.compute_score(sentence_pairs, max_passage_length=128, weights_for_different_modes=[0.4, 0.2, 0.4])
    

BGE-M3 提供了高效的多功能、多语言、多粒度文本嵌入解决方案,适用于多种复杂的检索任务。
在基于 Milvus 的工程化应用中,使用 BGE-M3 模型进行混合语义搜索可以极大提升搜索的准确性和效果。下面将介绍如何在 Milvus 环境中应用 BGE-M3 模型进行密集与稀疏向量的混合搜索,并使用 BGE CrossEncoder 模型对搜索结果进行重新排序。

环境准备

  1. 安装依赖
    需要安装 pymilvus 作为客户端连接 Milvus 服务器,并安装 pymilvus[model] 以支持 BGE-M3 模型嵌入功能:

    pip install pymilvus
    pip install pymilvus[model]
    
  2. 设置 Milvus 环境
    Milvus 支持在 2.4.0 及以上版本中进行稀疏向量搜索,因此需要确保本地 Milvus 环境版本符合要求。可以通过 Docker 安装最新版本的 Milvus:

    docker run -d --name milvus-standalone -p 19530:19530 -p 9091:9091 milvusdb/milvus:v2.4.0
    

应用场景示例

在这个示例中,我们使用 BGE-M3 模型对文本进行密集和稀疏向量的嵌入,并将结果插入到 Milvus 数据库中进行搜索和排序。你可以选择随机生成向量,或使用 BGE-M3 模型生成高质量的密集和稀疏向量表示。

实现步骤

  1. 嵌入文本为密集和稀疏向量
    使用 BGE-M3 模型将文档和查询转换为向量表示:

    from pymilvus.model.hybrid import BGEM3EmbeddingFunction
    ef = BGEM3EmbeddingFunction(use_fp16=False, device="cpu")
    dense_dim = ef.dim["dense"]
    
    docs_embeddings = ef(docs)
    query_embeddings = ef([query])
    
  2. 创建 Milvus 集合
    定义包含文本、密集向量和稀疏向量的集合:

    fields = [
        FieldSchema(name="pk", dtype=DataType.VARCHAR, is_primary=True, auto_id=True, max_length=100),
        FieldSchema(name="text", dtype=DataType.VARCHAR, max_length=512),
        FieldSchema(name="sparse_vector", dtype=DataType.SPARSE_FLOAT_VECTOR),
        FieldSchema(name="dense_vector", dtype=DataType.FLOAT_VECTOR, dim=dense_dim),
    ]
    schema = CollectionSchema(fields, "")
    col = Collection("hybrid_demo", schema, consistency_level="Strong")
    
  3. 插入数据并创建索引
    将生成的稀疏和密集向量插入集合并创建索引:

    entities = [docs, docs_embeddings["sparse"], docs_embeddings["dense"]]
    col.insert(entities)
    col.create_index("sparse_vector", {
          
          "index_type": "SPARSE_INVERTED_INDEX", "metric_type": "IP"})
    col.create_index("dense_vector", {
          
          "index_type": "FLAT", "metric_type": "IP"})
    col.load()
    
  4. 进行混合搜索
    使用稀疏和密集向量进行搜索,并结合 BGE CrossEncoder 模型对结果重新排序:

    res = col.hybrid_search([sparse_req, dense_req], rerank=RRFRanker(), limit=k, output_fields=['text'])
    
  5. 结果展示
    如果使用 BGE CrossEncoder 模型对结果进行排序,可以看到查询相关性更高的结果。

工程化应用

这种基于 Milvus 和 BGE-M3 的混合搜索系统具备强大的工程化应用能力,能够处理大规模的文本数据,特别适合用于如金融、法律等领域的智能检索系统。

BGE-M3 - 嵌入模型的王者
2024年1月30日,北京智源研究院(BAAI)发布了BGE模型系列的新成员——BGE-M3。

M3代表多语言性(支持100多种语言)、多粒度(输入长度可达8192)、多功能性(融合稠密检索、词法匹配、多向量(ColBERT)检索)。

此笔记本展示了如何使用BGE-M3嵌入,并在Vespa中同时表示这三种嵌入表示!Vespa是唯一能够处理所有M3表示的可扩展服务引擎。

此代码灵感来源于模型中心BAAI/bge-m3的README文件。

开始之前,先安装依赖:

!pip3 install -U pyvespa FlagEmbedding vespacli

探索M3的多种表示

在编码文本时,我们可以选择所需的表示形式:

  1. 带权重的稀疏向量,用于表示多语言分词后的Token ID。
  2. 稠密(DPR)常规文本嵌入。
  3. 多稠密(ColBERT)上下文多Token向量。

模型加载

在CPU上使用此模型时,我们设置 use_fp16=False,如果是在GPU上进行推理,推荐使用 use_fp16=True 以加速推理。

from FlagEmbedding import BGEM3FlagModel

model = BGEM3FlagModel("BAAI/bge-m3", use_fp16=False)

演示示例

我们先对一段简单的文本进行编码:

passage = [
    "BGE M3 是一个支持稠密检索、词法匹配和多向量交互的嵌入模型。"
]
passage_embeddings = model.encode(
    passage, return_dense=True, return_sparse=True, return_colbert_vecs=True
)
passage_embeddings.keys()

结果将返回:

dict_keys(['dense_vecs', 'lexical_weights', 'colbert_vecs'])

定义Vespa应用

PyVespa帮助我们构建Vespa应用包。Vespa应用包由配置文件、架构、模型和代码(插件)组成。

首先,我们定义一个Vespa架构,包含要存储的字段及其类型。我们使用Vespa张量来表示M3的三种不同表示:

  • 使用 t{} 映射张量表示稀疏词法表示。
  • 使用 x[1024] 索引张量表示1024维度的单个稠密向量表示。
  • 对于ColBERT的多向量表示,我们使用组合张量,它结合了映射维度和索引维度,从而表示可变长度。

我们使用 bfloat16 张量数据类型,与 float 相比节省50%的存储空间。

from vespa.package import Schema, Document, Field, FieldSet

m_schema = Schema(
    name="m",
    document=Document(
        fields=[
            Field(name="id", type="string", indexing=["summary"]),
            Field(name="text", type="string", indexing=["summary", "index"], index="enable-bm25"),
            Field(name="lexical_rep", type="tensor<bfloat16>(t{})", indexing=["summary", "attribute"]),
            Field(name="dense_rep", type="tensor<bfloat16>(x[1024])", indexing=["summary", "attribute"], attribute=["distance-metric: angular"]),
            Field(name="colbert_rep", type="tensor<bfloat16>(t{}, x[1024])", indexing=["summary", "attribute"]),
        ],
    ),
    fieldsets=[FieldSet(name="default", fields=["text"])],
)

配置Vespa应用包

from vespa.package import ApplicationPackage

vespa_app_name = "m"
vespa_application_package = ApplicationPackage(name=vespa_app_name, schema=[m_schema])

配置排名

接下来,我们通过添加排名配置来配置排名策略,定义稠密、稀疏和ColBERT表示的不同评分函数,然后使用线性组合将它们结合起来。

from vespa.package import RankProfile, Function, FirstPhaseRanking

semantic = RankProfile(
    name="m3hybrid",
    inputs=[
        ("query(q_dense)", "tensor<bfloat16>(x[1024])"),
        ("query(q_lexical)", "tensor<bfloat16>(t{})"),
        ("query(q_colbert)", "tensor<bfloat16>(qt{}, x[1024])"),
        ("query(q_len_colbert)", "float"),
    ],
    functions=[
        Function(name="dense", expression="cosine_similarity(query(q_dense), attribute(dense_rep),x)"),
        Function(name="lexical", expression="sum(query(q_lexical) * attribute(lexical_rep))"),
        Function(name="max_sim", expression="sum(reduce(sum(query(q_colbert) * attribute(colbert_rep), x),max, t),qt)/query(q_len_colbert)"),
    ],
    first_phase=FirstPhaseRanking(
        expression="0.4*dense + 0.2*lexical +  0.4*max_sim", rank_score_drop_limit=0.0
    ),
    match_features=["dense", "lexical", "max_sim", "bm25(text)"],
)
m_schema.add_rank_profile(semantic)

部署到Vespa Cloud

from vespa.deployment import VespaCloud
import os

# 替换成你在Vespa Cloud中的租户名称
tenant_name = "vespa-team"

vespa_cloud = VespaCloud(
    tenant=tenant_name,
    application=vespa_app_name,
    application_package=vespa_application_package,
)
app = vespa_cloud.deploy()

数据传输与查询

我们可以将嵌入结果转换为Vespa的feed格式,并进行查询:

vespa_fields = {
    
    
    "text": passage[0],
    "lexical_rep": {
    
    key: float(value) for key, value in passage_embeddings["lexical_weights"][0].items()},
    "dense_rep": passage_embeddings["dense_vecs"][0].tolist(),
    "colbert_rep": {
    
    index: passage_embeddings["colbert_vecs"][0][index].tolist() for index in range(passage_embeddings["colbert_vecs"][0].shape[0])},
}
app.feed_data_point(schema="m", data_id=0, fields=vespa_fields)

查询数据时,编码查询文本并构建查询字段:

query = ["BGE M3是什么?"]
query_embeddings = model.encode(query, return_dense=True, return_sparse=True, return_colbert_vecs=True)
query_length = query_embeddings["colbert_vecs"][0].shape[0]

query_fields = {
    
    
    "input.query(q_lexical)": {
    
    key: float(value) for key, value in query_embeddings["lexical_weights"][0].items()},
    "input.query(q_dense)": query_embeddings["dense_vecs"][0].tolist(),
    "input.query(q_colbert)": str({
    
    index: query_embeddings["colbert_vecs"][0][index].tolist() for index in range(query_embeddings["colbert_vecs"][0].shape[0])}),
    "input.query(q_len_colbert)": query_length,
}

response = app.query(
    yql="select id, text from m where userQuery() or ({targetHits:10}nearestNeighbor(dense_rep,q_dense))",
    ranking="m3hybrid",
    query=query[0],
    body={
    
    **query_fields},
)
print(response.hits[0])

删除Vespa实例

vespa_cloud.delete()

通过以上步骤,我们成功实现了如何在Vespa中表示并查询BGE-M3嵌入模型。

猜你喜欢

转载自blog.csdn.net/weixin_41046245/article/details/142215886