返回介绍

数学基础

统计学习

深度学习

工具

Scala

十三、Applying Deep Learning To Airbnb Search [2018]

发布于 2023-07-17 23:38:24 字数 25822 浏览 0 评论 0 收藏 0

  1. Airbnbhome sharing platform 是一个双边市场,其中房东host 可以出租他们的空间(称作listings ),以供来自世界各地的潜在租客guest 预订。典型的预订开始于租客在 airbnb.com 上搜索特定地理位置的房屋。search ranking 任务是从库存中的成千上万个listing 中挑选一个有序的 listing 列表来响应租客。

    search ranking 的第一个实现是手动制作的评分函数scoring function 。用梯度提升决策树gradient boosted decision tree: GBDT 模型代替手动评分函数是 Airbnb 历史上房屋预订量方面最大的改进之一,随后还有多次成功的迭代。在线预订量的收益最终饱和,其中很长一段时间的实验都是中性的(即没有提升)。这为尝试对系统进行全面改造提供了时机。

    从这一背景出发,论文 《Applying Deep Learning To Airbnb Search》讨论了作者将互联网上的一个大规模搜索引擎之一切换为深度学习的经验。本文针对是拥有机器学习系统、并开始考虑神经网络的团队。论文的目的并不是推进前沿的、新的建模技术,而是讲述了如何将神经网络应用于现实产品。

    • 首先,论文对模型体系结构随着时间的演变进行了总结。
    • 然后,论文给出了特征工程feature engineering 和系统工程 system engineering 的注意事项。
    • 最后,论文描述了一些工具和超参数探索。
  2. Airbnbsearch ranking 模型是模型生态系统的一部分,所有这些模型都有助于决定向租客展示哪些listing 。这些模型包括:预测房东接受租客预订请求可能性的模型、预测租客将旅行体验评为五星好评5-star的概率的模型等等。论文目前的讨论集中在这个生态系统中的一个特定模型上,并且被认为是排序难题ranking puzzle 中最复杂的一块。这个模型负责根据租客预订的可能性来对可用的 listing 进行排序。

    典型的租客搜索会话search session 如下图所示。

    • 租客通常会进行多次搜索,点击一些 listing 从而查看它们的详情页。
    • 成功的 session 以租客预订一个listing 而结束。

    租客的搜索以及他们和产品的交互被作为日志而记录下来。在训练期间,新模型可以访问交互日志,也可以访问产品中之前使用的模型。新模型被训练从而学习一个评分函数,该函数将曝光日志中预订 listing 分配到尽可能高的排名。

    然后,新模型在 A/B test 框架中进行在线测试,从而查看新模型和当前模型的对比,看看新模型是否可以实现统计意义上显著的预订量提升。

