想象一档选秀节目。早期的赛制是打分制:导师给每位选手“音准 8 分,台风 7 分”,但这种分数常常引发争议——8 分和 7 分到底差在哪?于是节目组改成 PK 制:两位选手同台,观众只要回答“谁更打动我”。比赛结束后,工作人员把一张张 PK 记录整理成实力榜,排名靠前的人获得晋级资格。搜索引擎的排序学习,也走过同样的弯路。最朴素的想法是“给每个网页打一个相关度分”,可标注员很难说清“苹果官网”该得 8 分还是 9 分;但若问“搜苹果,官网和百科哪个更相关”,几乎所有人都能立刻回答。Pairwise 排序学习正是抓住这个直觉:不直接预测单篇文档的分数,而是比较两两文档谁更相关,用海量“谁赢谁输”的 PK 数据训练排序模型。本文的主角是两种经典算法——把排序问题变成大间隔分类问题的 RankSVM,和把排序问题变成胜率学习问题的 RankNet。跟随这个选秀 PK 的比喻,你将轻松弄懂它们的原理、差异与工程落地。

岗位关联

学会 Pairwise 排序学习,你就能设计出更贴合用户直觉的搜索与推荐排序模型:两两比较的标注信号更可靠、训练目标更贴近排序本身,这是工业界排序模型的主流思路,能直接提升搜索体验与业务指标。

目录
  1. 可视化演示
  2. 核心思想:PK 流胜过打分流
  3. 损失函数:给 PK 定规则
  4. RankSVM 原理:裁判的安全距离
  5. RankNet 原理:让胜率说话
  6. 评估与优化:排名不看场次
  7. 工程实践:让 PK 上线
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

展示文档对排序、RankSVM间隔最大化和RankNet神经网络训练三种Pairwise排序方法,通过分数对比、特征空间和网络结构直观理解排序学习核心原理。

本节配有交互动效(进入视口后自动加载,约 3KB)。

文档对排序 相关文档分数高于不相关文档,Pairwise方法学习文档对的相对顺序 score(d⁺)>score(d⁻) 蓝色文档为相关文档,红色为不相关文档,连线表示文档对,右侧显示排序分数

核心思想:PK 流胜过打分流

选秀节目最早的赛制是“打分制”:导师对每位选手的音准、台风、感染力逐项打分,再算一个总分。问题随之而来——8 分和 9 分的差距到底是什么?两位导师对“唱功”的理解不同,打分就打架。改成 PK 制后,一切变得简单:选手 A 和选手 B 同台演唱,观众只需回答“谁更打动我”。这种“二选一”的判断,比“打一个绝对分数”稳定得多。

搜索引擎的排序学习也经历了同样的进化。最朴素的 Pointwise 思路是给每个网页打一个相关度分,比如“苹果官网”的分数是 8.5、“苹果百科”是 8.0,按分数高低排序。但标注员很难说清 8.5 和 8.0 的具体差别;反过来,问“搜'苹果'时,官网和百科哪个更相关”,几乎人人都能立刻给出答案。Pairwise 排序学习就从这个直觉出发:不直接预测单个文档的分数,而是把训练数据组织成一个个文档对,标注出“谁比谁更相关”。

技术上讲,给定一个查询 q,把文档 $i$ 和文档 $j$ 组成一对,用偏好标签 $y_{ij}=+1$ 表示“i 比 j 相关”,$y_{ij}=-1$ 表示相反。模型要学习一个打分函数 $f(x)$,使得相关度更高的文档拿到更大的分数。值得注意的是:训练时看的是两两比较,但预测时并不需要两两配对——模型只需对每个文档独立打分,再按分数从大到小排序即可。

这就好比节目组从海量 PK 记录中反推出每位选手的“实力值”。之后不再需要逐对 PK,只要把实力值亮出来,名次自然排定。Pairwise 算法要解决的,正是“如何从一堆胜负关系中,练出一个靠谱的打分函数”。

