sentence-transformers 多向量编码器评估指南:MultiVectorEncoder 的 MaxSim 评测体系与 NanoBEIR 实战
2026/9/21 15:37:36 网站建设 项目流程

sentence-transformers 多向量编码器评估指南:MultiVectorEncoder 的 MaxSim 评测体系与 NanoBEIR 实战

【免费下载链接】sentence-transformersState-of-the-Art Embeddings, Retrieval, and Reranking项目地址: https://gitcode.com/gh_mirrors/se/sentence-transformers

导读

本指南围绕 sentence-transformers 仓库中多向量编码器(MultiVectorEncoder,即 ColBERT 风格 late-interaction 模型)的评估体系展开,核心场景是检索质量(IR)、重排序(Reranking)、三元组排序与知识蒸馏跟踪等任务的离线评测。读完本文,你将掌握评估器基于 MaxSim 打分端到端运行的原理,能用 nano_beir.py 在 13 个 NanoBEIR 子集上快速评估预训练模型,并熟练配置dataset_namescorpus_chunk_sizechunk_elements等关键参数,同时了解全套评估器的数据格式与指标含义。

一、多向量编码器为什么需要专门的评估器

与 SentenceTransformer 将每个输入编码为单个向量不同,多向量编码器把每个输入编码为一串 token 向量(每个 token 一个向量),查询与文档的比较采用 ColBERT 风格的 MaxSim(late-interaction)打分:对每个查询 token,取其与文档所有 token 的最大相似度,再对所有查询 token 求和,即sum_i max_j (a_i · b_j)。该公式的权威实现见 sentence_transformers/util/similarity.py 中的maxsim函数,它在sentence_transformers/multi_vector_encoder之外同样被多处复用。

正是这种"查询一组 token 向量 vs 文档一组 token 向量"的形态,决定了普通的余弦/点积评估器无法直接套用——它们定义在单向量之上,对非齐次(ragged)的 per-token 嵌入无法正确计算。sentence_transformers/multi_vector_encoder/evaluation/下的评估器把打分链路端到端封装好了:

  • 编码阶段使用encode_queryencode_document(而非统一的encode),因此模型的[Q]/[D]前缀、查询扩展(query expansion)以及文档 skiplist 都会在评估时生效;
  • 打分阶段使用模型自身的similarity_fn_name"maxsim""meanmaxsim");
  • 指标阶段在分数之上计算标准的检索/排序指标。

MultiVectorEncoder只支持这两种相似度函数,见 sentence_transformers/multi_vector_encoder/model.py 中的SUPPORTED_SIMILARITY_FN_NAMES = ("maxsim", "meanmaxsim")。两者的区别在于maxsim会随查询长度累积分数(归一化嵌入下约每个查询 token 贡献 1 分),而meanmaxsim将总分除以真实查询 token 数,把分数拉回余弦的[-1, 1]区间——后者用于以长度归一化打分训练的模型。

一个必须注意的约束:这些评估器不支持truncate_dim。原因在源码 docstring 中写得很清楚——多向量 token 嵌入没有 Matryoshka 式截断,任何非Nonetruncate_dim都会直接抛出ValueError(见 nano_beir.py 与 information_retrieval.py 的构造函数校验)。

二、运行评估脚本的通用流程

目录下的每个评估脚本都遵循统一的五步流程:

  1. 加载预训练的多向量模型(MultiVectorEncoder(...));
  2. 准备评估数据集;
  3. 配置合适的评估器;
  4. 运行评估;
  5. 报告结果。

评估器与示例脚本的对应关系如下:

评估器示例脚本
MultiVectorNanoBEIREvaluatorexamples/multi_vector_encoder/evaluation/nano_beir.py

运行方式很简单:直接执行 Python 脚本即可,无需任何额外的前置数据处理步骤(NanoBEIR 子集由评估器自行加载)。

三、NanoBEIR 快速评测实战

3.1 什么是 NanoBEIR

NanoBEIR 是 BEIR)。

3.2 完整示例代码

以下是 nano_beir.py 的完整内容,评估lightonai/LateOn模型在全部 13 个 Nano-* 检索数据集上的 MaxSim 表现:

"""Evaluate a pretrained multi-vector model on NanoBEIR. NanoBEIR is a fast benchmarking suite of 13 small BEIR subsets, useful for quickly comparing models without running the full BEIR evaluation. This script loads a model from the Hub and runs all 13 Nano-* IR datasets with MaxSim scoring. """ from __future__ import annotations from pprint import pprint from sentence_transformers import MultiVectorEncoder from sentence_transformers.multi_vector_encoder.evaluation import MultiVectorNanoBEIREvaluator def main() -> None: model = MultiVectorEncoder("lightonai/LateOn") evaluator = MultiVectorNanoBEIREvaluator(batch_size=16) results = evaluator(model) print(f"Primary metric: {evaluator.primary_metric} = {results[evaluator.primary_metric]:.4f}") pprint({k: v for k, v in results.items() if "ndcg@10" in k}) if __name__ == "__main__": main()

