论文笔记+模型实现TransNets: Learning to Transform for Recommendation

摘要

最近,一些深度学习方法相对于传统方法提高了推荐系统的性能,尤其是当评论文本可用时。举个例子,最近的一个模型DeepCoNN,使用神经网络,根据目标用户所有评论学得一个潜在向量,根据目标项目的所有评论学得第二个潜在向量,然后把它们结合起来,在推荐任务中获得了最先进的性能。

我们证明了(不足为奇)来自目标用户对目标项目的评论具有很高的预测价值。然后我们介绍了如何在推荐系统中使用这些信息,甚至是当目标用户对目标项目的评论不可用时。我们的模型叫作TransNets,由DeepCoNN模型拓展而来,通过引入额外的潜在向量表达<目标用户-目标项目>对。然后我们调整这个层,与其他层的表示类似。我们证实了TransNets及其拓展版本比以前最先进的方法有极大的提升。

1. 介绍

用评论文本来预测评分已经被证实大大改进了推荐系统的性能[4,22,24],相对于协同过滤(CF)只用历史评分来说。近来,深度学习研究的进步使得 在众多领域使用包括推荐系统 这件事变得有可能。大多数神经网络推荐模型[3,10,16,21,40]都关注了与用户和项目有关联的内容,常常用来构建他们的潜在表示。与用户有关联的信息包含他们的人口信息、社会经济特征、他们的产品喜好。与项目相关联的内容包含产品中的价格、外观、可用性、相似属性,或者饭店的食物质量、格调、服务和等待时间,或者电影里的演员、导演、类型和相似元素。这些表示形式喂入一个CF风格的模型或回归模型去做评分预测。

评论文本不像上面所说的“内容”,不是用户仅有的或商品仅有的属性;而是与他们的联合交互有关系的属性。目前只有少数神经网络模型[2,34,44]提出使用评论文本来预测评分。
基于此,最近一个模型DeepCoNN使用神经网络,从用户写的所有评论文本中为用户学得一个潜在表示,同理从项目的所有评论文本中为项目本身学得一个潜在表示;然后用一个回归层把这两个潜在表示合并起来,从而在评分预测中获得最先进的效果。

然而,正如我们将要证明的,很大的预测价值来自目标用户对目标项目的评论,这些评论应当只在训练中生效而在测试时不可用。在本文,我们介绍了一种方法:把这种(预测价值)信息用到推荐系统的训练中。

2. 提出的方法

2.1 CNN处理文本 & 2.2 DeepCoNN模型

该部分介绍了DeepCoNN的基本模型,上一篇笔记已经详细记录:论文学习(DeepCoNN):Joint Deep Modeling of Users and Items Using Reviews for Recommendation

DeepCoNN模型实现(pytorch 1.60):zhaojinglong/DeepCoNN

2.3 DeepCoNN的一下局限性

DeepCoNN超越以往最先进使用评论文本的方法,得出了令人印象深刻的均方误差值。

比如这些模型:

  • Hidden Factors as Topics (HFT) model [24]
  • Collabora-tive Topic Regression (CTR) [39]
  • Collaborative Deep Learning(CDL)[40]

更不用说仅使用评分信息的协同过滤方法:

  • Matrix Factorization (MF) [18]
  • Probabilistic Matrix Factorization (PMF) [33]。

然而,在DeepCoNN实验中我们发现,只有当测试的时候样本中包含目标用户对目标项目的评论时,才能获得最好的表现效果。而在现实世界中,我们的推荐常识是应当在一个用户购买一个商品之前把这个商品推荐给他,而他此时还没有对该商品进行过评论。因此,我们怎么能在预测时,使用这个“还没出生”的评论作为输入呢?

具体来说,假设一个输入样本用户为A,项目为B, t e x t A text_A textA表示A所有写过的评论(包括对B),同理 t e x t B text_B textB表示项目B所有收到过的评论(包括A写的), r e v A B rev_{AB} revAB表示用户A对项目B写过的评论,即 t e x t A text_A textA t e x t B text_B textB的交集。上一段所讲的“目标用户对目标项目的评论”就是指 r e v A B rev_{AB} revAB

