评测

RecBole设置了专门的评测模块用以评估推荐算法的性能。


评测部分简介

评测模块的功能主要是用于测试推荐模型的效果。为了方便地在同等设置条件下对不同的模型进行测试,RecBole提供了推荐系统中各种标准的测试流程。


评测规定和设置

下表总结了我们支持的六种评测设置。其中前四个为数据切分方式,后两个与排序策略有关。

符号 解释
RO_RS 随机顺序+比例切分
TO_LS 时间排序+留一法切分
RO_LS 随机顺序+留一法切分
TO_RS 时间排序+比例切分
full 全排序
uniN 负采样排序:每个正例采N个负例

在RecBole中,评测模块主要包含Ranking-based Evaluator以及Value-based Evaluator这两个类,他们均可以自适应上述的各种评测方式。对于`t\op`-`k`商品推荐, 我们支持的评测方式也涵盖了我们早期的工作(Zhao et al., 2020)。在那个工作中,我们研究了不同的评测方式对模型表现的影响。



Ranking-based Evaluator

Ranking-based Evaluator主要负责排序类任务的评测,目前已经提供的评测指标有hit(hit ratio),NDCG,MRR,recall,MAP,precision。这些指标经常会使用其截断的`k`版本,所以其往往带有后缀@`k`,如Recall@`5`NDCG@`10`

各个`t\op`-`k`指标的具体含义请参考的我们的文档:metrics


Value-based Evaluator

Value-based Evaluator主要应用于评分预测以及点击率预估等任务,目前已经提供的评测指标有: AUC, LogLoss, MAE, RMSE。

各个loss指标的具体含义请参考的我们的文档:metrics



`T\op`-`k`评估效率优化

计算`t\op`-`k`商品的评估指标通常非常耗时,主要原因是计算时需要完整地评估每一个用户-物品配对项的分数。但是不同的模型计算每个商品得分的方法不同, 所以统一整个评测流程是一件很困难的事情。因此,我们主要关注于模型得到每个商品得分后,进行`t\op`-`k` 商品的生成和选择这一步。

下图展示了我们提出的全排序的加速策略。其中`u0, · · · , u5` 表示6个用户,黑色块,蓝色块和灰色块分别表示训练集商品,测试集商品以及其它候选商品。矩阵`A`中的数字表示经过重赋值后的模型得到的`t\op`-`k`商品的位置索引。 矩阵`B`中的数字表示是物品是否在测试集中出现(图中的蓝色块).矩阵`C`中的数字表示是矩阵`A`的对应位置是否预测正确。




分数矩阵重赋值

  • reshaping: 设有`n`个用户与`m`件物品,当对所有物品进行排序时,我们可以得到一个`n \times m`的矩阵`D`,这个矩阵包含了模型在完整的物品集的打分情况。当仅针对部分采样物品进行排序时,我们同样可以初始化一个`n \times m`的矩阵`D`,矩阵的所有元素初始化为负无穷。然后,我们在矩阵中填入模型对采样物品的打分值。
  • filling: 当对所有物品进行排序时,我们提供了一个可以屏蔽训练集物品的方式。如果用户选择丢弃训练集的物品,我们并不能直接对上述步骤得到的矩阵进行`t\op`-`k`预测。我们的解决方案是将训练集的物品打分设置为负无穷,这样就可以在不移除训练集物品的情况下对所有物品进行排序。

计算`t\op`-`k`商品


我们利用Pytorch提供的topk()函数来寻找每个用户打分值最高的`k`件物品.GPU版本的topk()函数基于CUDA进行特殊优化,极大地优化了我们的计算效率。通过调用topk()函数,我们可以得到一个大小为`n \times k`的矩阵`A`, 它记录了每个用户分数最高的`k`件物品在原矩阵的索引。


计算`t\op`-`k`商品和正样本交集


  • indexing: 我们进一步生成一个`n \times m`的二进制矩阵`B`,表示是物品是否在测试集中出现。接下来,我们用矩阵A的每一行对矩阵B的对应行进行索引,得到一个大小为`n \times k`的二进制矩阵`C`,它的元素表示矩阵`A`的对应位置是否预测正确,这个过程可以使用Pytorch提供的gather()函数高效实现。

`T\op`-`k` 指标计算

考虑到用户可能希望同时得到多个`t\op`-`k`下的评测指标,我们又对指标计算环节进行了并行设计。使用到的关键技术如下:

  • 如果一个用户需要计算在多个`k`值下的评测指标,那么我们在获得`t\op`-`k`矩阵的时候,选择计算最大的`k`所对应的矩阵。即`\max(k)`,那么我们一个batch将得到 `b_i \times \max(k)` 的矩阵。
  • 在具体的指标计算中,我们采用NumPy提供的如np.cumsum()(累加和)而非np.sum()的方式来计算指标。那么传统的指标计算函数,返回的是在一个指定`t\op`-`k`情况下的结果,而我们的指标计算函数返回的则是一个list, 其记录了 `k`从`1`到`\max(k)`的结果,从而实现了不同k值间相对并行。
  • 使用矩阵运算来替代for语句。因为我们的所有操作都是在矩阵上进行的,那么我们便可以充分利用NumPy提供的丰富的矩阵运算,从而实现提速。