要点拆解:

  • MultiVectorEncoder("lightonai/LateOn")从 Hub 加载预训练模型,等价于用任意多向量模型(如lightonai/GTE-ModernColBERT-v1,见评估器 docstring 中的示例)替换;
  • MultiVectorNanoBEIREvaluator(batch_size=16)配置评估器,batch_size控制编码时每次处理的文本数;
  • evaluator(model)触发端到端评估,返回一个dict[str, float]
  • 默认配置下evaluator.primary_metric对应各子集主指标的均值聚合(aggregate_fn默认np.meanaggregate_key默认"mean"),示例中的过滤条件"ndcg@10" in k会打印每个子集的 NDCG@10 以及聚合均值。

3.3 报告哪些指标

对每个子集,评估器报告MRR@k、NDCG@k、Recall@k、Precision@k、Accuracy@k、MAP@k,并在最后跨子集聚合这些指标。各 k 值的默认配置(可覆盖)为:MRR@k =[10]、NDCG@k =[10]、Accuracy@k =[1, 3, 5, 10]、Precision/Recall@k =[1, 3, 5, 10]、MAP@k =[100]

四、MultiVectorNanoBEIREvaluator 关键参数详解

结合 sentence_transformers/multi_vector_encoder/evaluation/nano_beir.py 的 docstring,以下参数最值得掌握:

参数默认值说明
dataset_names全部 13 个子集限制评测范围,如["msmarco", "nq", "fiqa2018"]。13 个子集为:climatefeverdbpediafeverfiqa2018hotpotqamsmarconfcorpusnqquoraretrievalscidocsarguanascifacttouche2020
dataset_id"sentence-transformers/NanoBEIR-en"指向具备相同布局(corpus / queries / qrels)的其他数据集,例如 NanoBEIR 集合中的翻译变体,用于非英语评估
corpus_chunk_size5000每轮往返(round-trip)编码并打分的文档数量。越大则同时驻留内存的文档嵌入越多,但编码轮次越少
chunk_elementsNoneMaxSim 打分中间结果的元素预算上限。调低可降低打分阶段内存占用
batch_size32编码时的每批输入数量
mrr_at_k/ndcg_at_k[10]MRR 与 NDCG 的 k 值
accuracy_at_k[1, 3, 5, 10]Accuracy 的 k 值
precision_recall_at_k[1, 3, 5, 10]Precision 与 Recall 的 k 值
map_at_k[100]MAP 的 k 值
show_progress_barFalse评估时是否显示进度条
write_csvTrue是否把每次调用(按 epoch/steps 一行)追加写入 CSV
write_predictionsFalse是否将每查询 top-k 预测写入 JSONL,可直接作为ReciprocalRankFusionEvaluator的输入

典型使用建议:训练过程中常用dataset_names=["msmarco", "nq", "fiqa2018"]这类子集做快速迭代评估,完整 13 子集留到训练收尾再跑。

4.1chunk_elements背后的内存原理

chunk_elements直接透传给 similarity.py 中的maxsim函数,它约束的是补零后的(chunk, d_tokens, dim)文档张量与 4D 打分中间张量(batch_q, chunk, q_tokens, d_tokens)的总元素数。文档按预算贪心打包进块(逐块补零,因此单个超长文档只会撑大自己所在块),默认None时采用maxsim内置的1 亿元素预算(最多约 400 MB,bf16/fp16 下减半)。在非常大的查询批量下,单文档兜底下限仍然可能很大,此时需要在外部对查询分片。

另外注意:MultiVectorNanoBEIREvaluator构造时会把corpus_chunk_sizechunk_elements注入到每个子集内部构造的 IR 评估器(见源码_ir_extra_kwargs_load_dataset的合并逻辑),因此这两个参数对全部子集统一生效。

五、其他 MaxSim 评估器:数据格式与指标

NanoBEIR 是本目录唯一带示例脚本的任务,但包内还内置了其他任务的 MaxSim 评估器(全部导出自 sentence_transformers/multi_vector_encoder/evaluation/init.py),每个类的 docstring 都附有可运行示例:

评估器必需数据
MultiVectorInformationRetrievalEvaluator查询(qid => 问题文本)、语料(cid => 文档文本)、相关文档(qid => set[cid])
MultiVectorRerankingEvaluator形如{'query': ..., 'positive': [...], 'negative': [...]}的字典列表
MultiVectorTripletEvaluator(anchor, positive, negative) 三元组
MultiVectorDistillationEvaluator查询 + 候选文档 + teacher 分数

5.1 MultiVectorInformationRetrievalEvaluator:自建语料的检索评估

