K-NRM — 用核函数把交互矩阵变成可微排序信号
待复核K-NRM(Kernel-based Neural Ranking Model)是 BERT 之前一类代表性的神经搜索排序器。日常类比:图书管理员判断一本书和你查询的相关度,先把关键词和书里的词两两比一遍,再用一组“软抽屉”统计有多少对词靠得很近、有多少对意思接近、有多少对完全无关,最后把这些软统计量交给一个会打分的小函数。
输入是查询 q(几个词)和候选文档 d(几十到几百个词)。K-NRM 给每个 (q, d) 算出一个分数,再按分数排候选文档。它不负责从百万文档里“找出来”,只负责把已经召回的候选排得更准。
核心三步:算 |q|×|d| 的余弦相似度矩阵 M → 用 K 个 RBF 核(径向基函数:离中心越近权重越大的软计数器)把每行软计数成 K 维向量 → 取 log 求和后线性投影成标量分数。整条链路对词向量可微,能端到端反向传播(BP:把打分误差一路传回词向量去改)。
不理解 K-NRM 这条线,下面这些事都解释不通:
- 为什么 2017 年前的神经 ranker(DRMM 2016)用直方图,2017 年突然换成核——直方图桶边界会断梯度
- 为什么 2018 年 Conv-KNRM 一出来横扫各种 benchmark,但 2019 年 BERT 一来整条路线被收编
- 为什么 ColBERT 这种 late interaction 路线说自己“继承 K-NRM 衣钵”——它们都是先两两比再聚合
- 为什么工业搜索常用 K-NRM 当重排层,召回仍是 BM25
-
交互矩阵 M 像相似度地图。每个查询词和每个文档词先查 word embedding,再算余弦相似度,得到 |q| 行 |d| 列的表。完全相同的词那格是 1,毫不相干接近 0。类比:把查询词和书页词两两贴上“像不像”的温度计。
-
核池化是可微的软抽屉。DRMM 用直方图硬切桶,相似度跨过桶边界时梯度断掉。K-NRM 用 RBF 核:
K_k(M_i) = Σ_j exp(-(M_ij-μ_k)²/(2σ_k²)),距离中心越近权重越大,但总大于零,所以微动也会传到词向量。类比:硬抽屉一跨格就跳档;软抽屉永远有一点重量。 -
11 个核压成定长特征再打分。μ=1.0、σ=0.001 只数精确匹配;其余 μ 从 0.9 到 -0.9(步长 0.2)、σ=0.1 分别数近义到无关。每查询词得 K 维软计数,取 log 后按维相加,再 tanh + 线性投影成标量。类比:11 个抽屉的库存表,最后折成一个“相关度总分”。
案例 1:玩具查询上的软计数
Section titled “案例 1:玩具查询上的软计数”查询 q = [“机票”, “便宜”],文档片段 d = [“低价”, “机票”, “促销”]。
import math# 概念:M[i][j] = cos(emb(q_i), emb(d_j))M = [ [0.30, 1.00, 0.20], # 机票 vs 低价/机票/促销 [0.85, 0.25, 0.40], # 便宜 vs 低价/机票/促销]
def rbf(sims, mu, sigma): return sum(math.exp(-((s - mu) ** 2) / (2 * sigma ** 2)) for s in sims)
exact = rbf(M[0], mu=1.0, sigma=0.001) # “机票-机票”≈1near = rbf(M[1], mu=0.9, sigma=0.1) # “便宜-低价”≈0.85逐部分解释:
M是 2×3 相似度地图,不是真实训练数值,只帮助看清“哪一对词在喂哪个抽屉”。exact几乎只响应完全匹配;near会给近义词一对不小的软计数。- 这两个软计数进入最终分数后,文档会比“只有字面重叠、没有近义”的版本更高。
案例 2:损失如何把词向量拉近
Section titled “案例 2:损失如何把词向量拉近”# pairwise hinge:相关文档分数应比不相关至少高 marginloss = max(0, margin - (score(q, d_plus) - score(q, d_minus)))# loss → 核值 → M → embedding,整条可微逐部分解释:
- 训练时成对比较:相关文档
d_plus应压过不相关d_minus。 - 误差能传回 embedding,于是“便宜”和“低价”在这个检索任务里会被拉得更近。
- 这就是卖点:通用词向量被调成 IR 任务专用。
案例 3:先 BM25 召回,再 K-NRM 重排
Section titled “案例 3:先 BM25 召回,再 K-NRM 重排”百万文档库 → BM25 / Anserini 召回 top 100 → K-NRM 对这 100 篇算 |q|×|d| 并打分重排逐部分解释:
- 直接对全库算交互矩阵不现实,矩阵随文档长度线性涨。
- 工程上固定成“稀疏召回 + 神经精排”;后来 BERT ranker 也沿用这套两段式。
- 适用边界:候选集通常 < 1000;没有点击/标注时,往往不如 BM25。
- 消融直觉:只开精确匹配核会退化成 TF 思路;加上中等相似度核后 NDCG 才明显上来。
- 核中心 μ 不学:论文里 11 个 μ 是手工设的;后续 Conv-KNRM 让 μ 可学,效果更好但更慢。
- 点击日志有噪:大规模弱监督容易让高频查询过拟合,长尾 NDCG(排序质量指标)涨幅小很多。
- 零样本反而输 BM25:没有监督信号时,embedding 调不动,只靠预训练词向量往往没优势。
- 长文档内存爆炸:|q|×|d| 随长度线性增长,超长文档必须先截断或分段。
适用 vs 不适用场景
Section titled “适用 vs 不适用场景”适用:
- Web/电商/学术搜索的重排阶段,候选集 < 1000
- 有点击日志或人工相关度标注当监督信号
- 查询词和文档都偏短(几十词以内)
不适用:
- 海量召回阶段——用倒排索引 + BM25
- 没有任何监督信号的场景——常比 BM25 差
- 需要 cross-attention 的复杂语义任务——直接上 BERT ranker
- 超长文档检索——交互矩阵内存撑不住
历史小故事(可跳过)
Section titled “历史小故事(可跳过)”- 2013 年:微软 DSSM 把查询和文档各自压成向量算余弦——双塔路线起点。
- 2016 年:DRMM 提出交互矩阵 + 直方图,能看见词级匹配,但桶边界断梯度。
- 2017 年:Xiong 等在 SIGIR 发表 K-NRM,用 RBF 核解决可微问题,成为 pre-BERT 交互式神经排序代表作。
- 2018 年:Conv-KNRM 在前面加 n-gram CNN 学短语向量,进一步提升。
- 2019 年之后:BERT ranker 横扫;K-NRM 的思想进入 ColBERT 等 late interaction 工作。
- 可微 vs 不可微是神经 IR 的胜负手:DRMM 直方图 → K-NRM 核池化是一次跃迁。
- 召回-精排两段式由这一代固化:BM25 召回,神经模型精排。
- 弱监督 + 大点击日志第一次在 IR 里跑通,后来被 ColBERT / DPR 继续用。
- embedding 从通用走向任务专用——检索场景会改写“便宜/低价”这类近邻关系。
- 核的数量不必盲目加:论文消融显示 11 个核已接近饱和,再加密抽屉边际收益很小。
- 论文 PDF:K-NRM SIGIR 2017
- 代码:github.com/AdeDZY/K-NRM(作者官方实现)
- Conv-KNRM:WSDM 2018
- drmm-2016 —— 直方图交互矩阵,K-NRM 的直接前身
- colbert-v2 —— late interaction 路线,思想血脉来自 K-NRM
- anserini-2017 —— BM25 召回实验台,常与神经精排搭配
- drmm-2016 —— 交互矩阵 + 直方图,K-NRM 的直接对手
- dssm-2013 —— 双塔/向量路线起点,K-NRM 走交互路线
- anserini-2017 —— Lucene 上的 BM25 baseline,召回阶段伙伴
- bm25-okapi —— 词袋检索天花板,K-NRM 的对照组
- colbert-v2 —— late interaction 代表,思想血脉来自 K-NRM
- lambdarank-2006 —— pairwise 排序学习祖先
- ranknet-2005 —— pairwise 神经排序早期工作
- colbert-2020 —— ColBERT — 让 BERT 检索既准又能扛大规模