pairwise、listwise在lgb中的应用,以及相关listwise的简单实现

1、lgb.LGBMRanker
lgb.LGBMRanker是LightGBM中的一个用于排序任务的模型类。它使用基于梯度提升的算法,能够训练出一个能够对一组对象进行排名的模型。

在训练过程中,LGBMRanker会使用Pairwise-FTRL算法来优化排序的目标函数,该目标函数可以考虑到对象间的相对顺序。具体来说,Pairwise-FTRL使用类似于逻辑回归的方法,通过最大化正确的对象对之间的相对排序来训练模型。

在使用LGBMRanker时,需要将数据集转换为LightGBM的特定格式,并指定排名任务使用的目标函数和评估指标。此外,可以使用超参数调整和交叉验证来优化模型性能。

总之,LGBMRanker是一种高效、灵活的排序模型,适用于各种排序任务,例如搜索结果排序、推荐系统中的物品排序等。

2、lgb相关模型使用listwise
在使用lgb模型进行listwise训练时,需要将数据集按照样本排列顺序,以列表的形式传入模型,其中每个子列表包含了单个查询(query)的所有样本。例如,一个包含3个查询的数据集,每个查询包含5个样本,可以表示为一个包含3个子列表的列表,每个子列表包含5个样本。

具体而言,需要使用LightGBM的Dataset类来加载数据集,并设置参数group表示每个查询(query)中的样本数目,例如:

import lightgbm as lgb
train_data = lgb.Dataset(X_train, label=y_train, group=group_train)
其中,group_train为一个包含每个查询中样本数的列表。

在训练时,设置objective为’rank_xendcg’或’rank_xendcg_map’,表示使用listwise排序损失函数,例如:

x_train_group = train_metrics_df.groupby(['order']).count()['listwise_label'].values
x_valid_group = valid_metrics_df.groupby(['order']).count()['listwise_label'].values

lgb_ranker = lgb.LGBMRanker(
        boosting_type='gbdt', num_leaves=63, reg_alpha=0.0, reg_lambda=1,
        max_depth=-1, n_estimators=1500, subsample=0.7, colsample_bytree=0.7, subsample_freq=1,
        learning_rate=0.05, min_child_weight=30, random_state=2018,
        n_jobs=-1) 
# objective 在 默认是LambdaRank
objective (str, callable or None, optional (default=None)) – Specify the learning task and the corresponding learning objective or a custom objective function to be used (see note below). Default: ‘regression’ for LGBMRegressor, ‘binary’ or ‘multiclass’ for LGBMClassifier, ‘lambdarank’ for LGBMRanker.
https://lightgbm.readthedocs.io/en/v3.3.2/pythonapi/lightgbm.LGBMRanker.html

lgb_ranker.fit(X_train, y_train[:,5], group=x_train_group, 
               eval_set=[(X_valid, y_valid[:,5])], eval_group=[x_valid_group], eval_at=[1], eval_metric=['ndcg'],
              early_stopping_rounds=100)
             
lgb_ranker = lgb.Booster(model_file='./LGBMRanker_no_normal_-1.txt')
y_pred_train = lgb_ranker.predict(X_train)
y_pred_valid = lgb_ranker.predict(X_valid)
y_pred_test = lgb_ranker.predict(X_test)

# clf_loads = lgb_ranker.booster_.save_model("./LGBMRanker_1500_0.05_63_100rounds_max.txt")

import treelite
import pickle
    
model0_booster = treelite.Model.load('./LGBMRanker_no_normal_-1.txt', model_format='lightgbm')
model0_booster.export_lib(toolchain='gcc', 
                          libpath='./LGBMRanker_listwise_nonorm.so', 
                          verbose=True)

params = {‘objective’: ‘rank_xendcg’,
‘metric’: ‘ndcg’,
‘learning_rate’:0.1,
‘max_depth’:6,
‘num_leaves’:64,
‘feature_fraction’:0.8,
‘bagging_fraction’:0.8}
model = lgb.train(params, train_data, num_boost_round=100)
在预测时,需要将测试集按照样本排列顺序,以列表的形式传入模型的predict方法,例如:

