DPR — 用 BERT 双塔把检索从 BM25 时代拉进稠密向量时代
是什么
DPR(Dense Passage Retrieval)是一种用神经网络做开放域问答检索的模型——给一个问题,它从千万级段落库里挑出最可能含答案的几段。日常类比:旧搜索引擎(BM25)像图书管理员只认书名和关键词,你问 ‘苹果手机售价’ 必须文档里写过 ‘苹果’ 和 ‘手机’ 才能召回;DPR 像一个读过全部书的人,他把每段话理解后浓缩成一张 768 维的语义卡片,你问问题时也浓缩成同样的卡片,然后比对卡片间的相似度——哪怕原文一个关键词都不重,也能找到。
它解决的痛点是 2019 年开放域 QA 的瓶颈:BM25 召回的段落里正确答案常常根本不在,下游 reader 模型再强也无能为力。DPR 把召回阶段换成稠密检索,端到端 QA 准确率提升 9-19 个绝对点。
为什么重要
不理解 DPR,下面这些事都没法解释:
- 为什么 2020 年之后 RAG 系统的默认检索器是 ‘双塔 BERT + faiss’,而不是 BM25
- 为什么 ColBERT / SPLADE / E5 / BGE 这些后续模型全在 ‘DPR 框架的某个零件’ 上做改进
- 为什么 ‘in-batch negatives’ 成了对比学习训练检索器的工业标配
- 为什么开放域 QA 的两阶段架构(retriever + reader)能在 2020 年突然爆发——retriever 终于配得上 reader
核心要点
DPR 的全部巧思可以拆成 三步:
-
双塔编码:问题用一个 BERT,段落用另一个 BERT(不共享权重)。各自取
[CLS]那个 768 维向量当作整段的代表。这一步关键在 不共享权重——问题和段落的语言风格不同,分开学习更准。 -
内积相似度:问题向量 q 和段落向量 p 算
sim(q, p) = q · p,最大的就是答案最可能在的段落。预先把所有段落编码后存进 faiss,查询时只算一次问题编码 + 一次 ANN 搜索。 -
对比学习训练:每个正例(问题,正确段落)配一堆负例。负例两种来源——同 batch 里别人的正例(in-batch negatives,免费拿)+ BM25 召回但不含答案的段落(hard negatives,更难辨)。loss 推动正例对内积高、负例对内积低。
三种检索范式对比
| 范式 | 表达方式 | 速度 | 精度 | 关键词依赖 |
|---|---|---|---|---|
| BM25 | 词频统计+IDF | 快 | 中 | 强 |
| DPR 单向量 | 768 维 [CLS] | 极快 | 高 | 弱 |
| late interaction | token 级向量聚合 | 快 | 更高 | 弱 |
DPR 占据 ‘极快 + 高精度’ 的格子,是后来稠密检索的工业默认起点。
实践案例
案例 1:DPR 召回为什么比 BM25 强
问题:‘谁发明了万维网?‘。文档:‘蒂姆·伯纳斯-李在 1989 年于 CERN 提出了一种超文本系统的设计……’。
BM25 看 ‘万维网’ 是否出现——文档里写的是 ‘超文本系统’,关键词不重合,召回失败。DPR 把问题和文档各自编成 768 维向量,‘万维网’ 和 ‘超文本系统’ 在语义空间中靠近,内积高,召回成功。
这就是 ‘从字面到语义’ 的跃迁。
案例 2:五个 QA 数据集上的实测
| 数据集 | BM25 Top-20 | DPR Top-20 | 提升 |
|---|---|---|---|
| Natural Q. | 59.1 | 78.4 | +19 |
| TriviaQA | 66.9 | 79.4 | +13 |
| WebQuestions | 55.0 | 73.2 | +18 |
| CuratedTREC | 70.9 | 79.8 | +9 |
| SQuAD | 68.8 | 63.2 | -6 |
注意 SQuAD 上 DPR 反而输给 BM25——SQuAD 的问题是注释员看着段落写的,关键词重合天然高,BM25 的字面匹配反而占优。这给后人留下经验:领域不同则检索器选择不同。
案例 3:in-batch negatives 为什么这么省
batch 大小 128,里面是 128 对(问题,正例段落)。训练时把它当成一个 128×128 的矩阵——对角线是正例,其他全是别人的正例当成 ‘我的负例’。这样一次前向就有 127 个负样本,不用额外 GPU 计算。
加上 BM25 hard negatives(每个问题挂 1-2 个),总负样本超过 250 个/问题,训练信号充足。
案例 4:检索质量如何影响下游 QA
DPR 论文里给了 retriever 召回率到端到端 QA EM 的传导:retriever Top-100 召回率从 BM25 的 76% 提到 DPR 的 86%,下游 reader 同款不变,QA EM 从 32 涨到 41。这十个百分点几乎全来自检索阶段的提升——证明了 ‘检索是 QA 的天花板’。
踩过的坑
-
训练数据要带正例:没有 ‘问题-正例段落’ 配对就训不了,所以 DPR 强依赖 NQ / TriviaQA 这种已标注集,冷启动困难。
-
领域漂移严重:MS MARCO / NQ 训出的 DPR 直接用到医学、法律、代码上效果会大幅下降。后来 BEIR 基准证明这点,并催生了 GPL / E5 等领域无关训练法。
-
hard negatives 选择敏感:BM25 挑出的 ‘负例’ 里偶尔混着真正的正例(标注遗漏),训练时被当负例打压,模型反而学坏。实践里要做去重和置信度过滤。
-
single-vector 信息瓶颈:768 维浓缩一段几百字必然丢信息。问题里多个细节(日期+地点+人名)很难全保留,这是 ColBERT / late interaction 后来要解决的痛点。
-
batch size 决定上限:in-batch negatives 越多越好,但 GPU 显存有限;后来 GradCache / cross-device 通信解决这个。原文用 V100 32G 跑 batch 128。
-
inner product vs cosine:DPR 用内积不归一化,向量长度参与打分——长向量天然分高,可能产生偏置。后来很多工作改用 cosine(先归一化)。
-
reader 端是否一起训:原文分两阶段(先训 retriever 再训 reader),后来 RAG / REALM 证明端到端联合训练能再涨点,但实现复杂。
-
段落切分粒度敏感:DPR 假设输入是 100 词左右的段落,太长会被截断丢尾,太短则上下文不全。预处理阶段的 chunking 策略(固定窗口 / 句子边界 / 滑动重叠)直接影响最终召回率,这是工程上常被忽视的隐含超参。
适用 vs 不适用场景
适用:
- 开放域 QA 的检索阶段,候选段落量级 1M-100M
- 用户查询和文档语言风格差异大(口语问 vs 正式答)的场景
- 已有大量标注 ‘问题-段落’ 对的领域(NQ / TriviaQA / 客服 FAQ)
- 需要毫秒级检索 + 千万级索引的工业 RAG 系统
不适用:
- 关键词匹配天然强(SQuAD 类、产品 SKU 搜索)→ 先试 BM25
- 完全没标注数据的冷启动 → 选 BM25 或 contriever 这种无监督稠密检索
- 候选段落 < 1000 → 直接用 cross-encoder 全量打分
- 需要可解释打分(合规要求)→ 选 BM25 加神经 reranker
历史小故事(可跳过)
- 2018 年:BERT 出世,但拿来检索只有少量探索,主流仍是 BM25 + 神经 reranker 两段式
- 2019 年:ORQA(Lee et al.)首次端到端联合训练 BERT 检索器+reader,效果好但训练昂贵
- 2020 年 4 月:Karpukhin 等人在 Facebook AI 提出 DPR——把检索单独训练,简单粗暴但全面碾压 BM25,发表在 EMNLP 2020
- 2020 年下半年:ColBERT / RAG / REALM 三个方向同时爆发,全把 DPR 当起点
- 2022 年:BEIR 基准揭示 DPR 跨领域弱点,催生 contriever / GPL / E5 一系列零样本检索方案
- 2024 年:DPR 思想在 RAG 工业落地中无处不在——Cohere / OpenAI Embeddings / BGE / Jina 都是 ‘DPR 加大版’
学到什么
- ‘语义 vs 字面’ 的换代——DPR 让检索从 1972 年 BM25 时代正式进入神经向量时代,后续十年的检索研究全在这个框架内
- 双塔的工程价值是 ‘可预索引’——问题和段落各自独立编码,段落向量可提前算好存 faiss;这是和 cross-encoder 的根本分界
- 对比学习负样本是命门——in-batch negatives + BM25 hard negatives 是 DPR 的核心训练秘方,几乎所有后续检索器都沿用
- ‘够用就好’ 的力量——DPR 没用什么花哨结构,就是 BERT [CLS] + 内积 + 对比损失,但通过精心选择训练数据和负例就赢了;提醒后人系统设计常常拼细节而非新概念
- 领域是检索器的隐含维度——同一架构换领域要重训,这个限制至今没完全解决,是 BEIR / E5 等后续工作的主战场
- 数据胜过架构——DPR 没有引入新结构却赢了 BM25,说明 ‘怎么训’ 比 ‘怎么搭’ 重要,这条经验被后来 SimCSE / E5 反复印证
- 检索是 QA 的天花板——下游 reader 再强也救不了召回失败的样本,DPR 把这个天花板抬高了 10 个点,这是开放域 QA 在 2020 年集中爆发的真正原因
延伸阅读
- 论文 PDF:DPR arXiv(13 页正文)
- 视频教程:Stanford CS224U — DPR(讲 DPR 训练流程,60 分钟)
- 代码与模型:facebookresearch/DPR(PyTorch 官方实现)
- colbert-2020 —— 直接后继,用 late interaction 改进 DPR 的单向量信息瓶颈
- bert —— DPR 的双塔 backbone
关联
- bert —— 提供 [CLS] 向量作为整段语义代表,是 DPR 双塔的基础
- colbert-2020 —— 直接后继,把 DPR 单向量换成 token 级 late interaction,精度更高
- dssm-2013 —— 双塔思想的鼻祖,DPR 是 BERT 时代的重写版
- bm25-okapi —— DPR 的对照基线,论文里展示了 5 个数据集上的对比
- okapi-bm25-1994 —— 经典字面检索算法,DPR 在 4/5 QA 数据集上压制它
- anserini-2017 —— BM25 的现代实现,DPR 论文里的实际跑分基线
- transformer —— BERT 的底层架构,间接是 DPR 表达能力的来源
- attention —— BERT 内部的核心机制,让 [CLS] 能聚合整段语义
反向链接
- ance-2020 —— ANCE — 让模型自己挖训练负例,对比学习的”自给自足”
- anserini-2017 —— Anserini — 把工业搜索引擎 Lucene 改造成学术 IR 实验台
- attention —— Attention Is All You Need
- bert —— BERT — 双向 Transformer 预训练
- cocondenser-2021 —— coCondenser — 让 BERT 的 [CLS] 在预训练就学会”代表整段话”
- colbert-2020 —— ColBERT — 让 BERT 检索既准又能扛大规模
- doc2query-2019 —— doc2query — 让模型替文档预想”会被怎么搜”再写进倒排表
- e5-2022 —— E5 — 用海量”自然出现的文本对”训通用 embedding
- ms-marco-2016 —— MS MARCO — 1 千万 Bing 真实查询喂饱神经检索的标准评测集
- replug-2023 —— REPLUG — 不动 LLM 一根毛,只把检索器调到它的”口味”上
- rocketqa-2021 —— RocketQA — 把稠密检索的训练拧到工业级
- splade-2021 —— SPLADE — 让神经网络学出稀疏向量,直接复用倒排索引