【阅读笔记】Applying Deep Learning To Airbnb Search

Applying Deep Learning To Airbnb Search

Airbnb Inc.
malay.haldar@airbnb.com
2018年10月25日

ABSTRACT

最初使用 gradient boosted decision tree model 来做 search ranking ,搜索效果从刚开始的上升逐渐趋于稳定。本文讨论如何突破趋于平稳的效果。本文的目的不是讲述模型上的突破,而是如何建立一个神经网络模型在一个实际的产品上。
KEYWORDS: Search ranking, Deep learning, e-commerce

INTRODUCTION

Airbnb 搜索排名的打分函数最早的版本是手动设计的,后来使用 GBDT(gradient boosted decision tree) 模型替换手动设计的打分函数,房屋预定得到了大幅度的提升,接着迭代优化了很多次。经过很长一段时间的迭代优化实验,发现在线预定房屋的收益达到了瓶颈。所以,在这个时候想尝试一些新的突破。
Fig.1
完整的模型生态是预测 guest 预定房间,预测 host 接受,预测 guest 给出5星好评的整个流程。本文讨论的是对可选房间进行排序的问题。如图1所示,典型的 guest 搜索 session 是 guest 搜索若干次,偶尔点击来查看房间细节,成功的 session 是 guest 预定预定某个 listing。这一过程被记录在 log 中。利用 log 训练新模型,使得离线效果有所提升,再使用 A/B test 线上测试,看指标是否有明显的提升,然后再上线新模型。
本文概述:首先概述模型架构演变的情况; 其次是一些工程方面的注意事项;然后描述了一些使用的工具和超参数探索;最后总结回顾。

MODEL EVOLUTION

我们模型的演变是一个渐进的过程,图2展示了离线指标 NDCG 和预定数随着模型演变而增长的过程。
Fig.2

Simple NN

Andrej Karpathy 对于 model architecture 有一个建议: don’t be a hero。
我们第一个模型是 a simple single hidden layer NN with 32 fully connected ReLU activations (minimizing the L2 regression loss where booked listings are assigned a utility of 1.0 and listings that are not booked a utility of 0.0)。结果是与 GBDT model 效果差不多。这个过程验证了神经网络上线的流程的可行性。

Lambdarank NN

当我们将 NN 与 Lambdarank 背后的想法结合起来时,我们的第一个突破就来了。Lambdarank 为我们提供了一种直接针对 NDCG 优化 NN 的方法。这涉及到简单 NN 的基于回归的公式的两个关键改进:

  • 损失函数转变为交叉熵。
  • 通过对 NDCG 影响的差异来权衡 pairwise loss。 例如,从第2位调整为第1位将优先于从第10位移动到第9位。
def apply_discount(x): 
    '''Apply positional discount curve''' 
    return np.log(2.0)/np.log(2.0 + x)

def compute_weights(logit_op, session): 
    '''Compute loss weights based on delta ndcg. 
    logit_op is a [BATCH_SIZE, NUM_SAMPLES] shaped tensor 
    corresponding to the output layer of the network. 
    Each row corresponds to a search and each column a listing in the 
    search result. Column 0 is the booked listing, while columns 1 through 
    NUM_SAMPLES - 1 the not-booked listings. '''
    logit_vals = session.run(logit_op)
    ranks = NUM_SAMPLES - 1 - logit_vals.argsort(axis=1)
    discounted_non_booking = apply_discount(ranks[:, 1:])
    discounted_booking = apply_discount(np.expand_dims(ranks[:, 0], axis=1))
    discounted_weights = np.abs(discounted_booking - discounted_non_booking)
    return discounted_weight

# Compute the pairwise loss 
pairwise_loss = tf.nn.sigmoid_cross_entropy_with_logits(targets=tf.ones_like(logit_op[:, 0]), logits=logit_op[:, 0] - logit_op[:, i:] ) 
# Compute the lambdarank weights based on delta ndcg 
weights = compute_weights(logit_op, session) 
#Multiply pairwise loss by lambdarank weights 
loss = tf.reduce_mean(tf.multiply(pairwise_loss, weights))

Decision Tree/Factorization Machine NN

