RUCAIBox / RecBole

A unified, comprehensive and efficient recommendation library
https://recbole.io/
MIT License
3.37k stars 606 forks source link

sample metrics #1256

Closed kuzma-long closed 2 years ago

kuzma-long commented 2 years ago

您好,KDD有一篇论文讨论过评价指标的问题,在他看来,采样指标是有偏差的,这是否意味着在评估的时候使用除full rank以外的其他方式都是不准确的,那为什么recbole还提供了各种采样评估方式的接口呢?

2017pxy commented 2 years ago

@kuzma-long 你好,关于你的问题,我的回答如下:

问题1:

这是否意味着在评估的时候使用除full rank以外的其他方式都是不准确的

推荐系统的公平评测确实是一个值得研究的问题,我也阅读过你所说的那篇论文(On Sampling Top-K Recommendation Evaluation)。我个人理解,原文的观点是:采样指标和全排序指标相比存在偏差,这篇论文提出了一种调整的方式来减小这个偏差。但这是否说明采样指标一定是不可用的,没有任何参考意义的?我觉得可能还有待商榷。

问题2:

那为什么recbole还提供了各种采样评估方式的接口呢?

我们在做开发和架构设计时,考虑到过去有很多推荐相关的论文都是以采样指标评测的,为了让用户复现结果时能够尽可能贴合这些原文的实验环境,我们在评测部分设计了采样和全排序两种评测方式。这种采样方式的实现只是为了丰富我们框架的功能,并不代表我们鼓励大家使用采样评测,也不代表我们的学术立场和学术观点。而且,我们的默认配置也是全排序评测的,我们没有强制用户使用。

总之,我们的功能多样只是为了满足多种用户需要,如果你没有采样评测的需要,或者你不认同这种方式,完全可以使用全排序评测来开展你的实验。

以上是我的回复,谢谢!

kuzma-long commented 2 years ago

@kuzma-long 你好,关于你的问题,我的回答如下:

问题1:

这是否意味着在评估的时候使用除full rank以外的其他方式都是不准确的

推荐系统的公平评测确实是一个值得研究的问题,我也阅读过你所说的那篇论文(On Sampling Top-K Recommendation Evaluation)。我个人理解,原文的观点是:采样指标和全排序指标相比存在偏差,这篇论文提出了一种调整的方式来减小这个偏差。但这是否说明采样指标一定是不可用的,没有任何参考意义的?我觉得可能还有待商榷。

问题2:

那为什么recbole还提供了各种采样评估方式的接口呢?

我们在做开发和架构设计时,考虑到过去有很多推荐相关的论文都是以采样指标评测的,为了让用户复现结果时能够尽可能贴合这些原文的实验环境,我们在评测部分设计了采样和全排序两种评测方式。这种采样方式的实现只是为了丰富我们框架的功能,并不代表我们鼓励大家使用采样评测,也不代表我们的学术立场和学术观点。而且,我们的默认配置也是全排序评测的,我们没有强制用户使用。

总之,我们的功能多样只是为了满足多种用户需要,如果你没有采样评测的需要,或者你不认同这种方式,完全可以使用全排序评测来开展你的实验。

以上是我的回复,谢谢!

感谢回复!再请教一个问题,一般来说采样评估是为了节省时间提高效率,但为什么我在使用全评估的时候所用的时间要比采样的时间少很多?

2017pxy commented 2 years ago

@kuzma-long 你好,这是因为我们对全排序基于GPU做了优化,如果你看过我们的代码,会发现我们有些模型代码中会有一个full_sort_predict函数,这个函数是我们做的优化,当选择全排序时,会调用这个函数而不是predict函数。

大部分模型的全排序都是用矩阵乘法直接算出来的,所以会非常快。但采样评测的话,首先我们的采样过程是在cpu上进行的,这里会有开销;其次,采样评测在运算时,可能会对user emb进行重复计算,比如sasrec,每次一次predict都要重复跑一次self-attention来得到输出,这也会造成很大的开销。

然而,采样排序的优势在于对显存需求不高,假设你数据里的item数量很大,那全排序就可能因为无法开出那么大的矩阵而不能执行,这时,选择采样评测可能就是一种解决方案。

kuzma-long commented 2 years ago

@kuzma-long 你好,这是因为我们对全排序基于GPU做了优化,如果你看过我们的代码,会发现我们有些模型代码中会有一个full_sort_predict函数,这个函数是我们做的优化,当选择全排序时,会调用这个函数而不是predict函数。

大部分模型的全排序都是用矩阵乘法直接算出来的,所以会非常快。但采样评测的话,首先我们的采样过程是在cpu上进行的,这里会有开销;其次,采样评测在运算时,可能会对user emb进行重复计算,比如sasrec,每次一次predict都要重复跑一次self-attention来得到输出,这也会造成很大的开销。

然而,采样排序的优势在于对显存需求不高,假设你数据里的item数量很大,那全排序就可能因为无法开出那么大的矩阵而不能执行,这时,选择采样评测可能就是一种解决方案。

我注意到,din、dien、autoint这些CTR模型是没有实现full_sort_predict的,但是有predict,这类模型是只能采样评估吗,如果我把它点击率排个序,是不是可以也变相地看成推荐模型 next item 预测的一种?

2017pxy commented 2 years ago

@kuzma-long 你好,他们也可以全排序评估,和采样一样,做全排序的时候会调用predict函数,所以这种情况下采样排序的速度会更快。

kuzma-long commented 2 years ago

@kuzma-long 你好,他们也可以全排序评估,和采样一样,做全排序的时候会调用predict函数,所以这种情况下采样排序的速度会更快。

