论文分享-- From RankNet to LambdaRank to LambdaMART: An Overview

博客内容将首发在微信公众号"跟我一起读论文啦啦",上面会定期分享机器学习、深度学习、数据挖掘、自然语言处理等高质量论文,欢迎关注!
在这里插入图片描述

严格来说,这并不是一篇论文,只是一个 r e p o r t report report ,里面系统的介绍了三个比较著名的排序模型 R a n k N e t 、 L a m b d a R a n k 、 L a m b d a M A R T RankNet、LambdaRank、LambdaMART RankNetLambdaRankLambdaMART ,链接 Rank

本篇博文将分析总结下这三个排序模型 R a n k N e t 、 L a m b d a R a n k 、 L a m b d a M a r t RankNet、LambdaRank、LambdaMart RankNetLambdaRankLambdaMart。其参考的代码RankNet、LambdaRank,LambdaMart。

需要说明的是,本篇博文在主要总结论文和实现代码同时,也小部分的参考了这篇文章Learning to Rank算法介绍:RankNet,LambdaRank,LambdaMart

RankNet

这是基于 p a r i w i s e pariwise pariwise 方法的排序模型。

数据集由 q u e r y query query 分开。

24 [[-1.0, 0.85, 0.35], [1.0, 0.66, 1.0], [-1.0, 0.42, 0.18], [-1.0, 0.46, 0.1]]
25 [[-1.0, 0.51, 0.6], [-1.0, 0.35, 0.61], [1.0, 0.75, 1.0], [-1.0, 0.58, 0.23]]
26 [[-1.0, 0.55, 0.63], [-1.0, 0.62, 0.74], [-1.0, 0.01, 0.8], [1.0, 0.63, 0.35]]
27 [[1.0, 0.97, 0.27], [-1.0, 0.89, 0.42], [-1.0, 0.56, 0.06], [-1.0, 0.49, 1.0]]
20 [[-1.0, 0.37, 1.0], [-1.0, 0.0, 0.88], [-1.0, 0.0, 0.92], [1.0, 0.97, 0.65]]
21 [[1.0, 0.76, 1.0], [-1.0, 0.52, 0.11], [-1.0, 0.74, 0.6], [-1.0, 0.02, 0.54]]
22 [[1.0, 0.76, 1.0], [-1.0, 0.21, 1.0], [-1.0, 0.0, 0.52], [-1.0, 0.8, 0.31]]
23 [[-1.0, 0.96, 0.02], [-1.0, 0.91, 0.35], [-1.0, 0.59, 1.0], [1.0, 0.87, 0.99]]
28 [[-1.0, 0.35, 0.79], [-1.0, 0.26, 0.39], [-1.0, 0.18, 1.0], [1.0, 0.79, 0.03]]
29 [[-1.0, 0.64, 0.52], [-1.0, 0.56, 0.16], [1.0, 0.83, 1.0], [-1.0, 0.12, 0.55]]
0 [[1.0, 0.85, 0.62], [-1.0, 0.77, 0.13], [-1.0, 0.22, 0.88], [-1.0, 0.79, 0.27]]
4 [[1.0, 0.97, 0.29], [-1.0, 0.0, 0.09], [-1.0, 0.43, 0.72], [-1.0, 0.52, 0.52]]

上面字典数据集是实现代码中生成的, k e y key key q u e r y _ i d query\_id query_id v a l u e value value 为一个列表,表示与该 q u e r y query query 可能相关的所有文档集,每个子列表的第一个数表示该文档与 q u e r y query query 是否相关,第二、第三个数表示该文档的特征。

对于一个给定的 q u e r y query query 而言,与其可能相关的文档集合中(假设大小为 d o c s _ s i z e docs\_size docs_size),不同 l a b e l label label 的两两文档形成一个文档对( U i 、 U j U_i、U_j UiUj ),模型 f f f 可以对这两个文档进行打分分别得到 s i 、 s j s_i、s_j sisj,可以理解为相关性得分,那么 U i U_i Ui 应该排在 U j U_j Uj 前面的概率为:
P i j = P ( U i ▹ U j ) = 1 1 + e − σ ( s i − s j ) P_{ij}=P(U_i \triangleright U_j) = \frac{1}{1+e^{-\sigma(s_i-s_j)}} Pij=P(UiUj)=1+eσ(sisj)1
注意:这里面的 σ \sigma σ 是个常数,决定了 s i g m o i d sigmoid sigmoid 函数的形状。
上面公式中的 s i − s j s_i-s_j sisj 为两两文档打分的差,显然结果应该是一个矩阵。根据公式可知, s i s_i si 越大于 s j s_j sj ,其的 p i j p_{ij} pij 越大,符合逻辑。那么在实做时如何实现这一步呢?

