• 文章
  • miniCOIL:迈向可用稀疏神经网络检索之路
返回机器学习

miniCOIL:迈向可用稀疏神经网络检索之路

Evgeniya Sukhodolskaya

·

2025年5月13日

miniCOIL: on the Road to Usable Sparse Neural Retrieval

你听说过稀疏神经检索吗?如果听说过,你有没有在生产环境中使用过它?

这是一个潜力巨大的领域——谁不想使用一种结合了密集检索和基于词项检索优势的方法呢?然而,它却不那么流行。是因为“纸上谈兵很好,但实际操作不行”的常见弊病吗?

本文描述了我们通往“应有的”稀疏神经检索之路——即轻量级、基于词项的检索器,能够区分词义。

我们吸取了以往尝试的教训,创建了 miniCOIL,这是一种新的稀疏神经候选模型,旨在取代混合搜索中的 BM25。我们很高兴与你分享,并期待你的反馈。

好的、坏的和丑的

与它所基于的方法——基于词项检索和密集检索——不同,稀疏神经检索并不那么广为人知。它们的弱点促成了这个领域的发展,并指导了它的演变。让我们追随它的足迹。

Retrievers evolution

检索器的演变

基于词项的检索

基于词项的检索通常将文本视为一个词袋。这些词扮演着不同重要性的角色,有助于计算文档和查询之间的整体相关性得分。

著名的 BM25 根据词语的以下特性来估计其贡献:

  1. 在特定文本中的重要性——基于词频(TF)。
  2. 在整个语料库中的重要性——基于逆文档频率(IDF)。

它还有几个参数反映语料库中典型的文本长度,你可以在我们对 BM25 公式的详细解读中查看其确切含义。

精确定义文本中词语的重要性并非易事。

BM25 的构建思想是词项重要性可以通过统计学定义。在长文本中,某个词的频繁重复确实表明文本与该概念相关,这与事实相去不远。但在非常短的文本中——例如,用于检索增强生成(RAG)的文本块——它的适用性较低,词频为 0 或 1。我们在对 BM25 算法的 BM42 修改中尝试解决了这个问题。

然而,词语的重要性中有一个 BM25 完全没有考虑到的组成部分——词语的含义。相同的词语在不同的上下文中具有不同的含义,这会影响文本的相关性。想想“果蝠”(fruit bat)和“棒球棒”(baseball bat)——在文本中重要性相同,但含义不同。

密集检索

如何捕捉含义?像 BM25 这样的词袋模型假设词语在文本中是独立放置的,而语言学家则说:

“人应通过词语所伴之词而知其意”——约翰·鲁珀特·弗斯

这一思想,加上用数字表达词语关系的动机,推动了检索的第二个分支——密集向量的发展。带有注意力机制的 Transformer 模型解决了在文本上下文中区分词义的挑战,使其成为检索中相关性匹配的一部分。

然而,密集检索并未(也无法)完全取代基于词项的检索。密集检索器能够进行广泛的语义相似性搜索,但在需要包含特定关键词的结果时,它们缺乏精确性。

试图让密集检索器进行精确匹配是徒劳的,因为它们建立在每个词在某种程度上都与其他词语义匹配的范式之上,而且这种语义相似性取决于特定模型的训练数据。

稀疏神经检索

因此,一方面,我们对匹配的控制较弱,有时会导致检索结果过于宽泛;另一方面,我们有轻量级、可解释且快速的基于词项的检索器,如 BM25,但它们无法捕捉语义。

当然,我们希望将两者的优点融合在一个模型中,并且不包含任何缺点。稀疏神经检索的演变正是由这种愿望推动的。

  • 为什么是稀疏?基于词项的检索可以在稀疏向量上操作,其中文本中的每个词都被赋予一个非零值(它在该文本中的重要性)。
  • 为什么是神经?与其根据词语的统计数据推导出其重要性得分,不如使用能够编码词语含义的机器学习模型。

那么,为什么它没有被广泛使用呢?

