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

2023-11-11 12:20

本文主要是介绍【阅读笔记】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 这样的模型受限于规模,易于操作,性能方面也表现不错,可以用来处理中等大小的问题。)
基于我们尝试的经验,我们极力向大家推荐深度学习。这不仅仅是因为深度学习在线获得的强大收益,它还改变了我们未来的技术路线图。早期的机器学习主要精力花费在特征工程上,转移到深度学习后,特征组合的计算交给神经网络隐层来处理,我们有更多的精力思考更深层次的问题,比如:改进我们的优化目标。目前的搜索排名是否满足所有用户的需求?经过两年探索,我们迈出了第一步,深度学习在搜索上的应用才刚刚开始。

这篇关于【阅读笔记】Applying Deep Learning To Airbnb Search的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/390018

相关文章

Tolua使用笔记(上)

目录   1.准备工作 2.运行例子 01.HelloWorld:在C#中,创建和销毁Lua虚拟机 和 简单调用。 02.ScriptsFromFile:在C#中,对一个lua文件的执行调用 03.CallLuaFunction:在C#中,对lua函数的操作 04.AccessingLuaVariables:在C#中,对lua变量的操作 05.LuaCoroutine:在Lua中,

AssetBundle学习笔记

AssetBundle是unity自定义的资源格式,通过调用引擎的资源打包接口对资源进行打包成.assetbundle格式的资源包。本文介绍了AssetBundle的生成,使用,加载,卸载以及Unity资源更新的一个基本步骤。 目录 1.定义: 2.AssetBundle的生成: 1)设置AssetBundle包的属性——通过编辑器界面 补充:分组策略 2)调用引擎接口API

《offer来了》第二章学习笔记

1.集合 Java四种集合:List、Queue、Set和Map 1.1.List:可重复 有序的Collection ArrayList: 基于数组实现,增删慢,查询快,线程不安全 Vector: 基于数组实现,增删慢,查询快,线程安全 LinkedList: 基于双向链实现,增删快,查询慢,线程不安全 1.2.Queue:队列 ArrayBlockingQueue:

操作系统实训复习笔记(1)

目录 Linux vi/vim编辑器(简单) (1)vi/vim基本用法。 (2)vi/vim基础操作。 进程基础操作(简单) (1)fork()函数。 写文件系统函数(中等) ​编辑 (1)C语言读取文件。 (2)C语言写入文件。 1、write()函数。  读文件系统函数(简单) (1)read()函数。 作者本人的操作系统实训复习笔记 Linux

探索Elastic Search:强大的开源搜索引擎,详解及使用

🎬 鸽芷咕:个人主页  🔥 个人专栏: 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引入 全文搜索属于最常见的需求,开源的 Elasticsearch (以下简称 Elastic)是目前全文搜索引擎的首选,相信大家多多少少的都听说过它。它可以快速地储存、搜索和分析海量数据。就连维基百科、Stack Overflow、

LVGL快速入门笔记

目录 一、基础知识 1. 基础对象(lv_obj) 2. 基础对象的大小(size) 3. 基础对象的位置(position) 3.1 直接设置方式 3.2 参照父对象对齐 3.3 获取位置 4. 基础对象的盒子模型(border-box) 5. 基础对象的样式(styles) 5.1 样式的状态和部分 5.1.1 对象可以处于以下状态States的组合: 5.1.2 对象

DDS信号的发生器(验证篇)——FPGA学习笔记8

前言:第一部分详细讲解DDS核心框图,还请读者深入阅读第一部分,以便理解DDS核心思想 三刷小梅哥视频总结! 小梅哥https://www.corecourse.com/lander 一、DDS简介         DDS(Direct Digital Synthesizer)即数字合成器,是一种新型的频率合成技术,具有低成本、低功耗、高分辨率、频率转换时间短、相位连续性好等优点,对数字信

数据库原理与安全复习笔记(未完待续)

1 概念 产生与发展:人工管理阶段 → \to → 文件系统阶段 → \to → 数据库系统阶段。 数据库系统特点:数据的管理者(DBMS);数据结构化;数据共享性高,冗余度低,易于扩充;数据独立性高。DBMS 对数据的控制功能:数据的安全性保护;数据的完整性检查;并发控制;数据库恢复。 数据库技术研究领域:数据库管理系统软件的研发;数据库设计;数据库理论。数据模型要素 数据结构:描述数据库

【软考】信息系统项目管理师(高项)备考笔记——信息系统项目管理基础

信息系统项目管理基础 日常笔记 项目的特点:临时性(一次性)、独特的产品、服务或成果、逐步完善、资源约束、目的性。 临时性是指每一个项目都有确定的开始和结束日期独特性,创造独特的可交付成果,如产品、服务或成果逐步完善意味着分步、连续的积累。例如,在项目早期,项目范围的说明是粗略的,随着项目团队对目标和可交付成果的理解更完整和深入时,项目的范围也就更具体和详细。 战略管理包括以下三个过程

【软考】信息系统项目管理师(高项)备考笔记——信息化与信息系统

信息化与信息系统 最近在备考信息系统项目管理师软考证书,特记录笔记留念,也希望可以帮到有需求的人。 因为这是从notion里导出来的,格式上可能有点问题,懒的逐条修改了,还望见谅! 日常笔记 核心知识 信息的质量属性:1.精确性 2.完整性 3.可靠性 4.及时性 5.经济性 6.可验证下 7.安全性 信息的传输技术(通常指通信、网络)是信息技术的核心。另外,噪声影响的是信道