Press "Enter" to skip to content

KDD’2018 Best Paper-Embedding技术在Airbnb实时搜索排序中的应用

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

「本文概览」

 

 

2018年,Airbnb在KDD上发表了论文《Real-time Personalization using Embeddings for Search Ranking at Airbnb》,并被评为当次会议的最佳论文。Microstrong再次精读这篇论文的感受是:初读不知文中意,再读已是文中人。很早之前第一次读这篇论文,因为没有太多推荐相关背景及工业落地实践经验,对于文中的很多细节,没有太深的感悟。最近在工作中越发觉得自己遇到瓶颈,因此想把一些经典的论文再仔细精读一遍,希望能有更多的收获。这次再读这篇论文,文中提到的各种方法和思想已深入影响到实际落地算法中,总结成一句话就是:工程与理论、业务与算法都结合得极佳的经典之作。

 

1. Word2vec的Skip-gram模型的损失函数

 

1.1 Word2vec简介

 

对于词的向量表达的研究早已有之,但让Embedding方法空前流行,我们还是要归功于Google的Word2vec。我们简单讲一下Word2vec的原理,这对于我们后面理解Airbnb对loss function的改进至关重要。

 

既然我们要训练一个对word的语义表达,那幺训练样本显然是一个句子的集合。假设其中一个长度为T的句子为。这时我们假定每个词都跟其相邻的词的关系最密切,换句话说每个词都是由相邻的词决定的(CBOW模型的动机),或者每个词都决定了相邻的词(Skip-gram模型的动机)。如下图,CBOW的输入是周边的上下文词,预测的输出是,而Skip-gram则反之,经验上讲Skip-gram的效果好一点,所以本文从Skip-gram模型出发讲解模型细节。

 

 

1.2 原始的Skip-gram模型的目标函数

 

那幺为了产生模型的正样本,我们选一个长度为2m+1(目标词前后各选m个词)的滑动窗口,从句子左边滑倒右边,每滑一次,窗口中的词就形成了我们的一个正样本。

 

有了训练样本之后我们就可以着手定义优化目标了,既然每个词都决定了相邻词,基于极大似然,我们希望所有样本的条件概率之积最大,那幺Skip-gram模型的目标函数为:

 

其中,表示的是当前词预测到的目标上下文词的概率,是中心词的所有上下文集合。相应地可以简化为:

 

上式中是语料中所有单词和上下文的集合。

 

接下来的问题是怎幺定义,作为一个多分类问题,最简单最直接的方法当然是直接用softmax函数,我们又希望用向量表示每个词,用词之间的距离表示语义的接近程度,那幺我们的条件概率的定义就可以很直观的写出:

 

其中和可以看成是上下文词和中心词的词向量。关于如何得到这个目标函数接下来会讲,那幺将该式子代入上式并取log可以得到:

 

对上述目标函数求最大化,可以让相似的词具有相似的向量值。

 

1.3 如何推导得到目标函数

 

 

几个参数说明:表示词典大小,表示词向量的纬度,表示大小为矩阵。该图可以看成是Skip-gram的简单情况,其中假设中心词的上下文只有一个。输入层是one-hot编码,经过中间层的变换后,得到隐藏层为,刚好对应的是输入词的词向量。由于隐藏层采用线性变换,那幺隐藏层输出仍然是。再次经过的变换后,可以得到输出层为。这里将看做是,那幺:

 

在输出层中采用softmax函数,那幺可以得到对应概率为:

 

「那幺到底什幺是我们通常意义上所说的词向量呢?」

 

在获得输入向量矩阵后,其中每一行对应的权重向量就是通常意义上的“词向量”。于是这个权重矩阵自然转换成了Word2vec的查找表(lookup table),如下图所示。例如,输入向量是10000个词组成的one-hot向量,隐层纬度是300维,那幺输入层到隐层的权重矩阵为纬。在转换为词向量查找表后,每行的权重即成了对应词的Embedding向量。

 

 

「那幺问题来了,我们能把输出矩阵的列向量当作word的vector表达吗?」

 

从Word2vec的网络结构上看Skip-gram的反向就是CBOW,CBOW的反向就是skip-gram,输入矩阵的向量和输出矩阵的向量是等价的,都可以作为单词的Embedding。

 

1.4 采用负采样的目标函数

 

上面给出了Word2vec的模型结构和训练方法,但事实上,完全遵循原始的Word2vec多分类结构的训练方法并不可行。假设语料库中的词的数量为10000,就意味着输出层神经元有10000个,在每次迭代更新隐层到输出层神经元的权重时,都需要计算所有字典中的所有10000个词的预测误差,在实际训练过程中几乎无法承受这样巨大的计算量。

 

为了减轻Word2vec的训练负担,往往采用负采样(Negative Sampling)的方法进行训练。相比原来需要计算所有字典中所有词的预测误差,负采样方法只需要对采样出的几个负样本计算预测误差。在此情况下,Word2vec模型的优化目标从一个多分类问题退化成了一个近似二分类问题。接下来我们仔细推导一下。

 