For the FM model we took the final prediction as a feature into the NN. From the GBDT model, we took the index of the leaf node activated per tree as a categorical feature.
在这里插入图片描述

Deep NN

Typical configuration of the network: an input layer with a total of 195 features after expanding categorical features to embeddings, feeding the first hidden layer with 127 fully connected ReLUs, and then the second hidden layer with 83 fully connected ReLUs.
为DNN提供的 feature 大多是用最少的特征工程得到的简单的属性,如价格,便利设施数目种类,历史预订计数等。还有少量的其他评价模型输出的特征。
随着训练数据量的增加,我们明显的减少了 generalization gap。
Fig.3

FAILED MODELS

Listing ID

把每个 listing 变成一个 embedding 作为特征训练模型,发现过拟合了。这是因为 Airbnb 独特的性质,就算是最受欢迎的房间一年也只能预定365次,对于某些需要 embeding 的特征数某些值的数据量受到了很大的限制(我的理解就是噪声太大,导致 embeding 的结果不准确)。

Multi-task learning

把任务分为两个(对某个 listing 浏览多久和是否预定)进行多任务学习。在线效果不好。对看页面多久的理解是我们要继续的课题。

FEATURE ENGINEERING

Feature normalization

刚开始时,我么用与 GBDT 相同的特征训练 NN,效果很差。因为树模型对特征的大小关系敏感,而神经网络需要进行归一化,我们对正态分布进行中心归一化( f e a t u r e − μ σ \frac{feature-\mu}{\sigma} σfeatureμ),对幂律分布进行 log 归一化( l o g ( 1 + f e a t u r e 1 + m e a n ) log(\frac{1+feature}{1+mean}) log(1+mean1+feature))。

Feature distribution

除了将特征映射到受限制的数值范围外,我们还确保其中大部分分布平滑。 为什么要沉迷于分布的平滑? 以下是我们的一些原因。

发现错误

在处理数以亿计的特征样本时,我们如何验证它们中的一小部分没有错误? 范围检查很有用但有限。 我们发现分布的平滑性是发现错误的宝贵工具,因为错误的分布通常与典型的分布不同。 举个例子,我们在某些地区的价格记录中,存在与市价明显不一致的错误。 这是因为在这些地区,对于超过28天的期间,记录的价格是每月价格而不是每日价格。 这些错误表现为分布图上的尖峰。

有利于泛化

解释 DNN 的泛化能力是研究前沿的复杂话题。我们发现在我们构建的 DNN 中,输出层的分布会逐渐变得越来越平滑。 图8显示了最终输出层的分布,而图9和图10显示了隐藏层的一些样本。 为了显示隐藏层中的值,我们忽略了零值并且进行 l o g ( 1 + v a l u e ) log(1 + value) log(1+value)变换。这些分布图给予我们 DNN 泛化能力的直觉。当建立一个以数百个特征为基础的模型时,所有特征的组合空间不可思议的大,并且在训练期间,而且覆盖了一小部分组合特征。来自较低层的平滑分布确保了上层可以正确的输出。 将这种直觉一直延伸到输入层,我们尽最大努力确保输入功能具有平滑的分布。
我们而且发现下面的技术可用做模型鲁棒性检查:缩放测试集中给定特征的所有值,例如价格为2x,3x,4x等,并观察 NDCG 的变化。我们发现模型的性能非常稳定。
Fig.4
为了使地理特征分布更平滑,通过计算与中心点的偏移量来表征地理特征信息。

Checking feature completeness.

某些特征分布的不平滑,会导致模型的学习信息缺失。图 12(a)展示的是原始房屋占用分布,(b)展示的是(房屋占用 / 居住时长)归一化后的分布,分布不太符合正常理解,调查发现列表中有一些房屋有最低的住宿要求,可能延长到几个月。然而,开始我们没有添加最低的居住时长特征。所以,我们考虑添加最低居住时长作为模型的一个特征。
Fig.5

High cardinality categorical features

低数量类别的特征可以使用 one-hot 编码,对于高数量类别特征(例如邮编)利用一个哈希函数映射成一个数字。类别特征映射成 embedding,输入神经网络模型中,训练过程中,通过反向传播来学习这些位置偏好信息。