代码中定义了一个三层的神经网络作为排序模型,给输入的一个 q u e r y query query 下的每个文档进行打分。

def compute_graph(X):"""Build compute graphdefine a function for computing ds_i/dw_k respectively,┆   as the tf.gradient() computes sum_{k} dy_k/dx_i w.r.t x_iArgs:┆   X: the input feature vector tensor shaped [None, x_i]Returns:┆   y: the output predict tensor shaped [None, y_i]"""if config.USE_HIDDEN_LAYER == True:┆   with tf.name_scope("hidden_layer"):┆   ┆   layer_h1 = tf.add(tf.matmul(X, weights["hidden"]), biases["hidden"])┆   ┆   layer_h1 = tf.nn.relu(layer_h1)┆   with tf.name_scope("out_layer"):┆   ┆   y = tf.add(tf.matmul(layer_h1, weights["out"]), biases["out"])else:┆   with tf.name_scope("linear_layer"):┆   ┆   y = tf.add(tf.matmul(X, weights["linear"]), biases["linear"])return y

这样我们就可以给文档打分了,并且计算两两文档之间的打分差:

y = compute_graph(X)
sigma_ij = y - tf.transpose(y)##广播操作

得到 d o c s _ s i z e ∗ d o c s _ s i z e docs\_size * docs\_size docs_sizedocs_size 大小的 s i g m a sigma sigma 矩阵。

P i j P_{ij} Pij 是指预测的分数分布,那么真实的得分分布呢?论文中是这样定义的:
P i j ^ = 1 2 ( 1 + S i j ) \hat{P_{ij}}= \frac{1}{2}(1+S_{ij}) Pij^=21(1+Sij)
其中 S i j ∈ { 0 , ± 1 } S_{ij} \in \{0,\pm 1\} Sij{0,±1},为 1 1 1 时,表示文档 i i i j j j q u e r y query query 更相关,反正为 − 1 -1 1 ,相关性相等时则为 0 0 0

那么损失函数就可想而知了,论文中用 c r o s s − e n t r o p y cross-entropy crossentropy 来衡量这两种分布的距离:
C = − P i j ^ l o g P i j − ( 1 − P i j ^ ) l o g ( 1 − P i j ) C = -\hat{P_{ij}}logP_{ij}-(1-\hat{P_{ij}})log(1-P_{ij}) C=Pij^logPij(1Pij^)log(1Pij)

那么代码中如何实现这一步呢?

Sij_ = Y - tf.transpose(Y)## Y 为真实得分
Sij = tf.minimum(1.0, tf.maximum(-1.0, Sij_))##将其取值控制在0,1,-1
Pij_hat = 1.0 / 2.0 * (1 + Sij)
Cij = tf.nn.sigmoid_cross_entropy_with_logits(┆   logits=sigma_ij, labels=Pij_hat)

这样就得到了损失函数了,直接利用 t e n s o r f l o w tensorflow tensorflow m i n i m i z e l o s s minimize\ loss minimize loss

loss = tf.reduce_mean(Cij)
train_op = tf.train.GradientDescentOptimizer(┆   ┆   config.LEARNING_RATE).minimize(loss)

R a n k N e t RankNet RankNet 实现起来很简单?不对啊,论文中还有大量的梯度推导的公式啊,对, t e n s o r f l o w tensorflow tensorflow 把参数更新的过程都自动化的实现了,无需我们自己实现这些麻烦的过程。

LambdaRank