Problems of modern sparse neural retrievers

现代稀疏神经检索器的问题

稀疏神经检索的详细历史是另一篇文章的内容。总而言之,有很多尝试将密集编码器生成的词表示映射到单值重要性得分,但其中大部分从未在研究论文之外的真实世界中出现(DeepImpactTILDEv2uniCOIL)。

大多数稀疏编码器在相关性目标上进行端到端训练,但它们仅在特定领域能很好地估计词语重要性。它们在训练期间未“见过”的数据集上的域外准确性比 BM25 更差

稀疏神经检索的 SOTA 是 SPLADE——(稀疏词汇和扩展模型)。该模型已进入检索系统——你可以在 Qdrant 中使用 FastEmbed 来使用 SPLADE++

但这里有个问题。SPLADE 名称中的“扩展”部分指的是一种对抗基于词项检索的另一个弱点——词汇不匹配——的技术。虽然密集编码器可以成功连接“果蝠”和“飞狐”等相关词项,但基于词项的检索在此任务上却失败了。

SPLADE 通过用额外的拟合词项扩展文档和查询来解决这个问题。然而,这导致 SPLADE 推理变得繁重。此外,生成的表示不再那么稀疏(因此,也不轻量),并且由于扩展选择是由机器学习模型做出的,因此可解释性大大降低。

“穿盔甲的大个子。脱掉盔甲,你是什么?”

实验表明,没有词项扩展的 SPLADE 讲述的是稀疏编码器的老故事——它的性能比 BM25 更差

目标:可用的稀疏神经检索

为了在特定基准上追求完美,稀疏神经检索领域要么产生了在域外表现不如 BM25 的模型(讽刺的是,用基于 BM25 的困难负样本训练),要么产生了基于大量文档扩展、降低稀疏度的模型。

为了在生产中可用,稀疏神经检索器应满足的最低标准是:

  • 生成轻量级稀疏表示(顾名思义!)。它应继承基于词项检索的优点,轻量级且简单。对于更广泛的语义搜索,有密集检索器。
  • 在不同领域排名优于 BM25。目标是构建一个能够区分词义的基于词项的检索器——这是 BM25 无法做到的——同时保留 BM25 经过时间验证的域外性能。
The idea behind miniCOIL

miniCOIL 的理念

灵感来自 COIL

稀疏神经检索领域的一次尝试——上下文反向列表(COIL)——以其词项权重编码方法脱颖而出。

COIL 的作者并没有将高维标记表示(通常是 768 维的 BERT 嵌入)压缩成一个单一的数字,而是将它们投影到 32 维的较小向量。他们建议将这些向量原样存储在倒排索引(用于基于词项的检索)的倒排列表中,并通过点积比较向量表示。

这种方法捕获了更深层次的语义,因为一个单一的数字根本无法传达一个词可能拥有的所有细微含义。

尽管有这个优点,COIL 未能获得广泛采用,原因有几个:

  • 倒排索引通常不是设计用来存储向量和执行向量操作的。
  • MS MARCO 数据集上,COIL 经过端到端的相关性目标训练,其性能严重受限于领域。
  • 此外,COIL 在标记上操作,重用 BERT 的分词器。然而,在词级别工作对于基于词项的检索来说要好得多。想象一下,我们想在文档中搜索“retriever”。COIL 会将其分解为`re`、`#trie`和`#ver`三个 32 维向量,并分别匹配这三个部分——这很不方便。

然而,COIL 表示可以区分同形异义词,这是 BM25 缺乏的能力。最好的想法不是从零开始。我们提出一种建立在 COIL 之上并牢记需要改进之处的方法:

  1. 我们应该放弃在相关性目标上进行端到端训练,以获得在域外数据上表现良好的模型。没有足够的数据来训练一个能够泛化的模型。
  2. 我们应该保持表示稀疏,并在经典的倒排索引中可重用
  3. 我们应该修复分词。这个问题最容易解决,因为在几个稀疏神经检索器中已经解决了,而且我们也在 BM42 中学会了这样做