13.1 模型演变

  1. 我们向深度学习的转变不是原子atomic 操作的结果,而是一系列迭代改进的最终结果。

    • 下图 (a)显示了我们的主要离线指标 normalized discounted cumulative gain: NDCG 的相对提升,其中预订listing 的曝光 impression 被分配为相关性1.0、其它listing 的曝光被分配为相关性 0.0X 轴描述了模型及其投入生产的时间。
    • 下图 (b) 显示了模型在线预订量的相对增长。

    总体而言,这代表了 Airbnb 上最有影响力的机器学习应用之一。以下各节简要描述了每个模型。

  2. Simple NNAndrej Karpathy 对模型架构有一些建议:不要成为英雄don’t be a hero 。在 “我们为什么不能成为英雄?” 的驱动下,我们从一些复杂的自定义架构开始,结果却被它们的复杂性淹没,最终浪费了很多时间。

    我们最终想方设法上线的第一个体系架构是具有ReLU 激活的、简单的单隐层(32 个神经元)神经网络NN 。事实证明该神经网络和 GBDT 相比,预订量指标是中性neutral 的(即效果既不正向、也不负向)。

    NNGBDT 模型具有相同的特征,其训练目标也和 GBDT 保持不变:最小化 L2 回归损失regression loss,其中预订 listing 的效用utility 分配为 1.0、未预订 listing 的效用分配为 0.0

    整个练习exercise的价值在于,它验证了整个 NN pipeline 已经准备就绪,并且能够为实时流量提供服务。稍后在特征工程和系统工程部分讨论该 pipeline 的具体细节。

  3. Lambdarank NN:不是英雄not being a hero 让我们有了一个开始,但没有走很远。最终我们及时的将 Karpathy 的建议调整为:在开始的时候不要成为英雄don’t be a hero, in the beginning

    我们的第一个突破是将Simple NNLambdarank 思想相结合。在离线时,我们使用 NDCG 作为主要指标。Lambdarank 为我们提供了一种直接针对 NDCG 优化 NN 的方法。这涉及为Simple NNregression based 公式的两个关键改进:

    • 转向 pairwise 偏好公式,其中预订者看到的listing 被用于构建 pairwise{booked listing, not-booked listing} ,从而作为训练样本。在训练期间,我们将预订 listing 和未预订listing 之间得分差异的交叉熵损失最小化。

      即:预订 listing 和未预订 listing 之间差异尽可能大。

    • 通过交换组成该pair 对的两个listing 的位置position而导致的 NDCG 差异,从而加权每个 pairwise 损失。这使得预订listing 的排名优化rank optimization 朝向搜索结果列表的头部,而不是底部。例如,把预订listing 的排名从位置2 提升到 1,将优于把预订listing 的排名从位置10 提升到 9

      即:预订 listing 位置尽可能靠前。

    下面给出了 TensorFlow 中的部分实现,尤其是如何对 paiwise loss 进行加权:

    ​x1
    def apply_discount(x):2
        '''3
        计算位置折扣曲线 positional discount curve4
        '''5
        return np.log(2.0)/np.log(2.0 + x)6
    def compute_weights(logit_op, session):7
        '''8
        根据 ndcg 的差异来计算损失的加权系数.9
        logit_op 是一个形状为 [BATCH_SIZE, NUM_SAMPLES] 的张量,对应于网络的输出层。每一行代表一个搜索,每一列代表搜索结果中的一个 listing。列 0 表示预订的 listing,剩余的 NUM_SAMPLES-1 列表示未预订的 listing。10
        '''11
        logit_vals = session.run(logit_op)12
        ranks = NUM_SAMPLES - 1 - logit_vals.argsort(axis=1).argsort(axis=1)13
        discounted_non_booking = apply_discount(ranks[:, 1:])14
        discounted_booking = apply_discount(np.expand_dims(ranks[:, 0], axis=1))15
        discounted_weights = np.abs(discounted_booking - discounted_non_booking)16
        return discounted_weight17
    ​18
    # 计算 pairwise loss19
    pairwise_loss = tf.nn.sigmoid_cross_entropy_with_logits(20
        targets=tf.ones_like(logit_op[:, 0]),21
        logits=logit_op[:, 0] - logit_op[:, i:] )22
    # 计算基于 ndcg 加权的 lambdarank 权重23
    weights = compute_weights(logit_op, session)24
    # 计算 lambdarank 权重加权的 pairwise loss25
    loss = tf.reduce_mean(tf.multiply(pairwise_loss, weights))
  4. Decision Tree/Factorization Machine NN:虽然目前服务于生产流量的主力排序模型是神经网络,但是我们仍然在研究其它模型。值得一提的模型有:

    • GBDT 模型,其中使用使用替代方法对搜索进行采样从而来构建训练数据。
    • 因子分解机factorization machine:FM 模型,它通过将 listingquery 都映射到一个 32 维的空间,从而预测一个 listing 在给定 query 的情况下被预订的概率。

    这些研究search ranking 问题的新方法揭露了一些有趣的东西:尽管这些模型在测试数据上的性能和神经网络相当,但是它们排名靠前uprankedlisting 却大不相同。

    受到 《Deep & Cross Network for Ad Click Predictions》 这样的神经网络体系架构的启发,新模型试图结合所有三种模型(GBDT 模型、FM 模型、NN 模型)的优势:

    • 对于 FM 模型,我们将最终预测作为特征纳入NN 模型。
    • 对于 GBDT 模型,我们将每棵树激活的叶节点的索引作为离散特征纳入 NN 模型。

    下图给出了一个概览。

  5. Deep NNDeep NN 模型的复杂性是惊人的,而且 《Hidden Technical Debt in Machine Learning Systems》 中提到的一些问题开始出现。在我们的最后一次飞跃中,我们能够通过简单地将训练数据扩展 10 倍,并切换到具有两层隐层的 DNN 来消除所有这些复杂性。

    Deep NN 网络的典型配置:

    • 一个输入层input layer。其中,在将离散特征扩展到 embedding 之后,输入一共有 195 个特征。
    • 第一个隐层 hidden layer。其中,该层具有 127 个全连接的 ReLU 激活的神经元。
    • 第二个隐层 hidden layer。其中,该层具有 83 个全连接的 ReLU 激活的神经元。

    馈入 DNN 的特征大部分是简单的 listing 属性,诸如价格、设施amenities、历史预订量等等。这些特征通过最少的特征工程来提供。除此之外,还包括从其它模型输出的特征:

    • 启用了智能定价Smart Pricing 功能的 listing 价格,该特征由专门的模型提供。
    • 候选 listing 和用户历史查看listing 的相似度similarity,这是基于co-view embedding 来计算得到。

    这些模型利用了不直接隶属于 search ranking 训练样本的数据,为 DNN 提供了额外的信息。

    为了更深入地了解 DNN,我们在下图中绘制了它的学习曲线 learning curve。我们在训练集和测试集上对比了 NDCG ,其中训练集有 17 亿的 pair 对。

    可以看到:我们能够弥合close 训练集和测试集之间的泛化距离 generalization gap

  6. 我们能否跳过演变evolution 的所有阶段直接启用 DNN?我们试图在追溯部分中回答这一问题。

    顺便说一句,虽然 DNN 在某些图像应用上取得了人类水平的性能,但我们很难判断我们在类似的比较中处于什么位置。问题的部分原因是,目前尚不清楚在 search ranking 问题中如何定义人类水平的性能。通过浏览日志信息,我们很难准确地判断哪些 listing 将会被预订。我们在日志中找不到客观的事实,只能根据租客的预算budget 和口味 tastes进行tradeoff ,而租客的口味大多数情况下还是看不到的。一些学者指出,即使是对于熟悉的shopping items,也很难进行人工评估。对于我们的 application,由于库存的新颖性novelty,这些困难将进一步加剧。

    说到困难,接下来我们讨论一些鲜为人知的事情:失败的尝试。