R a n k N e t RankNet RankNet 以错误 p a i r pair pair 最少为优化目标的算法,然而许多时候仅以错误 p a i r pair pair 数来评价排序的好坏是不够的,像 N D C G NDCG NDCG 或者 E R R ERR ERR 等评价指标就只关注 t o p k top k topk 个结果的排序,当我们采用 R a n k N e t RankNet RankNet 算法时,往往无法以这些指标为优化目标进行迭代,所以 R a n k N e t RankNet RankNet 的优化目标和 I R IR IR 评价指标之间存在不一致的地方。然而这些指标的缺点是不平滑、不连续,无法求梯度,如果将这些指标直接作为模型评分的函数的话,是无法直接用梯度下降法进行求解的。

由上面的分析,我们必须要重新定义 l o s s loss loss 函数,并且 l o s s loss loss 函数需要考虑指标的优化。这就要我们仔细的推导了。下面我们仔细推导下 R a n k N e t RankNet RankNet 参数更新的过程

上面 R a n k N e t RankNet RankNet 的交叉商损失函数为:

C = − P i j ^ l o g P i j − ( 1 − P i j ^ ) l o g ( 1 − P i j ) C = -\hat{P_{ij}}logP_{ij}-(1-\hat{P_{ij}})log(1-P_{ij}) C=Pij^logPij(1Pij^)log(1Pij)


这里写图片描述

可以计算得:

这里写图片描述

再用梯度下降法可以更新参数:

这里写图片描述

加速训练过程

由上面的推导,我们可以再进行简单的化简:

这里写图片描述

如此,论文中这样定义 λ i j \lambda_{ij} λij

这里写图片描述

在代码中如何实现这一步呢?

# pairwise lambda matrix
# lambda_ij = dCij/ds_i = 1/2 * (1 - Sij) * dsigma(s_i - s_j)/d(s_i - s_j) * 1
#    - (dsigma(s_i - s_j)/d(s_i - s_j) * 1) / (1 + e^(sigma_ij))
# here we assign sigma = Identity, thus dsigma/d(si - sj) = 1
# thus lambda_ij = 1.0 / 2.0 * (1 - Sij) - 1.0 / (1 + tf.exp(sigma_ij))
# but tf.exp may have numerical precision issue
# comforming to sigma_ij + sigma_ji = 0, lambda_ij + lambda_ji = 0
# use the reformulation exp(-x) = exp(log(1 + exp(-|x|)) - min(0, x)) - 1
lambda_ij = 1.0 / 2.0 * (1 - Sij) - 1.0 / \tf.exp(tf.log(1 + tf.exp(-tf.abs(-sigma_ij))) - tf.minimum(0.0, -sigma_ij))

论文中进一步提到,在 R a n k N e t RankNet RankNet 中不需要对每个文档进行 b e l a b e l e d be\ labeled be labeled,只需要知道两两文档之间的相对关系即可。

由上面的 λ i j \lambda_{ij} λij 的计算可知:

这里写图片描述

在求得 δ w k \delta w_k δwk 后,我们就可以利用梯度下降法 批量的加速反向更新过程。

应该如何理解上面的 λ i \lambda_i λi 呢?论文中是这样说的, λ i \lambda_i λi 是针对预测排序后的第 i i i 个文档而言,我们假设 { i , j } ∈ I \{i,j\} \in \ I {i,j} I { k , i } ∈ I \{k,i\} \in \ I {k,i} I,有:

这里写图片描述

这一步不太好理解,举例来说:假设有三个文档 U 1 , U 2 , U 3 U_1, U_2, U_3 U1,U2,U3,其中有 U 1 ▹ U 2 , U 2 ▹ U 3 , U 3 ▹ U 1 U_1 \triangleright U_2, U_2 \triangleright U_3, U_3 \triangleright U_1 U1U2,U2U3,U3U1,则集合 I \ I  I 中就包含 ( 1 , 2 ) , ( 1 , 3 ) , ( 2 , 3 ) {(1,2), (1,3), (2,3)} (1,2),(1,3),(2,3) 共三个文档对,则按照上面损失函数对参数 w w w 求偏导的公式来说有:

这里写图片描述

合并相同的 ∂ S i ∂ W k \frac{\partial S_i}{\partial W_k} WkSi,可知 λ 1 = λ 12 + λ 13 \lambda_1 = \lambda_{12}+\lambda_{13} λ1=λ12+λ13 λ 2 = λ 23 − λ 12 \lambda_2 = \lambda_{23}-\lambda_{12} λ2=λ23λ12 λ 3 = − λ 13 − λ 23 \lambda_3=-\lambda_{13}-\lambda_{23} λ3=λ13λ23