MultiVectorNanoBEIREvaluator内部就是逐子集运行MultiVectorInformationRetrievalEvaluator,因此它接受与上面相同的指标与内存选项(corpus_chunk_sizechunk_elements、各*_at_kwrite_predictions等),用于你自己的语料。实现细节(见 information_retrieval.py):

  • 未显式传入score_functions时,打分函数在每次调用时根据model.similarity_fn_name动态解析(_model_score_functions),因此模型换用"meanmaxsim"时评估自动跟随;若显式传入chunk_elements,则会以functools.partial把它绑定到默认打分函数上;
  • 查询嵌入会被预补零并跨语料块复用(embed_inputspad_sequence),每个块只重新编码文档,降低重复开销;
  • 自定义score_functions时,若其中混入 XTR 打分(xtr_scores/XTRScores),会直接抛ValueError——XTR 做的是跨整个候选集的全局 top-k,与评估器"逐块打分语料"的机制不兼容,逐块取 top-k 会静默出错,因此源码主动拒绝;
  • 显式 prompt 与模型注册 prompt 不匹配时会发出warning_once提示,避免显式 prompt 悄悄替换掉模型训练时的 marker prompt。

5.2 MultiVectorRerankingEvaluator:二阶重排

MultiVectorRerankingEvaluator对每个查询的固定候选列表打分,报告MAP、MRR@k、NDCG@kat_k默认 10)。这正是把多向量模型用作**二阶重排器(second-stage reranker)**的评测形态:一阶段检索器返回每个查询的候选(正例与干扰项混合),多向量模型再对其重打分排序。实现上(见 reranking.py),查询与文档分别经encode_query/encode_document非对称编码,打分默认回退到model.similarity(会把单查询归一化为 one-query batch)。

5.3 MultiVectorTripletEvaluator:三元组排序准确率

MultiVectorTripletEvaluator检查 anchor 对 positive 的分数高于对 negative 的次数比例,判定条件为MaxSim(anchor, positive) > MaxSim(anchor, negative) + margin。anchor 经encode_query编码(带查询前缀与长度),positive / negative 经encode_document编码。

margin 有一个容易踩坑的细节:margin字典必须按相似度类型(maxsimmeanmaxsim)分别指定(传入 float 则对两者同时生效),因为两种打分的量纲不同——maxsim分数随查询长度累积(归一化嵌入下约每查询 token 一分),而meanmaxsim除以 token 数后落在余弦的[-1, 1]区间,两者需要不同的 margin 值。源码通过MultiVectorEncoder.SUPPORTED_SIMILARITY_FN_NAMES枚举生成全部受支持的成对打分函数,默认选用模型当前的similarity_fn_name

5.4 MultiVectorDistillationEvaluator:蒸馏过程跟踪

MultiVectorDistillationEvaluatorKL 散度(越低越好)与Spearman 秩相关(越高越好,主指标)比较学生分数与 teacher 分数,用于跟踪知识蒸馏训练。它支持两种数据形态(见 distillation.py):

  • 逐查询候选集(KD 训练格式)documents为每查询一个 N 路候选列表,scores为对应的 2 维 teacher 分数。两个指标都按查询计算,直接对齐训练损失:KL 使用与MultiVectorDistillKLDivLoss相同的温度处理(temperaturestudent_temperatureteacher_temperature三个参数,KL 还会乘上学生温度平方),Spearman 为各查询秩相关的均值;若训练使用了非默认的similarity_fct(如 MeanMaxSim 打分),评估器也支持传入similarity_fct镜像训练设置,否则逐查询 KL 无法与训练损失对齐;
  • 扁平配对:每查询一个文档、1 维分数。此时逐查询分布无定义,KL 把整个数据集 softmax 成单个分布报告总散度(不做配对数量归一,因此不可与逐查询 KL 或 PyLate 直接比较),Spearman 则是全体配对的单一全局相关。

细节上:teacher 或学生分数为常量时秩相关无定义,对应查询会被跳过(全部跳过则报 0.0);因为 MaxSim 分数跨查询不可比(随查询长度累积),逐查询相关才是能跟踪损失的那个信号——这也是 Spearman 被设为主指标的原因。

六、评估实践要点小结

  1. 训练中快速迭代:用dataset_names挑 3 个子集(如["msmarco", "nq", "fiqa2018"]),完整 13 子集留到训练结束;
  2. 内存控制:打分内存优先调chunk_elements(默认 1 亿元素预算、约 400 MB,bf16/fp16 减半);编码内存用corpus_chunk_size控制同时驻留的文档嵌入数;
  3. 保持一致打分:若模型以"meanmaxsim"(长度归一化)训练,评估器会自动按model.similarity_fn_name解析打分,无需额外配置;蒸馏评估则务必把temperature与训练损失对齐;
  4. 非英语评测:把dataset_id换成 NanoBEIR 集合中的翻译变体即可,无需改动其余代码;
  5. 结果落盘:默认write_csv=True会把每次调用(epoch/steps 一行)追加到 CSV;write_predictions=True输出的 JSONL 可作为稀疏检索融合评估器(ReciprocalRankFusionEvaluator)的输入做下游分析。

如需深入实现,可继续阅读 nano_beir.py(子集加载与truncate_dim校验)、information_retrieval.py(动态打分解析与逐块打分)、similarity.py(maxsim/meanmaxsim的底层实现与内存预算逻辑),以及配套测试 tests/multi_vector_encoder/test_evaluators.py 验证各评估器的行为。

【免费下载链接】sentence-transformersState-of-the-Art Embeddings, Retrieval, and Reranking项目地址: https://gitcode.com/gh_mirrors/se/sentence-transformers

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询