深度学习在序列化推荐中的应用 (1)-GRU4REC 以及扩展



转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com

AIQ 机器学习大数据 知乎专栏 点击关注

文章来源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模型来进行刻画:

  1. 这边第一步的输入是用户的行为序列:$ [x_1,x_2,x_3,..,x_N]$
  2. 这些行为序列可以接下来使用两种 Embedidng 表示,一种是One-Hot方式, 另一种是在One-Hot接下来过一个 Embedding 层
  3. 将所有的输入进行向量化表示之后,会过若干层的 GRU(就是比较核心的序列化建模了)
  4. 完成序列化建模之后再进行一个Feedforward的网络转换
  5. 最终对下一个目标进行预测, 这边的目标其实就是 $X_{N+1}$

( 作者说这种方式性能好,但是我到觉得这种场景下One-Hot不是很合适,One-Hot在这边他的 DIM 会巨大,并且会特别的稀疏, 可能还是查表的来的好 )

其实GRU4REC的整个思路还是很清晰,模型也很简单,但是该算法中比较重要的应该是他的加速优化和 LOSS 的选择可能会有比较大的参考价值意义:

为了能提高训练的效率,采用两种策略来进行训练的优化:

  1. 使用Mini-Batch来进行训练:

    因为用户行为的 Session 有长有短,并且他的差异性很大,传统的滑窗方式来构建训练数据并不适用,他这里用的策略是将不同的Session给拼接了起来,在同一个序列中如果遇到下一次 Session 时,会将 GRU 中的向量参数给重新初始化掉,因为这边 GRU 是对 Step 进行预测,所以在序列中间直接初始化掉问题也不大,这样还可以提升数据的利用率,会比简单PADDING的方式更加的合适。

  2. 取巧的训练数据采样:
    原始的模型中是需要过 softmax 对于每个 item 都计算才能对目标的 item 进行训练,因为 item 的维度非常高,所以这里的计算量是超级大的。作者在这里比较机智的在目标的样本中根据热门程度进行了采样,采样完成之后将同一个mini-batch中但是是其他Session的 next-item 作为负样本。用这些正负样本来训练整个神经网络。下面这个图对于采样非常形象了:

因此这个模型现在已经转为对正负样本的一个0-1分类的问题, 而且推荐里面,并不存在绝对的正负样本,用户也可能会对多个 item 存在偏好,所以这边比较合适Loss Function就是用Pair-Wise的模式了 (只需要 正样本的 score 大于负样本即可):

  1. BPR(Bayesian Personalized Ranking): 这是一种基于矩阵分解的损失函数,他的式子是:

9c6911dea21b4e58b15d9fef5e419c04.png

$N_s$ 是样本量的大小,$\hat{r}{s,i}$ 表示正样本的分数,$\hat{r}{s,j}$ 表示负样本的分数。

  1. TOP1: 这是种基于正则化方式的损失函数

519c1186e4114386becb8aeea2972b66.png

这种方式可以将 $\hat{r}_{s,i}$ 的分数计算的更高,但是他同是也会是负样本,所以这边加了二范数来压制 $\hat{r}$ 作为负样本时的分数

GRU4REC的实验结果也是蛮简单的,Baseline 的实验不在这个表中,数据后面跟着的涨幅就是和 Baseline 的对比:

这边显示的也是BPRTOP1这两种 LOSS 的效果会明显好于传统的交叉熵.
GRU4REC是较早的将序列行为和 GRU 进行结合,其中LOSS这块的构建还是非常值得借鉴的。

该作者还开放了源码https://github.com/hidasib/GRU4Rec

GRU4REC-Sampling

其中GRU4REC-SamplingGRU4REC是同一个作者 ^_^

GRU4REC-Sampling也是在基于GRU4REC上的缺陷提出了额外的Sampling和新的Loss Function
作者认为GRU4REC存在下面三种局限:

  1. BatchSize一般都是比较小的,在总样本较多时,如果采样少的话,分数比较高的负样本被采样进来的概率就偏少了(这里高分数要用于下面的 Loss)
  2. BatchSize会影响运行速度,但是由于设计的是Mini-Batch并行的方式,所以增加BatchSize也不会对速度有多大的影响
  3. 虽然GRU4REC用的是根据热度采样,但是实际中全根据热度也不一定适应所有数据集

所以在GRU4REC-Sampling中又进行了额外的采样: 同样是在Mini-Batch中进行采样,采样时根据这个公式 $supp_i^\alpha$,而这边的 $a$ 是一个0~1的值,如果 $a=0$ 表示均匀采样,那么 $a=1$ 为完全的热门采样。
另外GRU4REC中的BPRTOP1会存在梯度的消失问题,因此作者设计了一种新的损失函数希望来最大化正样本的分数:

8734ff1ae76f48f7b4984ccf625bf280.png
从这儿可以看出,新的损失函数是对Max-Score的负样本做 pair,但是这种是不可求导了,所以作者用了一种近似的方式来实现, 刚刚对Max-Score做负样本的方式可以转为Score越大,则Loss中的权重也越大,而这个权重可以用归一化的softmax来表示:
186a1a67ab914409a428abea42684b0a.png

有了每个样本的权重表示之后,原先的Loss Function可以更改为:

  1. TOP1-MAX:
    1fba33e970cb49fea9d7c318ef99f66f.png

  2. PR-max:
    fddc4524b6fe45a385017efed331d55f.png

对比一下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$ 代表对应SessionRepresentations(也就是最终一个 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-Levelfinal state,用户维护当前用户在整个应用的行为建模,并且会将当前 Session 的 state 输出作为下一次 Session 的init state


主要对比的是原生的GRU4REC,性能大约有 10% 左右的提升,但是用的数据和GRU4REC-Sampling以及GRU4REC-DWell的不一样,感觉没有他们的提升多,并且在现实过程中,对于Session的划分也是需要很多的trick啊。

总结

其实GRU4REC在 DL 中是一个非常straight-forward的框架,但是他的厉害之处就是设计了Mini-BatchSampling将整个模型跑了起来并且起到了一定的效果, 另外后面的几个改进中停留时间的改进以及层次的Session还是比较不错,并且可实用性高一些。

参考

  1. Hidasi, Balázs, et al. “Session-based recommendations with recurrent neural networks.” arXiv preprint arXiv:1511.06939 (2015).
  2. Hidasi, Balázs, and Alexandros Karatzoglou. “Recurrent neural networks with top-k gains for session-based recommendations.” arXiv preprint arXiv:1706.03847 (2017).
  3. Bogina, Veronika, and Tsvi Kuflik. “Incorporating dwell time in session-based recommendations with recurrent Neural networks.” CEUR Workshop Proceedings. Vol. 1922. 2017.
  4. Quadrana, Massimo, et al. “Personalizing session-based recommendations with hierarchical recurrent neural networks.” Proceedings of the Eleventh ACM Conference on Recommender Systems. ACM, 2017.

更多高质资源 尽在AIQ 机器学习大数据 知乎专栏 点击关注

转载请注明 AIQ - 最专业的机器学习大数据社区  http://www.6aiq.com