13.2 失败的模型

  1. 上一节中介绍的一个成功的 launch 后又接着另一个成功的launch 的叙述并没有讲出完整的故事。现实中失败的尝试比成功的尝试更多。复述每一次失败的尝试比较耗时,所以我们选择了两个特别有趣的失败来讲述。这些模型很有趣,因为它们说明了一些外部非常有效和受欢迎的技术,但是内部使用时可能会失效。

  2. Listing IDAirbnb 上的每个 listing 都有相应的唯一IDNN 提供的一个令人兴奋的新能力是使用这些 listing id 作为特征。想法是使用 listing id 作为 embedding 的索引 index ,这使得我们能够学习每个 listing 的向量 representation,从而编码 listing 独有的属性property

    我们之所以兴奋,是因为其它application 已成功地将如此高基数cardinality 的离散特征映射到 embedding,例如在 NLP application 中学习 word embedding 、在推荐系统中学习 video id embeddinguser id embedding

    但是,在我们尝试的不同变体中,listing id 大多数会导致过拟合。下图绘制了一次这类尝试的学习曲线,我们看到 NDCG 在训练集上有显著提升,但是在测试集上却没有任何改善。

    这种成熟的技术在 Airbnb 上失败的原因是由于底层市场underlying marketplace 的某些独特属性propertyembedding 需要每个 item 有大量数据才能收敛到合理的值。

    • item 可以无限地重复时,例如在线视频或语言中的单词,那么 item 拥有的用户交互数量也没有限制。为 item 兴趣获取大量的数据相对容易。
    • 另一方面,listing 受到物理世界的限制。即使是最受欢迎的 listing,一年最多也就可以预订 365 次。平均每个listing 的预订量要少得多。这一基础限制 fundamental limitation 生成的数据在 listing-level 非常稀疏。过拟合就是这种限制的直接后果。

    如果 item id 频次太少,则很难学到有意义的 embedding

  3. 多任务学习Multi-task Learning :虽然预订有物理限制,但是用户对listing 详情页的查看并没有物理限制。下图显示了 listing 的详情页查看量和预订量的比例的分布,预订量通常比查看量稀疏了几个数量级(横轴为查看量和预订量之比,纵轴为listing 数量)。更进一步,我们发现,不出所料,对listing 详情页的长时间观看long view 和预订相关。

    为了解决 listing id 过拟合的问题,我们建立了一个多任务学习模型。该模型使用两个独立的输出层同时预测预订概率和 long view 的概率:

    • 一个以预订 listing 作为正样本来优化损失,从而预测预订概率。
    • 另一个以 long view listing 作为正样本来优化损失,从而预测 long view 概率。

    两个输出层共享一个公共的隐层,如下图所示。更重要的是,listing id embedding 是共享的。背后的想法是,模型能够将 long view 中学到的知识迁移到预订任务中,从而避免过拟合。

    由于 long view 标签的数量比预订标签的数量多几个数量级,因此对预订损失施加了较高的补偿权重,从而保持对预订目标的关注。

    《Beyond Clicks: Dwell Time for Personalization》 所建议的,每个 long view 标签的损失进一步由 log(view_duration) 进行缩放。

    最终在线listing 评分时,我们仅使用预订预测 booking prediction

    但是当在线测试时,该模型大幅增加了 long view,而预订量保持不变。人工检查了具有较高 long viewlisting,我们发现了可能导致这种gap 的几种原因:

    • 这种 long view 可能是由于高端的、但价格昂贵的listing 所驱动(所以用户会停留一段时间来慎重考虑)。
    • listing 的描述太长,且难以阅读。
    • 极其独特、且有时很幽默的 listing
    • 还有一些其它原因。

    同样,正是 Airbnb 市场的独特性,使得 long view 和预订相关,但是也有很大的正交部分(即不相关的部分),这使得基于 long view 来预测预订具有挑战性。更好地理解 listing view 仍然是我们研究的主题。

    注:笔者在 ctrcvr 多任务建模过程中也发现类似的规律。即希望丰富的点击样本能够有助于迁移学习到转化预估任务。但是结果发现,ctr 预估任务效果很好,但是 cvr 预估任务效果持平或略有下降。