如果对上述目标函数进行优化,第二项需要对词典里的所有词进行优化,所以计算量比较大。如果换个角度考虑,我们将正常的上下文组合看成是1,不正常的上下文组合看成是0,那幺问题转换为二分类问题,我们现在的目标是找到参数来最大化输出的上下文词都是中心词的上下文词的概率:

 

将输出层的softmax函数改为sigmoid函数,那幺:

 

同样代入上式可以得到:

 

但是这个目标函数存在问题,如果,并且足够大的话,就能取到最大值,这样所有词向量都是一样的,得到的词向量没有意义。所以考虑负采样,即引入负样本,那幺:

 

上式结果中,损失函数的 「正样本项前面有负号」 ,是由于sigmoid 自带负号。 「负样本项前面是无负号」 ,是由于

 

令:

 

那幺得到:

 

至此,基于Negative sampling方法的Skip-gram模型的损失函数已经推导完毕,该损失函数也和Airbnb这篇论文初始的objective function几乎一模一样,形式如下:

 

2. Airbnb基于用户短期和长期兴趣的Embedding召回

 

2.1 Airbnb业务场景

 

Airbnb作为全世界最大的短租网站,提供了一个连接房主(Host)挂出的房源(Listing)和主要是以旅游为目的的租客(Guest/User)的中介平台。这样一个中介平台的交互方式比较简单,租客输入地点、价位、关键词等,Airbnb会给出房源的搜索推荐列表,如下图所示。

 

 

在根据用户搜索返回推荐结果后,用户和房主之间的交互如下图所示。用户在点击房源后(Click),发出预定请求(Booking Request),房主有可能拒绝(Reject)、同意(Accept)或者不响应(No Response)。

 

 

Airbnb主要基于点击序列和预定序列,生成房源的Embedding,然后用于召回或排序。在Embedding方法上,Airbnb基于Word2vec原理,生成了两种不同的Embedding,分别用于表达用户的短期兴趣和长期兴趣。短期兴趣Embedding可以用于相似房源推荐,长期兴趣Embedding可以用于推荐用户之前预定的房源偏好。论文通过两种方式生成了这两种不同的Embedding分别捕捉用户的“短期”和“长期”的兴趣:

 

「一是通过Click session数据生成listing的Embedding」,生成这个Embedding的目的是为了进行Listing的相似推荐,以及对用户进行session内的实时个性化推荐。

 

「二是通过Booking session生成User-type和Listing-type的Embedding」,目的是捕捉不同User-type的长期喜好。之所以要引入预定房源序列,是因为用户的预定是低频行为,而点击是高频行为,用户可能在一天就点击了很多房源,因此点击序列更多刻画的是短期兴趣,而用户在一年可能只预定过几次,因此预定行为反应的是长期兴趣。由于预定信息过于稀疏,Airbnb对同属性的User和Listing进行了聚合,形成了User-type和Listing-type这两个Embedding的对象。

 

2.2 基于短期兴趣的房源Embedding

 

2.2.1 目标函数的进化

 

Airbnb采用了Click session数据对房源进行Embedding,捕捉用户在一次搜索过程中的短期兴趣。其中Click session指的是一个用户在一次搜索过程中“点击的房源序列”,这个序列需要满足两个条件:

 

一个是只有在房源详情页(Listing page)停留时间超过30秒的房源才被算作Session中的一个数据点;

 

二是如果用户超过30分钟没有动作,那幺这个Session会断掉,不再是一个序列。

 

这幺做的目的有两个:

 

一是清洗噪声点和负反馈信号;

 

二是避免非相关序列的产生。

 

 

有了Session的定义,就可以使用Word2vec中的Skip-gram模型训练房源Embedding,优化目标定义如下:

 

其中是session内的中心房源,是滑动窗口内的房源,是正样本集合,是负样本集合。正样本很自然的取自Click session滑动窗口里的两个Listing,负样本则是在确定Central listing后随机从语料库(这里就是Listing的集合)中选取一个Listing作为负样本。

 

Airbnb希望能够把预定房源(Booked listing)信息引入Embedding的生成过程中。这样直观上可以使Airbnb的搜索列表和Similar item列表中更倾向于推荐之前预定成功Session中的房源。从这个Motivation出发,Airbnb把Click session分成两类:

 

Booked sessions:用户最终产生预定行为的点击session;

 

Exploratory sessions:用户最终没有产生预定行为的点击session。

 

在Booked session中,只有最后一个房源是被预定的,为了将这个预定行为引入目标函数,不管这个预定行为是否在Word2vec的滑动窗口内,都假设这个预定房源与滑动窗口的中心房源相关,所以相当于引入了一个Global context到目标函数中。因此,Skip-gram模型结构变成下图的形式。

 

 

上图显示了将预定房源(Booked listing)引入Skip-gram模型中,相当于增加了一个正样本,优化目标变成下面的形式:

 

其中,最后一项代表被预定房源。因为预定是一个正样本行为,这一项前也是有负号的。

 

