阿里深度召回模型实践

召回结果的好坏对整个推荐结果有着至关重要的影响 , 最近的一系列实践和研究表明 , 基于行为序列的深度学习推荐模型搭配高性能的近似检索算法可以实现既准又快的召回性能;与此同时 , 用户在天猫精灵上还可以进行实时指令操控 , 利用丰富的反馈信息改进召回模型的性能 。
01
背景
传统的推荐系统通常由两部分构成 , 分别是 Candidate Generation(候选生成)和 Ranking(排序) , 以下图中经典的 YouTube 视频推荐为例[1] , 整个系统分为了两层:第一层是 Candidate Generation(候选生成) , 负责从全量的视频中快速筛选出几百个候选视频 , 这一步通常也被成为 Matching(召回);第二层是 Ranking(排序) , 负责对几百个视频进行精准打分并重新排序 , 决定最终向用户展示的结果顺序 。
阿里深度召回模型实践文章插图
图 1 YouTube 视频推荐
本文主要研究 Matching(召回)部分 , 这部分通常面对的是整个推荐 item 集合 , 既要尽可能多的保留相关性高的结果 , 又要保证速度 , 召回结果的好坏对整个推荐结果有着至关重要的影响 。 最近的一系列实践和研究表明 , 基于行为序列的深度学习推荐模型[2-4]搭配高性能的近似检索算法[5]可以实现既准又快的召回性能(这套方案通常被称为DeepMatch) , 和传统的召回方法相比(比如 swing、etrec、SVD) , DeepMatch 的优势主要如下:

  • 可以建模 user-item 间更深层次的非线性关系
  • 可以在模型中使用各种 user 和 item 的特征
  • 基于行为序列的模型可以建模用户不断变化的兴趣 , 并且能够融合用户的长短期兴趣
DeepMatch 已经广泛应用于天猫精灵推荐场景中(APP 信息流推荐、音乐推荐等)并取得了比传统 i2i 方法更好的效果 , 但目前的模型仍存在着一些问题 , 有一些关键的信息还未引入进来(以“我要听歌”场景为例 , 在这个场景中天猫精灵会根据用户的喜好来给用户推荐音乐):
负向反馈信号(Play Rate)
初始训练日志数据中仅包含正向反馈 , 也即使用播放完成率高的歌曲序列训练 DeepMatch 模型 。 而在天猫精灵的场景中 , 用户有主动切歌的行为 , 如主动的“停止播放”、“下一首” , 其中大部分这类型是用户在出现不喜欢的歌曲时触发 , 这些信号可以作为用户的负反馈加入到模型中 。 而且一些实践已经表明了负向反馈的作用[6-7] , 如果能将这些信号有效的利用起来 , 模型有能力去捕捉用户时刻变化兴趣 , 在用户进行切歌行为时 , 减少同类型的音乐推荐 。 在这个场景中 , 我们用每首歌曲的播放完成率来表示用户反馈 , 完播率较大即为正反馈 , 完播率较小即为负反馈 。
歌曲点播 query 意图信号(Intent Type)
天猫精灵歌曲的播放大部分由用户的 query 点播而来 , 每一首歌曲背后都有用户的点播意图 , 天猫精灵背后有一套专门的歌曲 query 意图解析 , 比如精确点播(歌名点播:“播放七里香”、歌手点播:“我要听刘德华的歌曲”)、推荐(风格流派推荐:“来点摇滚”、随便听听推荐:“放歌”) 。 通过对用户行为的分析来看 , 不同意图类型下的歌曲对于推荐模型贡献的权重是不同的 , 在模型中融入歌曲对应的意图 attention , 能更准确把握用户的兴趣 。 因此本文提出了一种基于多任务学习和负反馈的深度召回模型 。
02
方法
总体来说 , 由于近似最近邻检索算法的限制 , 我们的召回模型需要独立地对用户历史行为序列进行编码以生成用户的每一步的向量表示 , 然后再和 Target Item 向量做内积运算 , 得到打分 , 模型基于 Self-Attention 的架构来实现 , 总体结构如下:
阿里深度召回模型实践文章插图
图 2 模型总体结构
1. Input Representations
如前所述 , 为了建模负向反馈信号和用户意图类型信号 , 我们的模型引入了对 Play Rate 和 Intent Type 的表示 。 但初始数据集不包含这两种信号 , 因此我们用 Train Set 1 来表示初始数据集 , Train Set 2 表示带有负向反馈信号和用户意图类型信号的数据集 , 我们对它们做了统一的表示 。 总的来说 , 用户历史行为序列中的每个 Item 的表示由如下四部分构成:
① Item Embedding
我们首先把每个 Item 嵌入到固定大小的低维向量中 , Train Set 1 和 Train Set 2 共用一套 Item Vocabulary , 不需要做区分:
其中 , Xi 为 Item 的 One-Hot 表示 , Vi是 Item Embedding 矩阵 , 另外需要注意的是输出层和输入层共用一套 Item Embedding , 这样做的目的主要是节省显存占用空间 , 因为推荐场景的 Item 数量是巨大的 , 而且有很多工作已经证明了这样的做法对于模型性能影响不会很大[2] 。