13.3 特征工程

  1. 我们开始的 baseline GBDT pipeline 具有广泛的特征工程。典型的变换包括计算比率ratio、窗口平均等等。这些特征工程技巧是经过多年实验积累的。然而,目前还不清楚这些特征是否是最好的,或者是否随着市场动态变化而更新。

    NN 的一大吸引力在于引入了特征自动化feature automation:馈入原始数据并让特征工程在以数据驱动的 NN 的隐单元中自动进行。

    然而,本节内容是专门针对特征工程的,因为我们发现让NN 有效工作不仅仅是提供原始数据,也需要特征工程。这种特征工程不同于传统的特征工程:在将特征输入到模型之前,无需人工对特征执行数学计算,而是将重点转移到确保特征符合某些属性properties ,以便神经网络可以自己有效地进行数学计算。

  2. 特征归一化Feature Normalization:在我们第一次训练NN 的尝试中,我们简单地将所有用于训练 GBDT 模型的特征输入到神经网络中。这种情况非常糟糕,损失函数在训练过程中达到饱和,后续的step 没有任何效果。我们将问题追溯到以下事实:特征未能正确地归一化。

    • 对于决策树,只要特征的相对顺序有意义,那么特征的确切数值几乎无关紧要。
    • 神经网络对于特征的数值非常敏感。超出正常特征范围的馈入值可能会导致较大梯度的反向传播。由于梯度消失,这可以使得 ReLU 这类激活函数永久死亡。

    为了避免这种情况,我们确保将所有特征限制在较小的取值范围内,并且大部分分布在 [-1,1] 区间、均值映射到 0 。总的来说,这涉及检查特征,并应用以下两种转换中的任何一种:

    • 如果特征分布类似于正态分布,我们将其变换为:

      $ \frac{\text{feature_value} - \mu}{\sigma} $

      其中 $ \mu $ 为特征均值, $ \sigma $ 为特征标准差。

    • 如果特征分布类似于幂律分布power law distribution,我们将其变换为:

      $ \log \left(\frac{1+ \text{feature_value}}{1+ \text{median}}\right) $

      其中 median 为特征的中位数。

    另一种简单的选择是采用 BN Layer

  3. 特征分布Feature Distribution:除了将特征映射到有限的数值范围,我们还确保大多数特征都具有平滑的分布。为什么要纠结于分布的平滑性smoothness ?以下是我们的一些理由。

    • 发现错误spotting bugs:在处理上亿个特征样本时,如何验证其中一小部分没有 bug?范围检查很有用,但是很有限。我们发现分布的平滑性是发现错误的宝贵工具,因为错误的分布通常和典型的分布形成鲜明对比。

      举个例子,我们在某些地区记录的价格中发现了 bug 。对于超过 28 天的区间,记录的价格是每月价格、而不是每日价格。这些错误在原始分布图上显示为尖峰。

    • 促进泛化facilitating generalization:确切回答为什么 DNN 善于泛化是研究前沿的一个复杂课题。同时,我们的工作知识working knowledge 是基于以下观察:在为我们的 application 构建的 DNN 中,各层的输出在其分布方面变得越来越平滑。下图显示了来自一些样本的最终输出层分布、以及隐层分布。为了绘制隐层的分布,零值被省略,并且应用了 log(1 + relu_output) 转换。

      这些图激发了我们的直觉:为什么 DNN 可以很好地泛化到我们的 application 中。当建立一个基于数百个特征的模型时,所有特征取值的组合空间非常庞大,并且在训练过程中常常会覆盖一定比例特征组合。来自较低层的平滑分布确保了较高层可以正确地对未看过unseen 的值进行插值。将这种直觉一直扩展到输入层,我们尽力确保输入特征具有平滑的分布。

      这里有个平滑性假设:假设相似的特征带来相似的 label

      我们如何测试模型是否在样本上良好地泛化?真正的测试当然是模型的在线性能,但是我们发现以下技术可以作为完整性检查sanity check :将测试集中给定特征上所有的值都缩放(例如将 price 特征缩放为 2 倍或者 3 倍或者 4 倍),然后观察 NDCG 的变化。我们发现,在这些从未见过的price 取值上,该模型的性能是非常稳定的。

      对特征的取值缩放可能会破坏样本的完整性。例如:对于郊区的、单个房间的 listing,如果 price 缩放 4 倍会导致一个奇怪的 listing,看起来应该很便宜的 listing 但是标价很高。

      在调试debugged 并应用适当的归一化之后,大多数特征都获得了平滑分布。但是,有少数几个特征,我们不得不进行专门的特征工程。一个例子是listing 的地理位置geo-location,以经度和纬度来表示。下图 (a)(b) 显示了原始经纬度的分布。为了使得分布更加平滑,我们计算的是距展示给用户的地图的中心点的偏移量。如下图 (c)所示,质量似乎集中在中心,因为地图的尾部被zoomed out 了很多。因此,我们使用经度/纬度偏移量的 log() ,从而得到了下图 (d) 的分布。这使得我们能够构造两个平滑分布的特征,如下图 (e)(f) 所示。

      需要明确的是,原始经度/纬度到地图中心的距离变换是有损的多对一函数many-to-one function。因为它可以将多个经度/纬度转换为相同的偏移量。这使得模型可以基于距离属性而不是特定的地理位置属性来学习全局属性。要学习特定于局部地理位置的属性,我们使用了稍后描述的高基数high cardinali离散特征。

    • 检查特征完整性checking feature completeness:在某些情况下,调查某些特征缺乏平滑性会导致发现模型缺失missing 的特征。

      例如,我们有一个 listing 未来已预订天数占available days 的比例作为一个特征(即占用率occupancy),这个特征是listing 质量的信号。背后的直觉是:高质量的 listing 会提前售罄。但是,由于缺乏平滑性,占用率的分布却令人困惑,如下图 (a) 所示。

      经过调查,我们发现了另一个影响占用率的因素:listing 有不同的最低住宿时间minimum required stay 要求,有的会要求最低住宿几个月。因此这些 listing 得到了不同的占用率。但是,我们没有在模型中添加最低住宿时间作为特征,因为它取决于日历并且被认为过于复杂。但是在查看了占用率分布之后,我们增加了 listing 的平均住宿时间作为一个特征。

      在占用率通过平均住宿时间归一化之后,我们可以看到下图 (b) 中的分布。在一个维度中缺乏平滑性的特征可能在较高维度上变得平滑。这有助于我们思考这些维度是否可以应用在我们的模型中。

  4. 高基数离散特征High Cardinality Categorical Features :过拟合的 listing id 并不是我们尝试的唯一高基数离散特征。还有其它尝试,如 NN 的承诺所言,我们用很少的特征工程就取得了很高的回报。一个具体的例子最能说明这一点。

    租客对于城市各个街区neighborhoods 的偏好是一个重要的位置信号location signal 。对于 GBDT 模型,该信息是由一个精心设计的 pipeline 提供的,该 pipeline 跟踪了各个街区和城市的层级分布 hierarchical distribution 。建立和维护该 pipeline 的工作量很大,而且它也没有考虑诸如预订 listing 价格之类的关键因素。

    NN 的世界中,处理这类信息本身就是简单的。我们基于 query 中指定的城市、以及对应于listinglevel 12 S2 cell 创建的一个新的离散特征,然后使用哈希函数将这二者整体映射到一个整数。例如,给定 query “旧金山” 以及位于 Embarcadero 附近的 listing,我们选择 listing 所在的 S2 cell539058204),然后将将 {"San Francisco", 539058204} 哈希映射到 71829521 从而建立我们的离散特征。然后该离散特征被映射到一个 embedding ,接着馈入 NN 。在训练期间,该模型通过反向传播来学习 embedding,该 embedding 编码了在给定城市query 的情况下由 S2 cell 代表的街区的位置偏好location preference

    即将地域划分为一个个的网格,然后学习每个网格的 grid id embedding

    下图可视化了为 query “旧金山” 学到的各街区的 embedding (通过 t-SNE )。这符合我们对该地区的直觉理解:embedding 值不仅突出了该城市的主要 points of interest: poi ,它还表明了人们更喜欢位于西湾west bay 以南一点的位置,而不是靠近主要交通拥堵桥梁的位置。

