论文《Contrastive Learning for Sequential Recommendation》

265 阅读18分钟

论文地址:arxiv.org/abs/2010.14…

摘要

序列推荐经常因为数据稀疏性问题,导致很难学习到高质量的用户向量表示。论文引入对比学习,提出Contrastive Learning for Sequential Recommendation(CL4SRec).,不仅有下一个序列预测的优势,还利用对比学习框架从原始用户行为序列中获取自监督信号。另外论文提出3种构造自监督信号的数据增强方法,在4个公开数据集上面大量实验表明得到的用户表示更好。

简介

序列推荐任务能捕捉用户动态的兴趣,序列推荐的基本问题是从用户历史交互中学习到高质量的用户表示,因此主要研究工作都是通过更强大的序列模型来得到更好的用户表示。像RNN,Self-Attention能从用户行为中捕获更复杂的用户模式,还有GNN,能从用户序列中探索更复杂的物料转换模式。这些方法的尽管都是用序列预测方式,很容易遇到数据稀疏性问题。

最近自监督学习在表示学习领域有巨大突破,在CV、NLP,直接从未标记数据中抽取数据相关性。一个直接的做法是采用强大的序列模型像GPT,但是在推荐系统中不合适,2点原因

  1. 推荐系统通常没有大量的原料库用作预训练,推荐系统各个不同的任务并不共享相同的知识,这会限制预训练的应用
  2. 预测式的自监督学习的目标函数和序列推荐的目标函数几乎相同,在相同的数据上应用另外一个目标函数无法帮助用户进行表示学习

基于上述问题,自监督在推荐系统的研究较少。最近的研究试图从原始特征数据的内在结构中提取自监督信号,来增强特征表示。这些研究集中在提升物料表示的水平,如何提升用户表示的研究较少。

我们打算通过用户行为的自监督信号学习更好的用户表示,哪怕只有序列ID信息。模型包括传统的序列预测目标函数和对比学习目标函数。在对比学习的loss约束下,通过在用户序列上面进行不同视角的数据增强,最大化相同序列的不同视角在向量空间的一致性,来编码用户行为表示。此外还提出3种不同的数据增强方式来讲用户行为序列映射成行为序列的不同视角。总结如下:

  1. 提出新模型Contrastive Learning for Sequential Recommendation (CL4SRec),第一次将对比学习引入到序列推荐
  2. 提出3种不同的数据增强方法,包括裁剪(cropping),遮蔽(masking),重排序(reordering),构造用户行为序列的不同视角
  3. 与所有的baseline相比,提升巨大,在7.37%-11.02%

相关工作

序列推荐

早期的序列推荐使用马尔科夫链Markov Chain (MC),结合一阶MC和矩阵分解来捕捉用户行为,后面为了考量更长的序列,也有研究探索了高阶MC。深度学习RNN,变种LSTM,GRU用来做序列推荐(GRU4Rec),还有一些修改GRU4Rec的变种,通过修改层级结构,或者使用基于用户的门控网络。

还有学者提出基于卷积的序列推荐Convolutional Sequence Embedding Recommendation Model,通过将用户行为抽象为一维的图像,水平和垂直卷积滤波器在捕获相邻序列模式方面是有效的。Self-Attention最近在序列推荐显示了很好从场景,有研究用Transformer层为之前的物料分配权重。因为用户序列可能并不是刚性的顺序,有研究使用双向Transformer来整合两个方向上的用户行为序列。

另外一个研究方向是GNN方向,因为GNN能从用户序列中捕获隐藏的物料转换信息,很多工作试图在序列推荐中使用GNN,例如有研究使用基于门控的图网络去聚合邻居信息,还有研究使用Attention机制来区分不同邻居的影响,而不是采用平均pooling的方式。

自监督学习

自监督学习的基本想法是从原始数据中构建训练信号来设计训练任务,我们将自监督任务分为预测任务号和判别任务。

预测任务在CV和NLP广泛使用,在CV领域,自监督学习应用在图像旋转、相关块位置的预测,以及解决拼图和着色问题。在NLP领域,则大部分应用于词向量表示和句子有效编码上面。语言模型自然地是一个自监督学习过程,通过前面的词序列来预测下一个词。

