五、Wide&Deep

  1. 推荐系统中的一个挑战是:同时实现 memorizationgeneralization

    • memorization:学到 item 或者 feature 共现关系,并基于历史数据中的这种相关性来推荐。

      基于memorization 的推荐通常更具有话题性,并且和用户已经发生行为的 item 直接关联。

    • generalization:根据 item 或者 feature 的共现关系,探索过去从未发生或者很少发生的新特征组合。

      基于 generalization 的推荐通常更具有多样性。

  2. 广义线性模型通常对特征执行 one-hot 编码。如 性别=男 表示特征:如果用户是 男性,则该特征为 1 。

    • 通过特征交叉可以有效的达到 memorization。如特征交叉 AND(性别=男,曾经购买汽车=奇瑞QQ) :当用户是男性、且曾经购买奇瑞 QQ 汽车时该交叉特征为 1。

    • 如果希望提升泛化能力,则可以提升特征的粒度。如: AND(性别=男,曾经购买汽车=10万以下汽车)

      这种方式的限制是无法推广到训练集中没有出现过的 query-item 或者 feature pair

  3. 基于 embedding 的模型(如 FM 或者 DNN )为每个 queryitem 学习一个低维的 dense embedding 向量,通过 embedding 向量来泛化到训练集中未见过的 query-item feature pair ,同时也缓解了特征工程的代价。

    但是当 query-item 矩阵非常稀疏且矩阵的秩较高时(如:用户具有特定偏好,产品非常小众),很难学到有效的 query/item 的低维表达。

    此时大多数 query-item pair 之间不应该存在任何交互,但是 dense embedding 仍然给出了非零的预测结果。这会导致严重的过拟合,并给出一些不怎么相关的推荐结果。

    在这种场景下,基于特征交叉的广义线性模型能够记住这些特定偏好或者小众产品的 exception rule

  4. 广义线性模型(称为 wide 模型)可以通过大量交叉特征来记住特征交互 feature interaction ,即 memorization 。其优点是可解释性强,缺点是:为了提升泛化能力,需要人工执行大量的特征工程。

    深度神经网络模型(称为 deep 模型)只需要执行较少的特征工程即可泛化到未出现的特征组合,即 generalization 。其优点是泛化能力强,缺点是容易陷入过拟合。

    论文 “Wide & Deep Learning for Recommender Systems” 结合了 wide 模型和 deep 模型,同时实现了 memorizationgeneralization

    即:广义线性模型表达能力不强,容易欠拟合;深度神经网络模型表达能力太强,容易过拟合。二者结合就能取得平衡。