SYSTEM ENGINEERING

我们目前的 pipeline :一个访客的搜索查询通过 Java 服务端返回检索结果和分数;Thrift 来存储查询日志,Spark 来处理训练数据,TensorFlow 训练模型,各个工具都是使用 Scala 和 Java 来编写,模型上传到 Java 服务端给访客提供搜索服务。

Protobufs and Datasets

最开始使用训练 GBDT 的 CSV 格式,输入给 TensorFlow 模型的 feed_dict,后来发现我们的 GPU 利用率只有 25%,大部分的训练时间花费在解析 CSV 数据。后来使用 Protobufs 格式的数据集来训练,速度提升了 17 倍,GPU 利用率提升到 90%。

Refactoring static features

我们业务中有一些特征变化不大,比如位置、房间卧室的数量等,为了减少每次重复读取磁盘消耗时间,我们将它们组合起来为其创建一个索引,通过 list 的 id 来检索。

Java NN library.

在 2017 年我们打算开始将 TensorFlow 运用到生产环境的时候,发现没有基于 Java 的高效的技术栈。多个语言之间切换导致产生服务延迟。所以,我们在 Java 上自己创建了自己的神经网络打分函数库。

HYPERPARAMETERS

像 GBDT 中的超参数树的个数、正则化等一样,神经网络也许多超参数。下面是我们调超参数的一些经验分享:

Dropout

Dropout 对神经网络防止过拟合是必不可少的,但是在我们的实际应用中,尝试了多种正则化,都导致离线评估效果下降。所以,我们在训练数据集中随机复制一些无效的场景,是一种类似数据增强(data augmentation)的技术,来弥补这种缺失。另外,考虑到特定特征分布,我们手工添加了一些噪声数据,离线评估的 NDCG 提高大约 1%,但是在线统计评估并没有显著的提升。

Initialization

第一个模型所有权重和 embeddings 都初始化为零,效果非常差。现在选择 Xavier 来初始化所有的神经网络权重,使用 random uniform 初始化所有的 embeddings,其分布区间在{-1,1}之间。

Learning rate

对于我们的数据,发现使用 Adam 优化算法的默认参数很难提升效果,最后选择了 LazyAdamOptimizer,当训练 embeddings 时,速度非常快。

Batch size

改变 batch size 对训练速度影响非常大,但是它对模型的确切影响是很难把握的。在我们使用的 LazyAdamOptimizer 优化器中,剔除学习率的影响外,我们选择 batch size 的大小为 200 时,对我们目前的模型来说是最好的。

FEATURE IMPORTANCE

估计特征重要性和模型可解释性对于模型的实际应用有很重要的意义。特征重要性可以指导我们更好的迭代模型。神经网络最大的优势是解决特征之间非线性组合。这同时导致了解哪些特征对模型效果提升起关键作用这件事情变得困难了。下面分享一下我们在神经网络特征重要性方面的一些探索:

Score Decomposition

在神经网络中,分析特征的重要性很困难,容易让人产生混乱。我们最初的做法是获取神经网络产生的最终得分,并尝试将其分解为各个节点贡献得分。但是,在查看结果之后发现这个想法在逻辑上有个错误:没有一个清晰的方法可以将特定输入节点和经过非线性激活函数(ReLU 等)后的影响分开。

Ablation Test

另一种简单想法是一次次删减、替换特征,重新训练然后观察模型的性能,同时也可以考虑特征缺失导致性能成比例下降来衡量特征的重要性程度。然而,通过这种方法评估特征重要性有点困难,因为一些冗余的特征缺失,神经网络模型是可以弥补这种缺失的。

Permutation test

受随机森林模型特征重要性排序的启发,这一次我们尝试复杂一点的方法。在测试集上随机的置换特征,然后观察测试上模型的性能。我们期望的是越重要的特征,越会影响模型的性能。经试验测试发现好多无意义的结果,比如: 列表中房屋的数量特征对于预测房屋预定的概率影响非常大,但是仅仅测试这个特征,其实是无意义的,因为房屋的数量还跟房屋的价格有关联。