13.4 系统工程

  1. 这部分是关于加速训练training 和加速打分scoring 。我们pipeline 的一个quick summary

    • 来自租客的搜索query 命中了一个进行检索retrieval 和评分scoringJava server
    • 这个 server 还生成日志,这些日志存储为序列化的 Thrift 实例。
    • 日志使用 Spark pipeline 来处理从而创建训练数据。
    • 使用 TensorFlow 来训练模型。
    • 使用 ScalaJava 编写的各种工具用于评估模型和计算离线指标。
    • 模型上传到执行检索和评分的 Java server

    所有这些组件都在 AWS 实例上运行。

  2. Protobufs and DatasetsGBDT 模型是以 CSV 格式来提供训练数据的,并且我们重复使用这个pipeline 的大部分,从而使用 feed dict 馈入 TensorFlow 模型。

    乍一看,这似乎不是一个机器学习的问题,并且在我们的优先级清单中是相当低的。但是当我们发现 GPU 利用率接近 25% 时,我们马上警醒了。大部分训练时间都花在解析 CSV 和通过 feed dict 拷贝数据上。我们实际上是在用骡子拖着一辆法拉利。

    重构 pipeline 以产生 Protobufs 训练数据,并使用 Dataset 可以将训练速度提高 17 倍,并将 GPU 利用率提高到大约 90% 。这最终允许我们将训练数据从几周扩展到几个月。

  3. 重构静态特征refactoring static features:我们的很多特征都是很少变化的 listing 属性。例如,地理位置location、卧室数量、便利设施amenities 、租客规则guest fules 等等。将所有这些特征作为训练样本的一部分将产生输入瓶颈input bottleneck

    为了消除这种磁盘流量,我们仅使用 listing id 作为离散特征。所有静态特征都被打包为由 listing id 索引的、不可训练non-trainableembedding 。对于在训练期间发生突变的特征,这需要在少量噪声和训练速度之间进行trade-off

    注意:这个 embedding 就是这些静态特征拼接而成的,因此是不可训练的。是否对这些属性进行 embedding 训练会更好?论文并未讨论这一点。

    这个 embedding 常驻在 GPU 内存,消除了每个训练样本数千KB 的数据,这些数据通常是通过 CPU 从磁盘加载的。这种效率使得探索全新类型的模型成为可能,该模型考虑了用户历史交互的数十个listing 的详细信息。

  4. Java NN library:在 2017 年初,当我们开始将 Tensorflow 模型投入生产时,我们发现没有有效的解决方案可以在 Java stack 中对模型进行评分scoring 。 通常需要在 Java 和另一种语言之间来回转换数据,这个过程中引入的延迟latency 对我们而言是一个障碍。

    为了满足严格的搜索延迟要求,我们在 Java 中创建了一个自定义的神经网络评分库。虽然到目前为止这对我们很有帮助,但是我们希望重新讨论这个问题,看看有没有最新的替代方案。