需要注意的是最后一项前是没有符号的,前面的符号是因为滑动窗口中的中心房源(Central listing)与所有滑动窗口中的其他房源都相关,最后一项没有符号直观理解是因为预定房源只有一个,所以中心房源只与这一个有关。

 

2.2.2 Airbnb中负样本的构造

 

(1)随机负样本

 

Airbnb中选取负样本的第一种方法是,用Word2vec的Negative sampling方法,从所有房源中随机带权选取负样本。根据Item频度的幂来采样负样本,可以解决高频(热门)Item在正样本出现过多、Embedding学习完后,大多Item embedding最相似的都是这些高频Item的问题。

 

「这里引申出一个问题:在推荐系统中模型召回是怎幺实现热门item的打压?」

 

针对这个问题,我们可以把它拆解成两个小问题来逐步解答。

 

首先第一个小问题就是: 「为什幺要打压热门item?」

 

任何一个推荐系统,都难逃“2-8”定律的影响,即20%的热门item占据了80%的曝光量或点击量。因为三元组<user, item+, item->中item+来源于“用户点击过”的item,因此item+主要是热门item。训练时,为了降低loss, 「算法会使每个user embedding尽可能接近少数热门item embedding」 。预测时,每个user embedding从FAISS检索出来的邻居都是那少数几个热门item  embedding, 「完全失去了个性化」 。由此可见,“打压热门item”的必要性。

 

然后第二个小问题就是: 「打压热门item的方法?」

 

因为item出现的位置既可能是item+也可能是item-,因此打压热门item,也需要从这两方面入手,而采取截然不同的策略。

 

1)生成item+时,打压高热item。目标是 「降低热门item成为item+的可能性」 。因此,item越热门,其成为item+的概率就应该越低。

 

2)生成item-时,打压高热item。目标是 「提升热门item成为item-的概率」 。可以从两个角度来理解:

 

既然热门item已经“绑架”了item+,我们也需要提高热门item在item-中的比例,以 「抵销」 热门item对loss的影响;

 

如果在采样生成item-时采取uniform sampling,因为有海量的候选item,而采样量有限,因此极有可能采样得到的item与user“八杆子打不着”,既所谓的 「easy negative」 。而如果多采集一些热门item当item-,因为绝大多数用户都喜欢热门item,这样采集到的item-是所谓的 「hard negative」 ,会极大地提升模型的分辨能力。

 

所以在随机采样负样本时,一方面需要采集到的item-能够尽可能广泛地覆盖所有候选item,另一方面又需要使采集到的item-尽量集中于高热item。

 

关于具体解决推荐系统模型召回打压热门item的方法,可以详细阅读我下面给出的文章。

 

「【推荐阅读】」

 

推荐系统传统召回是怎幺实现热门item的打压? – 石塔西的回答 – 知乎 https://www.zhihu.com/question/426543628/answer/1631702878

 

(2)相同Market的负样本

 

在Airbnb场景,用户总是喜欢搜索同一地区的房源,比如用户想去纽约,就会一直搜索纽约的房源,这样导致正样本集合中的房源主要来自同一地区,而负样本集合中的房源主要来自不同地区,这种不平衡导致一个地区内的相似性不是最优的,会出现并不相似的房源计算出的相似度也很高。为了解决这一问题,Airbnb新增了一组负样本,从与中心房源l同一地区的房源中进行随机采样。新的目标函数变成下面的形式:

 

其中,指的是与中心房源在同一地区的负样本集合。

 

在房源Embedding表示学习中,除随机负样本以外,通常可以选取一些Hard negatives ,例如和正样本在相同类目下的其他样本。通过将随机负样本和Hard negatives以一定比例混合,可以使学习的模型更加有区分度。论文《Embedding-based Retrieval in Facebook Search》介绍了Facebook在负样本选取、混合的一些经验。

 

2.2.3 新房源的冷启动问题

 

Airbnb每天都有新上的房源,但是因为其没有出现在训练集中,导致无法产出其Embedding。这里采用的解决办法是用最相近的三个房源的平均Embedding进行表示。衡量房源的相近程度可以采用位置、价格、房源类型等,且要求距离在10英里内。

 

这里可以带给我们很多思考,不仅对于新物品,同样对于新用户,依旧可以采用其属性相近的n个用户的平均Embedding作为其Embedding表示。

 

2.2.4 对房源Embedding的相似效果进行检验

 

8亿的搜索点击房源Session作为训练集构建房源的Embedding,每个房源Embedding的维度为32,后文也提到了32维实验效果比较好,而且节省存储空间。

 

对于 Embedding 质量的评估,Airbnb 使用了很多方法,主要的思想还是通过 Embedding 相似度的方法来进行的,论文中提到了以下几种方式:

 

(1)通过K-Means对房源Embedding进行聚类,对于房源的重新定价很有参考意义。评估地理位置相似性是否被包含,对 Embedding 进行了k 均值聚类 (k-means clustering)。下面的图显示了美国加州产生的 100 个聚类,确定了来自近似位置的房源基本能够聚集在一起。

 

 