判别任务是用对比学习框架来对不同样本进行比较。以前的工作在CV领域已经取得了很好的成绩,在不同的CV任务中,即使预训练没有监督学习信号,效果也比baseline要好。为了增加对比的难度,有学者设计了一个共享内存银行在训练时增加batch_size,还有学者通过动态队列及移动平均编码来改进。

在推荐领域,有学者使用自监督的对比学习框架结合一系列类别特征来学习物料向量表示,还有学者提出通过一个辅助的自监督任务目标来学习目标物料和行为序列之间的相关性。论文和这些不同,在用户行为序列上使用对比学习来提升用户的向量表示。

CL4SREC

符号标记和问题陈述

论文中向量用户小写加粗(e.g.u,v\mathbf{u,v}),矩阵用大写加粗表示(e.g.R\mathbf{R}),矩阵R\mathbf{R}的第j行表示为RjT\mathbf{R}_j^T,使用花体字母表示集合(e.g.U,V,A\mathcal{U,V,A}),使用U\mathcal{U}V\mathcal V表示用户和物料的集合,U\vert \mathcal{U} \vertV\vert \mathcal{V} \vert表示用户和物料的数量,一个用户或者一个物料表示为uU,vVu \in \mathcal{U}, v \in \mathcal{V},用户序列一般是按照时间顺序,因此表示一个用户序列为su=[v1(u),v2(u),...,vsu(u)]s_u = [v_1^{(u)}, v_2^{(u)}, ..., v_{\vert s_u \vert}^{(u)}],其中vt(u)v_t^{(u)}表示用户uu在时刻tt交互的行为物料,su\vert s_u \vert表示用户uu的行为序列长度,su,t=[v1(u),v2(u),...,vt(u)]s_{u,t} = [v_1^{(u)}, v_2^{(u)}, ..., v_{t}^{(u)}]表示用户在时刻t+1t+1之前的用户行为子序列。A\mathcal A表示增强(augmentations)集合。序列推荐任务就是预测在时刻su+1\vert s_u \vert + 1用户最可能交互的行为物料,表示如下 vu=argmaxviVP(vsu+1(u)=visu)          (1)v_u^* = \underset {v_i \in \mathcal V} {argmax} P(v_{\vert s_u \vert + 1}^{(u)} = v_i \vert s_u) \ \ \ \ \ \ \ \ \ \ (1)

对比学习框架

数据增强模块

每个数据样本应用一个随机的数据增强方法,产生2个相关的新数据样本。如果两个新样本由同一个样本产生,被视为正样本对,如果是🈶不同的样本产生,视为负样本对。我们对每个用户序列sus_u使用2个随机的数据增强方法(aiA,ajAa_i \in \mathcal A, a_j \in \mathcal A),产生两个新的用户序列suais_u^{a_i}suajs_u^{a_j},这两个新序列是用户行为的2个新视角。

用户表示编码

使用神经网络来编码增强后的用户行为序列,用户向量表示sua=f(sua)\mathbf{s}_u^{a} = f(s_u^{a}),使用Transformer来表示用户行为序列。值得注意的是,SIMCLR使用了在f()f(\cdot)之后使用了 一个辅助的非线性映射,但是作者发现在推荐场景去掉这个辅助的非线性映射效果更好。

对比损失函数