13.5 超参数

  1. 尽管在 GBDT 世界中有一些超参数,如树的数量、正则化等,但是 NN 却将超参数的规模提升到一个新的高度。在最初的迭代中,我们花了大量时间探索超参数世界。调研所有选项和试验组合上的努力并没有给我们带来任何有意义的改进。但是,这个练习exercise 确实让我们对我们的选择有了一些信息,我们将在下面描述。

  2. dropout:我们最初的印象是,dropout 和神经网络的正则化相对应,因此必不可少。然而对于我们的 application,我们尝试了不同的 dropout 形式,所有这些都会导致离线指标略有下降。

    为了理解dropout 和我们的失败,我们目前对 dropout 的解释更接近于一种数据增强技术。当随机性的引入模拟了有效的场景时,这种技术是有效的。对于我们的情况,随机性只能产生无效的场景。

    作为替代方案,我们在考虑特定特征的分布的情况下,添加了人工制作的噪声,从而使得离线 NDCG 降低了大约 1%。但是我们在在线性能方面没有取得任何统计意思上的显著提升。

  3. 初始化initialization:出于纯粹的习惯,我们通过将所有权重和 embedding 初始化为零来开始我们的第一个模型,结果发现这是开始训练神经网络的最差的方法。在研究了不同的技术之后,我们目前的选择是对网络权重使用 Xavier 初始化,对 embedding 使用 {-1 ~ +1} 范围内的均匀随机初始化。

  4. 学习率 learning rate:这里面临着各种各样的策略,但是对于我们的 application,我们发现很难使用默认的设置来改善 Adam 的性能。当前,我们使用了 LazyAdamOptimizer 变体,我们发现使用 large embedding 训练时该变体会更快。

  5. batch sizebatch size 的变化对于训练速度有着显著影响,但是对于模型本身的确切影响却难以把握。我们发现最有用的指南是《Don’t Decay the Learning Rate, Increase the Batch Size》 。但是我们并没有完全遵守该论文的建议。在 LazyAdamOptimizer 解决了学习率问题之后,我们选择了 200 的固定 batch size,这似乎对当前模型有效。