Traceback (most recent call last): File "main.py", line 123, in run_single_model(args) File "main.py", line 83, in run_single_model best_valid_score, best_valid_result = trainer.fit( File "/home/chaolong/code/recbole/trainer.py", line 66, in fit valid_score, valid_result = self._valid_epoch(valid_data, show_progress=show_progress) File "/home/chaolong/.conda/envs/recbole/lib/python3.8/site-packages/recbole/trainer/trainer.py", line 209, in _valid_epoch valid_result = self.evaluate(valid_data, load_best_model=False, show_progress=show_progress) File "/home/chaolong/.conda/envs/recbole/lib/python3.8/site-packages/torch/autograd/grad_mode.py", line 27, in decorate_context return func(*args, **kwargs) File "/home/chaolong/.conda/envs/recbole/lib/python3.8/site-packages/recbole/trainer/trainer.py", line 475, in evaluate interaction, scores, positive_u, positive_i = eval_func(batched_data) File "/home/chaolong/.conda/envs/recbole/lib/python3.8/site-packages/recbole/trainer/trainer.py", line 424, in _neg_sample_batch_eval batch_user_num = positive_u[-1] + 1 TypeError: 'NoneType' object is not subscriptable

上面是我跑autoint之后报的错,想请教一下问题出在哪里,是在评估的时候出了错,谢谢!

2017pxy commented 2 years ago

请你提供一下配置文件,所用数据集的情况,不然我很难复现你的问题

kuzma-long commented 2 years ago

请你提供一下配置文件,所用数据集的情况,不然我很难复现你的问题

配置文件: embedding_size: 10 attention_size: 16 n_layers: 3 num_heads: [2] dropout_probs: [0.2,0.2,0.2] mlp_hidden_size: [128,128] hyper_parameters: ['num_heads'] train_batch_size: 128 eval_batch_size: 256

数据集:Amazon_instant_video 数据集配置:

Atomic File Format

field_separator: "\t" seq_separator: " "

Common Features

USER_ID_FIELD: user_id ITEM_ID_FIELD: item_id RATING_FIELD: rating TIME_FIELD: timestamp seq_len: ~

Label for Point-wise DataLoader

LABEL_FIELD: rating

NegSample Prefix for Pair-wise DataLoader

NEGPREFIX: neg

Sequential Model Needed

ITEM_LIST_LENGTH_FIELD: item_length LIST_SUFFIX: _list MAX_ITEM_LIST_LENGTH: 50 POSITION_FIELD: position_id

Knowledge-based Model Needed

HEAD_ENTITY_ID_FIELD: head_id TAIL_ENTITY_ID_FIELD: tail_id RELATION_ID_FIELD: relation_id ENTITY_ID_FIELD: entity_id

Selectively Loading

load_col: ~ unload_col: ~ unused_col: ~ selected_features: ['categories', 'price']

Filtering

rm_dup_inter: ~ val_interval: ~ filter_inter_by_user_or_item: True user_inter_num_interval: '[5,inf)' item_inter_num_interval: '[5,inf)'

Preprocessing

alias_of_user_id: ~ alias_of_item_id: ~ alias_of_entity_id: ~ alias_of_relation_id: ~ preload_weight: ~ normalize_field: ~ normalize_all: True

2017pxy commented 2 years ago

@kuzma-long 你确定你的配置文件是这个吗?如果load_col为空,你就没有导入数据呀?你可以告诉我你的实验怎么跑的吗?怎么复现呢?

kuzma-long commented 2 years ago

@kuzma-long 你确定你的配置文件是这个吗?如果load_col为空,你就没有导入数据呀?你可以告诉我你的实验怎么跑的吗?怎么复现呢?

recbole官方文档里有,Note that if load_col is None, then all the existed atomic files will be loaded. 为空的话就是默认全部加载

2017pxy commented 2 years ago

@kuzma-long 不好意思,确实是这样的,我忘记了;那请问怎么复现你的这个实验呢?因为你目前提供的信息我依然不清楚你的评测方式等信息

kuzma-long commented 2 years ago

@kuzma-long 不好意思,确实是这样的,我忘记了;那请问怎么复现你的这个实验呢?因为你目前提供的信息我依然不清楚你的评测方式等信息

是这样的,我只是想跑一下该模型用其结果作为baseline,所有的配置我都是使用的默认的,代码我也没有动,评估方式我在配置文件里没有写,然后我在输出的打印信息中看到默认为: eval_args = {'split': {'RS': [0.8, 0.1, 0.1]}, 'order': 'RO', 'group_by': None, 'mode': 'labeled'} 此时第一个epoch训练正常,但无法evaluate,导致程序终止,这是我第一个疑惑的地方。

当我手动在配置文件里指定评估方式为: eval_args: [{'split': {'LS': 'valid_and_test'}, 'order': 'TO', 'group_by': 'user', 'mode': 'pop100'}] 时,程序能够正常跑通,但这个地方就是我前面在讨论的是个采样的评估方式,而我想要得到全排序的评估结果,我如果将mode改为full,程序就会报错,因为AutoInt并没有实现full_sort_predict这个函数,这是第二个疑惑的地方。

2017pxy commented 2 years ago

1、如果你设置的是labeled,需要确保你的数据有label。请你检查一下你是否设置label了。参考label文档

2、对于context-aware的模型,我们在支持全排序时,需要保证.inter文件里面只加载了user fielditem field,以及对应的rating信息,不能添加其他的比如timestamp的交互时特征。具体原因可以参考 #891。full_sort_predict只是针对全排序的加速函数,并不是说模型没有这个函数就不能做全排序了。