站在 BM25 的肩膀上

BM25 多年来一直是各种领域的良好基线,这是有充分理由的。那么,为什么要放弃一个经过时间考验的公式呢?

与其训练我们的稀疏神经检索器来分配词语的重要性得分,不如在 BM25 公式中添加一个受 COIL 启发的语义组件。

$$ \text{score}(D,Q) = \sum_{i=1}^{N} \text{IDF}(q_i) \cdot \text{Importance}^{q_i}_{D} \cdot {\color{YellowGreen}\text{Meaning}^{q_i \times d_j}} \text{, where term } d_j \in D \text{ equals } q_i $$

这样,如果我们将一个词的含义成功捕获,我们的解决方案本身就可以像 BM25 结合了语义感知的重排序器一样工作——换句话说

  • 它可以区分同形异义词;
  • 与词干一起使用时,它可以区分词性。
Meaning component

含义组件

如果我们的模型遇到一个在训练期间未“见过”的词,我们可以简单地回退到原始的 BM25 公式!

4D 词袋

COIL 使用 32 个值来描述一个词项。我们需要这么多吗?在没有额外研究的情况下,我们能说出多少个具有 32 种不同含义的词?

然而,即使我们在 COIL 表示中使用更少的值,密集向量不适合经典倒排索引的最初问题仍然存在。
除非……我们玩个小把戏!

miniCOIL vectors to sparse representation

miniCOIL 向量到稀疏表示

想象一个词袋稀疏向量。词汇表中的每个词占据一个单元格。如果该词存在于编码文本中,我们分配一些权重;如果不存在,则为零。

如果我们有一个 mini COIL 向量,例如在 4D 语义空间中描述一个词的含义,我们可以简单地为稀疏向量中的每个词分配 4 个连续的单元格,每个“含义”维度一个单元格。如果我们没有,我们可以回退到经典的一个单元格描述,使用纯 BM25 分数。

此类表示可用于任何标准倒排索引。

训练 miniCOIL

现在,我们来到了需要以某种方式获得词语含义的低维封装——miniCOIL 向量的部分。

我们希望更聪明地工作,而不是更辛苦,并尽可能多地依赖经过时间考验的解决方案。密集编码器擅长在上下文中编码词语的含义,因此重用它们的输出将很方便。此外,如果我们将 miniCOIL 添加到混合搜索中,我们可以一石二鸟——无论如何,混合搜索都需要进行密集编码器推理。

降维

密集编码器输出是高维的,因此我们需要执行降维,这应该在上下文中保留词语的含义。目标是:

  • 避免相关性目标和对标注数据集的依赖;
  • 找到一个能够捕获词义之间空间关系的目标;
  • 使用尽可能简单的架构。

训练数据

我们希望 miniCOIL 向量能够根据词语的含义进行比较——“果蝠”和“吸血蝙蝠”在低维向量空间中应该比“棒球棒”更接近。因此,在对词语的上下文表示进行降维时,我们需要一些东西来进行校准。

据说,一个词的含义隐藏在周围的语境中,或者简单地说,包含这个词的任何文本中。在较长的文本中,我们有词义模糊的风险。因此,让我们在句子层面工作,并假设共享一个词的句子应该以这样一种方式聚集,即每个簇都包含这个词以一种特定含义使用的句子。

如果这是真的,我们可以用复杂的密集编码器编码各种句子,并为输入密集编码器形成一个可重用的空间关系目标。当我们有像OpenWebText 数据集这样涵盖整个网络的数据集时,找到大量包含常用词的文本数据并不是一个大问题。有了如此多的可用数据,我们可以负担得起泛化和领域独立性,这在相关性目标下很难实现。

我赌它会成功

让我们来验证一下我们的假设,看看“bat”这个词。

我们从OpenWebText 数据集中抽取了几千个包含这个词的句子,并使用mxbai-embed-large-v1编码器对其进行向量化。目标是检查我们是否能够区分包含“bat”具有相同含义的句子的任何簇。