f(xi)>f(xj)⟺i≻jf(x_i) > f(x_j) \quad \Longleftrightarrow \quad i \succ j
这个公式是 Pairwise 的核心契约:谁的打分高,谁就排在前面。它把“谁更相关”的定性判断,变成了“分数大小”的定量比较。
  1. 打分函数每个文档经过模型计算得到一个实数分数,相当于每位选手的“实力值”。
    f(x): Rd→Rf(x):\ \mathbb{R}^d \to \mathbb{R}
  2. 分数差两个文档的分数相减,得到相对优势。
    sij=f(xi)−f(xj)s_{ij} = f(x_i) - f(x_j)
  3. 判定条件分数差大于 0,说明 $i$ 比 $j$ 更相关,应排在前面。
    sij>0  ⟺  i≻js_{ij} > 0 \iff i \succ j

损失函数:给 PK 定规则

PK 赛要有一套计分规则,规则决定选手的成长方向。如果规则是“赢一场加 1 分,输一场扣 1 分”,选手就只求赢,不求赢得漂亮;如果规则变成“按优势大小计分,赢得越多加分越多”,强者就会更努力地拉开差距。排序学习同样需要一套“计分规则”,也就是损失函数,用来告诉模型:当前这个文档对排得对不对、错得多离谱。

把排序问题转化为损失函数有一个巧妙的角度:每个文档对其实就是一个“带符号的二分类样本”。令 $z = y_{ij}(f(x_i)-f(x_j))$,当模型判断正确时 $z>0$,判断错误时 $z<0$。我们希望损失函数在 $z$ 越小时惩罚越重,在 $z$ 足够大时惩罚趋近于 0。最理想的是“0/1 损失”——判断对了罚 0,判断错了罚 1,但它不光滑、不可导,没法用梯度下降优化。于是需要“凸代理损失”:用一个性质良好、形状接近的凸函数替代 0/1 损失。

两个最经典的替代品,正好对应文中的两位主角。RankSVM 用合页损失:只要分数差超过安全线 1,就不罚;没超过就按差距线性惩罚,鼓励模型把“赢得明显的对”和“赢得勉强但对”区分开。RankNet 用对数损失(也叫交叉熵):差距越小惩罚越大,但随着差距增大惩罚平滑地趋近 0,处处可导,方便神经网络反向传播。

规则一旦定下,选手(模型参数)就会沿着规则指引的方向成长。RankSVM 和 RankNet 的差异,本质上就是这两套“计分规则”的差异。