(2)评估房源特征相似性是否被包含。评估了洛杉矶附近不同类型房源的Embedding相似度(Table 1)和不同价格区间房源的Embedding相似度(Table 2)。

 

表1是不同房源类型的相似度,可以看到对角线上的相似度最大,也就是同类型房源的相似度更大。

 

 

表2是不同价格区间房源的相似度,同样是对角线上的相似度最大,即相同价格区间的房源相似度更大。从表2还可以看出,价格区间越接近,相似度越大。

 

 

论文评估了不同类型(整套房源,独立房间,共享房间)和价格范围的房源之间的平均余弦相似性 (cosine similarity),并确认相同类型和价格范围的房源之间的余弦相似性远高于不同类型和不同价格的房源之间的相似性。 从实验结果中可以看出相同类型或者相同价格范围内的房源平均相似度要明显高于不同类型或者不同价格范围的房源平均相似度,因此说明Emedding是有效的。我们可以得出结论,房源特征也被很好的包括在训练好的 Embedding 中了。

 

(3)评估一些隐式房源特征。部分类型的房源特征(例如建筑风格、样式和感觉)很难提取为房源特征的形式。 为了评估这些特性并能够在 Embedding 空间中进行快速简便的探索,Airbnb 内部开发了一个相似性探索工具 (Similarity Exploration Tool),下图的示例表明,通过 Embedding 能够找到相同独特建筑风格的相似房源,包括船屋、树屋、城堡等,说明即使我们不利用图片信息,也能从用户的 click session 中挖掘出相似风格的房源。

 

 

(4)论文还提出一种离线评估方法,测试通过用户最近的点击来推荐的房源,有多大可能最终会产生预订。更具体地,假设已经获得了最近点击的房源和需要排序的房源候选列表,其中包括用户最终预订的房源;通过计算点击房源和候选房源在 Embedding 空间的余弦相似度,对候选房源进行排序,并观察最终被预订的房源在排序中的位置。这种方法的详细介绍在本文的“3.2 召回效果评估”。

 

2.3 基于长期兴趣的用户Embedding和房源Embedding

 

论文刚看到这里的时候,有两个词把我搞懵了:booked sessions 和 booking sessions。这里我重新解释一下这两个序列的区别:

 

Booked sessions:用户最终产生预定行为的点击session;

 

Booking sessions:用户按时间顺序预定的一系列房源组成的session。

 

短期兴趣Embedding使用用户的 「点击数据」 构建了房源的Embedding,基于该Embedding可以很好的找出相似房源,但有所欠缺的是,该Embedding并没有包含用户的长期兴趣信息。比如用户6个月前订过一个房源,其中包含了该用户对于房屋价格、房屋类型等属性的长期偏好,但由于之前的Embedding只使用了session级别的点击数据,从而明显丢失了用户的长期兴趣信息。

 

为了捕捉用户的长期偏好,Airbnb使用了预定会话序列(booking session)。比如用户j在过去1年依次预定过5个房源,那幺其预定会话就是。既然有了预定会话的集合,是否可以像之前对待点击会话(click session)那样将Word2vec的方法得到Embedding上呢?答案是否定的,因为会遇到非常棘手的数据稀疏问题。

 

具体来讲预定会话的数据稀疏问题表现在下面四点上:

 

预定数据相对点击数据要稀疏的多;

 

很多用户在过去时间段内只有一个预定;

 

如果要学习listing(房源)的Embedding,至少需要该房源出现5-10次,但是通过预定构建的数据集很多都小于5-10次;

 

用户的两次预定之间相差时间较长,这期间用户的兴趣会发生变化;

 

如何解决如此严重的数据稀疏问题,训练出有意义的用户Embedding和房源Embedding呢?Airbnb给出的答案是基于某些属性规则做相似用户和相似房源的聚合。

 

2.3.1 用户类型和房源类型的定义

 

举例来说,房源的属性如下表所示:

 

 

比如美国的一个房源,其属性为:

 

listing type:entire home

 

per night:$60.8

 

per guest:$29.3

 

number reviews:5

 

list 5 star%:全部是5 star

 

capacity:2 person

 

num beds:1

 

bedroom:1

 

bathroom:1

 

new guest accept:100%

 

那幺可以用属性名和分桶id(这里指属性值对应的序号)组成一个属性标识。例如,上面房源的国家是US,房源类型(listing type)是Ent(bucket 1),每晚的价格(per night)是56-59美金(bucket 3),那幺该房源的listing_type可以表示为:。

 

用户属性的定义同理,从下表中可以看出,用户属性包括设备类型、是否填写简介、是否有头像照片、之前定过的平均价位、历史预定次数等等。可以看出,用户属性是指一些非常基础和通用的属性,这对于我们来说也有借鉴意义,因为任何网络服务都可以很容易的找出这些属性。

 

 

同样对于一个用户,其属性为:

 

market:San Franciso

 

Language:English

 

Device Type:MacBook laptop

 

Full Profile:full profile

 

Profile Photo:user photo

 

Number Bookings:0

 

Per night:$52.52

 

Per Guest:$31.85

 

capacity:2.33

 

num reviews:8.24

 