TopBot

TopBot 是我们自己设计的分析特征重要性的工具,它可以依据排序自上向下分析。图 14 展示了如何判断特征重要性,从图中可以看出 price 特征比较重要,review count 特征不是特别重要。
Fig.6

RETROSPECTIVE

在无处不在的深度学习成功案例中,最初我们很乐观的认为用深度学习直接取代 GBDT 模型就可以带来巨大的收益。所以最初的讨论都是围绕其他保持不变的情况下,仅替换当前的 GBDT 模型为神经网络模型,看能带来多大的收益。但这么做使我们陷入了绝望的低谷,没有得到任何的收益。随着时间的推移,我们意识到仅仅替换模型不够,还需要对特征处理加以细化,并且需要重新思考整个模型系统的设计。(像 GBDT 这样的模型受限于规模,易于操作,性能方面也表现不错,可以用来处理中等大小的问题。)
基于我们尝试的经验,我们极力向大家推荐深度学习。这不仅仅是因为深度学习在线获得的强大收益,它还改变了我们未来的技术路线图。早期的机器学习主要精力花费在特征工程上,转移到深度学习后,特征组合的计算交给神经网络隐层来处理,我们有更多的精力思考更深层次的问题,比如:改进我们的优化目标。目前的搜索排名是否满足所有用户的需求?经过两年探索,我们迈出了第一步,深度学习在搜索上的应用才刚刚开始。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
2019年 Manning出版, 全英文 ,下面是preface: The field of natural language processing bewitched me as soon as I came to know about it nearly 10 years ago, while studying for my master’s degree. The promise that computers could help us understand the (already, even then) vast amount of textual documents in existence sounded like magic. I still remember how exciting it was to see my first NLP programs extract even vaguely correct and useful information from a few text documents. About the same time, at work, I was asked to do some consulting for a customer on their new open source search architecture. My colleague, who was an expert in the field, was busy on another project, so I was given a copy of Lucene in Action,1 which I studied for a couple of weeks; then I was sent out on the consulting job. A couple of years after I worked on that Lucene/Solr-based project, the new search engine went live (and, as far as I know, it’s still used). I can’t tell you how many times the search engine algorithms needed to be adjusted because of this or that query or this or that fragment of indexed text, but we made it work. I could see users’ queries, and I could see the data that was there to be retrieved, but a minimal difference in spelling or omitting a certain word could cause very relevant information to not show up in the search results. So while I was very proud of my work, I kept wondering how I could have done better to avoid the many manual interventions the product managers asked me to perform in order to provide the best possible user experience. Right after this, I quite by chance found myself involved in machine learning thanks to Andrew Ng’s first machine learning online class (which originated the Coursera MOOC series). I was so fascinated with the concepts behind the neural networks shown in the class that I decided to try to implement a small library for neural networks in Java myself, just for fun (http://svn.apache.org/repos/asf/labs/yay/). I started hunting for other on
### 回答1: MDA(Model Driven Architecture)是一种用于企业的应用开发方法论。MDA的核心理念是将系统的建模、设计、实现和部署过程从技术细节中解耦,以实现系统的可扩展性和可维护性。 在应用MDA到企业中,首先需要进行系统的建模。通过对企业业务流程、数据模型和需求进行建模,可以将企业系统抽象成一系列模型。这些模型描述了系统的组成部分、功能和行为。建立基于模型的设计,可以使开发人员更加关注系统的业务逻辑,而不是技术实现细节。 然后,通过使用MDA工具和技术,可以自动生成系统的代码和配置文件。这样,开发人员可以避免手动编写繁琐的代码,提高开发效率。MDA中使用的元模型和模板语言可以根据不同的目标平台生成适当的代码。 在企业中应用MDA还可以提高系统的可维护性。通过将系统抽象成模型,可以轻松地对系统进行修改和扩展,而不会影响底层的实现。这使得企业可以更加灵活地应对不断变化的市场需求和业务需求。 此外,应用MDA还可以促进企业的组件化和重用。通过将系统分解成可重用的组件,可以提高软件开发的生产力和质量。组件化还可以使企业能够更好地组织、维护和管理复杂的软件系统。 总之,应用MDA到企业中可以提高系统的可维护性、可扩展性和可重用性。通过将系统建模、自动生成代码和配置文件,可以减少开发时间和成本,并使开发人员能够更专注于业务逻辑。因此,MDA是现代企业应用开发的一种重要方法论。 ### 回答2: MDA(Model Driven Architecture)是一种软件开发方法论,适用于企业级应用程序的开发。MDA的核心理念是将业务逻辑与应用程序的实现相分离,通过使用模型来驱动应用程序的开发过程。 MDA的第一步是创建一个概念模型,该模型描述了企业的业务需求和过程。概念模型包括实体、关系、属性和规则等元素。这些元素帮助开发团队理解企业的运作方式,确定业务需求,并为应用程序开发提供基础。 接下来,使用模型转换工具将概念模型转换为平台无关模型(PIM)。PIM是一个抽象的模型,不依赖于任何具体的技术或平台。它描述了应用程序的结构、行为和交互方式,但不指定编程语言或硬件平台。 在PIM的基础上,使用模型转换工具将其转换为平台相关模型(PSM)。PSM是根据特定的技术和平台生成的模型,如Java、.NET或Android平台。PSM将PIM中的抽象概念转化为具体的编程代码和配置。 最后,通过模型转换工具将PSM转换为最终的运行时代码。这些生成的代码可以在特定的技术和平台上编译和运行,从而实现了基于模型的应用程序开发。 应用MDA到企业级应用程序的开发中,可以提供以下好处: 1. 提高开发效率:通过使用模型驱动的方法,开发人员能够更加专注于业务逻辑的描述和规划,而不必关注具体的技术细节。这能够节省开发时间,提高开发效率。 2. 简化维护和更新:企业级应用程序通常具有复杂的业务逻辑和功能需求。使用模型驱动的方法能够提供更清晰、可维护的代码结构,使得应用程序的维护和更新更加容易。 3. 提高系统的质量和一致性:通过使用MDA,整个应用程序的设计和实现可以基于一个统一的模型。这确保了系统的一致性和质量,并减少了代码错误和漏洞的可能性。 综上所述,将MDA应用到企业级应用程序的开发中,可以提供更高的开发效率、更简化的维护和更新以及更高的系统质量和一致性。这对于企业来说是非常有价值的,可以帮助企业更好地满足业务需求并提升竞争力。 ### 回答3: 将 MDA 应用于企业可以带来许多好处。MDA (Model Driven Architecture,模型驱动架构) 是一种面向模型的软件开发方法论,它将业务需求和系统设计分解为多个层次的模型,并通过模型转换来自动生成代码。 首先,应用 MDA 可以提高软件开发的效率。通过将系统设计分解为模型层次,开发人员可以更清楚地理解业务需求,并根据需求对模型进行调整。随后,可以利用模型转换工具将模型自动转换为可执行的代码,减少了手动编码的工作量,从而快速生成高质量的代码。 其次,应用 MDA 可以增强系统的可维护性和扩展性。由于模型是对系统设计的抽象表示,通过对模型进行修改可以很容易地更新系统的功能和逻辑。而且,由于模型和代码之间的映射关系明确,当需求改变时,只需对模型进行调整,而不需要对现有代码进行大规模的修改。 此外,应用 MDA 还可以促进系统的标准化和重用。通过定义通用的模型和模型规范,可以使开发人员在开发不同系统时具有一致的设计方法和开发框架。同时,可以将常见的模型和模型转换规则作为模型库和模型转换插件进行共享和重用,提高开发效率和代码质量。 最后,应用 MDA 还可以提升系统的可测试性和可靠性。通过使用模型来生成代码,可以快速生成可执行的系统,从而方便地进行测试和验证。此外,通过模型转换过程中的自动化检查和验证,可以发现和修复潜在的设计和实现问题,提高系统的质量和可靠性。 总之,将 MDA 应用于企业可以提高软件开发的效率、增强系统的可维护性和扩展性、促进系统的标准化和重用,并提升系统的可测试性和可靠性。这些优势可以帮助企业更有效地开发和维护软件系统,提高业务的竞争力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值