ℓpair(z)={max⁡(0, 1−z)RankSVM (合页)log⁡(1+e−z)RankNet (对数)其中 z=yij(f(xi)−f(xj))\ell_{\mathrm{pair}}(z)=\begin{cases}\max(0,\,1-z) & \text{RankSVM (合页)}\\[4pt]\log(1+e^{-z}) & \text{RankNet (对数)}\end{cases}\quad\text{其中 } z = y_{ij}\bigl(f(x_i)-f(x_j)\bigr)
一句话理解:合页损失像“裁判看安全距离”,对数损失像“按胜率算分”。两者都把排序错误转化为一个可优化的数值。
  1. 一致性变量$z$ 综合了真实偏好和模型预测,两者一致时为正,不一致时为负。
    z=yij (f(xi)−f(xj))z = y_{ij}\,\bigl(f(x_i)-f(x_j)\bigr)
  2. 合页损失当 $z\ge1$ 时不惩罚,当 $z<1$ 时线性上升,鼓励拉开差距。
    max⁡(0, 1−z)\max(0,\,1-z)
  3. 对数损失$z$ 越小惩罚越大,但永远光滑可导,适合梯度下降。
    log⁡(1+e−z)\log(1+e^{-z})

RankSVM 原理:裁判的安全距离

一位经验丰富的裁判在判 PK 时,会格外关注“赢得够不够明显”。两位选手实力接近,谁赢都有运气成分;如果胜者赢得毫无争议,判罚才让人信服。RankSVM 把这种直觉形式化成了“大间隔”:在文档对的差值空间中,找到一个分类超平面,不仅要把“正序对”和“逆序对”分开,还要让分界线离两类样本尽可能远。

具体做法是:把每个文档对 $(i,j)$ 折叠成一个差值向量 $z_{ij}=x_i-x_j$,真实偏好 $y_{ij}$ 就是这个“样本”的标签。如果 $y_{ij}=+1$,我们希望 $w^{\top}z_{ij}>0$;如果 $y_{ij}=-1$,我们希望 $w^{\top}z_{ij}<0$。这与训练一个线性 SVM 分类器在数学上完全同构,只是样本空间从“文档特征”变成了“文档特征差”。学到的权重向量 $w$,就是对每个特征重要性的权衡。

现实中的排序数据不可能完全线性可分,所以 RankSVM 引入软间隔:允许少量文档对违反间隔约束,用松弛变量 $\xi_{ij}$ 记录违规程度,再用超参数 $C$ 平衡“间隔大小”和“违规惩罚”。$C$ 越大,模型对训练对的违规越不能容忍,越容易过拟合;$C$ 越小,模型越宽容,边界越平滑。训练完成后,预测时只需计算 $f(x)=w^{\top}x$ 给每个文档打分,按分数排序。

学到的 $w$ 就是裁判手里那把“统一标尺”:文本匹配度、点击率、时效性等特征各自乘以权重,加总得到每个文档的实力值。有了这把标尺,任何两位选手同台,谁赢谁输一目了然。

min⁡w,ξ 12∥w∥2+C∑(i,j)∈Pξijs.t.yij w⊤(xi−xj)≥1−ξij, ξij≥0\min_{w,\xi}\ \frac{1}{2}\|w\|^2 + C\sum_{(i,j)\in P}\xi_{ij}\quad \text{s.t.} \quad y_{ij}\,w^{\top}(x_i-x_j)\ge 1-\xi_{ij},\ \xi_{ij}\ge0
这个优化目标可解读为“在保证多数 PK 判对的前提下,把裁判的判定标准打磨得尽可能清晰、稳健”。
  1. 差值向量把一对文档变成一个新的样本,这是 RankSVM 区别于普通 SVM 的关键。
    zij=xi−xjz_{ij}=x_i-x_j
  2. 间隔约束正序对的投影至少要大于 1,逆序对至少要小于 -1,二者之间留出宽度为 2 的“安全区”。
    yij w⊤zij≥1−ξijy_{ij}\,w^{\top}z_{ij}\ge 1-\xi_{ij}
  3. 软间隔$\xi_{ij}$ 是非负的违规量,允许少数样本对越界,避免模型被噪声带偏。
    ξij≥0\xi_{ij}\ge0
  4. 权衡系数$C$ 乘以所有违规量之和,$C$ 越大则对违规越严格。
    C∑(i,j)∈PξijC\sum_{(i,j)\in P}\xi_{ij}

RankNet 原理:让胜率说话

有些评委不满足于判断“谁赢了”,还想量化“赢多少”。两位实力均衡的选手对决 100 次,可能各赢 50 次;实力悬殊的选手对决,强者可能赢 90 次。胜率比胜负本身携带更多信息。RankNet 的思路正是如此:不直接输出“谁赢”,而是输出一个 0 到 1 之间的胜率。

RankNet 用一个神经网络(也可以是线性模型)给每个文档打分 $s_i=f(x_i)$,然后通过 sigmoid 函数把分数差映射成“文档 i 排在文档 j 前面的概率”:分数差越大,胜率越接近 1;分数差为 0 时,胜率正好是 0.5。训练时,对于每个文档对,我们有一个真实偏好:如果 $i$ 比 $j$ 相关,真实胜率 $\bar{P}_{ij}=1$,否则为 0。模型输出的胜率 $P_{ij}$ 和真实胜率之间的差距,用交叉熵来衡量——这就是 RankNet 的损失函数。

对这个损失求梯度,会得到一个非常优雅的结果:梯度的方向由“模型自信程度”和“真实偏好”的差异决定。当模型认为 $i$ 排在 $j$ 前的胜率低于真实情况时,梯度会推着参数增大 $s_i-s_j$;反之,当模型过度自信时,梯度会把分差往回拉。而且注意,梯度同时包含 $\partial s_i/\partial w$ 和 $\partial s_j/\partial w$ 两项,也就是说每一次更新,赢家和输家的文档特征都会参与参数调整——正如一场 PK 之后,两位选手都会根据比赛结果调整训练方向。

每次 PK 结束后,系统根据“出乎意料的程度”同时微调两位选手的实力值——这就是梯度下降的直觉。RankNet 把排序学习变成了一场温柔的“胜率校准”,这也是它能平滑地扩展到神经网络的深层次原因。

Pij=11+e−σ(si−sj),Lij=− Pˉijlog⁡Pij−(1−Pˉij)log⁡(1−Pij)P_{ij}=\frac{1}{1+e^{-\sigma(s_i-s_j)}},\qquad\mathcal{L}_{ij}=-\,\bar{P}_{ij}\log P_{ij}-(1-\bar{P}_{ij})\log(1-P_{ij})
胜率是“这一对的胜算”,真正用于排序的是打分 $s_i$。模型预测时按打分降序排列,不需要计算任何胜率。
  1. 分数差两个文档的打分相减,表示当前模型的相对判断。
    Δij=si−sj\Delta_{ij}=s_i-s_j
  2. sigmoid 映射把实数分差压到 0 到 1 之间,变成可解释的胜率。
    Pij=σ(Δij)=11+e−ΔijP_{ij}=\sigma(\Delta_{ij})=\frac{1}{1+e^{-\Delta_{ij}}}
  3. 真实偏好如果 $i$ 确实比 $j$ 相关,则 $\bar{P}_{ij}=1$,否则为 0。
    Pˉij={1i≻j0j≻i\bar{P}_{ij}=\begin{cases}1 & i\succ j\\[2pt]0 & j\succ i\end{cases}
  4. 交叉熵损失衡量预测胜率与真实胜率的偏差,偏差越大罚得越重。
    Lij=−Pˉijlog⁡Pij−(1−Pˉij)log⁡(1−Pij)\mathcal{L}_{ij}=-\bar{P}_{ij}\log P_{ij}-(1-\bar{P}_{ij})\log(1-P_{ij})

评估与优化:排名不看场次

节目火了之后,主办方发现一个尴尬的问题:PK 胜场数最多的选手,未必是观众心中最该夺冠的人。因为观众最在意的是决赛圈名次,尤其是前几名的排位;而 PK 胜场只反映“赢了多少对”,不关心赢的是强手还是弱手。搜索引擎也面临同样的错位:Pairwise 损失降得很低,不代表用户看到的头部结果真正变好了。

因此,我们需要一个更贴近用户体验的评估指标。业界最常用的是 NDCG(归一化折损累计增益)。它有三个关键设计:第一,相关性用分级分数表示(如 0 到 4 分),而不是简单的二值;第二,位置越靠后,收益被对数折扣得越狠——第 1 名和第 2 名的差距远大于第 9 名和第 10 名的差距;第三,用理想排序的 DCG 做归一化,让不同查询的得分可以横向比较。NDCG@k 只看前 k 个位置,对应搜索用户“只看第一页”的真实习惯。

训练效率方面,Pairwise 还有一个必须正视的问题:样本对数量是文档数的平方。一个查询下有 100 个候选文档,就能构造近 5000 个文档对;如果有 10 万个查询,配对数量会爆炸。而且正负偏好对严重不平衡——绝大多数候选文档都“不相关”,互相配对产生的负样本远多于正样本。常用的对策包括:随机采样部分文档对参与训练、只保留排序靠前的候选构造文档对、对同一文档对去重合并。这些技巧牺牲一点理论上的完备性,换来训练速度和稳定性的巨大提升。

就像一档节目既要有观众口碑调查,也要有合理的赛程安排一样,排序系统既要盯着 NDCG 这个“业务指标”,也要用采样截断解决“比赛场次爆炸”的工程问题。

DCG@k=∑i=1k2reli−1log⁡2(i+1),NDCG@k=DCG@kIDCG@k\mathrm{DCG}@k=\sum_{i=1}^{k}\frac{2^{\mathrm{rel}_i}-1}{\log_2(i+1)},\qquad\mathrm{NDCG}@k=\frac{\mathrm{DCG}@k}{\mathrm{IDCG}@k}
NDCG 回答“排序到底好不好”,采样截断回答“训练还能不能跑完”。二者相辅相成,缺一不可。
  1. 分级相关度$\mathrm{rel}_i$ 是第 $i$ 位文档的人工标注等级,等级越高越相关。
    reli∈{0,1,2,3,4}\mathrm{rel}_i\in\{0,1,2,3,4\}
  2. 指数增益高度相关的文档($\mathrm{rel}$ 大)通过 $2^{\mathrm{rel}}-1$ 获得指数级放大。
    Gi=2reli−1G_i=2^{\mathrm{rel}_i}-1
  3. 位置折扣第 $i$ 名的收益除以 $\log_2(i+1)$,排名越靠后,贡献越小。
    Di=1log⁡2(i+1)D_i=\frac{1}{\log_2(i+1)}
  4. 归一化除以理想排序的 DCG,得到 0 到 1 之间的 NDCG,便于跨查询对比。
    NDCG@k=DCG@kIDCG@k\mathrm{NDCG}@k=\frac{\mathrm{DCG}@k}{\mathrm{IDCG}@k}

工程实践:让 PK 上线

当一档选秀变成系列 IP,它就不再是零散的比赛,而是一条生产线:海选、晋级 PK、成团排名、后续运营。搜索和推荐系统也是同构的流水线:先由召回模块从千万级文档库中快速筛出几百个候选,再由精排模型对候选精确排序,最后把排序结果呈现给用户。Pairwise 排序学习,正是精排模块的核心算法之一。

在实际落地中,训练数据通常从用户行为日志自动构造:用户点击了结果 A 却没点击结果 B,就构造一个偏好对“B 比 A 更相关”(更精细的做法是区分点击、深度阅读、购买等不同强度行为)。特征工程则围绕“查询与文档的匹配度”展开:文本相似度、点击率、停留时长、内容时效性、来源权威度等都是常见特征。模型训练好之后,用 NDCG 等指标离线评估,再通过 A/B 测试在线验证,确认指标提升后才逐步放量上线。

精排分数的计算可以非常直观地表示为特征加权求和:

其中 $\phi_k(q,d)$ 是第 $k$ 个特征函数,$w_k$ 是它对应的权重——RankSVM 学到的正是这组权重,RankNet 则可以让 $\phi$ 本身也被深度网络学习。这个公式揭示了 Pairwise 方法在工业界经久不衰的原因:训练时用两两比较获得稳定信号,预测时退化为一次简单的打分运算,既能保证效果,又满足线上服务的低延迟要求。

从选秀生产线回到搜索引擎:一位资深导演的职责,是把最值得看的画面放在最显眼的位置。Pairwise 排序学习教给算法的,正是“谁更值得被用户看到”——两两比较的严谨训练,换来的是最终排名中位置与价值的高度一致。

s(d)=∑k=1mwk ϕk(q,d)s(d)=\sum_{k=1}^{m} w_k\,\phi_k(q,d)
  1. 特征函数每个特征函数提取查询与文档之间的一种匹配信号。
    ϕk(q,d)\phi_k(q,d)
  2. 加权求和所有特征信号按权重相加,得到文档的最终排序分数。
    s(d)=∑k=1mwk ϕk(q,d)s(d)=\sum_{k=1}^{m} w_k\,\phi_k(q,d)

AI 应用场景

电商搜索精排

阶段:模型训练与排序精排阶段

解决的问题:传统电商搜索按销量或文本匹配度直接排序,结果经常与用户真实意图相悖。“搜运动鞋,用户想买的是轻便跑鞋,但按销量排在前面的却是厚重篮球鞋。”Pairwise 模型利用点击、加购、购买日志构造海量偏好对,让模型学习“用户当前更想看哪个商品”,从而把真正满足意图的商品提到前排。

具体案例:某电商平台搜索“机械键盘”,召回 500 个候选商品。算法工程师用用户点击数据构造偏好对(被点击商品 > 被跳过商品),训练 RankNet 线性版本,再结合价格、品牌、评论数等特征精排。上线后首屏点击率提升 8%,加购转化率提升 5%。

新闻信息流推荐

阶段:推荐排序与个性化召回

解决的问题:信息流推荐的核心是“哪条新闻更值得用户现在看”。人工运营只能覆盖热门话题,无法为每个用户定制顺序。Pairwise 方法用阅读时长、点赞、分享等行为作为偏好信号,训练模型比较两条新闻的“当下价值”,实现千人千面的排序。

具体案例:某新闻 App 在精排阶段使用 Pairwise 排序模型,特征包含用户历史兴趣、新闻新鲜度、点击率预估等。模型每周离线重训,配合实时特征服务。实验组相比旧的点击率排序,人均阅读时长提升 12%,用户次日留存提高 1.5 个百分点。

相关性标注效率提升

阶段:数据标注与评测阶段

解决的问题:传统标注任务要求标注员给每个网页打“相关度 1-5 分”,不同标注员的标准差异大,导致标注一致性低、返工率高。改用 Pairwise 后,“结果 A 是否比结果 B 相关”是天然的二选一判断,标注员之间的一致性显著提高。

具体案例:某搜索引擎团队将新查询的标注任务从“绝对打分”改为“两两比较”后,标注员一致性(Kappa 系数)从 0.55 提升到 0.78,标注周期缩短 40%。同时标注产生的偏好对直接作为 Pairwise 模型的训练数据,形成“标注—训练—评估”的正向闭环。

Python 演示

python55 行
import numpy as np  def sigmoid(x):    # 把实数映射到 0 到 1 之间    return 1.0 / (1.0 + np.exp(-x))  def generate_data(n_docs=12, seed=42):    # 前半是相关文档, 后半是不相关文档    labels = np.array([1] * (n_docs // 2) + [0] * (n_docs - n_docs // 2))    rng = np.random.default_rng(seed)    features = rng.normal(size=(n_docs, 5))    # 让相关文档的特征整体偏大, 保证任务可学    features[: n_docs // 2] += 0.8    # 构建偏好对: i 比 j 相关等价于 labels[i] > labels[j]    pairs = [(i, j) for i in range(n_docs)             for j in range(n_docs) if labels[i] > labels[j]]    return features, labels, pairs  def ranknet_train(features, pairs, lr=0.1, epochs=60):    # 线性打分函数 f(x) = w^T x, 学习权重 w    n, d = features.shape    w = np.zeros(d)    for epoch in range(epochs):        total_loss = 0.0        for i, j in pairs:            s_i = features[i].dot(w)            s_j = features[j].dot(w)            delta = s_i - s_j            # 对数损失, 等价于单对交叉熵            loss = np.log(1.0 + np.exp(-delta))            p_ij = sigmoid(delta)            # 真实偏好为 i 更相关, 所以 dL/dw = (p_ij - 1)(x_i - x_j)            grad = (p_ij - 1.0) * (features[i] - features[j])            w -= lr * grad            total_loss += loss        if epoch % 10 == 0:            print("epoch {} loss {:.4f}".format(epoch, total_loss))    return w  def main():    features, labels, pairs = generate_data(12)    w = ranknet_train(features, pairs)    # 预测阶段: 对每个文档独立打分, 按分数降序排列    scores = features.dot(w)    order = np.argsort(-scores)    print("labels:       ", labels)    print("predicted top:", order)  if __name__ == "__main__":    main()
目的:用一个可运行的微型 RankNet 演示 Pairwise 排序学习的完整流程——构造偏好对、计算交叉熵损失、梯度下降更新权重、最终按打分排序。
  1. features[: n_docs // 2] += 0.8让相关文档的特征整体偏大,使模拟数据对模型“可学习”
  2. pairs = [(i, j) ... if labels[i] > labels[j]]从相关性标签构造“i 比 j 相关”的偏好对
  3. delta = s_i - s_j计算两个文档的分数差,相当于 PK 优势
  4. loss = np.log(1.0 + np.exp(-delta))这一对样本的交叉熵损失,胜率越低损失越大
  5. grad = (p_ij - 1.0) * (features[i] - features[j])损失对权重的梯度,负梯度方向会拉大分数差
  6. w -= lr * grad梯度下降更新权重,每次更新同时用到文档 i 和文档 j 的特征
  7. order = np.argsort(-scores)预测阶段独立打分排序,整个过程无需再两两配对

常见误区

误区以为 Pairwise 训练出的模型,在线上预测时也要把候选文档两两配对,逐个输入模型比较谁赢。感觉训练用文档对,预测时自然也要先构造文档对。

正解训练阶段用文档对是为了获得稳定的“谁更相关”信号,最终目的是学出一个单文档打分函数 $f(x)$。预测时模型对每个文档独立计算一个分数,然后按分数全局排序。就像选手通过一场场 PK 训练出实力值,正式比赛时并不需要再把所有选手逐对比一遍,直接亮实力值排名即可。只有在某些特殊设计(如列表式方法)中才需要整体建模,Pairwise 方法不在此列。

为何常见:训练数据的形态(成对)太醒目,容易让人误以为预测流程也是同样的形态,忽略了“打分函数”这个最终产物。

误区以为 RankSVM 是把每个文档单独拿来判断“相关/不相关”,和普通 SVM 文本分类没有区别,只是换了个名字。

正解RankSVM 的“样本”是文档对的差值向量 $z_{ij}=x_i-x_j$,标签是偏好关系(谁比谁相关),而不是文档本身的类别。学到的超平面存在于“差值空间”:$w^{\top}(x_i-x_j)>0$ 表示 $i$ 排在 $j$ 前。它解决的是排序问题,而不是“这个文档是否相关”的分类问题。虽然数学形式与 SVM 分类一致,但样本构造和问题语义完全不同。

为何常见:两者的优化目标都是“最大间隔 + 合页损失”,数学外壳太像,容易让人忽略样本空间的差异。

误区以为 RankNet 的最终输出是某个文档排在它前面的胜率,排序时把胜率当作每个文档的分数来用。

正解$P_{ij}$ 是“文档 i 排在文档 j 前面”的胜率,它依赖当前配对的另一方,无法独立描述单个文档的质量。真正用于排序的是每个文档的打分 $s_i=f(x_i)$。胜率只是训练过程中的中间量,帮助模型理解“差距有多大”。类比:胜率描述的是“这对 PK 谁会赢”,而实力值才是排名依据。

为何常见:教程和可视化常画胜率曲线,学习者容易把训练过程的中间产物误认为预测输出。

误区以为模型在训练集上的 pairwise 损失越小,线上排序效果越好,不需要再看 NDCG 等排序指标。

正解Pairwise 损失衡量的是“文档对的先后有没有判对”,而不是“用户关心的头部位置排得好不好”。模型可能把大量易分的文档对全部判对,却把第 1 名和第 2 名排反了——这个错误对 NDCG 的伤害远大于一对尾部文档的错排。因此训练损失只能作为过程监控,上线决策必须依赖 NDCG 等位置加权指标和 A/B 测试。

为何常见:“训练损失越低,效果越好”是机器学习初学者的普遍直觉,但排序任务的优化目标和业务指标之间存在结构性错位。

面试题

Q1. 对于查询“苹果”,Pairwise 排序学习使用的训练样本是?

单选题 · easy

  • A.单个网页的相关度分数
  • B.两个网页的谁更相关标注← 正确答案
  • C.用户点击热力图的统计
  • D.查询词条被搜索的次数

答案:B。Pairwise 的核心是构造文档对,并用“谁比谁更相关”的偏好标签训练模型。单个网页的分数是 Pointwise 思路,点击热力图和搜索次数都不是 Pairwise 的训练样本形态。

Q2. RankSVM 在预测排序时输出什么?

单选题 · easy

  • A.两两比较的胜负表格
  • B.每个文档的排序分数← 正确答案
  • C.文档对出现的概率
  • D.用户点击的预估次数

答案:B。RankSVM 训练完成后,用一个打分函数对每个文档独立打分,按分数排序。它不需要在预测时输出胜负表或概率,这两者分别是流程性表示和 RankNet 的中间量。

Q3. RankNet 用哪个函数把分数差映射为胜率?

单选题 · mid

  • A.ReLU 激活函数
  • B.softmax 多分类函数
  • C.sigmoid 逻辑函数← 正确答案
  • D.tanh 双曲正切函数

答案:C。RankNet 把两个文档的分数差送入 sigmoid,得到 0 到 1 之间的胜率。ReLU 是分段线性函数,softmax 面向多类,tanh 输出范围是 -1 到 1,都不符合“胜率”的含义。

Q4. RankSVM 的软间隔参数 C 变大意味着什么?

单选题 · mid

  • A.允许更多样本对出错
  • B.模型对训练对更严格← 正确答案
  • C.特征维度自动降低
  • D.训练速度自动加快

答案:B。C 乘在松弛变量之和上,C 越大,对文档对违规的容忍度越低,模型越严格。C 不改变特征维度,也不直接决定训练速度。C 过小才允许更多样本出错。

Q5. Pairwise 中偏好标签 y=+1 表示什么?

单选题 · easy

  • A.两个文档分数相同
  • B.第一个比第二个相关← 正确答案
  • C.两个文档都不相关
  • D.第二个比第一个相关

答案:B。$y_{ij}=+1$ 表示文档 i 比文档 j 更相关,模型应让 $f(x_i)>f(x_j)$。分数相同是 $y=0$ 的情况,而两个都不相关不应构造偏好对。

Q6. NDCG 的“位置折扣”主要体现什么思想?

单选题 · hard

  • A.越靠前的位次权重越高← 正确答案
  • B.相关等级之间差异等差
  • C.精排可以忽略头部位置
  • D.所有位置权重完全一样

答案:A。位置折扣用 $\log_2(i+1)$ 做分母,第 2 名往后的收益迅速衰减,体现“用户几乎只看前面几个结果”。相关等级差异用指数增益体现而非等差,C 和 D 与折扣思想相反。

Q7. 相比 Pointwise,Pairwise 排序学习的优势有哪些?

多选题 · mid

  • A.标注“谁更相关”更稳定← 正确答案
  • B.直接优化文档先后关系← 正确答案
  • C.无需构造任何配对数据
  • D.能处理多级相关标注← 正确答案

答案:ABD。两两比较的标注一致性远好于绝对打分;模型直接学习“谁排前谁排后”;多级标注可以通过构造不同等级间的偏好对来利用。C 说反了——Pairwise 恰恰需要构造配对数据。

Q8. Pairwise 样本对膨胀会带来哪些问题?

多选题 · hard

  • A.每轮计算量大幅增加← 正确答案
  • B.正负样本严重不平衡← 正确答案
  • C.模型直接忽略位置折扣
  • D.训练收敛速度变慢← 正确答案

答案:ABD。文档数量 n 会产生 O(n²) 个文档对,计算量和训练时间显著上升;而大部分候选互不相关,负偏好对远多于正偏好对,导致不平衡。C 是 Pairwise 本身的固有缺陷(不直接优化位置权重),与样本对膨胀无关。

Q9. 关于 RankNet 的梯度下降更新方向,正确的是?

多选题 · hard

  • A.胜率低于真实偏好时提升分差← 正确答案
  • B.胜率高于真实偏好时缩小分差← 正确答案
  • C.两个文档的参数都会更新← 正确答案
  • D.参数只沿着打分高者更新

答案:ABC。梯度的方向由“预测胜率与真实偏好的差异”驱动:预测偏低就拉大分差,预测偏高就缩小分差。由于梯度包含 $\partial s_i/\partial w$ 和 $\partial s_j/\partial w$ 两项,两个文档的特征向量都会影响更新。D 在 RankNet 中不成立。

Q10. 为提升 Pairwise 模型的训练效率,可以采用哪些做法?

多选题 · mid

  • A.随机采样部分文档对← 正确答案
  • B.只保留得分前 K 的候选← 正确答案
  • C.对文档对做去重合并← 正确答案
  • D.无限扩充所有文档对

答案:ABC。随机采样降低每轮计算量,只保留头部候选能过滤大量无效配对,去重合并避免同一文档对重复贡献。D 是“样本对膨胀”本身,会让训练更慢而不是更快。