listing 5 star%:76.1%

 

guest 5 star%:83.4%

 

那幺其类型可以表示为:

 

「注意的是,对于第一次预定的新用户或未登录用户,使用表中的前5行进行用户类型的定义,这在一定程度上可以缓解用户冷启动问题。」

 

2.3.2 目标函数

 

有了用户类型(user type)和房源类型(listing type)之后,就可以用聚合数据的方式生成新的 「预定序列」 (booking session sequence)。直接用用户类型替代原来的user id,生成一个由所有该用户类型预定房源历史组成的预定序列。这种方法解决了用户预定数据稀疏的问题。

 

在得到用户类型的预定序列之后,如何得到用户类型和房源类型的Embedding呢?为了让user type Embedding 和 listing type Embedding在同一个向量空间中生成,Airbnb采用了一种比较“反直觉”的方式。

 

针对某一user id按时间排序的booking session,我们用(user_type, listing_type)组成的元组替换掉原来的listing item,因此原序列就变成了,这里指的就是房源对应的listing type,指的是该user在预定房源时的user type,由于用户的user_type会随着时间变化,所以不一定相同。

 

有了预定序列,接下来便可以使用Skip-gram训练Embedding,模型结构如下图所示。

 

 

上图显示了中心词是user_type时的模型结构,从图中可以看出,Airbnb在训练user_type Embedding和listing_type Embedding时没有任何区分,把user_type和listing_type当作完全相同的词进行训练,这样可以保证用户Embedding和房源Embedding在相同空间,可以直接计算二者的相似度。

 

当中心词是时,目标函数如下所示:

 

当中心词时时,目标函数如下:

 

其中是中心词附近用户分组(user_type)和房源分组(listing_type)的集合。由于预定序列中的房源大多来自不同地区,因此这里不再需要对相同地区房源进行负采样。

 

2.3.3 目标函数上增加了被拒绝的优化项

 

和点击行为只反映用户信息不同,预定行为还包含了房主的信息,有些房主在接到预定请求后,可能选择拒绝,原因可能是用户信息不全,或者用户信誉低。因此,在预定序列中,Airbnb引入了额外的房主拒绝的负样本集合,模型结构如下图所示。

 

 

上图显示了用户user i预定房源listing i,被房主拒绝,模型结构中增加了该负样本。

 

当用户进行房源预定时,房主也可以根据用户的情况进行拒绝,因此在目标函数上增加了被拒绝的优化项,其目标函数如下所示:

 

如果更新的中心词是user_type()时,目标函数如下所示:

 

如果更新的中心词时listing_type()时,目标函数如下:

 

因为进行booking sessions构建时,将用户类型和房源类型进行了展开,将其Embedding映射到同一空间内,因此可以通过计算用户类型和房源类型的Embedding余弦相似度进行候选池的召回,如下图所示。

 

 

3 实验部分

 

3.1 训练房源Embeddings的细节

 

基于用户短期兴趣进行房源Embedding的构造:8亿的搜索点击房源session作为训练集构建房源的embedding,每个房源Embedding的维度为32(后文也提到了32维实验效果比较好,而且节省存储空间)。在进行数据构造时,移除了用户停留时间小于30秒的房源,保留了房源出现次数大于等于2的。同时对booked sessions进行了5倍的过采样。

 

基于用户长期兴趣进行房源Embedding的构造:使用5千万用户的预定数据进行预定sesssion的构建。

 

实验表明每天重新对房源进行embedding学习要比增量训练效果好。

 

试验参数:embedding维度32,滑动窗口为5,迭代次数为10。

 

训练平台:C版本的word2vec,基于MapReduce进行训练,300个mappers 1个reduce,使用AirFlow进行pipline的构建。

 

在构造booked sessions时,因为预定房源的行为较少,因此对此进行了加强,采用了过采样(重复正样本的比例,与之对应的是欠采样)的技术,比例为5倍,关于过采样和欠采样会对模型产生怎幺样的影响可以参考:欠采样(undersampling)和过采样(oversampling)会对模型带来怎样的影响? – 知乎 https://www.zhihu.com/question/269698662

 

「这里讨论一个问题:为什幺每天重新训练房源Embedding要比增量训练要好呢?」

 

模型增量训练,有没有定时全量重跑训练,比如,增量训练后期模型的梯度值都特别小,发现模型的参数矩阵方差和均值都没有变化,有没有拿最近三天的数据重新训练模型上线呢?因为增量后期,模型参数变化较少,可能不适应最新的数据分布变化,影响线上打分结果。

 

以上是我根据自己平时的实践思考的答案,欢迎有不同见解的同学留言讨论呀~

 

3.2 召回效果评估

 

离线评估一直是召回的难题,Airbnb的方法是通过测试用户最近的点击来推荐房源,有多大可能最终会产生预定,使用这一方法来评估模型训练出的Embedding效果。

 

具体地,假设获得了用户最近点击的房源和候选房源集合,其中包含用户最终预定的房源,通过计算点击房源和候选房源的相似度,对候选房源进行排序,并观察预定房源在候选房源中的排序位置,如果排序位置越靠前,说明Embedding效果越好。

 

 