论文中提到,这个 λ i \lambda_i λi 正负号指的就是文档 i i i 下一次的移动方向,其大小指的是移动距离。

这里写图片描述

如上图所示,每个线条表示文档,蓝色表示相关文档,灰色表示不相关文档, R a n k N e t RankNet RankNet p a i r w i s e e r r o r pairwise\ error pairwise error 的方式计算 c o s t cost cost,左图的 c o s t cost cost 13 13 13,右图通过把第一个相关文档下调3个位置,第二个文档上条5个位置,将 c o s t cost cost 降为11,但是像 N D C G NDCG NDCG 或者 E R R ERR ERR 等评价指标只关注 t o p k top k topk 个结果的排序在优化过程中下调前面相关文档的位置不是我们想要得到的结果虽然较小的下调前面文档的位置和较大的提升后面文档位置,得到的 p a i r e r r o r pair\ error pair error 可能会变小,但是实际上指标值却下降了。右图左边黑色的箭头表示 R a n k N e t RankNet RankNet 下一轮的调序方向和强度,但我们真正需要的是右边红色箭头代表的方向和强度,即更关注靠前位置的相关文档的排序位置的提升。 L a m b d a R a n k LambdaRank LambdaRank 正是基于这个思想演化而来,其中 L a m b d a Lambda Lambda 指的就是红色箭头,代表下一次迭代优化的方向和强度,也就是梯度。

那么在代码中如何求得 λ i \lambda_i λi 呢?

# dC/dw_k = \sum{lambda_ij * (ds_i/dw_k - ds_j/dw_k)}
#    = \sum{lambda_i * ds_i/dw_k}
# lambda_i is the coefficiency of dC/dw_k
# which is factorized as lambda_i = \sum_{if Sij = 1}{lambda_ij} -
#    \sum_{if Sji = 1}{lambda_ji}
ij_positive_label_mat = tf.maximum(Sij, 0) #Mij = 1 if (i, j) \in P
ij_positive_mat = ij_positive_label_mat * lambda_ij## 论文中提到在Sij=1的情况下
ij_sum = tf.reduce_sum(ij_positive_mat, [1])
ji_sum = tf.reduce_sum(ij_positive_mat, [0])
lambda_i = ij_sum - ji_sum #lambda_i for \sum_{i}dCij/dsi - \sum_{i}dCji/dsj

这样就求出了 λ i \lambda_i λi 了。

因为 R a n k N e t RankNet RankNet 优化目标与评价指标不一致,所以在 l a m b d a r a n k lambdarank lambdarank 的损失函数中,我们需要考虑评价指标的因素,例如 N D C G NDCG NDCG

在论文中,其实就是在上面 λ i j \lambda_{ij} λij 基础上引入评价指标 N D C G NDCG NDCG把交换两个文档的位置引起的评价指标的变化作为其中一个因子,此时要优化的 λ i j \lambda_{ij} λij 变为:

这里写图片描述

那么这个 △ N D C G \triangle NDCG NDCG 如何求呢?显然这应该是个矩阵。代码中是这样实现的:

