传统的搜索引擎排序(Ranking)问题,通常会涉及到很多的排序策略。这些策略根据不同的特征,在不同的适用范围中起作用。因此,一个传统的排序算法,至少涉及到两方面的内容:策略的制定,以及不同策略的组合。策略的组合需要考虑策略分析适用的特征,以及相应策略的适用情况。根据这些内容,通过人工或者半机器半人工的方式组合起来,才能组成一个可堪使用的排序算法。
和自然语言处理中遇到的情况一样,随着数据量的增加,使用人工的方式做策略的组合,会变得越来越困难。因此,将机器学习引入搜索引擎排序问题,也就是相当自然的事情了。在排序问题中使用的机器学习算法,被称为 Learning to Rank (LTR) 算法,或者 Machine-Learning Rank (MLR) 算法。
LTR 算法通常有三种手段,分别是:Pointwise、Pairwise 和 Listwise。Pointwise 和 Pairwise 类型的 LTR 算法,将排序问题转化为回归、分类或者有序分类问题。Listwise 类型的 LTR 算法则另辟蹊径,将用户查询(Query)所得的结果作为整体,作为训练用的实例(Instance)。
LambdaMART 是一种 Listwise 类型的 LTR 算法,它基于 LambdaRank 算法和 MART (Multiple Additive Regression Tree) 算法,将搜索引擎结果排序问题转化为回归决策树问题。MART 实际就是梯度提升决策树(GBDT, Gradient Boosting Decision Tree)算法。GBDT 的核心思想是在不断的迭代中,新一轮迭代产生的回归决策树模型拟合损失函数的梯度,最终将所有的回归决策树叠加得到最终的模型。LambdaMART 使用一个特殊的 Lambda 值来代替上述梯度,也就是将 LambdaRank 算法与 MART 算法加和起来。考虑到 LambdaRank 是基于 RankNet 算法的,所以在搞清楚 LambdaMART 算法之前,我们首先需要了解 MART、RankNet 和 LambdaRank 是怎么回事。
MART 算法
MART,即多重增量回归树(Multiple Additive Regression Tree)有许多名字:
- MART - 多重增量回归树(Multiple Additive Regression Tree)
- GBDT - 梯度渐进决策树(Gradient Boosting Decision Tree)
- GBRT - 梯度渐进回归树(Gradient Boosting Regression Tree)
- TreeNet - 决策树网络(Tree Net)
这些名字的含义都一样,都是一个意思。
从这些名字,我们可以看出 MART 的一些特征:
- 使用决策树来预测结果;
- 用到的决策树有很多个;
- 每个树都比之前的树改进一点点,逐渐回归、拟合到真实结果。
实际上,这三点就是 Boosting 思想的精髓了。Boosting 思想源自 Kearns 和 Valiant 的提问,并最终从 Robert Schapire 在 1990 年的论文 The Strength of Weak Learnablity 中对上述问题明确的回答发展起来。
Boosting(渐进)思想
Boosting 思想,尝试通过不断迭代弱模型(Weak Learner),通过叠加弱模型的方式,渐进地逼近真实情况,起到足以预测真实值的强模型的作用。显而易见,Boosting 思想至少需要解决两个问题:
- 如何保证每一次迭代都对解决问题有所帮助,或者说如何确定迭代步骤中拟合的方向?
- 如何将每一次迭代产生的弱模型有效地叠加起来?
下面,我们通过 AdaBoost(Adaptive Boosting,自适应渐进法)来回答这两个问题。
AdaBoost
AdaBoost 是 Yoav Freund 和 Robert Schapire 提出的机器学习算法。两人因为该算法获得了 2003 年的哥德尔奖。
AdaBoost 是一种用于分类的算法,它的运行过程大致可以理解如下:
- 制作一个弱分类器(实际是一个决策树),去拟合实际情况,我们将它记录为
WL1。 - 运行
WL1,记录分类错误的那些样本。接下来,赋予这些被错误分类的样本比较高的权重,进行第二次拟合,得到新的弱分类器WL2。 - 依次运行
WL1-WL2,记录分类错误的那些样本。接下来,赋予这些被错误分类的样本比较高的权重,进行第三次拟合,得到新的弱分类器WL3。 - 依次运行
WL1-WL2-WL3,如此迭代……
上图来自 Pattern Recognition and Machine Learning 一书的 660 页,讲述的是运用 Boosting 思想进行分类的过程。
蓝色和红色的圆圈,代表两类样本,圆圈的大小代表当前该点的权重;绿色的线条代表训练既得分类器模型;虚线表示当前训练新增的分类器模型。
可以看到,在不断的迭代过程中,每一次迭代,分类器都会关注之前区分错误的那些样本点,进行有针对性的处理。因此,在进行到 150 次迭代之后(m=150m=150),最终叠加起来的模型已经非常细致,足够将红蓝两种类别细致地区分开来了。
整个过程,用数学符号表达如下(PRML Page 658):
在这里:
- w(k)nwn(k) 表示一个 nn 元向量,向量中的每一个元素都对应训练集中的一个样本点;向量中元素的值,就是所对应样本点在第 kk 次迭代中的权重。
- yk(x)yk(x) 是根据上述权重计算出来的第 kk 次迭代的模型。
- αkαk 是第 kk 次迭代的模型的权重。
- YM(x)YM(x) 是根据上述 MM 个弱分类器加权求和得到的最终分类器。
最开始的时候,每个样本点的权重都一致。随着算法不断迭代,被错误分类的样本,权重不断加强,与此同时被正确分类的样本,权重不断减弱。可以想象,越往后,算法越关注那些容易被分错的样本点,从而最终解决整个问题。
现在,我们至少可以从 AdaBoost 的角度回答上一小节的两个问题了:
- AdaBoost 通过调整样本的权值,来确定下一轮迭代中弱模型的拟合方向:提升分类错误的样本的权值,降低分类正确的样本的权值。
- AdaBoost 用一个「加法模型」,将每一轮迭代得到的弱模型组合叠加起来,得到一个有效的强模型。
MART 的数学原理
MART 是一种 Boosting 思想下的算法框架,它的目标是寻找强模型 f(x)f(x) 满足:
和 AdaBoost 一样,训练之后的 MART 模型也是一个加法模型,形式如下:
这里:
- f^=f^M:Rd↦Rf^=f^M:Rd↦R 是模型的目标函数;
- x∈Rdx∈Rd 是样本点,它包含 dd 个特征的值;
- f^(x)∈Rf^(x)∈R 是预测值;
- MM 是训练过程中迭代的次数,也就是模型中回归决策树的数量;
- fm:Rd↦Rfm:Rd↦R 是模型训练过程中得到的弱模型(也就是回归决策树)。
那么,关于 MART 的 Boosting,我们还剩下一个回答,即:如何保证每一次迭代都对解决问题有所帮助,或者说如何确定迭代步骤中拟合的方向。接下来的分析,我们就来解决这个问题。
假设我们已经迭代了 mm 次,得到了 mm 颗决策树。我们将这 mm 颗决策树的和记作 f^m(x)=∑mi=1fi(x)f^m(x)=∑i=1mfi(x),于是,第 m+1m+1 轮拟合的目标
现在我们要求这个 δf^m+1δf^m+1。我们引入损失函数
来描述预测函数 ff 的预测结果 y∗=f(x)y∗=f(x) 与真实值 yy 的差距。那么,我们的目的是要在进行第 m+1m+1 轮拟合之后,预测值与真实情况的差距会减小,即
考虑到
若取
则必有 δLm+1<0δLm+1<0。因此,这个 δf^m+1δf^m+1 就是 fm+1fm+1 拟合的目标;也就是说,fm+1fm+1 要拟合这样一个训练集:
式 22 描述的正是损失函数(泛函) LL 的梯度。亦即,循环迭代中,模型每次拟合的目标都是损失函数的梯度。这就是算法被称为「梯度渐进」的原因。
决策树实际上将样本空间划分成了若干区域,并对每个划分区域赋上预测值。假设 fmfm 划分而成的区域是 RmRm,预测值则是 γmγm。那么,我们有
也就是
那么,MART 的每一步也就是要解优化问题:
其中 FF 是一棵回归决策树。
现在我们引入一个非常小的正数 ηη,称为「学习度」或者「收缩系数」。如果,我们在每轮迭代中的预测结果前,乘上这么一个学习度;亦即我们将第 m+1m+1 轮拟合的目标,从 −gim−gim 调整为 −η⋅gim−η⋅gim。这样一来,我们每次拟合的目标,就变成了损失函数梯度的一部分。由于 δL<0δL<0 仍然成立,经过多次迭代之后,模型依然可以得到一个很好的结果。但是,与引入学习度之前的情况相比较,每次拟合像是「朝着正确的方向只迈出了一小步」。这种 Shrinkage(缩减),主要是为了防止「过拟合」现象。
小结
MART 是一种 Boosting 思想下的算法框架。它通过加法模型,将每次迭代得到的子模型叠加起来;而每次迭代拟合的对象都是学习率与损失函数梯度的乘积。这两点保证了 MART 是一个正确而有效的算法。
MART 中最重要的思想,就是每次拟合的对象是损失函数的梯度。值得注意的是,在这里,MART 并不对损失函数的形式做具体规定。实际上,损失函数几乎只需要满足可导这一条件就可以了。这一点非常重要,意味着我们可以把任何合理的可导函数安插在 MART 模型中。LambdaMART 就是用一个 λλ 值代替了损失函数的梯度,将 λλ 和 MART 结合起来罢了。
Lambda
Lambda 的设计,最早是由 LambdaRank 从 RankNet 继承而来。因此,我们先要从 RankNet 讲起。
RankNet 的创新
Ranking 常见的评价指标都无法求梯度,因此没法直接对评价指标做梯度下降。
RankNet 的创新之处在于,它将不适宜用梯度下降求解的 Ranking 问题,转化为对概率的交叉熵损失函数的优化问题,从而适用梯度下降方法。
RankNet 的终极目标是得到一个带参的算分函数:
于是,根据这个算分函数,我们可以计算文档 xixi 和 xjxj 的得分 sisi 和 sjsj
然后根据得分计算二者的偏序概率
再定义交叉熵为损失函数
进行梯度下降
再探梯度
这里每条横线代表一条文档,其中蓝色的表示相关的文档,灰色的则表示不相关的文档。在某次迭代中,RankNet 将文档的顺序从左边调整到了右边。于是我们可以看到:
- RankNet 的梯度下降表现在结果的整体变化中是逆序对的下降:13 → 11
- RankNet 的梯度下降表现在单条结果的变化中,是结果在列表中的移动趋势(图中黑色箭头)
- 我们通常更关注前几条文档的排序情况,因此我们会期待真正的移动趋势如图中红色箭头所示
那么问题就来了:我们能不能直接定义梯度呢?
LambdaRank
现在的情况是这样:
- RankNet 告诉我们如何绕开 NDCG 等无法求导的评价指标得到一个可用的梯度;
- 上一节我们明确了我们需要怎样的梯度;
- 梯度(红色箭头)反应的是某条结果排序变化的趋势和强度;
- 结果排序最终由模型得分 ss 确定。
于是,我要扼住 ∂Lij∂si∂Lij∂si 的咽喉!
先看看 RankNet 的梯度
注意有下面对称性
于是我们定义
考虑有序对 (i,j)(i,j),有 Sij=1Sij=1,于是有简化
在此基础上,考虑评价指标 ZZ(比如 NDCG)的变化
对于具体的文档 xixi,有
也就是说:每条文档移动的方向和趋势取决于其他所有与之 label 不同的文档。
现在回过头来,看看我们做了什么?
- 分析了梯度的物理意义;
- 绕开损失函数,直接定义梯度。
当然,我们可以反推一下 LambdaRank 的损失函数:
LambdaMART
现在的情况变成了这样:
- MART 是一个框架,缺一个「梯度」;
- LambdaRank 定义了一个「梯度」。
让他们在一起吧!于是,就有了 LambdaMART。
LambdaMART 的优点
LambdaMART 有很多优点,取一些列举如下:
- 直接求解排序问题,而不是用分类或者回归的方法;
- 可以将 NDCG 之类的不可求导的 IR 指标转换为可导的损失函数,具有明确的物理意义;
- 可以在已有模型的基础上进行 Continue Training;
- 每次迭代选取 gain 最大的特征进行梯度下降,因此可以学到不同特征的组合情况,并体现出特征的重要程度(特征选择);
- 对正例和负例的数量比例不敏感。




浙公网安备 33010602011771号