y_pred = model.predict(X_test, group=group_test)
其中,group_test为一个包含每个查询中样本数的列表。最后,可以根据预测结果进行排序和评估。

3、“objective为’rank_xendcg’或’rank_xendcg_map’,表示使用listwise排序损失函数”,这个描述是正确的吗

是的,这个描述是正确的。在LightGBM中,'rank_xendcg’和’rank_xendcg_map’是用于listwise排序的两种常见的目标函数(即损失函数)。这些目标函数可以同时考虑查询(query)中所有样本的贡献,从而更好地优化排序性能。其中,'rank_xendcg’是针对ndcg指标的排序损失函数,'rank_xendcg_map’是针对MAP指标的排序损失函数。

使用这些目标函数进行训练时,需要将数据集按照样本排列顺序,以列表的形式传入模型,其中每个子列表包含了单个查询(query)的所有样本。在预测时,需要将测试集也按照样本排列顺序,以列表的形式传入模型的predict方法。

4、使用pairwise
如果使用pairwise排序而不是listwise排序,则可以使用’rank:pairwise’作为LightGBM的目标函数。'rank:pairwise’是一种成对排序(pairwise)损失函数,它利用样本之间的比较关系来优化排序性能。与listwise排序不同,pairwise排序仅考虑每对样本之间的贡献,因此更适用于数据集中样本数较大的情况。

在使用’rank:pairwise’进行训练时,需要将数据集按照样本排列顺序,以列表的形式传入模型,其中每个子列表包含了单个查询(query)的所有样本。每个子列表中的样本应按照其真实排序顺序排列。在预测时,也需要将测试集按照样本排列顺序,以列表的形式传入模型的predict方法。

常用listwise的实现:
①ListNet
ListNet的关键思想是将每个查询(q)下的文档集合(D)转换成一个向量(例如召回6个点,直接把6个点合并成一条语料,标签长度为6),然后用神经网络对这些向量进行排序,最终将排序结果作为损失函数的优化目标。ListNet使用的是交叉熵损失函数,对于一个查询(q),它的损失函数可以表示为:

L(q) = -∑p(i|q)log(q(i))

其中,p(i|q)表示文档i在查询q中的相对等级。交叉熵损失函数的目标是最小化预测结果与真实结果之间的差异,因此它可以用来度量排序模型的排序质量。相比Pointwise Ranking模型,ListNet考虑了文档之间的相对关系,能够更直接地优化整个列表的排序质量,

②神经网络使用NDCG加权loss的封装和手写实现

l5 = tf.constant([[0.2, 0.8]], dtype=tf.float32)     #  1.2214027581601699   2.225540928492468
# l5_softmax = [0.3543436937742045, 0.6456563062257954]
true_label = tf.constant([[1, 3]], dtype=tf.float32)

lambda_weightweights = tfr.losses.DCGLambdaWeight(
    gain_fn=lambda labels: tf.pow(2.0, labels) - 1.0,         # [1, 7]
    rank_discount_fn=lambda rank: 1.0 / tf.math.log1p(rank), 
    normalized=True
)  

lambda_weightweights_2 = tfr.losses.DCGLambdaWeight(
    gain_fn=lambda labels: tf.pow(2.0, labels) - 1.0,         # [1, 7]
    rank_discount_fn=lambda rank: 1.0 / tf.math.log1p(rank),  # [0.91, 1.44]     
    normalized=False
) 


loss1 = tfr.losses._softmax_loss(labels=true_label, logits=l5, lambda_weight=lambda_weightweights)
loss2 = tfr.losses._softmax_loss(labels=true_label, logits=l5, lambda_weight=lambda_weightweights_2)
loss3 = tfr.losses._softmax_loss(labels=true_label, logits=l5)

with tf.Session() as sess:
    print(sess.run(loss1))
    print(sess.run(loss2))# print(7 * (1/np.log1p(1)) * np.log(0.6456563062257954) + 1 * (1/np.log1p(2)) * np.log(0.3543436937742045))
    print(sess.run(loss3))

idcg = 7 * 1.44 + 1 * 0.91 ≈11

0.48709634  除以idcg之后的loss 
5.3624945  没有除idcg之前的loss
2.349952    listnet损失函数

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值