论文笔记 - Wide & Deep Learning for Recommender Systems

1,496 阅读8分钟

这篇 paper 讲道理也 delay 很久了~最近终于又抽了点时间重新看了一下这篇 paper~看这篇 paper 的背景是因为目前我所负责的推荐项目所使用的模型和 wide&deep 这个模型的背景非常非常相似~基本都是线性模型作为 wide 模型,隐性模型作为 deep 模型,比如我们模型 deep 部分目前使用的是 embedding-based 模型,FM,而这篇 paper 是在 deep 这部分使用了神经网络。

先推荐一波自己之前的分享~

亿级用户个性化品类推荐实战

然后,放上 paper 地址~

Wide &Deep Learning for Recommender Systems

这篇 paper 的核心就是结合 wide 模型和 deep 模型,最终的组合模型可以达到有效的记忆和归纳。

Introduction

paper 中将推荐系统视作了一个检索系统,输入的查询条件是用户和上下文信息,输出是一个有序的推荐列表。当给定一个查询时,推荐系统的任务是:

  1. 从数据库中找到与查询条件相关性最强的推荐内容
  2. 然后将查询出的内容根据一定条件进行排序,比如点击或购买

如何同时实现记忆和归纳在推荐系统和检索系统中都是一个挑战~简单来说,记忆就是通过学习历史数据中频繁出现的品类或特征的共现,归纳是通过相关性传递并且探索历史数据中从未出现过的特征组合。基于记忆的推荐系统通常更有针对性,与用户历史的行为相关性更强。与记忆相比,归纳更倾向于改善推荐内容的多样性。在这篇 paper 中,更专注于 Google play 应用商店的应用推荐问题,但是这个研究同样适用于普通推荐系统。

大规模的在线推荐系统,LR 这样的线性模型非常常用,因为简单并且可解释性强,但是线性模型无法学习到没有出现过的特征组合,需要人工特征工程。

而 embedding-based 模型,比如 FM 或者神经网络,可以通过学习每一次 query 中低维的向量来泛化之前没有出现过得特征组合。但是,当数据稀疏且高维的时候,是很难学习到有效的低维向量的。

Recommender System Overview

上图给出了一个推荐系统的架构,整体由上一节说到的两部分组成,检索系统和排序系统,当用户访问 APP store 的时候视作一次查询,包含用户和上下文的特征,然后检索这部分会根据用户的偏好行为,比如点击、购买,返回用户最感兴趣的 APP 列表。同时,这一次的用户行为会记录在日志中作为训练数据。

目前数据库中已有的 APP 已经数以百万计,所以如果每一次查询的时候都计算用户对每个 APP 的 score,这样是不现实的。因此,第一步应该是挑选召回集。检索也就是召回系统会返回与当前用户最匹配的很少的 APP 列表,这里的检索通常会结合机器学习模型和人工定义规则的两种方法,召回最佳候选集后,再使用排序系统对每个 APP 进行 score 的计算和最终排序。这里计算出的 score 通常是P(y|x),即当给定特征 x,用户行为的概率,这里的 y 是用户的行为,即 label,这里的 x 为特征,包括

  • user feature
    • country,language,demographics
    • 即用户特征
  • Contextual feature
    • device,hour of the day,day of the week
    • 即上下文特征
  • Impression feature
    • app age,historical statistics of an app
    • 即 APP 统计特征

Wide & Deep Learning

在介绍中说到,这篇 paper 的核心点就在于,结合了 wide model 和 deep model,一个用作记忆,一个用作归纳泛化,结合各自的优势行程了 Wide&Deep 模型用于推荐排序。

Wide Model

上图的左半部分就是组合模型中的 wide model,这部分使用的模型是 LR,这部分主要用作学习样本中特征的共现性,产生的结果是和用户有过直接行为的 item,线性模型表达如下,

y = \mathbf{w}^T \mathbf{x} + b

其中 y 是预测的概率,x 是表示特征的向量,w 表示模型的参数,也就是最终训练出来的每个特征向量的权重,b 是 bias 项,也就是常数项。