relevance = tf.maximum(Y, 0) # negative label normalize to 0
##pdb.set_trace()
Y_r = tf.squeeze(Y)
Y_sort_r = tf.nn.top_k(Y_r, k=tf.shape(Y_r)[0]).values
Y_sort = tf.expand_dims(Y_sort_r, [1])
relevance_sort = tf.maximum(Y_sort, 0) # ideal result sequence
ranks_sort_r = tf.cast(tf.range(1, tf.shape(Y)[0] + 1, 1), dtype=tf.float32) # [1, 2, ..]
ranks_sort = tf.expand_dims(ranks_sort_r, [1]) # column vectory_r = tf.squeeze(y) # row vector (1-D tensor)
# y_indices_sort[i] = j means doc j ranks i
y_indices_sort = tf.nn.top_k(y_r, k=tf.shape(y_r)[0]).indices
def gen_mask_tensor(x):"""Generate mask tensorArgs:┆   x: location 1-D tensorReturn:┆   1-D tensor [0, 0, .. ,1, .., 0] with index x set to 1"""return tf.gather(identity_mat, tf.squeeze(x))
idx_to_rank_mat = tf.map_fn(gen_mask_tensor, tf.expand_dims(y_indices_sort, [1]))
# ranks_compute[i] = j means the document ranks i is doc j
# i.e. reverse mapping of y_indices_sort
ranks_compute_r = tf.reduce_sum(ranks_sort * tf.cast(idx_to_rank_mat, dtype=tf.float32), axis=[0])
ranks_compute = tf.expand_dims(ranks_compute_r, [1])# DCG(t) = \sum^(t)_{1}
def log2(x):"""Compute log(x)/log(2)"""return tf.log(x)/tf.log(tf.constant(2.0))
# current DCG
dcg_each = (2 ** relevance - 1) / log2(ranks_compute + 1)
dcg = tf.reduce_sum(dcg_each)
# ideal DCG
max_dcg_each =(2 ** relevance_sort - 1) / log2(ranks_sort + 1)
max_dcg = tf.reduce_sum(max_dcg_each)
# |\Delta NDCG| matrix by swapping each i, j rank position pair
# denoted li = relavance of i, ri = rank of i, lirj = 2^(li)/lg2(rj + 1)
# [l1r1 l1r1 l1r1
#  l2r2 l2r2 l2r2
#  l3r3 l3r3 l3r3]
dcg_each_col_tile = tf.tile(dcg_each, [1, tf.shape(y)[0]])
# [l1r1 l2r2 l3r3
#  l1r1 l2r2 l3r3
#  l1r1 l2r2 l3r3]
dcg_each_row_tile = tf.tile(tf.transpose(dcg_each), [tf.shape(y)[0], 1]) 
# [l1r1 l1r2 l1r3
#  l2r1 l2r2 l2r3
#  l3r1 l3r2 l3r3]
dcg_swap_col = (2 ** relevance - 1) / log2(tf.transpose(ranks_compute) + 1)
# [l1r1 l2r1 l3r1
#  l1r2 l2r2 l3r2
#  l1r3 l2r3 l3r3]
dcg_swap_row = tf.transpose(dcg_swap_col)
delta_dcg = 0 - dcg_each_col_tile - dcg_each_row_tile + dcg_swap_col + dcg_swap_row
delta_ndcg = delta_dcg / max_dcg

这十几步代码其实挺难理解的,我仔细的推了一遍,是正确的。其中最后得出的矩阵 d e l t a _ d c g delta\_dcg delta_dcg,其 d e l t a _ d c g [ i ] [ j ] delta\_dcg[i][j] delta_dcg[i][j] 即表示第 i i i 个文档和第 j j j 个文档互换位置后的 N D C G NDCG NDCG 差值。 d e l t a _ d c g [ i ] [ j ] = − l i r i − l j r j + l i r j + l j r i delta\_dcg[i][j] = -l_ir_i-l_jr_j+l_ir_j+l_jr_i delta_dcg[i][j]=liriljrj+lirj+ljri,拆分开就是 l j r i − l i r i l_jr_i-l_ir_i ljriliri (把第 j j j 个文档放在排序为 i i i 的位置的 D C G DCG DCG 值和原本第 i i i 个文档就在第 i i i 个位置的 D C G DCG DCG 的差值)和 l i r j − l j r j l_ir_j-l_jr_j lirjljrj (同理)

要特别说明的是,这里一定要注意 △ N D C G \triangle NDCG NDCG 是如何做的,不是我们想当然的 l i r j − l j r i l_ir_j-l_jr_i lirjljri,这样理解是错误的,应该是:
△ N D C G = ( l j r i − l i r i ) + ( l i r j − l j r j ) \triangle NDCG =(l_jr_i-l_ir_i)+(l_ir_j-l_jr_j) NDCG=(ljriliri)+(lirjljrj)

由此可以得到需要新的 λ i j \lambda_{ij} λij 和新的 λ i \lambda_i λi

lambda_ij_objective = lambda_ij * tf.abs(delta_ndcg)## 这句代码揭示了RankNet的不同。# lambda_i becomes
ij_positive_label_mat = tf.maximum(Sij, 0) # Mij = 1 if (i, j) \in P
ij_positive_mat_objective = ij_positive_label_mat * lambda_ij_objective
ij_sum_objective = tf.reduce_sum(ij_positive_mat_objective, [1])
ji_sum_objective = tf.reduce_sum(ij_positive_mat_objective, [0])
lambda_i_objective = ij_sum_objective - ji_sum_objective

