深度学习在序列化推荐中的应用以及扩展
文章来源 http://kubicode.me/2018/09/19/Deep+Learning/GRU4REC-Session-Based-Recommendation/
前言
用户在互联网应用上的绝大部分的行为都是可以用一个序列来表示,比如购物、听音乐、看feed流等,用式子来表示就是:
{x_1,x_2,x_3,..,x_N} -> x_{N+1}
因此对于这个序列如何建模来获取整个用户的意图行为至关重要,而之前传统的ML只能基于统计或者经验的方式来尽量抽取这些序列信息,并无法hold整个序列,16年提出的 GRU4REC
利用 RNN-Based
对用户序列进行建模并且取得了不错的效果,同时也会有一些研究对于 GRU4REC
做了不少改进和扩展,本文主要对 GRU4REC
以及扩展做一些简答的自我了解和记录。
GRU4REC
GRU4REC
是Session信息和GRU结合起来完成了推荐,他给定的场景是:
用户在我们的应用上有一段行为
Session
(比如说点击item的需求),然后在于该Session信息来预测接下来可能会发生点击的item,而这笔的Session信息主要使用GRU
模型来进行刻画:
- 这边第一步的输入是用户的行为序列: [x_1,x_2,x_3,..,x_N]
- 这些行为序列可以接下来使用两种Embedidng表示,一种是
One-Hot
方式,另一种是在One-Hot
接下来过一个Embedding层 - 将所有的输入进行向量化表示之后,会过若干层的GRU(就是比较核心的序列化建模了)
- 完成序列化建模之后再进行一个
Feedforward
的网络转换 - 最终对下一个目标进行预测,这边的目标其实就是X_{N+1}
(作者说这种方式性能好,但是我到觉得这种场景下
One-Hot
不是很合适,One-Hot
在这边他的DIM会巨大,并且会特别的稀疏,可能还是查表的来的好)
其实 GRU4REC
的整个思路还是很清晰,模型也很简单,但是该算法中比较重要的应该是他的加速优化和LOSS的选择可能会有比较大的参考价值意义:
为了能提高训练的效率,采用两种策略来进行训练的优化:
-
使用
Mini-Batch
来进行训练:因为用户行为的Session有长有短,并且他的差异性很大,传统的滑窗方式来构建训练数据并不适用,他这里用的策略是将不同的
Session
给拼接了起来,在同一个序列中如果遇到下一次Session时,会将GRU中的向量参数给重新初始化掉,因为这边GRU是对Step进行预测,所以在序列中间直接初始化掉问题也不大,这样还可以提升数据的利用率,会比简单PADDING
的方式更加的合适。 -
取巧的训练数据采样:
原始的模型中是需要过softmax对于每个item都计算才能对目标的item进行训练,因为item的维度非常高,所以这里的计算量是超级大的。作者在这里比较机智的在目标的样本中根据
热门
程度进行了采样,采样完成之后将同一个mini-batch
中但是是其他Session
的next-item作为负样本。用这些正负样本来训练整个神经网络。下面这个图对于采样非常形象了:
因此这个模型现在已经转为对正负样本的一个 0-1
分类的问题,而且推荐里面,并不存在绝对的正负样本,用户也可能会对多个item存在偏好,所以这边比较合适 Loss Function
就是用 Pair-Wise
的模式了(只需要 正样本的score大于负样本即可):
BPR(Bayesian Personalized Ranking)
:这是一种基于矩阵分解的损失函数,他的式子是:
N_s是样本量的大小,\hat{r}_{s,i}表示正样本的分数,\hat{r}_{s,j}表示负样本的分数。
TOP1
:这是种基于正则化方式的损失函数
这种方式可以将\hat{r}_{s,i}的分数计算的更高,但是他同是也会是负样本,所以这边加了二范数来压制\hat{r}作为负样本时的分数
GRU4REC
的实验结果也是蛮简单的,Baseline的实验不在这个表中,数据后面跟着的涨幅就是和Baseline的对比:
这边显示的也是 BPR
和 TOP1
这两种LOSS的效果会明显好于传统的交叉熵.
GRU4REC
是较早的将序列行为和GRU进行结合,其中 LOSS
这块的构建还是非常值得借鉴的。
该作者还开放了源码 https://github.com/hidasib/GRU4Rec
GRU4REC-Sampling
其中
GRU4REC-Sampling
和GRU4REC
是同一个作者 ^_^
GRU4REC-Sampling
也是在基于 GRU4REC
上的缺陷提出了额外的 Sampling
和新的 Loss Function
作者认为 GRU4REC
存在下面三种局限:
BatchSize
一般都是比较小的,在总样本较多时,如果采样少的话,分数比较高的负样本被采样进来的概率就偏少了(这里高分数要用于下面的Loss)BatchSize
会影响运行速度,但是由于设计的是Mini-Batch
并行的方式,所以增加BatchSize
也不会对速度有多大的影响- 虽然
GRU4REC
用的是根据热度采样,但是实际中全根据热度也不一定适应所有数据集
所以在 GRU4REC-Sampling
中又进行了额外的采样:同样是在 Mini-Batch
中进行采样,采样时根据这个公式supp_i^\alpha,而这边的a是一个 0~1
的值,如果a=0表示均匀采样,那么a=1为完全的热门采样。
另外 GRU4REC
中的 BPR
和 TOP1
会存在梯度的消失问题,因此作者设计了一种新的损失函数希望来最大化正样本的分数:
从这儿可以看出,新的损失函数是对 Max-Score
的负样本做pair,但是这种是不可求导了,所以作者用了一种近似的方式来实现,刚刚对 Max-Score
做负样本的方式可以转为 Score
越大,则 Loss
中的权重也越大,而这个权重可以用归一化的 softmax
来表示:
有了每个样本的权重表示之后,原先的 Loss Function
可以更改为:
-
TOP1-MAX
: -
PR-max
:
对比一下 GRU4REC
中的 Loss Function
,其实就是额外增加了一个s_j的权重值。
看下实验对比,额外的 Sampling
和新的 Loss Function
都还是有极大的提升的,惊呆。
我个人感觉
Sampling
起这么大的作用应该是采样之后样本不足了,这是一个训练时间和模型性能上的权衡,那么我如果不采样是不是效果就更好了-_-!!
GRU4REC-DWell
GRU4REC-DWell
也是基于 GRU4REC
的一个简单的改进,其中 GRU4REC
已经证明在时序的推荐中序列化的建模非常有用。
另外作者认为在用户行为序列中,每个item的停留时间是非常重要的一个特征,而之前的 GRU4REC
算法只是用于简单的交互行为来构建样本,所以 GRU4REC-DWell
主要是很巧妙将用户在序列item上的停留时间和GRU4REC 结合了起来:
这里主要的Idea就是在原始的用户行为中,作者根据item上面的停留时间根据阈值进行切片,如果停留时间长的可能会有很多个切片,每个切片都作为一个新的行为项:
给定一个行为序列的集合X=\{x_1,x_2,…,x_n\},每一个x_i对应的停留时间为dt_i,其中t为切片的阀值,则x_i可以分割的切片为d_t/t + 1。 也就是如上图所示,i_2,1就由于停留时间较久,所以分割成了三个切片。然后其他的就如原始的 GRU4REC
一样了,但是作者在做对比实验室加入了 GRU4REC-SAMPLING
进行了一起对比:
实验中显示,停留时间信息的加入对于模型的作用是非常巨大的。
HRNN
用户往往会存在多段不连续的Session(比如逛淘宝时,早上公交逛一次,中午午睡时逛一次,晚上睡前逛一次,这样就有三段Session序列,每一段内部是连续的),而之前的模型都是将这些Session行为都是独立训练的,文本中作者认为同一用户的不同Session间是有关联的,建模每一段Session可以发现用户的衍化。
所以作者提出了一种层次化的RNN序列建模,在每一段的 Session-Level
内部使用RNN建模的同时,会有一个 User-Level
的RNN来建模当前用户跨Session的行为,而 User-Level
的RNN的输入就是每一段 Session-Level
的final state。
用户的所用行为表示为
C^u = \{ S_1^u,S_2^u,…S_{M_u}^u \}
S_m^u代表一次完整的Session,其中S_m^u代表对应 Session
的 Representations
(也就是最终一个final state),则 User
级别的 Representations
为
c_m = GRU_{usr}(s_m,c_{m-1}),m = 1,…,M_u
所以这边 HRNN
的整个层次结构如图所示:
- 上面一层代表
Session-Level
的RNN,输入的是item,会对next basket
进行预测,同时输出final state
- 下面一层代表
User-Level
的RNN,输入的是Session-Level
的final state
,用户维护当前用户在整个应用的行为建模,并且会将当前Session的state输出作为下一次Session的init state
主要对比的是原生的 GRU4REC
,性能大约有10%左右的提升,但是用的数据和 GRU4REC-Sampling
以及 GRU4REC-DWell
的不一样,感觉没有他们的提升多,并且在现实过程中,对于 Session
的划分也是需要很多的 trick
啊。
总结
其实 GRU4REC
在DL中是一个非常 straight-forward
的框架,但是他的厉害之处就是设计了 Mini-Batch
和 Sampling
将整个模型跑了起来并且起到了一定的效果,另外后面的几个改进中停留时间的改进以及层次的 Session
还是比较不错,并且可实用性高一些。
参考
- Hidasi, Bal�
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/geek/post/%E4%BA%92%E8%81%94%E7%BD%91/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E5%9C%A8%E5%BA%8F%E5%88%97%E5%8C%96%E6%8E%A8%E8%8D%90%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8%E4%BB%A5%E5%8F%8A%E6%89%A9%E5%B1%95/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com