使用对比损失函数来区分两个表示是否来自相同的用户历史序列,为达到这个目标,对比学习损失旨在最小化同一个用户不同增强序列的差异,并且最大化来自不同用户增强序列的差异。对于batch内的NN个用户u1,u2,...,uNu_1,u_2,...,u_N,对每个用户使用两个随机的数据增强操作,会得到2N2N个新序列[su1ai,su1aj,su2ai,su2aj,...,suNai,suNaj,][s_{u_1}^{a_i}, s_{u_1}^{a_j}, s_{u_2}^{a_i}, s_{u_2}^{a_j},..., s_{u_N}^{a_i}, s_{u_N}^{a_j}, ],对于每个用户,(suai,suaj)(s_u^{a_i},s_u^{a_j})是正样本对,其余2(N1)2(N-1)个序列是负样本集SS^-,使用点乘来衡量每个向量的相似度,sim(u,v)=uTvsim(\mathbf u,\mathbf v)=\mathbf u^T \mathbf v。类似于softmax交叉熵损失定义,正样本对(suai,suaj)(s_u^{a_i},s_u^{a_j})的损失函数Lcl\mathcal L_{cl}表示如下 Lcl(suai,suaj)=logexp(sim(suai,suaj))exp(sim(suai,suaj))+sSexp(sim(suai,s)          (2)\mathcal L_{cl} (s_u^{a_i},s_u^{a_j}) = - \log \frac {exp( sim(\mathbf{s}_u^{a_i},\mathbf{s}_u^{a_j}) )} { exp( sim(\mathbf{s}_u^{a_i},\mathbf{s}_u^{a_j}) ) + \sum_{s^- \in S^-} exp( sim(\mathbf{s}_u^{a_i},\mathbf s^- ) }\ \ \ \ \ \ \ \ \ \ (2)

数据增强操作

介绍3种基本的数据增强操作,这些操作能构造同一个样本的不同视角,但是仍然能保持隐藏在用户序列中的主要模式。

物料裁剪(Item Crop)

随机裁剪在CV领域是一个常见的数据增强方法,经常从原始图像中随机创建一个子图像增强模型的泛化能力,我们在序列推荐的对比学习中引入。对于每个用户序列sus_u,随机选择子序列sucrop=[vc,vc+1,...,vc+Lc1]s_u^{crop} = [v_c,v_{c+1},...,v_{c+L_c-1}],子序列长度Lc=ηsuL_c=\lfloor \eta* \vert s_u \vert \rfloor,这里省略了每个物料vv的上标uu,公式表示如下: sucrop=acrop(su)=[vc,vc+1,...,vc+Lc1]          (3)s_u^{crop} = a_{crop}(s_u) = [v_c,v_{c+1},...,v_{c+L_c-1}]\ \ \ \ \ \ \ \ \ \ (3) 物料裁剪的效果能从两方面解释,第一,提供了用户行为序列的一个局部视角,在不全面的用户信息下学习用户的泛化偏好。第二,在对比学习框架下,如果两个用户子序列没有交集,可以被视作下一个句子预测任务,促使模型预测用户偏好的改变。

物料遮蔽(Item Mask)

随机将输入的词遮蔽掉,也叫word dropout,在很多NLP任务中用于避免过拟合,像句子生成、语义分析、自动问答,受此启发,提出一种随机将行为物料遮蔽的数据增强方法。对于每个用户行为序列sus_u,随机遮蔽一定比例γ\gamma的行为物料Tsu=(t1,t2,...,tLm)\mathcal T_{s_u} = (t_1,t_2,...,t_{L_m}),长度Lm=γsuL_m=\lfloor \gamma* \vert s_u \vert \rfloor,如果一个行为物料被遮蔽,会被一个特殊的单词[mask][mask]替换掉,公式表示如下:

\hat{v}_t=\left\{\begin{matrix}v_t,t \notin \mathcal T_{s_u} \\mask,t \in \mathcal T_{s_u} \end{matrix}\right.\ \ \ \ \ \ \ \ \ \ (4)$$ 因为一段时间内用户的偏好相对稳定,用户历史交互的物料反映相似的用户意图。例如,用户打算去买运动鞋,在买之前会点击很多运动鞋。因此,即便遮蔽一部分物料,新的序列也能保留主要的用户意图,而且还能防止编码器对用户行为过度编码。 ##### 物料重排序(Item Reorder) 很多方法是有严格的顺序假设的,即假设用户行为中大部分相邻的行为有顺序依赖。然而真实世界中,用户交互的顺序可能是灵活的。因此,可以提出一个在灵活顺序下的数据增强方法,在这个方法下,可以鼓励模型更少依赖用户交互序列的顺序,因此在模型遇到新序列时能够更加健壮。通过随机shuffle一定比例$\beta$的交互物料,改变行为序列的顺序,对于每个用户序列$s_u$,随机shuffle一个连续的子序列$[v_r,v_{r+1},...,v_{r+L_r-1}]$,变成$[\hat {v}_r,\hat {v}_{r+1},...,\hat {v}_{r+L_r-1}]$,乱序的序列长度为$L_r=\lfloor \beta* \vert s_u \vert \rfloor$,公式表示如下: $$s_u^{reorder} = a_{reorder}(s_u) = [v_1,v_2,...,\hat v_i,\hat v_{i+1},...,\hat v_{i+L_r-1},...,v_{\vert s_u \vert }]\ \ \ \ \ \ \ \ \ \ (5)$$ #### 用户表示模型 我们使用SASRec模型结构,因为它采用一个单向的Transformer编码器用于序列推荐,取得不错的效果,Transformer编码器包含三个子层:embedding层,多头注意力层,位置相关的前向神经网络层 ##### embedding层 Transformer使用物料embedding矩阵$\mathbf E \in R^{\vert \mathcal V \vert \times d}$,将高维物料one-hot稀疏输入映射为低维稠密向量,另外为了表示序列的位置信息,利用可学习的位置embedding矩阵$\mathbf P \in R^{T \times d}$来捕获序列特征,位置向量的个数由用户最长的序列约束决定。因此,我们在$t+1$时刻推断用户的向量表示时,用到的是用户最近$T$个历史交互序列。公式表示如下: $$s_{u,t} = [v_{t-T+1},v_{t-T+2},...,v_t]\ \ \ \ \ \ \ \ \ \ (6)$$ 因此我们可以得到用户的输入表示,物料embedding和位置embedding之和 $$\mathbf h_i^0 = \mathbf v_i + \mathbf p_t\ \ \ \ \ \ \ \ \ \ (7)$$ 其中$\mathbf v_i \in \mathbf E$是用户序列$s_{u,t}$召回物料$v_i$的向量表示。 ##### 多头注意力层 embedding层之后,Transformer引入了多头注意力模块,旨在捕捉用户序列中每个物料pair的依赖关系,序列建模中这非常有用。为了从每个位置的不同子空间中提取信息,论文使用了多头注意力而不是单头注意力。首先利用不同的映射方式将输入映射到$h$子空间中,然后利用注意力机制,并且将输出结果连接起来,表示如下: $$MH(\mathbf H^l) = concat(head_1,head_2,...,head_h)\mathbf W^O $$ $$ head_i = Attention(\mathbf H^l \mathbf W_i^Q, \mathbf H^l \mathbf W_i^K, \mathbf H^l \mathbf W_i^V)\ \ \ \ \ \ \ \ \ \ (8)$$ 其中$\mathbf W_i^Q, \mathbf W_i^K, \mathbf W_i^V \in R^{d \times \frac d h}$,$\mathbf W^O \in R^{d\times d}$ $$Attention(\mathbf Q,\mathbf K, \mathbf V) = softmax(\frac {\mathbf Q \mathbf K^T} {\sqrt{d/h}}) \mathbf V\ \ \ \ \ \ \ \ \ \ (9)$$ 其中$\mathbf Q, \mathbf K, \mathbf V$表示queries,keys,values,因子$\sqrt{d/h}$避免内积值过大。 ##### 位置相关前馈网络 尽管多头注意力机制对于抽取前面物料的信息上有用,但是它还是基于线性映射。我们赋予基于位置网络的前馈神经网络,它应用于上述子层输出的每个位置的共享学习参数。 $$PFFN(\mathbf H^l) = [FFN(\mathbf h_1^l)^T,FFN(\mathbf h_2^l)^T,.., FFN(\mathbf h_{\vert s_u \vert }^l)^T]$$ $$FFN(\mathbf h_i^l) = RELU(\mathbf h_i^l \mathbf W_1 + \mathbf b_1)\mathbf W_2 + \mathbf b_2\ \ \ \ \ \ \ \ \ \ (10)$$ ##### 堆积更多块 堆积更多的块有助于学习更复杂的模式,然而网络会更深且参数会更多,模型就更难收敛,为了解决这个问题,我们应用了包括残差网络、layer normalization、dropout等机制: $$LayerNorm(\mathbf x + Dropout(sublayer(\mathbf x)))\ \ \ \ \ \ \ \ \ \ (11)$$ ##### 用户向量表示 基于几个Transformer块,那么在时刻$\vert s_u \vert +1$,用户向量表示为 $$\mathbf s_u = [Trm^L(s_u)]_{\vert s_u \vert }^T\ \ \ \ \ \ \ \ \ \ (12)$$ 这里$T$是Transformer层的数量, $$Trm(\mathbf H^l) = LayerNorm(\mathbf F^{l-1} + Dropout(PFFN(F^{l-1})))$$ $$\mathbf F^{l-1} = LayerNorm(\mathbf H^{l-1} + Droupout(MH(\mathbf H^{l-1}))\ \ \ \ \ \ \ \ \ \ (13)$$ ##### 多任务训练 采用多任务策略,序列预测主任务和额外的对比学习任务,放在一起优化,表示如下 $$\mathcal L_{total} = \mathcal L_{main} + \lambda \mathcal L_{cl}\ \ \ \ \ \ \ \ \ \ (14)$$ 每一步基于采样的softmax采样来计算主任务loss $$\mathcal L_{main} = -\log \frac { exp(\mathbf s_{u,t}^T \mathbf v_{t+1}^+) } { exp(\mathbf s_{u,t}^T \mathbf v_{t+1}^+) + \sum_{v_{t+1}^- \in \mathcal V^- } exp( \mathbf s_{u,t}^T \mathbf v_{t+1}^- ) }\ \ \ \ \ \ \ \ \ \ (15)$$ ### 实验 大量实验回答下面4个研究问题(research question) $RQ1$:CL4SRec在序列推荐任务中相比于基线表现如何? $RQ2$:不同的数据增强方法对效果影响如何?增强方法中的超参数对效果影响如何? $RQ3$:对比学习的权重$\lambda$对效果的影响如何? $RQ4$:CL4SRec中不同的组件(数据增强模块和对比学习loss)是如何影响性能? $RQ5$:CL4SRec是否真的学到了更好的用户向量表示? #### 实验设置 ##### 数据集 在4个公开数据集上面开展实验,两个来自Amazon,另外一个数据集来自Yelp,一个著名的饭店、酒吧、化妆平台商业推荐平台,还有一个来自MovieLe-1M(ML-1M)。对于数据预处理,采用通用的做法,将所有数字评分或者评论转化为1或者0。去掉重复的交互行为,然后按照时间顺序对用户行为序列进行排序。另外未保证每个用户有足够的行为序列,去掉了小于5个行为的用户记录,数据集情况总结如下Table 1: ![在这里插入图片描述](https://img-blog.csdnimg.cn/0547be0eac284939b93bee3141b4cb1a.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5be05ouJ5be05ouJ5py1,size_20,color_FFFFFF,t_70,g_se,x_16) ##### 评估 使用留一法来评估每个方法,对于每个用户,使用最近一次交互的物料作为测试集,最近第二次交互的物料作为验证集,其余作为训练集,为了加快计算评估指标,之前的很多工作都使用采样的结果来评估,然而这种做法可能和未采样的结果不一致,因此我们在整个物料集上面进行评估,使用oy Hit Ratio (HR) and Normalized Discounted Cumulative Gain (NDCG)作为评估指标,HR关注的是正样本是否出现,而NDCG还将排序位置考虑进来,评估HR和NDCG时,我们设置$k=5,10,20$。 ##### 基线 Pop:非个性化推荐,给每个用户推荐的是相同的,都是整个物料集里面最流行的物料。 BPR-MF:典型的非序列推荐的基线,基于矩阵分解建模用户和物料的pair,使用Bayesian Personalized Ranking (BPR)loss。 NCF:使用神经网络来建模用户和物料的交互。 GRU4Rec$^+$:使用GRU模型建模用户行为序列。 SASRec:这是解决序列推荐任务最好的基线之一,使用自注意力机制捕捉用户的动态兴趣。 GC-SAN:结合了GNN和自注意力模块捕获包括隐藏在用户序列中的局部和长期的转变。 S$^3$-Rec$_{MIP}$:也是使用自监督方法,主要集中于融合上下文和序列数据,公平起见,我们仅比较mask item prediction (MIP) 。 ##### 实现细节 都使用pytorch,embedding层维度统一设置为$d=64$,对于baseline的方法,超参数设置都是基于论文提出的最优值。对于CL4SRec,所有参数初始化使用基于$[-0.01,0.01]$的正态分布,使用Adam优化器,学习率为$learning\_rate=0.001$,$\beta_1=0.9$,$\beta_2=0.999$,$batch_size=256$,根据验证集表现采用early stop操作,测试crop/mask/reorder物料的比例从0.1到0.9,堆了2个自注意块,每个块的head数量为2,序列长度设置为20-50。 #### 总体性能比较(RQ1) 回答问题1(RQ1),结果如下表Table 2所示,空间限制,最右边的提升表示CL4SRec与第二好的算法比较的相对提升,采用的的基于3种数据增强方法的最好结果。 ![在这里插入图片描述](https://img-blog.csdnimg.cn/e16203e5a654479dace1a74679d67555.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5be05ouJ5be05ouJ5py1,size_20,color_FFFFFF,t_70,g_se,x_16) 总结如下: Pop是最差的,忽视了隐藏在用户序列中的个性化因素。采用了序列式的方法(GRU4Rec$^+$和SASRec)比非序列式方法(BPR-MF和NCF)效果要好,它们使用了用户历史行为信息,在所有的序列式方法中,SASRec效果最好,说明强大的自注意力机制能有效捕捉用户序列模式。 GC-SAN并没有带来显著提升,有时甚至比SASRec差,一个可能的原因是用户序列行为没有环,而且这些数据集里面行为序列的度不超过2,GNN无法从这样的用户序列召回捕捉有用的信息。对于S$^3$-Rec$_{MIP}$,有时候也比SASRec差,在没有上下文的情况下,它的预训练及模型的微调可能导致灾难性的遗忘。 这个实验结果表明CL4SRec在序列推荐任务的有效性,相比于其他模型有不同程度的显著提升。 #### 比较不同的数据增强方法(RQ2) 对于问题2,分析不同的数据增强方法和比例对效果的影响,每次只使用一种数据增强操作。高比例的$\gamma$(mask)和$beta$(reorder)以及低比例的$\eta$(crop)会让模型区分起来更加困难。篇幅限制,仅展示Sports和Yelp两个数据集的结果,如Figure 4所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/943d74d2a1fd42889637ba765a8eae4c.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5be05ouJ5be05ouJ5py1,size_20,color_FFFFFF,t_70,g_se,x_16) $\gamma ,\beta,\eta$这些参数都是从0.1到0.9之间调整,可以看到,不管哪种数据增强操作,CL4SRec大部分几乎都比SASRec要好,这表明引入数据增强方法的有效性,因为他们都引入 一个辅助的自监督信号。而且我们发现这3种增强操作每个单独和其他增强操作相比,没有一个能表现出最好的效果,例如mask操作在Sports数据集上表现最好,但是crop在Yelp上面表现最好,这说明不同的数据增强操作适用于不同的数据集,因为它们是原始数据的不同视角。 另外,不同的增强比例影响也不一样,这些比例对应的效果有个峰值,减少或者增加比例就会降低效果。 #### 对比学习的loss权重(RQ3) 看对比学习的权重$\lambda$对于效果的影响,我们根据上面的结果,选择每个数据集最好的数据增强方法和增强比例,结果如下图所示Figure 5: ![在这里插入图片描述](https://img-blog.csdnimg.cn/5d2ba95861974fa0be74dcbfc7272133.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5be05ouJ5be05ouJ5py1,size_20,color_FFFFFF,t_70,g_se,x_16) 可以看到超过一定阈值,$\lambda$再增加就会导致模型效果下降,合适的权重值会使CL4Rec在各个数据集上都比SASRec要好。如果对比学习的loss主导了任务,会导致模型效果下降,我们将在将来的工作中仔细分析这种影响。 #### 拆解研究(RQ4) 做了一个拆解实验来论证数据增强方法和对比学习loss对模型效果的影响,为了验证每个部分的有效性,我们在不同的SASRec中进行实验,用SASRec$_{aug}$表示在SASRec中应用数据增强方法,结果如下表Table 3所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/89efda3cb31245f6911f8625d513e220.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5be05ouJ5be05ouJ5py1,size_20,color_FFFFFF,t_70,g_se,x_16) 数据表明,SASRec$_{aug}$比SASRec要好,这表明提出的数据增强方法是有效的,通过引入随机的噪音可以提升模型的效果。对于我们提出的对比学习loss,CL4SRec比SASRec$_{aug}要好,这验证了引入自监督信号的对比学习的有效性。 ##### 用户向量表示的质量(RQ5) 我们来验证CL4Rec是否真的产生了更好的用户向量表示,利用Yelp数据集的好友关系数据,去看如果他们是好友,他们在向量空间里面是否更近了。结果如下图Figure 6所示: ![在这里插入图片描述](https://img-blog.csdnimg.cn/6487873083b7452b89f7a879cb493b70.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5be05ouJ5be05ouJ5py1,size_20,color_FFFFFF,t_70,g_se,x_16) SASRec和CL4SRec平均相似度分别是0.5198和0.6100,CL4Rec相比SASRec产生了更好的用户向量表示。 ### 总结 提出了CL4SRec利用对比学习框架抽取原始数据中的自监督信号,提出了3种数据增强方法来构造对比学习任务,在4个公开数据集上表现优秀。 ### 对比部分代码实现 对比学习mask操作可以实现如下: ```python # input sequence_emb: shape(sequence_emb) = [batch_size, sequence_length, embedding_size] def contrastive_learning_masked(sequence_emb, mask_ratio): sequence_length = tf.shape(sequence_emb)[1] mask_num = tf.cast(tf.cast(sequence_length, tf.float32) * mask_ratio, tf.int32) mask_index = tf.random_shuffle(tf.sequence_mask(sequence_length - mask_num, sequence_length, dtype=tf.float32)) mask_tile_1 = tf.tile(tf.expand_dims(mask_index, axis=1), [1, tf.shape(sequence_emb)[2]]) # [sequence_length, embedding_size] mask_tile_2 = tf.tile(tf.expand_dims(mask_tile_1, axis=0), [tf.shape(sequence_emb)[0], 1, 1]) # [batch_size, sequence_length, embedding_size] sequence_emb_masked = tf.multiply(sequence_emb, mask_tile_2) return sequence_emb_masked ``` 对比学习reorder操作可以实现如下 ```python # input sequence_emb: shape(sequence_emb) = [batch_size, sequence_length, embedding_size] def contrastive_learning_reordered(sequence_emb, reorder_ratio): sequence_length = tf.shape(sequence_emb)[1] reorder_num = tf.cast(tf.cast(sequence_length, tf.float32) * reorder_ratio, tf.int32) reorder_begin = tf.random_uniform(shape=(), minval=0, maxval=(sequence_length - reorder_num), dtype=tf.int32) reorder_index = tf.concat([tf.range(0, reorder_begin), tf.random_shuffle(tf.range(reorder_begin, reorder_begin + reorder_num)),tf.range(reorder_begin + num_reorder, sequence_length)], axis=0) sequence_emb_reordered = tf.gather(sequence_emb, reorder_index, axis=1) # [batch_size, sequence_length, embedding_size] return sequence_emb_reordered ``` 最终经过编码器后,每个user会得到一个mask后的Embedding(下面的emb_mask)和reorder后的Embedding(下面的emb_reorder) 对比学习的loss如下 ```python # shape(emb_mask) = [batch_size, embedding_size] # shape(emb_reorder) = [batch_size, embedding_size] def contrastive_learning_loss(emb_mask, emb_reorder, temperature=1.0): batch_size = tf.shape(emb_mask)[0] logits_mask_mask = tf.matmul(emb_mask, emb_mask, transpose_b=True) / temperature # [batch_size, batch_size] masks = tf.one_hot(tf.range(batch_size), batch_size) logits_mask_mask = logits_mask_mask - masks * 1e10 # [batch_size, batch_size] logits_mask_reorder = tf.matmul(emb_mask, emb_reorder, transpose_b=True) / temperature # [batch_size, batch_size] labels = tf.one_hot(tf.range(batch_size), batch_size * 2) logits = tf.concat([logits_mask_reorder, logits_mask_mask], axis=1) loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits)) return loss ```