在求得新的 λ i \lambda_i λi 后,我们利用梯度上升法来更新参数:

这里写图片描述

因此相比 R a n k N e t RankNet RankNet L a m b d a R a n k LambdaRank LambdaRank 只是在 λ i \lambda_i λi 的基础上引入了评价指标的因素。

损失函数的梯度代表了文档下一次迭代优化的方向和强度,由于引入了 I R IR IR 评价指标, L a m b d a Lambda Lambda 梯度更关注位置靠前的优质文档的排序位置的提升。有效的避免了下调位置靠前优质文档的位置这种情况的发生。 L a m b d a R a n k LambdaRank LambdaRank 相比 R a n k N e t RankNet RankNet 的优势在于分解因式后训练速度变快,同时考虑了评价指标,直接对问题求解,效果更明显。

LambdaMart

在之前的博文已经详细总结过 G B D T GBDT GBDT 的推导,其实一句话就可以总结:每次生成的树都是在拟合之前所有已经生成的树的残差,也就是在梯度下降的方向来生成这课树。

那么在上面的 L a m b d a R a n k LambdaRank LambdaRank 方法中我们已经得到了梯度的计算方式,是否可以用集成学习的方式来学习呢?

在论文中提到 λ i j \lambda_{ij} λij 的计算方式:

这里写图片描述

注意这里面的 Z i j Z_{ij} Zij 可能是 N D C G NDCG NDCG 或者其他任何一个评价指标,当互换 i 、 j i、j ij 的位置引起的变化,具体计算上面已经详细讲到。

论文中以 λ i j \lambda_{ij} λij 为梯度重新定义了损失函数:

这里写图片描述

后面就是求损失函数的二阶梯度,再利用牛顿法去优化损失函数,得到当前生成的树。

这里写图片描述

我感觉上面这种讲法有点不太好理解,下面我直接以 G B D T GBDT GBDT 的套路讲下个人想法:

我们已经知道残差的计算方式为 λ i j \lambda_{ij} λij,那么直接去拟合每一步的残差去生成树不就可以了吗,都不需要知道损失函数。在实作时也是这样做的。

model_output = np.zeros(len(features))##初始化
for i in range(n_trees):##预先设定的树的个数print " Iteration: " + str(i + 1)# Compute psedo responces (lambdas)# witch act as training label for documentstart = time.clock()print "  --generating labels"##计算之前所有生成的树的预测结果所得lambda值。其就是计算残差,都不需要定义损失函数,因为残差已经定义好了。##在获取每一步模型打分后,根据真实相关,计算NDCG变化值。lambdas = compute_lambdas(model_output, scores, queries, k)print zip(lambdas, scores)#lambdas = mart_responces(model_output, scores)print "  --done", str(time.clock() - start) + " sec"# create tree and append it to the modelprint "  --fitting tree"start = time.clock()tree = DecisionTreeRegressor(max_depth=6)##新建一棵树# print "Distinct lambdas", set(lambdas)tree.fit(features, lambdas)##拟合残差print "  ---done", str(time.clock() - start) + " sec"print "  --adding tree to ensemble"ensemble.add(tree)# update model scoreprint "  --generating step prediction"prediction = tree.predict(features)##当前生成的这课树的预测结果。# print "Distinct answers", set(prediction)print "  --updating full model output"##这句是重点:将当前这颗树的预测结果累加到之前的预测结果去,作为新预测结果。model_output += learning_rate * prediction# print set(model_output)# train_scorestart = time.clock()print "  --scoring on train"##获取当前集成树的NDCG值。train_score = score(model_output, scores, queries, 10) 

λ i \lambda_i λi 计算过程:

def query_lambdas(page, k=10):true_page, model_page = page##真实打分,模型预测打分worst_order = np.argsort(true_page)true_page = true_page[worst_order]model_page = model_page[worst_order]model_order = np.argsort(model_page)idcg = dcg(np.sort(true_page)[-10:][::-1])size = len(true_page)position_score = np.zeros((size, size))for i in xrange(size):┆   for j in xrange(size):┆   ┆   position_score[model_order[i], model_order[j]] = \ ┆   ┆   ┆   point_dcg((model_order[j], true_page[model_order[i]]))lambdas = np.zeros(size)for i in xrange(size):┆   for j in xrange(size):┆   ┆   ┆   if true_page[i] > true_page[j]:┆   ┆   ┆   ┆   delta_dcg  = position_score[i][j] - position_score[i][i]┆   ┆   ┆   ┆   delta_dcg += position_score[j][i] - position_score[j][j]┆   ┆   ┆   ┆   delta_ndcg = abs(delta_dcg / idcg)┆   ┆   ┆   ┆   rho = 1 / (1 + math.exp(model_page[i] - model_page[j]))┆   ┆   ┆   ┆   lam = rho * delta_ndcg┆   ┆   ┆   ┆   lambdas[j] -= lam ┆   ┆   ┆   ┆   lambdas[i] += lam return lambdas

总结

R a n k N e t RankNet RankNet 在推导的时候只用了 U i U_i Ui U j U_j Uj 的相关性高还是低 ( − 1 , 0 , 1 ) (-1, 0, 1) 1,0,1,没用上包含位置信息的评估指标(如 N D C G NDCG NDCG),就推出了梯度 λ \lambda λ,在 R a n k N e t RankNet RankNet λ \lambda λ 的基础上加入评价指标因素。所以 L a m b d a M A R T LambdaMART LambdaMART λ \lambda λ,就强硬的在 R a n k N e t RankNet RankNet λ \lambda λ上乘上了评估指标的变化(因为评估指标不连续导致目标函数难以推导)。注意 R a n k N e t RankNet RankNet L a m b d a M A R T LambdaMART LambdaMART 的目标函数,从代价函数变成了效用函数,所以从使用负梯度变成了正梯度。感觉加上评价指标的因素这一做法有点像强化学习的反馈机制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/14995.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ChatGPT的一小步,NLP范式转变的一大步

作者:符尧,yao.fued.ac.uk,爱丁堡大学 (University of Edinburgh) 博士生,本科毕业于北京大学;与Tushar Khot,彭昊在艾伦人工智能研究院 (Allen Institute for AI) 共同完成英文原稿;与李如寐&a…

4月最新编程排行出炉,第一名ChatGPT都在用~

作为一名合格的(准)程序员,必做的一件事是关注编程语言的热度,编程榜代表了编程语言的市场占比变化,它的变化更预示着未来的科技风向和机会! 快跟着一起看看本月排行有何看点: 4月Tiobe排行榜前…

虚幻4蓝图通信

本案例的功能为让玩家控制小白人,并按E让选中的物体旋转 立方体蓝图 小白人蓝图 选人设置 运行结果

虚幻引擎之相机控制

通过本节学习,我们可以在虚幻引擎中按照特定时间来切换摄像机视角,我们可以很方便的进行观看不同摄像机的视野。 首先打开虚幻,在这里我是用的是虚幻4.19,打开虚幻之后,我们首先新建一个工程,在这里我们不使…

虚幻引擎5亮点整理,5大核心一目了然

由EPIC研发的UE5,于2022年4月正式发布。作为全新的实时工作平台,UE5有以下亮点值得关注! Nanite 可以制作海量细节的地图,通过nanite不需要手动贴图,也不需要手动创建LOD Lumen光照系统 为了获得最佳的光照效果&#x…

虚幻引擎C++开发学习(一)

文章内容来自于Udemy课程。第一章为设置C和虚幻环境,直接略过。 第二章内容为一个小游戏,名字叫Triple X,是个简单的数字益智游戏。它基于三个未知数字。你将侵入某种计算机锁。游戏的想法是找到一个有效的三个数字组合。 比如关卡1&#x…

虚幻引擎的控制台命令(长期更新)

小标题前如果标注具体虚幻的版本号,则仅在特定版本中有效 若没标注,则代表全版本通用 局内 【UE5】世界分区(World Partition) 显示世界分区加载网格 2D&3D wp.Runtime.ToggleDrawRuntimeHash3D 3D显示世界分区的加载网格 …

下载虚幻引擎提示错误代码MD-DL