13.6 特征重要性

  1. 一般来说,特征重要性的估计和模型的可解释性interpretability 是神经网络不擅长的一个领域。评估特征的重要性对于确定工程工作的优先级和指导模型迭代是至关重要的。

    NN 的优势在于找到特征之间的非线性相互作用。当理解特定特征扮演了什么角色时,这也是一个弱点,因为非线性相互作用使得很难孤立地研究任何特征。接下来,我们讲述解释神经网络的一些尝试。

  2. 分数分解 Score Decomposition:在 NN 的世界中,试图了解单个特征的重要性只会导致混乱。我们第一个朴素的尝试是获取网络产生的最终得分,然后尝试将其分解为来自每个输入节点input node 的贡献。

    在查看了结果之后,我们意识到这个想法存在概念上的错误:没有一种干净clean 的方法来区分一个特定的输入节点对像 ReLU 这样的非线性激活的影响。

  3. 消融测试 Ablation Test:这是对这个问题的又一次简单的尝试。这里的想法是一次移除一个特征,重新训练模型并观察性能的差异。然后,我们可以将这些特征的重要性与移除它们所导致的性能下降成正比。

    然而这里的困难在于,通过移除一个特征获得的任何性能差异都类似于在重新训练模型时观察到的离线指标中的典型噪声。这可能是因为我们的特征集合中存在大量的冗余,模型似乎能够从剩余的特征中弥补一个缺失的特征。

    这导致了忒休斯之船悖论Ship-of-Theseus paradox :你能一次从模型中删除一个特征,声称该模型没有显著的性能下降吗?

    忒修斯悖论:如果忒修斯的船上的木头被逐渐替换,直到所有的木头都不是原来的木头,那这艘船还是原来的那艘船吗?

    即:假定某物体的构成要素被置换后,但它依旧是原来的物体吗?

  4. 排列测试Permutation Test:在接下来的尝试中,我们从针对随机森林提出的排列特征重要性permutation feature importance 中得到启发。我们在测试中随机排列了特征在各个样本中的取值之后,在测试集上观察了模型的性能。我们的期望是,特征越重要,扰动它导致的模型退化degradation 就越大。

    但是,该操作会导致有些荒谬的结果。原因是在一次排列permuting 一个特征时,我们假设不同特征之间彼此独立,这是错误的。例如,预测预订概率的最重要特征之一就是 listing 中的房间数。而房间数量和价格、住宿人数、便利设施等特征息息相关。对特征进行独立排列会创建在现实生活中从未发生过的样本,并且特征在无效空间invalid space 中的重要性使我们误入歧途。

    但是,该测试在确定没有发挥作用的特征方面有些用处。如果随机排列特征完全不影响模型性能,则可以很好地表明模型可能不依赖于该特征。

  5. TopBot Analysis:有一个自主开发的工具旨在解释这些特征,并且不会以任何方式干扰它们。这个工具叫做 TopBot,它提供了一些有趣的洞察 insight

    TopBot 是自上而下分析器top-bottom analyzer 的缩写,它将一个测试集作为输入,并使用模型对每个测试querylisting 进行排序。然后它为每个query 从排名在 toplisting 生成特征取值的分布图,并将该分布图和排名在 bottomlisting 生成特征取值的分布图进行比较。这个比较comparison 表明了模型是如何利用不同取值范围内的特征。

    下图显示了一个例子。排名最高的listing 的价格分布偏向于较低的值,这表明模型对于价格的敏感性sensitivity 。但是,当比较排名top 和排名 bottomlisting 的评论数量的分布时,这两个分布看起来非常相似,表明这个版本的模型未按预期使用评论,从而为下一步研究提供了方向。

    还可以细化下:针对不同的细分市场(或者不同类型的 listing)来可视化。