Sentences with "bat" in 2D

2D 中的“bat”句子。
一个非常重要的观察:看起来像蝙蝠:)

结果有两个大的簇,分别与作为动物的“bat”和作为运动器材的“bat”相关,还有两个较小的簇,分别与扑动动作和运动中使用的动词相关。看起来它可能会成功!

架构与训练目标

让我们继续处理“bat”。

我们有一个训练池,其中包含不同含义的“bat”一词的句子。使用选定的密集编码器,我们从每个句子中获取“bat”的上下文嵌入,并学习将其压缩为低维 miniCOIL “bat”空间,由mxbai-embed-large-v1句子嵌入引导。

我们只处理一个词,因此仅使用一个线性层进行降维就足够了,顶层带有Tanh 激活函数,将压缩向量的值映射到 (-1, 1) 范围。选择激活函数是为了使 miniCOIL 表示与主要通过余弦相似度进行比较的密集编码器表示对齐。

miniCOIL architecture on a word level

词级别 miniCOIL 架构

作为训练目标,我们可以选择最小化三元组损失,其中三元组根据mxbai-embed-large-v1句子嵌入之间的距离进行选择和对齐。我们依赖mxbai-embed-large-v1的置信度(边距大小)来指导我们的“bat”miniCOIL 压缩。

miniCOIL training

miniCOIL 训练

一次一小口地吃大象

现在,我们对如何训练一个词的 miniCOIL 有了完整的想法。我们如何扩展到整个词汇表呢?

如果我们保持简单,继续为每个词训练一个模型会怎样?它有以下好处:

  1. 极其简单的架构:每个词一个层就足够了。
  2. 超快且简单的训练过程。
  3. 由于架构简单,推理成本低廉且速度快。
  4. 灵活地发现和调整表现不佳的词语。
  5. 灵活地根据领域和用例扩展和缩小词汇表。

然后我们可以训练所有我们感兴趣的词,并简单地将所有模型组合(堆叠)成一个大的 miniCOIL。

miniCOIL model

miniCOIL 模型

实施细节

上述训练方法的代码已在该存储库中开源

以下是我们根据此方法训练的 miniCOIL 模型的具体特点:

组件描述
输入密集编码器jina-embeddings-v2-small-en (512 维度)
miniCOIL 向量大小4 维度
miniCOIL 词汇表30,000 个最常用英语单词列表,已清除停用词和长度小于 3 个字母的词,取自此处。词语经过词干提取,使 miniCOIL 与我们的 BM25 实现对齐。
训练数据4000 万个句子——OpenWebText 数据集的随机子集。为了方便三元组采样,我们将句子及其mxbai-embed-large-v1嵌入上传到 Qdrant,并使用类型为word的分词器在句子上构建了一个全文载荷索引
每个词的训练数据我们为每个词采样 8000 个句子,并形成至少间隔 0.1 的三元组。
此外,我们还应用了数据增强——取一个句子,并剪切掉目标词及其 1-3 个邻居。为简化起见,我们对原始句子和增强句子重用相同的相似度得分。
训练参数迭代次数: 60
优化器:Adam,学习率为 1e-4
验证集: 20%

每个词都只在一颗 CPU 上训练,每个词大约需要五十秒。我们将此minicoil-v1版本包含在FastEmbed 库的 v0.7.0 版本中。

你可以在HuggingFace 卡片中查看minicoil-v1与 FastEmbed 的使用示例。

成果

验证损失

输入 Transformer jina-embeddings-v2-small-en 以 83% 的(通过三元组测量的)质量近似“榜样”Transformer mxbai-embed-large-v1 上下文关系。这意味着在 17% 的情况下,jina-embeddings-v2-small-en 将从 mxbai-embed-large-v1 中获取一个句子三元组,并以mxbai的角度来看,负例比正例更接近锚点的方式进行嵌入。

我们获得的验证损失,根据 miniCOIL 向量大小(4、8 或 16)的不同,分别表明 miniCOIL 正确区分了 76%(每批 256 个中平均 60 个三元组失败)到 85%(每批 256 个中平均 38 个三元组失败)的三元组。

