快速入门:序列推荐系统

示例:SLi_Rec——结合长短期偏好的自适应用户建模个性化推荐

与不考虑用户活动顺序的通用推荐系统(如矩阵分解或xDeepFM)不同,序列推荐系统将用户行为的顺序作为上下文,目标是预测用户在短时间内可能会互动的项目(极端情况下,是用户下一个互动的项目)。

本文旨在通过一个公共的Amazon数据集,为您提供快速训练序列模型的示例。目前,我们支持NextItNet、GRU、Caser、A2SVD、SLi_Rec和SUM模型。在不失一般性的前提下,本示例将以SLi_Rec模型为例。

SLi_Rec是一种基于深度学习的模型,旨在捕捉用户的长期和短期偏好,以实现精确的推荐系统。总结一下,SLi_Rec具有以下关键特性:

  • 采用注意力机制的“非对称SVD”范式进行长期建模;
  • 在LSTM的门控逻辑中考虑时间和语义的不规则性;
  • 使用注意力机制动态融合长期和短期组件。

在本文中,我们将测试SLi_Rec在一个公共数据集的子集上: Amazon_reviewsAmazon_metadata

本文在TensorFlow 2.6环境下测试。

0. 全局设置和导入

import os
import sys
import tensorflow.compat.v1 as tf
tf.get_logger().setLevel('ERROR') # 仅显示错误信息

from recommenders.utils.timer import Timer
from recommenders.utils.constants import SEED
from recommenders.models.deeprec.deeprec_utils import prepare_hparams
from recommenders.datasets.amazon_reviews import download_and_extract, data_preprocessing
from recommenders.models.deeprec.models.sequential.sli_rec import SLI_RECModel as SeqModel
from recommenders.models.deeprec.io.sequential_iterator import SequentialIterator
from recommenders.utils.notebook_utils import store_metadata

print(f"System version: {sys.version}")
print(f"Tensorflow version: {tf.__version__}")
参数设置
EPOCHS = 10
BATCH_SIZE = 400
RANDOM_SEED = SEED  # 设置为None则结果不确定

data_path = os.path.join("..", "..", "tests", "resources", "deeprec", "slirec")
yaml_file = '../../recommenders/models/deeprec/config/sli_rec.yaml'

1. 输入数据格式

输入数据包含8列,即:<label> <user_id> <item_id> <category_id> <timestamp> <history_item_ids> <history_cateory_ids> <hitory_timestamp>,各列之间用\t分隔。item_idcategory_id表示目标项目和类别,这意味着对于这个实例,我们想猜测用户user_id是否会在timestampitem_id互动。<history_*>列记录了用户在<timestamp>之前的行为列表,元素之间用逗号分隔。<label>是一个二进制值,1表示正实例,0表示负实例。实例示例如下:

1    A1QQ86H5M2LVW2    B0059XTU1S    Movies    1377561600    B002ZG97WE,B004IK30PA,B000BNX3AU,B0017ANB08,B005LAIHW2    Movies,Movies,Movies,Movies,Movies    1304294400,1304812800,1315785600,1316304000,1356998400

在数据预处理中,我们会生成一些ID映射字典,因此user_iditem_idcategory_id会被映射成从1开始的整数索引。您需要告诉输入迭代器ID映射文件的位置(例如在下节中,我们有一些映射文件如user_vocabitem_vocabcate_vocab)。

train_file = os.path.join(data_path, r'train_data')
valid_file = os.path.join(data_path, r'valid_data')
test_file = os.path.join(data_path, r'test_data')
user_vocab = os.path.join(data_path, r'user_vocab.pkl')
item_vocab = os.path.join(data_path, r'item_vocab.pkl')
cate_vocab = os.path.join(data_path, r'category_vocab.pkl')
output_file = os.path.join(data_path, r'output.txt')

reviews_name = 'reviews_Movies_and_TV_5.json'
meta_name = 'meta_Movies_and_TV.json'
reviews_file = os.path.join(data_path, reviews_name)
meta_file = os.path.join(data_path, meta_name)
train_num_ngs = 4 # 训练时每个正实例的负实例数量
valid_num_ngs = 4 # 验证时每个正实例的负实例数量
test_num_ngs = 9 # 测试时每个正实例的负实例数量
sample_rate = 0.01 # 采样率

input_files = [reviews_file, meta_file, train_file, valid_file, test_file, user_vocab, item_vocab, cate_vocab]

if not os.path.exists(train_file):
    download_and_extract(reviews_name, reviews_file)
    download_and_extract(meta_name, meta_file)
    data_preprocessing(*input_files, sample_rate=sample_rate, valid_num_ngs=valid_num_ngs, test_num_ngs=test_num_ngs)

1.1 准备超参数

prepare_hparams()函数将创建一组完整的超参数用于模型训练,如学习率、特征数量和丢弃率。我们可以将这些参数放在yaml文件中(完整参数列表见config文件夹),也可以作为函数参数传递(会覆盖yaml设置)。

