介绍 Ettin 重排序器系列

Reddit r/LocalLLaMA 模型

摘要

介绍 Ettin 重排序器系列:六款基于 ModernBERT 编码器、采用开源数据和训练方案的全新先进 CrossEncoder 重排序器,提供多种尺寸选择。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/05/19 16:47

引入 Ettin 重排序器(Reranker)家族

来源:https://huggingface.co/blog/ettin-reranker 返回文章列表(https://huggingface.co/blog)

Tom Aarsen 的头像(https://huggingface.co/tomaarsen)

- TL;DR(https://huggingface.co/blog/ettin-reranker#tldr) - 目录(https://huggingface.co/blog/ettin-reranker#table-of-contents) - 什么是重排序器,为什么要与嵌入器配对使用?(https://huggingface.co/blog/ettin-reranker#what-is-a-reranker-and-why-pair-one-with-an-embedder) - 使用方法(https://huggingface.co/blog/ettin-reranker#usage)- 端到端检索-再重排序流程(https://huggingface.co/blog/ettin-reranker#end-to-end-retrieve-then-rerank-pipeline) - 架构细节(https://huggingface.co/blog/ettin-reranker#architecture-details) - 结果(https://huggingface.co/blog/ettin-reranker#results)- MTEB(英文, v2)检索(https://huggingface.co/blog/ettin-reranker#mtebeng-v2-retrieval) - 速度(https://huggingface.co/blog/ettin-reranker#speed) - 训练(https://huggingface.co/blog/ettin-reranker#training)- 蒸馏方法(https://huggingface.co/blog/ettin-reranker#distillation-recipe) - 数据集(https://huggingface.co/blog/ettin-reranker#dataset) - 训练参数(https://huggingface.co/blog/ettin-reranker#training-arguments) - 评估(https://huggingface.co/blog/ettin-reranker#evaluation) - 完整训练脚本(https://huggingface.co/blog/ettin-reranker#overall-training-script) - 结论(https://huggingface.co/blog/ettin-reranker#conclusion) - 致谢(https://huggingface.co/blog/ettin-reranker#acknowledgements) - 引用(https://huggingface.co/blog/ettin-reranker#citation) https://huggingface.co/blog/ettin-reranker#tldrTL;DR

今天我将发布六个新的 Sentence Transformers(https://sbert.net/)CrossEncoder 重排序器,它们在其各自的参数规模上达到了最先进水平,建立在 Ettin(https://huggingface.co/collections/jhu-clsp/encoders-vs-decoders-the-ettin-suite)ModernBERT 编码器之上,同时还提供了生成它们的数据和完整训练方法:

  • cross-encoder/ettin-reranker-17m-v1(https://huggingface.co/cross-encoder/ettin-reranker-17m-v1)
  • cross-encoder/ettin-reranker-32m-v1(https://huggingface.co/cross-encoder/ettin-reranker-32m-v1)
  • cross-encoder/ettin-reranker-68m-v1(https://huggingface.co/cross-encoder/ettin-reranker-68m-v1)
  • cross-encoder/ettin-reranker-150m-v1(https://huggingface.co/cross-encoder/ettin-reranker-150m-v1)
  • cross-encoder/ettin-reranker-400m-v1(https://huggingface.co/cross-encoder/ettin-reranker-400m-v1)
  • cross-encoder/ettin-reranker-1b-v1(https://huggingface.co/cross-encoder/ettin-reranker-1b-v1)

这些模型采用蒸馏方法训练:在 cross-encoder/ettin-reranker-v1-data(https://huggingface.co/datasets/cross-encoder/ettin-reranker-v1-data)上使用 mixedbread-ai/mxbai-rerank-large-v2(https://huggingface.co/mixedbread-ai/mxbai-rerank-large-v2)的分数进行逐点 MSE 蒸馏,该数据集融合了 lightonai/embeddings-pre-training(https://huggingface.co/datasets/lightonai/embeddings-pre-training)的一个子集和 lightonai/embeddings-fine-tuning(https://huggingface.co/datasets/lightonai/embeddings-fine-tuning)的一个重排序子集。

我们的六个重排序器与 EmbeddingGemma-300M 配对在 MTEB(英文,v2)检索上的表现(https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/ettin-reranker/mteb_ndcg10_embeddinggemma-300m.png)

我们的六个重排序器与google/embeddinggemma-300m(https://huggingface.co/google/embeddinggemma-300m)配对在 MTEB(英文,v2)检索上的表现。其它五种嵌入器配对结果见结果部分。

如果你是重排序器新手,想先了解“为什么”,请跳到什么是重排序器,为什么要与嵌入器配对使用?。如果你只想直接使用模型,请跳到使用方法。如果你想训练自己的模型,请跳到训练

我使用 Sentence Transformers v5.5.0(https://github.com/huggingface/sentence-transformers/releases/tag/v5.5.0)中新增的 train-sentence-transformers Agent Skill(https://github.com/huggingface/sentence-transformers/tree/main/skills)自举了下面的训练方法。通过 hf skills add train-sentence-transformers [--global] [--claude] 安装后,你可以让 AI 编程助手(Claude Code、Codex、Cursor、Gemini CLI 等)基于你的数据微调 SentenceTransformerCrossEncoderSparseEncoder 模型。

目录(https://huggingface.co/blog/ettin-reranker#table-of-contents)

什么是重排序器,为什么要与嵌入器配对使用?(https://huggingface.co/blog/ettin-reranker#what-is-a-reranker-and-why-pair-one-with-an-embedder)

重排序器(即逐点交叉编码器)是一种神经模型,它接收一个 (query, document) 对并输出一个相关性分数。与嵌入模型(它将查询和文档分别编码,然后从两个嵌入向量计算它们的相似度)不同,重排序器允许两个文本在每一个 Transformer 层中相互关注。这种联合编码更准确,但也更昂贵:模型必须为每个 (query, document) 对运行一次,而不是每个文本运行一次。

由于交叉编码器在完整语料库上运行成本过高,常见的生产模式是检索-再重排序:一个快速的嵌入模型检索出 top-K 候选(廉价),然后一个交叉编码器仅对这 K 个候选进行高精度重排序。总成本保持有限,而最终排序更接近穷举交叉编码器得到的结果。

嵌入模型 vs 重排序器(https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/blog/train-reranker/embedding_vs_reranker_model.png)

在本博文中,“重排序器”和“交叉编码器”将互换使用。

使用方法(https://huggingface.co/blog/ettin-reranker#usage)

发布的模型是普通的 Sentence Transformers CrossEncoder 模型,因此只需 3 行代码即可使用:

from sentence_transformers import CrossEncoder

model = CrossEncoder("cross-encoder/ettin-reranker-32m-v1")
scores = model.predict([
    ("Where was Apple founded?", "Apple Inc. was founded in Cupertino, California in 1976 by Steve Jobs, Steve Wozniak, and Ronald Wayne."),
    ("Where was Apple founded?", "The Fuji apple is an apple cultivar developed in the late 1930s and brought to market in 1962."),
])
print(scores)
# [11.393298  2.968891]   <- 值越大表示越相关

对于查询和候选列表,你也可以使用 rank 来获取排序后的索引和分数:

ranked = model.rank(
    query="Which planet is known as the Red Planet?",
    documents=[
        "Venus is often called Earth's twin because of its similar size and proximity.",
        "Mars, known for its reddish appearance, is often referred to as the Red Planet.",
        "Jupiter, the largest planet in our solar system, has a prominent red spot.",
        "Saturn, famous for its rings, is sometimes mistaken for the Red Planet.",
    ],
    top_k=4,
    return_documents=True,
)
for r in ranked:
    print(f"({r['score']:.2f}): {r['text']}")
# (10.82): Mars, known for its reddish appearance, is often referred to as the Red Planet.
# (9.86): Saturn, famous for its rings, is sometimes mistaken for the Red Planet.
# (8.55): Jupiter, the largest planet in our solar system, has a prominent red spot.
# (6.21): Venus is often called Earth's twin because of its similar size and proximity.

你可以将 cross-encoder/ettin-reranker-32m-v1(https://huggingface.co/cross-encoder/ettin-reranker-32m-v1)替换成任何其他尺寸,以在质量和速度之间进行取舍。得益于 ModernBERT 的长上下文预训练,所有六个模型都支持最多 8K token 的上下文(适用于长文档重排序)。

建议安装 kernels(https://github.com/huggingface/kernels)并设置 model_kwargs={"dtype": "bfloat16", "attn_implementation": "flash_attention_2"} 以获得最高吞吐量。更多详情请参见下面的速度部分,但总的来说,根据模型大小和序列长度,相对于默认加载方式,你可以预期 1.7 倍到 8.3 倍的速度提升。

from sentence_transformers import CrossEncoder

model = CrossEncoder(
    "cross-encoder/ettin-reranker-32m-v1",
    model_kwargs={"dtype": "bfloat16", "attn_implementation": "flash_attention_2"},
)

端到端检索-再重排序流程(https://huggingface.co/blog/ettin-reranker#end-to-end-retrieve-then-rerank-pipeline)

一个完整的示例,使用快嵌入器进行检索,使用重排序器进行最终排序:

from sentence_transformers import SentenceTransformer, CrossEncoder

# 使用静态嵌入器进行快速检索(CPU 上每次查询不到一毫秒)
embedder = SentenceTransformer("sentence-transformers/static-retrieval-mrl-en-v1")
reranker = CrossEncoder("cross-encoder/ettin-reranker-68m-v1")

corpus = [
    "Apple Inc. was founded in Cupertino, California in 1976 by Steve Jobs, Steve Wozniak, and Ronald Wayne.",
    "The Fuji apple is an apple cultivar developed in the late 1930s.",
    "Steve Jobs introduced the iPhone in 2007 at Macworld.",
    "Macintosh computers were sold by Apple from 1984 onward.",
    # 生产环境中可能有成千上万甚至更多的文档
]
query = "Where was Apple founded?"

# 第 1 步:编码 + 检索 top-100
query_emb = embedder.encode_query(query, convert_to_tensor=True)
corpus_emb = embedder.encode_document(corpus, convert_to_tensor=True)
scores = embedder.similarity(query_emb, corpus_emb)[0]
top_k_idx = scores.topk(min(100, len(corpus))).indices.tolist()

# 第 2 步:重排序
top_k_docs = [corpus[i] for i in top_k_idx]
ranked = reranker.rank(query, top_k_docs, top_k=5, return_documents=True)
for r in ranked:
    print(f"({r['score']:.2f}): {r['text']}")
# (11.63): Apple Inc. was founded in Cupertino, California in 1976 by Steve Jobs, Steve Wozniak, and Ronald Wayne.
# (4.71): Steve Jobs introduced the iPhone in 2007 at Macworld.
# (1.96): The Fuji apple is an apple cultivar developed in the late 1930s.
# (1.49): Macintosh computers were sold by Apple from 1984 onward.

这与大多数现代搜索系统使用的模式相同。检索器决定哪些进入漏斗,重排序器决定最终排名。

架构细节(https://huggingface.co/blog/ettin-reranker#architecture-details)

所有六个重排序器共享相同的架构,仅在骨干网络大小上有所不同。骨干网络是约翰霍普金斯大学 Ettin 套件中的六个 Ettin 编码器(https://huggingface.co/blog/ettin)之一。这些是 ModernBERT 风格的模型,具有非填充注意力(unpadded attention)、RoPE 位置编码、GeGLU,并在 2T token 的开放许可预训练数据上训练,支持最多 8192 token 的上下文。

在每个编码器之上,重排序器使用一个 4 模块的分类头,该头模仿 ModernBertForSequenceClassification,但由 Sentence Transformers 的模块化组件构建。底层的 Transformer 是普通的 AutoModel 而非 AutoModelForSequenceClassification,这让我们可以对可变长度输入使用序列解填充(sequence unpadding),以支持 Flash Attention 2。在中等文档序列长度下,相比 fp32+SDPA,根据模型大小可实现 1.7 倍到 8.3 倍的速度提升(参见速度部分的完整基准测试):

1. Transformer(FA2)
2. Pooling(cls)
3. Dense(H, H, bias=False, GELU)
4. LayerNorm(H)
5. Dense(H, 1, scores)

在我的消融实验中,CLS 池化优于均值池化。这有点令人惊讶。ModernBERT 每隔三层才使用一次全局注意力,其余三分之二的层使用局部窗口注意力,无法从 CLS 位置访问远处的 token。但实证表明,那少数几个全局层携带了足够的信息,使得 CLS 成为更好的池化选择。

所有六个模型均以 Apache 2.0 许可证发布,与 Ettin 编码器一致。

结果(https://huggingface.co/blog/ettin-reranker#results)

MTEB(英文, v2)检索(https://huggingface.co/blog/ettin-reranker#mtebeng-v2-retrieval)

我将每个已发布模型在完整的 MTEB(eng, v2) 检索基准测试(https://github.com/embeddings-benchmark/mteb)(10 个任务,top-100 重排序)上进行了测试,使用 MTEB 的两阶段重排序流程,并将每个重排序器与六种覆盖速度/质量谱系的嵌入模型配对:

各图表中的虚线“仅检索器”线是需要超越的基准数字。低于该线意味着平均而言重排序器反而损害了流程:

完整结果表格(点击展开)各嵌入器配对的平均 NDCG@10,降序排列。我们的六个模型以粗体显示,教师模型 mixedbread-ai/mxbai-rerank-large-v2(https://huggingface.co/mixedbread-ai/mxbai-rerank-large-v2)以下划线标注。

† 限制为 max_seq_length=8192(基于 Qwen3 的 4B 重排序器在原生上下文下无法放入单个 H100 80GB)。原生上下文评估结果可能更高。

完整 NanoBEIR 结果表格(点击展开)NanoBEIR(https://huggingface.co/collections/sentence-transformers/nanobeir-with-bm25-rankings)是 BEIR(https://github.com/beir-cellar/beir)的一个快速 13 任务子集,每个数据集使用 50 个查询,针对最多 5000 个文档。NanoBEIR 是训练期间 metric_for_best_model 的设置(参见评估),也是我用于指导实验验证的指标。

我发布的最小模型,我们的 17M,在 MTEB 上以约一半的参数(0.5576 vs 0.5066)比 33M 的 ms-marco-MiniLM-L12-v2 高出 +0.051 NDCG@10,在 NanoBEIR 上高出 +0.038(0.6746 vs 0.6369)。32M 模型在 MTEB 上比 568M 的 BAAI/bge-reranker-v2-m3 高出 +0.025(0.5779 vs 0.5526),参数差距达 17 倍。如果你一直在检索-再重排序栈中使用传统的 MiniLM 重排序器作为默认选项,那么换成我们的 17M(或 32M)是一个低风险的直接替代,在两个基准测试上都能显著提升质量。

向上看表格,我们的 150M 在 MTEB 上是我测试过的 600M 以下范围内最强的重排序器,以 +0.005(0.5994 vs 0.5940)的优势略微超过了最新的 Qwen/Qwen3-Reranker-0.6B(596M),并比所有的 BAAI bge-reranker 变体高出 0.03 到 0.05。68M 也值得一提:它在 0.5915 的性能上几乎与 Qwen3-Reranker-0.6B(0.5940)持平,而参数仅为后者的九分之一。

相似文章

m3BERT:一种现代、多语言、套娃式双向编码器

arXiv cs.CL

本文介绍了m3BERT,一种多语言双向编码器,采用新颖的预训练策略,联合优化跨Transformer层和多个嵌入维度的表示,使得单个模型能够适应不同的资源约束。在Bing-Click工业检索数据集上,它显著优于现有最优模型。