13.7 回顾

  1. 下图总结了目前为止的深度学习之旅。

    • 根据无处不在的深度学习成功案例,我们从乐观主义的顶峰开始,认为深度学习将取代 GBDT 模型,并为我们带来惊人的收益。
    • 许多最初的讨论集中在保持其他一切不变,用神经网络替代当前的模型,看看我们能够得到什么收益。当最初没有实现这些收益时,这让我们陷入了绝望的深渊。
    • 随着时间的推移,我们意识到转向深度学习根本不是一个简单的模型替代,更确切的说这是关于系统扩展sytem scaling 。因此,它需要重新思考围绕模型的整个系统。

    如果仅局限于较小的规模,像 GBDT 这样的模型在性能上可以说是同等水平并且更易于处理,我们继续使用 GBDT 来解决中等规模的问题。那么,我们会向其他人推荐深度学习吗?答案是 Yes。这不仅是因为深度学习模型的在线性能大幅提升。还有部分原因是与深度学习如何改变了我们未来的 roadmap 有关。早期机器学习的重点主要放在特征工程上,但是在转向深度学习之后,试图手动特征工程已经失去了前景。这让我们可以在更高的层次上研究问题。比如,如何改进我们的优化目标?我们是否准确地代表了所有的用户?在迈出将神经网络应用于search ranking 第一步的两年之后,我们觉得我们才刚刚开始。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文