使用机器学习排序算法LambdaMART有一段时间了,但一直没有真正弄清楚算法中的所有细节。 学习过程中细读了两篇不错的博文,推荐给大家: 徐博From RankNet to LambdaRank to LambdaMART: An Overview 但经过一番搜寻之后发现,目前网上并没有一篇透彻讲解该算法的文章,所以希望这篇文章能够达到此目的。 本文主要参考微软研究院2010年发表的文章From RankNet to LambdaRank to LambdaMART: An Overview1,并结合自己的理解,试图将RankNet、LambdaRank和LambdaMART这三种算法的所有算法细节讲解透彻。 1. 概述RankNet、LambdaRank和LambdaMART是三个关系非常紧密的机器学习排序算法。简而言之,RankNet是最基础,基于神经网络的排序算法;而LambdaRank在RankNet的基础上修改了梯度的计算方式,也即加入了lambda梯度;LambdaMART结合了lambda梯度和MART(另称为GBDT,梯度提升树)。这三种算法在工业界中应用广泛,在BAT等国内大厂和微软谷歌等世界互联网巨头内部都有大量应用,还曾经赢得“Yahoo!Learning To Rank Challenge(Track 1)"的冠军。本人认为如果评选当今工业界中三种最重要的机器学习算法,以LambdaMART为代表的集成学习算法肯定占有一席之地,另外两个分别是支持向量机和深度学习。 2. RankNet2.1 算法基础定义 RankNet解决如下搜索排序问题:给定query集合,每个query都对应着一个文档集合,如何对每个query返回排序后的文档集合。可以想象这样的场景:某位高考生在得知自己的成绩后,准备报考志愿。听说最近西湖大学办得不错,所以就想到网上搜搜关于西湖大学的资料。他打开一个搜索引擎,输入“西湖大学”四个字,然后点击“搜索”,页面从上到下显示了10条搜索结果,他认为排在上面的肯定比下面的相关,所以就开始从上往下一个个地浏览。所以RankNet的目标就是对所有query,都能将其返回的文档按照相关性进行排序。 RankNet网络将输入query的特征向量x∈Rn映射为一个实数f(x)∈R。RankNet采用pairwise的方法进行模型训练。具体地,给定特定query下的两个文档Ui和Uj,其特征向量分别为xi和xj,经过RankNet进行前向计算得到对应的分数为si=f(xi)和sj=f(xj)。用Ui⊳Uj表示Ui比Uj排序更靠前(如对某个query来说,Ui被标记为“good”,Uj被标记为“bad”)。继而可以用下面的公式来表示Ui应该比Uj排序更靠前的概率: Pij≡P(Ui⊳Uj)≡11+e−σ(si−sj) 这个概率实际上就是深度学习中经常使用的sigmoid函数,参数σ决定sigmoid函数的形状。对于特定的query,定义Sij∈{0,±1}为文档i和文档j被标记的标签之间的关联,即文档比文档更相关文档和文档相关性一致文档比文档更相关Sij={1文档i比文档j更相关0文档i和文档j相关性一致−1文档j比文档i更相关 定义P¯ij=12(1+Sij)表示Ui应该比Uj排序更靠前的已知概率,则可以用交叉熵定义优化目标的损失函数: C=−P¯ijlogPij−(1−P¯ij)log(1−Pij) 如果不太熟悉什么是交叉熵,可以参考宗成庆老师的《统计自然语言处理》2.2节“信息论基本概念”,里面将熵、联合熵、互信息、相对熵、交叉熵和困惑度等概念都讲得相当清楚。 结合以上多个公式,可以改写损失函数C为: C=12(1−Sij)σ(si−sj)+log(1+e−σ(si−sj)) 对于Sij=1, C=log(1+e−σ(si−sj)) 然而对于Sij=−1, C=log(1+e−σ(sj−si)) 可以看出损失函数C具有对称性,也即交换i和j的位置,损失函数的值不变。 分析损失函数C的趋势发现,如果对文档Ui和Uj的打分可以正确地拟合标记的标签,则C趋向于0,否则C趋向于线性函数。具体地,假如Sij=1,也即Ui应该比Uj排序高,如果si>sj,则拟合的分数可以正确排序文档i和文档j, limsi−sj→∞C=limsi−sj→∞log(1+e−σ(si−sj))=log1=0 如果si<sj,则拟合的分数不能正确排序文档i和文档j, z limsi−sj→∞C=limsi−sj→∞log(1+e−σ(si−sj))=log(e−σ(si−sj))=−σ(si−sj) 利用神经网络对模型进行训练,目前最有效的方法就是反向传播算法。反向传播算法中最核心部分就是损失函数对模型参数的求导,然后可以使用下面的公式对模型参数进行迭代更新: wk←wk−η∂C∂wk=wk−η(∂C∂si∂si∂wk+∂C∂sj∂sj∂wk) 损失函数C对si和sj的偏导数为: ∂C∂si=σ(12(1−Sij)−11+eσ(si−sj))=−∂C∂sj si和sj对wk的偏导数可根据神经网络求偏导数的方式求得。求得了损失函数C对神经网络模型参数wk的偏导数之后,就可以使用梯度下降算法对其更新。这里的学习率η也是一个正数,因为η需要满足下面的不等式: δC=∑k∂C∂wkδwk=∑k∂C∂wk(−η∂C∂wk)=−η∑k(∂C∂wk)2<0 2.2 RankNet分解形式:加速RankNet训练过程 2.1节中定义的RankNet,对于每一个文档对(Ui,Uj)都将计算损失函数对神经网络的参数wk的偏导数,然后更新模型参数wk。这样做的缺点在于,对模型参数更新慢,耗时长。所以本节讲解如何通过分解组合的方式加快这一训练过程。 对于给定的文档对Ui和Uj,损失函数C对参数wk的偏导数为: ∂C∂wk=∂C∂si∂si∂wk+∂C∂sj∂sj∂wk=σ(12(1−Sij)−11+eσ(si−sj))(∂si∂wk−∂sj∂wk)=λij(∂si∂wk−∂sj∂wk) 其中: λij=∂C(si−sj)∂si=σ(12(1−Sij)−11+eσ(si−sj)) 定义I为索引对{i,j}的集合,在不损失信息量的情况下,可以将集合I中的索引对都转换成满足Ui⊳Uj的形式。另外集合I中的索引对还应该满足最多只出现一次的条件。在此基础上,累加权重参数wk的更新量: δwk=−η∑(i,j)∈I(λij∂si∂wk−λij∂sj∂wk)=−η∑iλi∂si∂wk 其中: λi=∑j:{i,j}∈Iλij−∑j:{j,i}∈Iλij 通俗地说,λi就是集合I中所有{i,j}的λij的和−集合I中所有{j,i}的λij的和。如果还是不太明白,那看下面这个例子就明白了。集合I={{1,2},{2,3},{1,3}},则 δwk=−η∑{i,j}∈I(λij∂si∂wk−λij∂sj∂wk)=−η(λ12∂s1∂wk−λ12∂s2∂wk+λ13∂s1∂wk−λ13∂s3∂wk+λ23∂s2∂wk−λ23∂s3∂wk)=−η((λ12+λ13)∂s1∂wk+(λ23−λ12)∂s2∂wk+(−λ23−λ13)∂s3∂wk) 于是可以得到λ1=λ12+λ13,λ2=λ23−λ12,λ3=−λ23−λ13 λi可以看成是作用在排序文档上的力,其正负代表了方向,长度代表了力的大小。最初的实现是对每个文档对,都计算一遍梯度并且更新神经网络的参数值,而这里则是将同一个query下的所有文档对进行叠加,然后更新一次网络的权重参数。这种分解组合形式实际上就是一种小批量学习方法,不仅可以加快迭代速度,还可以为后面使用非连续的梯度模型打下基础。 2.3 模型训练过程示例 假设某个搜索系统中,文档用2维的特征向量表示。给定一个query下的三个文档向量分别为x1=(5,4.5)T,x2=(4,3.7)T和x3=(2,1.8)T,标记情况为U1⊳U2⊳U3。为了简化训练过程,这里采用单层的神经网络模型,即输入层大小2,输出层大小为1,输出值为f(x)=w0+w1x(1)+w2x(2)。 初始化w=[0,−1,1],控制sigmoid函数形状的σ=0.1,神经网络学习率η=0.1。 根据初始化参数表达式为f(x)=−x(1)+x(2),所以可以计算出s1=−0.5,s2=−0.3和s3=−0.2,可见此时三个文档输出的分数并不满足标记U1⊳U2⊳U3。 因为λij=σ(12(1−Sij)−11+eσ(si−sj)),S12=S13=S23=1 所以可以计算出: λ12=σ(−11+eσ(s1−s2))=−0.050500 λ13=σ(−11+eσ(s1−s3))=−0.050750 λ23=σ(−11+eσ(s2−s3))=−0.050250 计算λ1=λ12+λ13=−0.10125,λ2=λ23−λ12=0.00025,λ3=−λ23−λ13=0.101。 对w求偏导数可得:,,∂s∂w0=1,∂s∂w1=x(1),∂s∂w2=x(2), δw0=−η(λ1∂s1∂w0+λ2∂s2∂w0+λ3∂s3∂w0)=0 δw1=−η(λ1∂s1∂w1+λ2∂s2∂w1+λ3∂s3∂w1)=0.030325 δw2=−η(λ1∂s1∂w2+λ2∂s2∂w2+λ3∂s3∂w2)=0.02729 更新网络权重: w0=w0+δw0=0+0=0 w1=w1+δw1=−1+0.030325=−0.969675 w2=w2+δw2=1+0.02729=1.02729 使用更新后的权重重新计算三个文档的分数,分别为s1=−0.225545,s2=−0.077707,s3=−0.090218。可见,经过一轮训练,单层神经网络的输出分数满足了U2⊳U3。 3. 信息检索评分信息检索研究者经常使用的排序质量评分指标有以下四种: MRR(Mean Reciprocal Rank),平均倒数排名 MAP(Mean Average Precision),平均正确率均值 NDCG(Normalized Discounted Cumulative Gain),归一化折损累积增益 ERR(Expected Reciprocal Rank),预期倒数排名 其中,MRR和MAP只能对二级的相关性(排序等级:相关和不相关)进行评分,而NDCG和ERR则可以对多级的相关性(排序等级>2)进行评分。NDCG和ERR的另一个优点是更关注排名靠前的文档,在计算分数时会给予排名靠前的文档更高的权重。但是这两种评分方式的缺点是函数不连续,不能进行求导,所以也就不能简单地将这两种评分方式加入到模型的损失函数中去。 3.1 MRR 对于一个查询i来说,ranki表示第一个相关结果的排序位置,所以: MRR(Q)=1|Q|∑i=1|Q|1ranki |Q|表示查询的数量,MRR表示搜索系统在查询集Q下的平均倒数排名值。MRR只能度量检索结果只有一个并且相关性等级只有相关和不相关两种的情况。 举个简单例子:
所以MRR(Q)=1/2+1/3+13=1118 3.2 MAP 假定信息需求qj∈Q对应的所有相关文档集合为d1,...,dmj,Rjk是返回结果中直到遇到dk后其所在位置前(含dk)的所有文档的集合,则定义MAP(Q)2如下: MAP(Q)=1|Q|∑j=1|Q|1mj∑k=1mjPrecision(Rjk) 实际上有两种计算MAP的方法或者说有两种MAP(Q)的定义方法。第一种方法是在每篇相关文档所在位置上求正确率然后平均(参考上面的公式)。另一种是在每个召回率水平上计算此时的插值正确率,然后求11点平均正确率,最后在不同查询之间计算平均。前者也称为非插值MAP(Q)。一般提MAP(Q)都指前者,所有这里也只讨论前者。 如果对定义的公式不太理解,可以结合下面的例子进行理解。
针对上面检索的结果,可计算出 AP(1)=(1∗1+1∗1+2/3∗0+2/4∗0+3/5∗1+3/6∗0+3/7∗0)/3=1315 AP(2)=(0∗0+1/2∗1+2/3∗1+2/4∗0+2/5∗0+3/6∗1+4/7∗1)/4=4784 MAP(Q)=AP(1)+AP(2)2=13/15+47/842=599420 3.3 NDCG NDCG是基于前k个检索结果进行计算的。设R(j,m)是评价人员给出的文档d对查询j的相关性得分,那么有: NDCG(Q,k)=1|Q|∑j=1|Q|Zj,k∑m=1k2R(j,m)−1log(1+m) 其中 DCGk=∑m=1k2R(j,m)−1log(1+m) Zj,k为第j个查询的DCG归一化因子,用于保证对于查询j最完美系统的DCGk得分是1。Zj,k也可以用1IDCGk表示。m是返回文档的位置。如果某查询返回的文档数k′<k,那么上述公式只需要计算到k′为止。 修改上面简单的例子进行辅助理解:
对于查询1:机器学习: DCG7=∑m=172R(j,m)−1log(1+m)=21.421516 查询1返回结果的最佳相关程度排序为:3,3,2,2,2,1,0,所以,IDCG7=22.686817,NDCG7=DCG7IDCG7=0.944227 对于查询2:苹果手机: DCG7=∑m=172R(j,m)−1log(1+m)=18.482089 查询2返回结果的最佳相关程度排序为:3,3,2,2,2,1,1,所以,IDCG7=23.167716,NDCG7=DCG7IDCG7=0.797752 最后可得:NDCG(Q,7)=(0.944227+0.797752)/2=0.870990 3.4 ERR ERR3旨在改善NDCG计算当前结果时未考虑排在前面结果的影响的缺点,提出了一种基于级联模型的评价指标。首先定义: R(g)=2g−12gmax,g∈{0,1,...,gmax} g代表文档的得分级别,gmax代表最大的分数级别。 于是定义: ERR=∑r=1n1r∏i=1r−1(1−Ri)Rr 展开公式如下: ERR=R1+12(1−R1)R2+13(1−R1)(1−R2)R3+...+1n(1−R1)(1−R2)...(1−Rn−1)Rn 举例来说(gmax=3):
R1=0.875,R2=0.375,R3=0.875,R4=0.125 ERR=0.875+12∗0.125∗0.375+13∗0.125∗0.625∗0.875+14∗0.125∗0.625∗0.125∗0.125=0.913391 4. LambdaRank4.1 为什么需要LambdaRank 先看一张论文原文中的图,如下所示。这是一组用二元等级相关性进行排序的链接地址,其中浅灰色代表链接与query不相关,深蓝色代表链接与query相关。 对于左边来说,总的pairwise误差为13,而右边总的pairwise误差为11。但是大多数情况下我们更期望能得到左边的结果。这说明最基本的pairwise误差计算方式并不能很好地模拟用户对搜索引擎的期望。右边黑色箭头代表RankNet计算出的梯度大小,红色箭头是期望的梯度大小。NDCG和ERR在计算误差时,排名越靠前权重越大,可以很好地解决RankNet计算误差时的缺点。但是NDCG和ERR均是不可导的函数,如何加入到RankNet的梯度计算中去? 4.2 LambdaRank定义 RankNet中的λij可以看成是Ui和Uj中间的作用力,如果Ui⊳Uj,则Uj会给予Ui向上的大小为|λij|的推动力,而对应地Ui会给予Uj向下的大小为|λij|的推动力。如何将NDCG等类似更关注排名靠前的搜索结果的评价指标加入到排序结果之间的推动力中去呢?实验表明,直接用|ΔNDCG|乘以原来的λij就可以得到很好的效果,也即: λij=∂C(si−sj)∂si=−σ1+eσ(si−sj)|ΔNDCG| 其中|ΔNDCG|是交换排序结果Ui和Uj得到的NDCG差值。NDCG倾向于将排名高并且相关性高的文档更快地向上推动,而排名地而且相关性较低的文档较慢地向上推动。 另外还可以将|ΔNDCG|替换成其他的评价指标。 5. LambdaMART5.1 MART LambdaMART是MART和LambdaRank的结合,所以要学习LambdaMART首先得了解什么是MART。MART是Multiple Additive Regression Tree的简称,很多时候又称为GBDT(Gradient Boosting Decision Tree)。MART是一种集成学习算法,不同于经典的集成学习算法Adaboost利用前一轮学习器的误差来更新下一轮学习的样本权重,MART每次都拟合上一轮分类器产生的残差。举个例子便于理解,比如一个人的年龄是50岁,第一棵树拟合的结果是35岁,第一轮的残差为15岁;然后第二棵数拟合的结果是10岁,两棵树相加总的拟合结果是45岁,第二轮的残差为5岁;第三棵数拟合的结果为2岁,三棵树相加拟合的结果是47岁,第三轮的残差是3岁......只要如此不断地进行下去,拟合结果就可以达到50岁,拟合残差的过程就是训练数据的过程。 对于一个给定的数据集{xi,yi},i=1,2,...,m,其中特征向量xi∈Rn,标签yi∈R,可以用来代表的第个特征值xij,j=1,2,...,d来代表xi的第j个特征值。对于一个典型的回归决策树问题,需要遍历所有特征j的全部阈值t,找到最优的j和t使下面的等式最小化: Sj=∑i∈L(yi−μL)2+∑i∈R(yi−μR)2 其中xij≤t的所有样本落入左子树L中,其中xij>t的所有样本落入右子树R中,μL(μR)表示左子树(右子树)所有样例标签值的均值。如果这就是一棵最简单的拥有一个根节点、两个叶子节点的二叉回归树,那么只需要根据最优阈值切分为左右子树,并且分别计算左右子树的值γl,l=1,2即可。如果将划分子树的过程继续进行L−1次即可得到一棵包含L个叶子节点的回归树。 上面公式使用最小二乘法计算拟合误差,所以通过上面方法得到的模型又称为最小二乘回归树。其实不管误差的计算方式如何,我们都可以拟合出相应的回归树,唯一的区别是梯度的计算不同而已。 MART使用线性组合的方式将拟合的树结合起来,作为最后的输出: Fn(x)=∑i=1Nαifi(x) fi(x)是单棵回归树函数,αi是第i棵回归树的权重。 在这里我们需要弄清楚为什么拟合残差就能不断减少拟合误差。假设拟合误差C是拟合函数Fn的函数C(Fn)。那么: δC≈∂C(Fn)∂FnδFn 如果取δFn=−η∂C∂Fn,就可以得到δC<0。其中η是学习率,为正实数。所以只要函数Fn拟合误差函数的负梯度就可以不断降低拟合误差的值。 设标签向量y=[y1,y2,...,ym]T,如果用最小二乘的方式表示拟合误差,则: C=12(Fn−y)2 那么δFn=−η∂C∂Fn=−η(Fn−y)。这其实就是上面提到的残差,所以拟合残差可以不断减少拟合误差。 5.2 逻辑回归+MART进行二分类 了解了MART之后,下面举一个MART实际应用的例子:使用MART和逻辑回归进行二分类。用于分类的样本xi∈Rn,标签yi∈{±1},拟合函数F(x)。为了简化表示,我们表示条件概率如下: P+≡P(y=1|x) P−≡P(y=−1|x) 用交叉熵表示损失函数: L(y,F)=−ylog(P+)−(1−y)log(P−) 逻辑回归使用对数机率(属于正例概率/属于负例概率)进行建模, Fn(x)=12log(P+P−) P+=11+e−2σFn(x) P−=1−P+=11+e2σFn(x) 将P+和P−带入L(y,F)中,得到: L(y,Fn)=log(1+e−2yσFn) Rjm表示落入第m棵树的第j个叶子节点中的样例集合,可以通过下式对该叶子节点的值进行优化: γjm=argminγ∑xi∈Rjmlog(1+e−2σyi(Fm−1(xi)+γ)) 上式可以使用Newton-Raphson方法按照下面的公式进行迭代求解: γn+1=γn−g′(γn)g″(γn) 5.3 LambdaMART基本定义 LambdaMART基于MART,优化λ梯度。根据上面的定义,对于任意Ui和Uj,有: λij=∂C(si−sj)∂si=−σ|ΔZij|1+eσ(si−sj) |ΔZij|表示交换Ui和Uj的位置产生的评价指标差值,Z可以是NDCG或者ERR等。对于特定Ui,累加其他所有排序项的影响,得到: λi=∑j:{i,j}∈Iλij−∑j:{j,i}∈Iλij 为了简化表示: ∑{i,j}⇌Iλij=∑j:{i,j}∈Iλij−∑j:{j,i}∈Iλij 于是我们可以更新损失函数: ∂C∂si=∑j:{i,j}∈I−σ|ΔZij|1+eσ(si−sj)=∑j:{i,j}∈I−σ|ΔZij|ρij 其中,我们定义: ρij=11+eσ(si−sj)=−λijσ|ΔZij| 然后可以得到: ∂2C∂si2=∑{i,j}⇌Iσ2|ΔZij|ρij(1−ρij) 所以我们可以用下面的公式计算第m棵树的第k个叶子节点上的值: γkm=∑xi∈Rkm∂C∂si∑xi∈Rkm∂2C∂si2=−∑xi∈Rkm∑{i,j}⇌I|ΔZij|ρij∑xi∈Rkm∑{i,j}⇌I|ΔZij|σρij(1−ρij) 所以总结LambdaMART算法如下: 6. 参考文献1. Christopher J.C. Burges. From RankNet to LambdaRank to LambdaMART: An Overview. Microsoft Research Technical Report MSR-TR-010-82. 2. Chrisopher D.Manning, Prabhakar Raghavan, Hinrich Schutze著, 王斌译. Introduction to Information Retrieval, 8.4 有序检索结果的评价方法, 2017年10月北京第11次印刷. 3. Olivier Chapelle, Ya Zhang, Pierre Grinspan. Expected Recipocal Rank for Graded Relevance. CIKM 2009. |
|