5.1 模型

  1. 一个典型的推荐系统整体架构如下图所示。推荐的流程如下:

    • 当用户访问 app store 时产生一个 query,它包含用户特征(如用户画像)和上下文特征(如 当前时刻LBS 信息、设备信息、页面信息)。

    • 检索 retrieval 模块根据用户的 query 返回一组相关 app 组成的 app list

      检索算法可以综合利用机器学习模型和人工定义的规则,它用于将百万级别的 app 集合降低到几百上千级别的候选 app list

    • 精排 ranking 模块对候选 app list 根据用户的行动(如:下载、购买)概率进行排名,返回概率最高的十几个或者几十个 app 组成的推荐结果。

    • 返回的推荐结果展示在用户界面,用户可以对这些 app 执行各种操作(如:下载、购买)。这些操作行为,以及query, result app list 都会被记录并发送到后台日志作为训练数据。

    五、Wide&Deep - 图1

  2. Wide & Deep 模型主要用于 ranking 精排模块,它包含一个 linear model:LM 部分和一个 neural network:NN 部分。

    设模型的输入特征向量为 五、Wide&Deep - 图2 是一个 五、Wide&Deep - 图3 维的特征向量(经过 one-hot ),仅包含原始特征。五、Wide&Deep - 图4 表示特征交叉转换函数,五、Wide&Deep - 图5 包含转换后的特征。

    • LM 部分:即左侧的 wide 子模型,它是一个线性模型:

      五、Wide&Deep - 图6

      其中 五、Wide&Deep - 图7 表示特征拼接, 五、Wide&Deep - 图8 是模型参数( 五、Wide&Deep - 图9 表示交叉特征的数量), 五、Wide&Deep - 图10 为偏置。

    • NN 部分:即右侧的 deep 子模型,它是一个 DNN 模型。

      • 输入层:为了缓解模型的输入大小,DNN 的所有离散特征的输入都是原始特征,而没有经过 one-hot 编码转换。

      • 第一层 embedding 层:将高维稀疏的 categorical 特征转换为低维的 embedding 向量。论文中的embedding 向量维度为 32 维。

      • 第二层特征拼接层:将所有的 embedding 向量拼接成一个 dense feature 向量。论文中该向量维度为 1200维。

      • 后续每一层都是全连接层:

        五、Wide&Deep - 图11

        其中 五、Wide&Deep - 图12 为层的编号,五、Wide&Deep - 图13 为激活函数。

    模型联合了 widedeep 的输出:

    五、Wide&Deep - 图14

    其中 五、Wide&Deep - 图15wide 部分的权重, 五、Wide&Deep - 图16deep 部分的权重, 五、Wide&Deep - 图17 为全局偏置。

    模型的损失函数为负的对数似然,并通过随机梯度下降来训练:

    五、Wide&Deep - 图18

    五、Wide&Deep - 图19

  3. Wide&Deep 模型与 LM & DNNensemble 集成模型不同。

    • 在集成模型中,每个子模型都是独立训练的,只有预测时才将二者结合在一起。

      Wide&Deep 模型中,每个子模型在训练期间就结合在一起,共同训练。

    • 在集成模型中,每个子模型必须足够大从而足够健壮,使得子模型集成之后整体的 accuracy 等性能足够高。

      Wide&Deep 模型中,每个子模型都可以比较小,尤其是 wide 部分只需要少量的特征交叉即可。

  4. Wide&Deep 模型的实现如下图所示。模型的 Pipeline 分为三个部分:

    • 数据生成 data generation 阶段:此阶段把一段时间内的用户曝光数据生成训练样本,每个样本对应一次曝光,标签为用户是否产生行为(如:下载 app)。

      在这个阶段执行两个特征工程:

      • 离散的字符串特征(如app name)映射成为整数ID ,同时生成映射字典vocabulary

        注意:对于出现次数低于指定阈值(如 10此)的字符串直接丢弃,这能够丢弃一些长尾的、罕见的字符串,降低字典规模。

      • 连续特征离散化:

        • 首先将连续特征归一化到 0~1 之间,它通过累积分布函数来归一化,计算特征的整体排名(1.0表示排名最高,0.0表示排名最低)

          五、Wide&Deep - 图20

          其中 五、Wide&Deep - 图21 为示性函数,五、Wide&Deep - 图22 为总样本数量。

        • 然后将 五、Wide&Deep - 图23 映射到 五、Wide&Deep - 图24 分位。如映射到10分位时,假设 五、Wide&Deep - 图25 (即排名在最高的 5%),则映射为 9 这个等级。

    • 模型训练 model training 阶段:此阶段的输入为样本数据、字典数据、标签数据。

      • wide 部分的特征由:用户已经安装的 app 、给用户曝光的 app 的两个特征的交叉组成。

      • deep 部分从每个离散特征中学习。

      • 每次有新的训练数据到达时,模型会利用该部分数据重新训练。

        由于重新训练模型的代价太大,因此我们实现了一个 warm-starting 系统:基于前一个模型的 embedding五、Wide&Deep - 图26 参数来初始化当前模型的这两个参数。

      • 在模型部署到线上之前,还需要验证模型的质量。

    • 模型使用 model serving 阶段:训练并验证模型后,将模型部署到服务器上来提供预测服务。

      为满足 10ms 量级的响应速度,采用多线程并行来优化性能。方法为:假设一个 batch500 个候选 app

      • 先将其拆分为更小的一组 batch:如 50batch,每个 batch10 个候选 app
      • 每个子线程并行的执行推断
      • 将所有子线程的推断结果收集在一起,拼接成整个 batch 的推断结果并返回

    五、Wide&Deep - 图27

5.2 实验

  1. 模型从谷歌应用商店的 app 下载量,以及 serving 性能这两方面来评估。

  2. 我们执行三个星期的在线A/B test,其中:

    • 对照组1:随机抽取 1% 的用户,该部分用户采用旧的精排模型:只有 wide 部分的、采取大量特征交叉的 LR 模型。
    • 对照组2:随机抽取 1% 的用户,该部分用户采用 DNN 精排模型:只有 deep 部分的 DNN 模型。
    • 实验组:随机抽取 1% 的用户,该部分用户采用 Wide&Deep 精排模型。

    另外我们还在一个离线的留出 holdout 数据集上评估了这三个模型的离线 AUC 指标。最终结果如下表:

    • 在线 app 下载量提升:Wide&Deep 提升幅度较大,达到 3.9%

      事实上仅 deep 模型就能提升 2.9%,但是结合了 widedeep 能进一步提升。

    • 离线 AUC 提升:Wide&Deep 稍微有所提升,但提升幅度不大。

      可能的原因:离线评估固定了曝光和 label,即:你给用户推荐的 app list 是固定的,用户是否安装的 label 也是固定的。

      这种假设实际上是有问题的,因为如果模型发生变化则推送给用户的 app list 会有所变化,是否安装的 label 也会有所变化。这使得 模型 --> 特征、label --> 模型 相互依赖。而离线的数据集无法体现这种模型和数据的相互依赖性。

      在线 A/B test 中,模型学习从用户最新的反馈中学习,然后推荐出新的 app list

    五、Wide&Deep - 图28

  3. 谷歌应用商店面临高流量,因此提供高吞吐量、低延迟的model serving 服务是一个挑战。在流量峰值,我们需要每秒为 1000万app 打分。

    • 当使用单线程时,一个 batch 的样本打分需要 31ms
    • 当使用多线程并行时,一个 batch 的样本拆分到多个更小的 batch,最终打分需要 14ms

    五、Wide&Deep - 图29