上图显示了评估结果,横坐标表示最近的17次点击,比如-2表示倒数第二次点击,纵坐标表示预定房源在排序中的位置,d32 reg表示序列中没有加预定房源,d32 book表示序列中引入预定房源,d32 book+neg表示引入了同一地区负样本集合。比如使用d32 book+neg计算倒数第2次点击(-2)和所有候选房源相似度,最终预定房源的平均位置在4.5,而d32 reg计算出的平均位置在4.9,因此book+neg的效果更好。

 

「这里讨论一下:如何离线准确地评估召回模型的效果?」

 

在我做召回的实际工作中,我一直缺乏一种置信、可靠的手段来准确地离线评估召回模型。当然,最好的方法肯定是线上ab实验,但是ps资源和线上流量都有限,最近我也一直在思考怎幺离线评估召回,提一些我的想法:

 

首先auc高并不代表召回的好,因为我们往往采样的负样本都是easy的,这样召回模型的auc一般都是偏高的(auc=0.8+/0.9+都是有可能的)。实际上好的召回可能auc低一些,但是会召回出更符合真实分布的内容,实际工作中auc当作参考就好。召回模型auc高也引出另一个召回的问题,就是如何挖掘hard负样本,以提升模型对于边界样本的区分能力,挖掘出好的hard负样本,也能减缓召回模型auc过高的问题。

 

拿Top K召回结果与用户实际点击做交集并计算precision/recall,感觉现在大多都是用的这个方法,但是我总感觉极端条件下N路召回全都100%准确率召回率,那其实5路变成1路就好了,而且完全在拟合精排,又陷入了无探索的困境,因为召回的结果未被用户点击,未必说明用户不喜欢,而可能是由于该召回结果压根没有给用户曝光过。

 

召回diff率。其实我现在还比较喜欢拿这个来预估要不要上线,因为diff高才有bagging一路召回的价值(当然还有是否保送,精排是否能排出来的问题)。

 

人肉debug:这种方法是我目前感觉最靠谱的一种方法,就是拿自己和组里同学的uid模拟请求该路召回算法,显示出Top20/Top50/Top100的结果,拿这些结果与自己的用户画像中的兴趣点进行比对,看召回出的内容是否符合自己的兴趣点。还有,就是观察召回出结果的后验数据(曝光量、点击率、点赞率等等),因为模型类召回都是偏热门,如果召回的结果曝光量较少,那肯定是有问题的。这个时候分两部分查问题:user部分就是看模型训练是否正常,auc是否正常,模型导出到上线链路是否正常。item部分就看item embedding导出和入Faiss库是否正常。还有就是模型和faiss库中Embedding版本要一致。

 

「再引申出一个问题:如何进行Embedding质量、效果的评估?」

 

论文中提出的4种Embedding效果评估方法很值得借鉴和学习,在日常的工作中其实很痛苦的就是Embedding的评估,但是本小节提出的这种方法在整理数据时会比较耗费时间,因此如何能够搭建一套有效的Embedding效果评估方案就变得比较重要。

 

另外一种评估方法就是直接上线进行AB实验,但这种方法周期会比较长,不利于模型的迭代和更新。

 

那幺你认为如何进行Embedding的效果评估?

 

3.3 Embedding在相似房源推荐中的应用

 

相似房源推荐用的是 Clicked Session 学习到的 Listing Embedding,用法也非常简单,就是通过 K 近邻找到与给定房源(点击的是该房源的详情页)最相似的 K 个房源,Airbnb 中的 K 设定是 12,并且对候选房源做了一定的筛选,比如只计算与给定房源在同一城市的房源,还有就是如果用户设置了入住和退房日期,则筛选在这个时段内的可预订的房源。从下图中可以看出,根据房源Embedding选出的相似房源在价格、类型、建筑风格上都很相似。

 

 

Airbnb 通过 A/B 测试显示,基于 Embedding 的解决方案使 「相似房源的点击率增加了 21%」 ,最终 「通过相似房源推荐场景产生的预订增加了 4.9%」 。因此,向量化(Embedding)非常适合用于推荐系统的召回阶段,服务线上推荐系统。

 

3.4 Airbnb的实时搜索排序模型及其特征工程

 

上面介绍了Airbnb对用户短期和长期兴趣进行用户和房源Embedding的方法,需要强调的是,Airbnb并没有直接把Embedding相似度排名当作搜索结果,而是基于Embedding得到不同的用户房源相关特征(user-listing pair feature),然后输入搜索排序模型,得到最终的排序结果。下面我们来看一看airbnb的搜索排序模型和特征。

 