在这部分特征使用 one-hot 编码,为了达到记忆的目的,对稀疏的特征采用了 cross-product transformation,表达如下

\phi_k(\mathbf{x}) = \prod_{i = 1}^d x_i^{c_{k_i}}\quad c_{k_i} \in {0, 1}

比如对于“AND(gender=female, language=en)”这个特征,当且仅当这个用户的性别为 female,语言为 en 的时候,这个特征值才为 1,其他情况都为 0。这个操作,增加了二元特征之间的相互作用,并且为线性模型增加了非线性因素。

Deep Model

图中的右半部分也就是组合模型中的 deep model,这部分使用的是前馈神经网络。对于分类特征,特征输入通常是 string,比如"language=en",这样的高维分类特征首先会被转换成一个低维的且密集的实数向量。向量的维数通常在O(10)到O(100)之间,这些向量一般使用随机的方法进行初始化,随机可以均匀随机也可以随机成正态分布,随机初始化的目的是将向量初始化到一个数量级,在训练过程中通过最小化损失函数来优化模型。然后将这些低维向量传入到神经网络的隐层中去。

每个隐层中都做这样的计算,

a^{(l+1)} = f(W^{(l)}a^{(l)} + b^{(l)})

其中,l 是层数,f 是激活函数,通常使用 ReLU。

通常情况下这部分特征使用的是用户行为特征,用于学习历史数据中不存在的特征组合。

组合训练

对于两个模型的输出分别计算比值比,然后取 log 后加权求和作为最终的 score。

区分 ensemble 和 joint\quad training

  • Emsemble 表示两个模型分别独立训练,只有在最终预测的时候才将两个模型组合计算
  • Join training 通过在训练的时候同时考虑 wide model 和 deep model 以及两个部分拼接起来的特征的权重来同时优化所有参数

同时,这两种训练的区别在模型大小上也有所体现,单独训练的模型会更大一些。wide&deep model 使用 mini-batch stochastic optimization 进行训练,在实验中,wide model 使用了 FTRL+L1 正则,而 deep model 使用了 AdaGrad。

对于 LR,模型预测如下,

P(Y = 1|\mathbf{x}) = \sigma(\mathbf{w}^T_{wide}[\mathbf{x},\phi(\mathbf{x})] + \mathbf{w}^T_{deep}a^{(l_f)}+b)

其中,Y 是二分类的 label,\sigma 表示 sigmoid 函数,\phi(\mathbf{x})表示原始特征\mathbf{x} cross product transformations,b 表示 bias 项,\mathbf{w}_{deep} 表示最终激活 a^{(l_f)} 的权重。

System Implementation

应用推荐的 pipline 主要包含三个阶段:数据生成,模型训练和模型服务,如下图,

数据生成

在这部分,选取一个时间周期内用户和 APP 数据作为训练数据。

Label:应用下载,当应用被下载,则为 1,否则为 0

Vocabularies:将类别特征映射为整型 ID,连续的实数特征先映射到 CDF,然后再做离散化。

模型训练

模型结构如图,

在训练过程中,我们输入的隐层获取训练数据和 vocabularies,生成稀疏和密集的特征并与 label 进行拼接。wide 部分包含用户展示和安装 APP 的 cross-product transformation,deep 部分,每个分类特征都是一个 32 维的向量进行学习。我们将所有 embedding 和密集的特征连接在一起,形成一个约为 1200 维的密集向量。然后将连接的向量输入3个 ReLU 层,最后输入到逻辑输出单元。

在这部分需要注意的点是,如果每一次都重新训练的话,时间成本很高,所以为了解决这个问题,当新的训练数据来的时候,我们使用热启动,方法是从之前的模型中读取 embeddings 和线性模型的权重来初始化新模型。同时,我们会使用之前的模型进行及安装检查,保证在接入实时流的时候不会出现问题。

模型服务

为了保证每个请求都可以在 10 ms 内返回结果,我们通过多线程并行运行来优化性能,而不是单个 batch 内对所有候选集的 score 进行计算。

总结

整体上来讲,这篇 paper 的模型适用的场景很广泛,目前也有很多公司都在用 wide&deep,可用性很强~