hparams = prepare_hparams(yaml_file, 
                          embed_l2=0., 
                          layer_l2=0., 
                          learning_rate=0.001,  # 如果禁用批量归一化,设为0.01
                          epochs=EPOCHS,
                          batch_size=BATCH_SIZE,
                          show_step=20,
                          MODEL_DIR=os.path.join(data_path, "model/"),
                          SUMMARIES_DIR=os.path.join(data_path, "summary/"),
                          user_vocab=user_vocab,
                          item_vocab=item_vocab,
                          cate_vocab=cate_vocab,
                          need_sample=True,
                          train_num_ngs=train_num_ngs)

1.2 创建数据加载器

为模型指定数据迭代器。我们所有的序列模型都使用SequentialIterator。数据格式如上所述。

input_creator = SequentialIterator

2. 创建模型

当超参数和数据迭代器准备好后,我们可以创建一个模型:

model = SeqModel(hparams, input_creator, seed=RANDOM_SEED)

2.1 训练模型

接下来我们要在训练集上训练模型,并检查其在验证集上的表现。训练模型非常简单,只需调用一个函数:

with Timer() as train_time:
    model = model.fit(train_file, valid_file, valid_num_ngs=valid_num_ngs) 

print('Time cost for training is {0:.2f} mins'.format(train_time.interval/60.0))

2.2 评估模型

再次查看模型的性能(训练后):

res_syn = model.run_eval(test_file, num_ngs=test_num_ngs)
print(res_syn)

如果我们想获取完整的预测分数而不是评估指标,可以这样做:

model = model.predict(test_file, output_file)

2.3 使用大数据集运行模型

以下是使用整个Amazon数据集在流行的序列模型上的性能,包含1,697,533个正实例。
设置如下:
learning_rate=0.001, dropout=0.3, item_embedding_dim=32, cate_embedding_dim=8, l2_norm=0, batch_size=400, train_num_ngs=4, valid_num_ngs=4, test_num_ngs=49

我们比较了仅使用CPU和使用GPU在较大数据集上的运行时间。结果显示GPU可以显著加速训练。硬件规格如下:

  • GPU: Tesla P100-PCIE-16GB
  • CPU: 6 cores Intel® Xeon® CPU E5-2690 v4 @ 2.60GHz
模型AUCg-AUCNDCG@2NDCG@10每个epoch的GPU时间(秒)每个epoch的CPU时间(秒)配置
A2SVD0.82510.81780.29220.4264249.5440.0N/A
GRU0.84110.83320.32130.4547439.04285.0max_seq_length=50, hidden_size=40
Caser0.82440.81710.2830.4194314.35369.9T=1, n_v=128, n_h=128, L=3, min_seq_length=5
SLi_Rec0.86310.85190.34910.4842549.65014.0attention_size=40, max_seq_length=50, hidden_size=40
NextItNet*0.67930.67690.06020.1733112.0214.5min_seq_length=3, dilations=[1,2,4,1,2,4], kernel_size=3
SUM0.84810.84060.33940.47741005.09427.0hidden_size=40, slots=4, dropout=0

注意:

  1. 这些模型的结果是通过粗粒度网格搜索得到的,仅供参考。
  2. NextItNet模型需要一个具有强序列特性的dataset,但本文使用的Amazon数据集不满足这一要求,因此NextItNet模型的性能可能不佳。如果使用其他具有强序列特性的数据集,推荐使用NextItNet。
  3. NextItNet模型的时间成本显著低于其他模型,因为它不需要扩展训练数据的历史记录。

3. 加载训练好的模型

此小节提供一个简单示例,说明如何使用训练好的模型以满足生产需求。

假设我们在一个新会话中。首先加载之前训练的模型:

model_best_trained = SeqModel(hparams, input_creator, seed=RANDOM_SEED)
path_best_trained = os.path.join(hparams.MODEL_DIR, "best_model")
print('loading saved model in {0}'.format(path_best_trained))
model_best_trained.load_model(path_best_trained)

检查是否正确加载了模型。测试指标应接近训练阶段的数值。

model_best_trained.run_eval(test_file, num_ngs=test_num_ngs)

使用加载的模型进行预测:

model_best_trained.predict(test_file, output_file)

参考文献

[1] Zeping Yu, Jianxun Lian, Ahmad Mahmoody, Gongshen Liu, Xing Xie. Adaptive User Modeling with Long and Short-Term Preferences for Personailzed Recommendation. In Proceedings of the 28th International Joint Conferences on Artificial Intelligence, IJCAI’19, Pages 4213-4219. AAAI Press, 2019.

[2] Kyunghyun Cho, Bart van Merrienboer, Caglar Gulcehre, Dzmitry Bahdanau, Fethi Bougares, Holger Schwenk, and Yoshua Bengio. Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation. arXiv preprint arXiv:1406.1078. 2014.

[3] Tang, Jiaxi, and Ke Wang. Personalized top-n sequential recommendation via convolutional sequence embedding. Proceedings of the Eleventh ACM International Conference on Web Search and Data Mining. ACM, 2018.

[4] Yuan, F., Karatzoglou, A., Arapakis, I., Jose, J. M., & He, X. A Simple Convolutional Generative Network for Next Item Recommendation. WSDM, 2019.

[5] Lian, J., Batal, I., Liu, Z., Soni, A., Kang, E. Y., Wang, Y., & Xie, X. Multi-Interest-Aware User Modeling for Large-Scale Sequential Recommendations. arXiv preprint arXiv:2102.09211. 2021.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

步子哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值