Validation loss

验证损失

基准测试

基准测试代码已在该存储库中开源

为了检查我们的 4D miniCOIL 版本在不同领域下的性能,我们(讽刺地)选择了一部分相同的BEIR 数据集,许多稀疏神经检索器都将这些数据集上的高基准值本身作为目标。然而,不同之处在于 miniCOIL 并未在 BEIR 数据集上训练,因此不应偏向它们

我们正在测试我们的 4D miniCOIL 模型与我们的 BM25 实现。BEIR 数据集使用以下参数索引到 Qdrant,两种方法均适用:

  • k = 1.2, b = 0.75,建议用于 BM25 评分的默认值;
  • avg_len 根据相应数据集的 50,000 份文档估算。

我们根据NDCG@10指标比较模型,因为我们对 miniCOIL 相对于 BM25 的排名性能感兴趣。两者都根据精确匹配检索索引文档的相同子集,但 miniCOIL 理想情况下应该根据其语义理解更好地对该子集进行排名。

我们在几个测试领域的结果如下:

数据集BM25 (NDCG@10)MiniCOIL (NDCG@10)
MS MARCO0.2370.244
NQ0.3040.319
Quora0.7840.802
FiQA-20180.2520.257
HotpotQA0.6340.633

我们可以看到 miniCOIL 在五个测试领域中的四个领域中表现略优于 BM25。这表明我们正朝着正确的方向前进

关键要点

本文描述了我们尝试制作一个能够泛化到域外数据的轻量级稀疏神经检索器。稀疏神经检索具有巨大的潜力,我们希望看到它获得更多的关注。

这种方法为何有用?

这种训练稀疏神经检索器的方法:

  1. 不依赖于相关性目标,因为它以自监督方式训练,因此不需要标记数据集即可进行扩展。
  2. 基于经过验证的 BM25 公式,只是为其添加了一个语义组件。
  3. 创建轻量级稀疏表示,适用于标准倒排索引。
  4. 充分重用密集编码器的输出,使其适用于不同的模型。这也使得 miniCOIL 成为混合搜索解决方案的廉价升级。
  5. 使用极其简单的模型架构,miniCOIL 词汇表中的每个词都有一个可训练的层。这使得训练和推理速度非常快。此外,这种词级别的训练使得为特定用例扩展 miniCOIL 的词汇表变得容易。

合适的工具做合适的事

miniCOIL 检索器何时适用?

如果你需要精确的词项匹配,但基于 BM25 的检索无法满足你的需求,将形式正确但语义含义错误的文档排名更高。

假设你正在为你的文档实现搜索。在这种用例中,基于关键词的搜索占主导地位,但 BM25 不会考虑这些关键词在不同上下文中的含义。例如,如果你在我们的文档中搜索“数据”(data point),你可能更希望看到“是 Qdrant 中的一条记录”(a point is a record in Qdrant)排名高于“浮精度”(floating point precision),而这时基于 miniCOIL 的检索是一个值得考虑的替代方案。

此外,miniCOIL 作为混合搜索的一部分非常适合,因为它在不明显增加资源消耗的情况下增强了稀疏检索,直接重用了密集编码器生成的上下文词表示。

总而言之,miniCOIL 的工作方式应该就像 BM25 理解了词语的含义并根据这种语义知识对文档进行排名一样。它只对精确匹配进行操作,因此如果你希望找到与查询语义相似但用不同词表达的文档,那么密集编码器是最佳选择。

下一步是什么?

我们将继续努力改进我们的方法——既深入地寻找提高模型质量的方法,又广度地将其扩展到英语之外的各种密集编码器和语言。

我们很乐意与你分享这段通往可用稀疏神经检索的道路!

此页面有用吗?

感谢您的反馈!🙏

很抱歉听到这个消息。😔 你可以在 GitHub 上编辑此页面,或者创建一个 GitHub 问题。