先放结论:因为已经下载过UE4版本的引擎,再下载其它版本引擎的时候默认会放到UE4版本的引擎的同级目录下,改下路径就行了。 把UE4改成UE5就好了,把他俩分开。UE4是我自己之前分给4.26版本的文件夹。 我在下载时遇到了这个问题&am…

虚幻商城模型转MetaHuman

一、导入虚幻商城的模型到UE 1.去虚幻商城下载一个人物模型,这里以SchoolGirl为例 2.导入UE,并找到模型,这里是SkeletalMesh 二、启动MetaHuman插件 1.通过Edit->Plugins启用MetaHuman和MetaHumanSDK插件,这里MetaHuman插件是用于创建MetaHuman的,MetaHumanSDK插件…

Unreal虚幻源代码的编译

很多小伙伴在做开发的时候都用Epic管理的UE引擎,可是在企业实际开发中,需要用到虚幻的源代码。UE和Unity相比的优势也是开源,所以使用引擎的源码很有必要,便于了解底层和修改底层逻辑很有帮助。很多小伙伴不清楚如何编译&#xff…

虚幻4基础知识——编辑器

一、前言 最近将虚幻4的知识点进行梳理了一遍,算作是初学者的角度学习该引擎时遇到的问题的汇总。包括UI、编辑器以及蓝图部分,不过都是挑了我自己需要记录的东西,没有涵盖所有内容。 二、编辑器知识 2.1、视口和模式面板 视口是观察和编辑…

虚幻引擎外部模型及动画导入

运行效果: 首先在底部素材文件加下右键选择导入 导入后选中小白人,右侧菜单栏选中细节,找到网格体,选择你要渲染的人物 动画绑定,在右侧找到动画类,选择要导入的动画

虚幻批量修改贴图

修改之前的属性为512*512. 批量选择贴图,右键。 找到Asset Actions(资产操作)的Bulk Edit via Property Materix(批量编辑属性材料) 选中所有后输入Bias。 修改LOD Bias的值(这里我改为256) 再打…

虚幻4 光照需要重建

在项目中添加新的物体时出现 光照需要重建的提示 解决办法1: 构建光照 解决方法2: 在世界大纲中搜索light,将所有光照设置成实时的

虚幻基础之编译

虽然不像Unity3D那样以多平台支持作为宣传点,虚幻本身依然是多平台支持的,如Windows,IOS,安卓等等。同时为了应对开发和部署的需要,编译的配置也是一个花样繁多的过程。 本篇文章就初步得从概念和工具的角度对虚幻的编…

全面了解虚幻引擎 5

Incredibuild 与 Epic 合作密切,并与虚幻引擎深度集成,因此对于虚幻引擎 5 的发布,我们也是既期待又兴奋。不得不说,虚幻引擎 5 没有辜负我们的期待,在技术上达到了真正的“虚幻”级别! 虚幻引擎 4 的进步…

虚幻引擎5安装踩坑记录

1、The required library hostfxr. dll could not be found. 通过以下链接下载并安装 Download .NET Core 3.1 (Linux, macOS, and Windows) 以我的安装路径为例,将以下hostfxr.dll (也就是报错的未找到文件)复制到虚幻引擎对应的文件夹中…

虚幻浏览器插件 中文输入

WebView 输入法设置 如上所示,在Switch Input Method 项勾选。然后运行项目即可效果如下。 git下载地址: https://github.com/aSurgingRiver/WebView 上一篇 虚幻浏览器插件 页面跳转 目录 下一篇 虚幻浏览器插件 加载透明网页

虚幻4基础人物移动

新建一个文件夹,命名Blueprint。 新建角色,玩家控制器,游戏模式基础。在世界场景中对应(世界场景设置找不到左上角窗口下拉菜单里) 点击新建的角色,左边点击网格体,右边骨骼网格体选择自己倒入…

开源“模仿”ChatGPT,居然效果行?UC伯克利论文,劝退,还是前进?

原创:谭婧ChatGPT 从“古”至今,AI的世界,是一个开源引领发展的世界。 虽然Stable Diffusion作为开源的图像生成模型,将图像生成提到了全新境界,但是ChatGPT的出现,似乎动摇了一些人的信念。 因为ChatGPT是…