经过对DeepCoNN的实验我们发现,当测试集样本中包含 r e v A B rev_{AB} revAB时,EMS=1.21,反之不包含 r e v A B rev_{AB} revAB时,EMS=1.89,显然后者才是真实世界的情况,而后者数据集在矩阵分解MF模型上MSE=1.86。 再者,如果我们在训练集和测试上都去除 r e v A B rev_{AB} revAB,实验结果EMS=1.70,仍然比训练集和测试集都包含 r e v A B rev_{AB} revAB的实验结果要高。实验数据如图:

情景 训练集 测试集 EMS
1 r e v A B rev_{AB} revAB r e v A B rev_{AB} revAB 1.21
2 r e v A B rev_{AB} revAB 不含 r e v A B rev_{AB} revAB 1.89
3 不含 r e v A B rev_{AB} revAB 不含 r e v A B rev_{AB} revAB 1.70

很显然,情景2才是我们真实世界的情况,但DeepCoNN的表现却不尽人意。

2.4 TransNets模型

通过上文我们了解到,在DeepCoNN模型的学习中,在训练集中保留 r e v A B rev_{AB} revAB将无意间导致模型在测试时依赖于测试集中的 r e v A B rev_{AB} revAB(由前一节表格的情景1与情景2对比得出),这种情况是不切实际的。虽然 r e v A B rev_{AB} revAB出现在测试集中是不合理的,但 r e v A B rev_{AB} revAB出现在训练集中是合乎现实的。

论文笔记+模型实现TransNets: Learning to Transform for Recommendation

如Figure 3所示,TransNets包含两个神经网络。一个目标网络(Target Network)用来单独处理 r e v A B rev_{AB} revAB样本;一个源网络(Source Network)用来处理不含 r e v A B rev_{AB} revAB的样本( t e x t A , t e x t B text_A,text_B textA,textB)。

目标网络 使用一个CNN文本处理层 Γ T \Gamma_T ΓT(与DeepCoNN相同)和一个分解机 F M T FM_T FMT(FM)去预测评分:

x T = Γ T ( r e v A B ) (1) x_T = \Gamma_T(rev_{AB}) \tag{1} xT=ΓT(revAB)(1)
x ‾ T = δ ( x T ) (2) \overline{x}_T = \delta(x_T) \tag{2} xT=δ(xT)(2)
r ^ T = F M T ( x ‾ T ) (3) \hat{r}_T = FM_T(\overline{x}_T) \tag{3} r^T=FMT(xT)(3)

其中 δ \delta δ表示dropout层。由于目标网络使用了实际评论,所以类似于情感分析[19,35]。

源网络和DeepCoNN模型一样:两个CNN文本处理层, Γ A \Gamma_A ΓA处理用户文本( t e x t A − r e v A B text_A-rev_{AB} textArevAB); Γ B \Gamma_B ΓB处理项目文本( t e x t B − r e v A B text_B-rev_{AB} textBrevAB);一个分解机 F M S FM_S FMS;另外有一个额外的 T r a n s f o r m Transform Transform层。 T r a n s f o r m Transform Transform层的目标是把用户文本和项目文本转换成一个 r e v A B rev_{AB} revAB的近似值 r e v ^ A B \hat{rev}_{AB} rev^AB,用于后面的评分预测。

首先是CNN层的处理,得到潜在向量 z 0 z_0 z0

x A = Γ A ( t e x t A − r e v A B ) (4) x_A = \Gamma_A(text_A - rev_{AB}) \tag{4} xA=ΓA(textArevAB)(4)
x B = Γ B ( t e x t B − r e v A B ) (5) x_B = \Gamma_B(text_B - rev_{AB}) \tag{5} xB=ΓB(textBrevAB)(5)
z 0 = [ x A x B ] (6) z_0 = [x_A x_B] \tag{6} z0=[xAxB](6)
公式(6)是将向量 x A x_A xA x B x_B xB直接连接。

