Pairwise原理
对于用户输入的一个query q, Ui和Uj是结果中其中两篇待排序的文章, si是模型打给文章Ui的分数, 分数的含义是预测了q和Ui之间的相关性, sj同理.
我们可以预测将文章Ui排在Uj之前的概率, 从而将排序转化成一个二分类问题. 将Ui排在Uj之前的概率定义如下:
Pij=P(Ui▹Uj)=1+e−σ(si−sj)1
这里的σ是一个超参数, 并不是sigmoid函数.
用Pˉij定义Ui排在Uj前面这个论述的真实性, 即二分类的真实标签. 1为论述为真, 0为论述为假, 0.5代表Ui与Uj的位置相同. 做一个简单的数据变换, 用Sij∈[−1,0,1]来代表Ui排在Uj前面这个论述的真实性, 从而定义损失函数binary cross entropy loss如下:
C=−PˉijlogPij−(1−Pˉij)log(1−Pij)=21(1−Sij)σ(si−sj)+log(1+eσ(si−sj)) 其中第一步到第二步的转换是带入了Pˉij=21(1+Sij)以及Sij∈[−1,0,1].
关于训练集, 也需要进行简化. 由于一对文章Ui和Uj, Ui排在Uj前和Uj排在Ui后两个论述真实性一定是互斥的, 所以如果把(Ui,Uj,1)(Uj,Ui,0)都放入在训练集中, 会出现冗余的情况. 因此在训练集中, 只保留所有Sij=1的样本.
然后以上面的binary cross entropy loss为损失函数, 对模型中所有的参数wk求导:
∂wk∂C=∂si∂C∂wk∂si+∂sj∂C∂wk∂sj=σ(21(1−Sij)−1+eσ(si−sj)1)(∂wk∂si−∂wk∂sj)=λij(∂wk∂si−∂wk∂sj) 将(∂wk∂si−∂wk∂sj)前面的项用λij表示, 由于训练样本中的Sij=1, 可以将λij简化如下:
λij=σ(21(1−Sij)−1+eσ(si−sj)1)=1+eσ(si−sj)−σ
而∂wk∂si和∂wk∂sj是模型的输出对参数的导数, 这个在不同的模型中有不同的解决方法(NN, GBDT等).
这里我们关心的是∂si∂C和∂sj∂C, 且有∂si∂C=−∂sj∂C, 因此计算得到其中的一项即可, 即损失函数对第i篇文章的预测得分的导数. 因为这里的导数我们用λij表示, 这也是LambdaRank, LambdaMART等一系列算法的由来.
总结两点:
binary loss function, 对列表头部的排序正确性
和列表尾部的排序正确性
一视同仁, 实际上是优化AUC
优化Pairwise
而如果我们要优化NDCG这样重点关注头部位置的指标, 这些指标对单个文档的预测得分的微小变化, 要么无动于衷(预测得分没有引起文档排序变化), 要么反应剧烈(引起了排序变化), 因此在训练的过程中, 无法定义一个连续可导的损失函数.
LambdaRank/LambdaMART的解决思路, 即为既然无法定义一个符合要求的损失函数, 就不再定义损失函数了, 直接定义一个符合我们要求的梯度. 这个不是由损失函数推导出来的, 被人为定义出来的梯度, 就是Lambda梯度.
如果我们现在的目标是优化NDCG指标, 如何定义梯度?
首先, 在上一轮迭代结束后, 将所有的文档(同一个query下的)按照上一轮迭代得到的预测分数从大到小进行排序.
然后对于文本对(Ui,Uj), 如果使用binary cross entropy loss, 则损失函数对于预测分数的预测仍为:
λij=σ(21(1−Sij)−1+eσ(si−sj)1)=1+eσ(si−sj)−σ
然后, 将Ui和Uj的排序位置调换, 计算NDCG指标的变化∣ΔNDCG∣, 然后构造Lambda梯度, 将∣ΔNDCG∣乘到上一步得到的Lambda梯度之上, 就得到了优化的Lambda梯度. 不同的优化指标, 对应着不同的优化的Lambda梯度.
注意
需要特别注意样本的组织方法. 排序只对同一个query下的候选文档/同一个推荐session下的候选商品才有意义, 所以与普通二分类不同, LTR训练集有一个分组的概念, 同一个组内的候选物料才能匹配成对, 相互比较. 这一点在xgboost或lightgbm模型框架中, 对应的数据组成形式, 都有体现.
参考资料