「Airbnb采用的搜索排序模型是一个pairwise的支持Lambda Rank的GBDT模型」。该模型已经由Airbnb的工程师开源,感兴趣的同学可以去学习一下(github地址:https://github.com/yarny/gbdt),此处对于 Embedding 应用,更多是在特征工程上。

 

根据前面得到的 Listing Embeddings 和 User-Type Embedding、Listing-Type Embeddings 生成的 Feature 如下表所示:

 

 

上表中第一区域内(前 6 个特征)的都是短期特征(short-term feature),首先利用 kafka 来实时收集和维护过去两周内的用户行为数据,然后通过对应的 Listing Embedding 计算相关的相似度,下面是这些特征描述中对应符号的具体含义:

 

 

其他应该都很好理解,这里重点说一下,它表示用户在过去 2 周内跳过的房源 ID。这里将跳过的房源定义为排序较靠前的房源,但用户跳过了此房源并点击了排序较靠后的房源。

 

来看看这六个短期特征具体是如何计算的,用户在搜索时会返回候选房源(无序),对于每个候选房源,计算其对应 Embedding 与用户两周内的各个行为(上面的六个)所产生的房源的平均 Embedding 相似度,以 EmbClickSim 为例,计算公式为:

 

这里关键是对于两周内点击的房源(listing)所对应 Embedding 的处理(得先处理成一个,然后才可以和候选 listing 做相似度计算),一般是直接取平均就行了,但 Airbnb 的做法考虑了房源所在地的因素,即是先对用户两周内点击的房源按照其所在地(market)分为个 market 集合,然后分别对每个 market 集合内的所有 Listing Embedding 向量求平均并与候选房源计算 cosine 相似度,最后从个 cosine 相似度中取最大的那个值作为最终的特征值。

 

剩余的五个计算方法与上面一样。

 

第二个区域的特征也是一个短期特征,不过它是单独增加的一个重要特征,即计算候选房源与最后一次 long-clicked 对应房源的 Embedding 相似度,通过这个特征可以得到用户 “实时” 在意的反馈信息,公式如下:

 

第三个区域就是 Type 类 Embedding 特征了,他们属于长期特征(long-term feature),首先根据候选房源查找到对应的 listing type以及 user type,然后计算二者对应的 Embedding 向量的 cosine 相似度,公式如下:

 

论文给出了以上特征在样本中的覆盖率及在模型中的特征重要度,见下表:

 

 

上面的特征由多种 Embedding 计算得来,所以包含了短期 session 内的(In-session)信息(例如,喜欢(liked)、点击(clicks)、与主人的联系(host contacts)等),也包含用户的长期兴趣信息,Airbnb 就是借助于这些特征来实现 「实时个性化搜索推荐」 的, 目标是给用户展示与 In-session 信号相似的多个 listings。Airbnb 称这种方法为 「Real-Time Personalization或In-session Personalization」 ,这也是论文标题中 Real-Time Personalization 所表达的意思。

 

细心的读者可能会有一个疑问——Airbnb强调的“实时”系统中的“实时”到底体现在哪儿?其实通过上面的特征设计就可以给出这个问题的答案了。在这些Embedding相关的特征中,Airbnb加入了“最近点击房源的相似度(EmbClickSim)”、”最后点击房源的相似度(EmbLastLongClickSim)”这类特征。由于这类特征的存在,用户在点击浏览的过程中就可以得到实时的反馈,搜索结果也可以实时地根据用户的点击行为而改变。

 

3.5 搜索 Query Embedding 的应用

 

其实除了计算用户和房源的Embedding外,Airbnb还在其搜索推荐系统中对搜索词(query)进行了Embedding,和普通搜索引擎的 Embedding 不太相同的是,这里的 Embedding 不是用自然语言中的语料库去训练的,而是用 Search Session 作为关系训练数据,训练方式更类似于 Item2Vec。Airbnb 中 Queue Embedding 的一个很重要的作用是捕获用户模糊查询与相关目的地的关联,这样做的好处是可以使搜索结果不再仅仅是简单地进行关键字匹配,而是通过更深层次的语义和关系来找到关联信息。比如下图所示的使用 Query Embedding 之前和之后的两个示例(Airbnb 非常人性化地在搜索栏的添加了自动补全,通过算法去 “猜想” 用户的真实目的,大大提高了用户的检索体验):

 

 

引入Embedding前后搜索“Greek Islands”的搜索结果对比

 

 

引入Embedding前后搜索“France Skiing”的搜索结果对比

 

可以看出,在引入Embedding之前,搜索结果只能是输入的关键词,而引入Embedding之后,搜索结果甚至能够捕捉到搜索词的语义信息。例如,输入France Skiing(法国滑雪),虽然结果中没有一个地点名带有Skiing这个关键词,但联系结果中都是法国的滑雪胜地,这无疑是更接近用户动机的结果。

 

为了让 Embedding 包含这种模糊查询和相关目的地的关联信息,利用 Search Session 构建训练序列的时候,就会非常注重这种关系的序列构成,所以这个 Search Session 序列构建的过程其实是通过用户查询关键词 Query 以及点击目的地来构建的,Airbnb 将目的地用 geo_ID 形式来表示,所以 Search Session 就成为如下图所示的样子:

 

 

有了 Search Session 序列,训练方式基本和之前谈到的方法差不多,这里不再赘述。

 

4. 这篇论文在工业界落地的案例

 

我收集了一些各个公司参考或借鉴Airbnb房源Embedding方法的落地案例,这里给大家列出来了。如果后续有同学看到和Airbnb这篇论文相关的其它工业界落地案例,也可以在留言区给出评论或链接哈~

 

Embedding技术在58房产推荐中的应用,地址:https://mp.weixin.qq.com/s/Qf-xVrO8FqonRNN9wh4WlA

 

Embedding在腾讯应用宝的推荐实践,地址:https://mp.weixin.qq.com/s/Hsw_IbphFotR-Q89wKpMXQ

 

美图个性化推送的 AI 探索之路,地址:https://mp.weixin.qq.com/s/HRGk5bfaOdj-6X4opEYA-w

 

Embedding技术在58商业的探索与实践,地址:https://mp.weixin.qq.com/s/XanNsacqzkywtKYlVUexSg

 

推荐系统 embedding 技术实践总结 – 腾讯技术工程的文章 – 知乎 https://zhuanlan.zhihu.com/p/143763320

 

大众点评搜索基于知识图谱的深度学习排序实践 ,地址:https://tech.meituan.com/2019/01/17/dianping-search-deeplearning.html

 

Embedding 模型在搜狐新闻推荐系统的应用,地址:https://mp.weixin.qq.com/s/sKHFD3XZ4HZOeZ4wqc-rMA

 

案例分享 | TensorFlow 在贝壳找房中的实践,地址:https://mp.weixin.qq.com/s/B29wlVM4E3efxCywCy8Xnw

 

深度广度模型在用户购房意愿量化的应用,地址:https://mp.weixin.qq.com/s/PKb28opxWGh0av-6WrOzZw

 

Embedding 技术在民宿推荐中的应用,https://mp.weixin.qq.com/s/MhRGX_tnhTrtvrkduf8OVQ

 

5. 总结模型中引入Global信息的做法

 

这篇论文是在优化目标里引入了全局信息-Global context,令人印象深刻。

 

阿里妈妈的论文《Search-based User Interest Modeling with Lifelong Sequential Behavior Data for Click-Through Rate Prediction》简称SIM,就是为了在Global的互动历史里搜索,不愿意丢弃任何一个历史互动。

 

推荐邻域算法关注更多的是Local的信息,而矩阵分解则能关注到全局的信息。

 

跨样本的处理,比如Gnn,相对于单样本处理来说,是引入了更多Global的信息。同时Gnn自身,邻居的选择上是Local处理,而消息的传播则会带动Global的传递。

 

Attention相对RNN,也是为了能够看到更多的信息,往Global信息方向努力。

 

Global Attention vs Local Attention,显而易见,为了引入全局信息。

 

Word2vec的处理窗口非常Local,但Bert等会引入更长的上下文,达到句子级别,这也是Local往Global的趋势。

 

甚至召回的负采样也可以看做往Global样本空间的努力。

 

如何在模型里利用好Local信息,但又兼顾到Global的处理,应该是一个提效的理想方向。

 

6. Reference

 

【1】Word2vec负采样 – linhao_0204 – 博客园 ,地址:https://www.cnblogs.com/linhao-0204/p/9126037.html

 

【2】万物皆Embedding,从经典的word2vec到深度学习基本操作item2vec – 王喆的文章 – 知乎 https://zhuanlan.zhihu.com/p/53194407

 

【3】《word2vec Explained: Deriving Mikolov et al.’s Negative-Sampling Word-Embedding Method》,地址:https://arxiv.org/pdf/1402.3722.pdf

 

【4】【总结】推荐系统——召回篇【4】 – 绝密伏击的文章 – 知乎 https://zhuanlan.zhihu.com/p/356560809

 

【5】从KDD 2018 Best Paper看Airbnb实时搜索排序中的Embedding技巧 – 王喆的文章 – 知乎 https://zhuanlan.zhihu.com/p/55149901

 

【6】Airbnb搜索:Embedding表示学习 – 谷育龙Eric的文章 – 知乎 https://zhuanlan.zhihu.com/p/240252162

 

【7】论文|Airbnb Embedding的实践和思考 – Thinkgamer的文章 – 知乎 https://zhuanlan.zhihu.com/p/305687427

 

【8】Airbnb如何解决Embedding的数据稀疏问题? – 王喆的文章 – 知乎 https://zhuanlan.zhihu.com/p/57313656

 

【9】EMBEDDING 在大厂推荐场景中的工程化实践,地址:Embedding 在大厂推荐场景中的工程化实践

 

【10】召回模型中的负样本构造 – iwtbs的文章 – 知乎 https://zhuanlan.zhihu.com/p/358450850

 

【11】模型里头的local和global – 彭红卿的文章 – 知乎 https://zhuanlan.zhihu.com/p/410008192

 

【12】再评Airbnb的经典Embedding论文 – 石塔西的文章 – 知乎 https://zhuanlan.zhihu.com/p/162163054

 

【13】学习Airbnb是如何将”业务”与”算法”结合的 – 石塔西的文章 – 知乎 https://zhuanlan.zhihu.com/p/50081120

 

 

Be First to Comment

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注