Transform层是一个L层非线性全连接层网络,将 z 0 z_0 z0作为其输入,第 l l l层到第 l + 1 l+1 l+1层传递公式为:
z l = σ ( z l − 1 G l + g l ) (7) z_l = \sigma(z_{l-1}G_l+g_l) \tag{7} zl=σ(zl1Gl+gl)(7)

其中 σ \sigma σ是非线性**函数;权重矩阵 G l ∈ { R 2 n × n , l = 1 R n × n , e l s e G_l \in \begin{cases} \R^{2n\times n}, & l=1 \\ \R^{n\times n},&else\end{cases} Gl{R2n×n,Rn×n,l=1else;偏置 g l ∈ R n g_l \in \R^n glRn。 我们使用TransNet模型得到了 r e v A B rev_{AB} revAB的近似值 r e v ^ A B \hat{rev}_{AB} rev^AB,也就是 z l z_l zl。最后源网络用下面的表达式预测评分:

z ‾ L = δ ( z l ) (8) \overline z_L = \delta(z_l) \tag{8} zL=δ(zl)(8)
r ^ S = F M S ( z ‾ L ) (9) \hat r_S = FM_S(\overline z_L) \tag{9} r^S=FMS(zL)(9)

在训练中,我们会让源网络输出的 z ‾ l \overline z_l zl逼近目标网络输出的 x T x_T xT,下节详述。

2.5 TransNets模型的训练

TransNets 的训练分为3个子步骤,见算法1。

  • 第一步,训练目标网络,其所有可训练参数记为 θ T \theta_T θT,损失函数为真实评分 r A B r_{AB} rAB与预测评分 r ^ T \hat r_T r^T之间的L1范数;
  • 第二步,训练源网络,其 F M S FM_S FMS层之前(不含)可训练参数记为 θ t r a n s \theta_{trans} θtrans,损失函数为dropout层输出的表达 z ‾ l \overline z_l zl和目标网络CNN层输出的评论表达 x T x_T xT之间的L2范数;
  • 第三步,源网络剩余可训练参数记为 θ S \theta_S θS,损失函数为 r A B r_{AB} rAB与预测评分 r ^ S \hat r_S r^S之间的L1范数;

模型训练伪代码:

论文笔记+模型实现TransNets: Learning to Transform for Recommendation

TransNets 的测试只使用源网络,见算法3:

论文笔记+模型实现TransNets: Learning to Transform for Recommendation

2.6 设计决策和一些其他结构的选择

本节主要是说本模型在设计时考虑过的不同方案,但这些方案最终都被淘汰了,下面详述了没有采用它们的原因。

2.6.1 分步训练 VS. 合并训练

算法1提出的方案分3步来训练各个子网。然而,如果采用在每次迭代中把所有参数一次性更新训练,即 l o s s t o t a l = l o s s T + l o s s t r a n s + l o s s S loss_{total}=loss_T+loss_{trans}+loss_S losstotal=lossT+losstrans+lossS,将会导致源网络的损失传播给目标网络,从而导致模型效果大大降低。因此,分别反向传播是非常重要的。

2.6.2 单独训练目标网络直至收敛

我们可以选择先把目标网络训练到收敛,然后再训练源网络直到收敛到跟目标网络看齐。然而,目标网络的输入是实际评论(即u对i的真实评论),是不能用在测试中的。换句话说,我们使用实际评论把目标网络训练好了,再用目标网络的结果去矫正源网络,不就间接地用实际评论训练源网络了吗?这正是2.3节提出的DeepCoNN的局限性。源网络不应当知道目标网络在良好泛化的情况下何时收敛,以及何时过拟合。

测试模型的唯一方法就是评估源网络的输出。

因此,我们同时训练源网络和目标网络,并在源网络验证性能最好时停止训练。

2.6.3 在源网络和目标网络使用同一个CNN层进行文本处理

我们可以直接用目标网络中的CNN层在源网络进行文本处理,也就是两个子网共用一个CNN层。毕竟,我们在学习将源网络的输出向目标网络的输出靠拢。然而,这将迫使TransNet模型生成通用的特征(源网络和目标网络通用),这是不合理的。举个例子,某用户“喜欢印度烹饪,但不喜欢等”,某饭店被评为“差劲的服务,糟糕的咖喱鸡”,那么在源网络中该用户对该饭店的预测评价应当是“失望的”,从而评分很低。让源网络拥有独立CNN层来处理文本,可以让它拥有更强的表达能力和效果。

2.6.4 训练Transform时不使用dropout

在算法1的步骤2中,不使用dropout来训练transform层,也就是说 l o s s t r a n s = ∣ ∣ z l − x T ∣ ∣ 2 loss_{trans}=||z_l - x_T||_2 losstrans=zlxT2而不是 l o s s t r a n s = ∣ ∣ z ‾ l − x T ∣ ∣ 2 loss_{trans}=||\overline z_l - x_T||_2 losstrans=zlxT2。(其实这也是我看完模型后的一个疑惑)。然而,这将导致Tranform层欠正则化,即很容易过拟合,从而模型效果变差。

2.7 拓展的TransNets模型

针对上文提出的TransNets模型存在一个问题:输入只有评论文本,而没有考虑用户或项目的身份(标识信息)。换句话说,TransNets并没有考虑输入的评论来自哪个用户或项目,而用户或项目应当由一定的个性。这一点在传统的协同过滤方法中是有考虑的(如矩阵分解)。

论文笔记+模型实现TransNets: Learning to Transform for Recommendation

如图Figure 4,在源网络中增加两个嵌入矩阵: Ω A \Omega_A ΩA, Ω B \Omega_B ΩB,分别为用户和项目的嵌入矩阵; Ω : i d → R n \Omega: id \rightarrow \R^n Ω:idRn。该映射把一个用户的唯一标识(可以是编号)映射为一个n维向量。

将用户和项目的编号经过嵌入后,进行dropout,然后与源网络Transform层的输出连接起来,最后送入FM(分解机)。给定 u s e r A user_A userA i t e m B item_B itemB,TransNet-Ext的评分计算方法为:
ω A = Ω ( u s e r A ) (10) \omega_A = \Omega(user_A) \tag{10} ωA=Ω(userA)(10)
ω B = Ω ( i t e m B ) (11) \omega_B = \Omega(item_B) \tag{11} ωB=Ω(itemB)(11)
z ‾ = [ δ ( ω A ) δ ( ω B ) z ‾ l ] (12) \overline z = [\delta(\omega_A) \delta(\omega_B) \overline z_l] \tag{12} z=[δ(ωA)δ(ωB)zl](12)
r ^ S E = F M S E ( z ‾ ) (13) \hat{r}_{SE} = FM_{SE}(\overline z) \tag{13} r^SE=FMSE(z)(13)

同时,在算法1的步骤3需要做一些修改。 l o s s S loss_S lossS替换为 l o s s S E = ∣ r A B − r ^ S E ∣ loss_{SE}=|r_{AB}-\hat{r}_{SE}| lossSE=rABr^SE,参数集合 θ S \theta_S θS将增加两个参数: Ω A \Omega_A ΩA Ω B \Omega_B ΩB

3. 实验和结果分析

3.1 数据集

本文选用了4个大型数据集:

数据集 类型 用户数目 项目数目 评论/评分数目
Yelp17 2019432 144072 4153150
AZ-Elec 数码类 4200520 475910 7820765
(7,824,482)
AZ-CSJ 服装鞋珠宝 3116944 1135948 5748260
(5,748,920)
AZ-Mov 影视类 2088428 200915 4606671
(4,607,047)

实际使用时进行了去重和去除空评论,括号中是原始数目。

3.2 评估方案和参数设定

将数据集乱序后,按照8:1:1的比例划分为训练集、验证集、测试集。在训练中每500个batches以及每个epoch之后再验证集上计算一次MSE(均方误差),只要发现更小的MSE,就保存当前的模型。

3.2.1 文本的预处理和词嵌入

所有的评论文本通过Stanford Core NLP Tokenizer[24]获得全部小写的字词。停用词(the,and,is等)和标点符号被考虑为隔离字符,并被保留。使用Skip-gram模型在语料库中50000个词频最高的词上预训练出来的64维词嵌入向量。

3.2.2 CNN文本处理器

本文的模型相较于DeepCoNN,在CNN文本处理上没有明显改进,所以沿用DeepCoNN的参数设定。
三个CNN文本处理器 Γ A , Γ B , Γ T \Gamma_A,\Gamma_B,\Gamma_T ΓA,ΓB,ΓT的参数一致,卷积核数目为100宽度为3,CNN输出维度是50,输入文本最大长度1000,当评论很多时,随机乱序抽取前1000个单词。

在本文的实验中,词嵌入维度为64,字典大小50000。非线性**函数为tanh

3.2.3 dropout层和FM分解机

dropout的保留概率设为0.5, F M T , F M S , F M S E FM_T,FM_S,FM_{SE} FMT,FMS,FMSE中特征组合矩阵的向量维度是k=8。所有分解机的权重参数w初始化为0.001,特征组合矩阵初始化服从均值为0标准差0.001的正态分布。所有分解机的训练都是通过最小化L1范数。

3.2.4 Transform层

默认全连接层数为2。所有权重矩阵初始服从均值为0,标准差为0.1的截断正态分布,所有偏置 g l g_l gl初始为0.1。非线性**函数为tanh

3.2.5 TransNet-Ext(拓展TransNets)

用户/项目嵌入矩阵 Ω \Omega Ω服从(-1,1)上的均匀分布,且每个用户/项目的嵌入维度为n=50。验证集或测试集中的用户取随机值。

3.2.6 训练

优化器使用Adam[17],学习率0.002。

3.3 与之相竞争的其他模型

  1. DeepCoNN:[44]. 在训练时,每个样本中user和item的公共评论 r e v A B revAB revAB分别被保留在用户评论和项目评论中。在测试中,公共评论不被保留。

  2. DeepCoNN-revAB:在训练时,每个样本中user和item的公共评论 r e v A B revAB revAB不保留。在测试中,公共评论也不保留

  3. MF:神经网络实现的矩阵分解,隐层维度为50,该模型只使用评分(没用评论文本)。

  4. DeepCoNN + Test Reviews:在训练时,每个样本中user和item的公共评论 r e v A B revAB revAB保留。在测试中,公共评论也保留

3.4 评估与分值预测

使用MSE(均方误差)评估模型效果:
M S E = 1 N ∑ i = 1 N ( r i − r ^ i ) 2 (14) MSE = \frac{1}{N} \sum_{i=1}^{N}(r_i - \hat r_i)^2 \tag{14} MSE=N1i=1N(rir^i)2(14)
其中, N N N是数据点个数, r i r_i ri是真实分值, r ^ i \hat r_i r^i是预测分值。MSE值越小,模型效果越好。

Table 2给出了每个方法对应每个数据集的MSE,最优值被标记为蓝色。
论文笔记+模型实现TransNets: Learning to Transform for Recommendation

3.5 选取Transform层的全连接层数

Transform有L层全连接层,Figure 5展示了层数L对模型效果的影响,使用的数据集是Yelp。L=2是个合理的选择。

论文笔记+模型实现TransNets: Learning to Transform for Recommendation

3.6 寻找最相似的(有用的)评论

这一小节讨论的是TransNets如何为用户找到最像其本人写的评论,从而做出更有根据的预测。举例说明,对一个关心服务质量和等待时间的用户最有帮助的评论,和对一个关心价格的用户最有用的评论,是不一样的。

设一个训练样本中,项目的所有评论中的一个评论为 r e v C Q revCQ revCQ,如果该评论非常接近用户A写给该项目的评论,那么其在目标网络的隐性表达(即 x C Q = Γ T ( r e v C Q ) x_{CQ}=\Gamma_T(revCQ) xCQ=ΓT(revCQ))跟源网络的 z L z_L zL应当是极为相似的(即欧几里得距离很近)。

使用pytorch实现TransNets模型

https://github.com/zhaojinglong/TransNets