背景介绍
论文《Real-time Personalization using Embeddings for Search Ranking at Airbnb》是airbnb公布的房源推荐算法,获得了2018年的KDD最佳论文,论文基于airbnb的房源推荐场景,需要对客人和房主都进行有效的推荐,即用户输入目的地和行程日期进行搜索时,将位置、价格、风格和评价等方面对用户有吸引力的房子排前,也要考虑房主的偏好,将可能会拒绝客人的排名名降低,比如用户评价差,有宠物,人数等。论文主要服务于相似物品的推荐和搜索排序两个场景,前者是用户在浏览一个房源时,界面上的相似房源推荐,后者是用户进行搜索后的房源展示顺序,99%的房源预定都发生在这两个场景下,算法的最终目标是提升推荐房源的预订率,论文所说的实时的个性化推荐,是根据用户和房主的实时行为对房源的推荐进行一定的调整,需要注意的是文章的标题是设计了一些embedding的方法用于实时的个性化推荐,而非实时的更新。
Embedding可以将高维的id/类别类特征转换为稠密、连续的向量,向量之间可以计算夹角计算相似性,也便于神经网络的学习。embedding的计算常见的有两种:
- 有监督学习,end-to-end。embedding作为优化变量,随机初始化,在优化最终logloss的过程中,得到有意义的embedding作为“副产品”,Youtube对video_id、Wide&Deep对app_id、Deep Interest Network对商品id的embedding都是这一思路。
- 无监督学习,两步走。以Item2vec: Neural Item Embedding for Collaborative Filtering为代表。第一步,就是简单套用word2vec的思路,在电商场景,就将word2vec中的句子换成购物车,将单词换成商品;新闻推荐场景中,将句子换成session,将单词换成文章。再直接调word2vec算法,就得到商品、文章的embedding向量。第二步,这些embedding向量,可以用于召回,可以用于第一类方法的embedding矩阵的初值,也可以当特征喂入其他模型。
本文的embedding计算方式属于第二种。
论文重点内容
这篇论文的重点可以分为以下三个部分:
- Listing Embeddings
- Listing_type Embeddings 和 User_type Embeddings
- 两类embedding如何用户实时的个性化推荐
这里的listing表示房源,listing_type和user_type是粗粒度的房源类型和用户类型,文章的重点是提出了与业务紧密结合的embedding方法。下面将分别对每种embedding的设计原理、有效性验证和如何应用于实时的个性化推荐进行详细的说明。
Listing Embedding
论文用点击行为表示用户的短期兴趣,基于用户的Listing点击序列,得到每个listing的embedding。看似平淡无奇,但是有一些别致的设计:
序列的构建
每个序列都由某个用户的点击时间构成,按时间先后顺序排序,相隔超过30min的点击时间被隔开为不同的序列。
原始计算方法+负采样
类似于word2vec中的skip-gram算法,窗口大小为2m,softmax损失函数,要优化的目标函数为:
其中
vl表示房源l的向量表示。
采用了随机负采样
其中Dp表示正例,Dn表示负采样的正例,l表示Listing,c表示上下文。
采用了随机梯度下降的优化方法。
增加预定的Listing为全局内容
最初的版本是上图中橙色的部分,用户的点击序列可以分为两类,以预定为结尾的和只有点击没有预定,为了让embedding的构造不仅体现出相邻上下文的相似关系,也能体现出最后的预定信息,可以对以预定为结尾的序列,将预定的Listing作为全局的上下文,每次窗口滑动时都作为正例参与训练,即每次训练都加上图中紫色的Listing,有点类似于doc2vec中的设置,目标函数的最后一项体现了这一点。
针对搜索的市场集中的特点增加负例
订房的搜索结果通常限制在某一个市场区域中,就容易导致正例集合Dp中包含的Listing都来自同一个市场区域,而反例由于随机采样包含各个市场区域,这样就导致同一个市场的Listing的embedding训练不充分,所以文章又增加了一些搜索区域的负例,用集合Dmn表示,在目标函数上的体现如下:
Listing的冷启动Embedding设置
对于新的Listing,肯定没有embedding可用,文章利用新Listing的一些基本信息,比如位置、价格、类型等,找到三个基本距离最近、类型、价位相同的已有Embedding的Listings,将它们的Embedding做平均,作为新Listing的初始Embedding,这样的设定可以覆盖98%的新Listing。
Listing的Embedding有效性初步验证
文章在上线这种方法之前先进行了Embedding效果的观察,分三个方面:
- 观察Kmeans分到同一蔟的Listing的地理位置是否相近,考察了Embedding对市场区域的相似度的学习情况,结果发现同一蔟的Listing地理位置相近,学习有效,聚类结果还可以反过来帮助市场区域的划分;
- 用cosine相似度评估相同类型、相同价格区间的Listing相似度,比较发现类型相同、价格区间相同的Listing往往相似度更高;
-
用KNN找一些特殊结构、类型的Listing最近邻,考察Embedding对房屋结构和风格这种不易挖掘的相似度学习情况,结果找到的最近邻往往也是有相似的结构和风格,比如城堡、树屋等。
实际应用中的生成和更新
训练Listing Embedding用了8亿点击序列,使用了登陆的用户,按id进行group并按时间排序,30min无动作则隔开,并且移除了停留时间短(30s)和过短的序列(<2),最后进行匿名训练,并且对预定结尾的序列进行了5倍的过采样,训练了450万的Listing embedding。
文章使用滑动窗口,每天都对Embedding进行更新,并发现重新训练比在之前的结果上进行增量训练效果更好,学习到的embedding维度为32,Skip-gram窗口大小为10(前5后5)。使用时将Embedding结果加载在内存,并用map reduce进行实时计算。
User-type & Listing-type Embeddings
通过点击序列得到的Embedding主要体现了相同市场区域的Listing相似度,反映了用户短期的兴趣,但是用户长期的兴趣也依然有用,比如用户搜索了Los Angeles的Listing,他之前在New York和London也有预定信息,就可以给他推荐和之前预定相似的Listing。于是文章就希望利用用户的预定序列,生成能反映长期兴趣的User Embedding和Listing Embedding,分别对应租客和房源的长期兴趣。
但是对每个用户或者Listing都生成预定序列用类似上文的学习方法面临着一些现实挑战:
- 用户的预定序列数据量少,预定的数据量远少于点击;
- 有很多用户只有一次预定记录,序列长度只为1,无法使用;
- 能有效学习到Embedding的对象至少需要出现5-10次,这样的限制条件使得能用的数据量更少了;
- 预定发生时间跨度较长的话,用户的偏好可能会发生变化。
基于以上现实业务情况考虑,文章决定不以User ID和生成预定序列,而是粗化粒度,从用户类型和Listing类型的角度生成embedding。
User type和Listing type的构造
文章通过规则映射的方式将用户和Listing划分成不同的类别,如下两张表所示,以用户为例,首先根据一些基本信息或历史消费信息,根据每一维度不同取值划分成不同的桶,不同用户就会落入到不同的桶中,再综合考虑所有维度,就得到了每个用户的类别,特别的,随着时间的拉近,不同时段的用户的类别可能不同,不同Listing的类别也可能不同。
另外,一些只有基本信息可以利用的用户分到的类别还可以起到冷启动的作用。
得到在相同向量空间的结果
如果用户向量和Listing向量在相同的向量空间中,就可以直接通过相似度计算来体现二者的契合匹配程度。
文章利用用户的预定序列,将用户ID和预定的Listing ID都替换成各自对应的type,然后以用户、Listing交替的方式排列组成可用的序列,值得注意的是,这里每个序列都是某一个用户的预定记录,但是用户的类型和Listing的类型是会随着时间变化的。如下图所示,Ut代表User type,Lt代表Listing type,这里是要对Uti进行更新。
和Skip-gram类似的,采用了滑动窗口,每次对窗口中心的元素进行更新,对User type和List type的更新公式是类似的。
User type:
Listing type:
其中,book表示预定,正例,neg是反例,负采样,C表示上下文,包括了User type和Listing type,这样使得学习到的embedding在同一个向量空间。
这样构造的Listing type分布在各个市场区域,没有必要进行额外市场区域的负采样了。
加入拒绝信号
点击和预定反映了用户的兴趣,但是在airbnb里,户主是可以拒绝用户预定的,拒绝是个强烈的反映户主偏好的信号,在得到的embedding中,户主和他讨厌的用户类型不能是相似的,如果相似了进行推荐,也是不利于提升预订率的。基于这方面的考虑,文章将拒绝信号加入了目标函数中:
两类embedding如何用户实时的个性化推荐
论文主要服务于相似物品的推荐和搜索排序两个场景,前者是用户在浏览一个房源时,界面上的相似房源推荐,用到了Listing Embedding,后者是用户进行搜索后的房源展示顺序,Listing Embedding和User/Listing Type embedding都有使用。
相似房源推荐
之前的方法是利用search model的结果,经过实验发现直接用Listing embedding找相似就可以达到比之前更好的效果,经过线下验证后上线,相似房源的点击率增加了20%以上。
这是线下评价指标图,蓝色表示baseline,其余的分别表示利用不同目标函数公式后的结果,纵坐标表示预定的Listing在相似中的排名,数值越低越好,横坐标表示距离预定的点击次数,可以看出使用了embedding的方法在早期点击的优势最为明显,添加了预定信息和区域负采样的embedding方法效果最好。
搜索排序模型
原始的搜索排序模型利用了Listing/user/query的feature以及它们之间交互信息的feature,根据用户对搜索结果的交互,设定了一些label,包括{0, 0.01, 0.25, 1, -0.4},0表示房源有曝光但是没点击,0.01表示用户点击了房源,0.25表示用户联系了房东但是并没有预订,1表示房源预订成功,-0.4表示房东拒绝了用户的预订。采用的是GBDT(Gradient Boosting Decision Trees)回归算法。
文章利用了用户实时的点击等信息来构造新的相似特征加入到GBDT算法中,具体地,将用户最近两周有行为的房源做个分类,一共包括6个类别,1)用户击过的房源,用 H_c 表示;2)用户点击并且停留时长超过60秒的房源,表示长点击房源,用 H_lc 表示;3)曝光却没有点击的房源,用 H_s 表示;4)用户加入收藏的房源,用 H_w 表示;5)用户联系过房东但是却未预订的房源,用 H_i 表示;6)用户在过去两周内预定过的房源,用 H_b 表示。将候选房源与上述6个类别的房源计算相似度,作为特征加入到搜索排序模型中,如图10的前6个特征,EmbClickSim, EmbSkipSim等。这些数据都是用的用户最近两周的行为,表示用户的短期兴趣。
具体如何计算,我们以 H_c 为例进行介绍,其他5个类别的计算方法相同。对于每个类别,根据城市再一次进行划分,比如H_c中的房源来自于New York和Los Angeles两个城市,将H_c划分为H_c(NY)和H_c(LA)。将 H_c(NY) 中所有房源的embedding求平均,作为centroid embedding,然后计算当前候选房源与centroid embedding的余弦相似度。类似的,计算候选房源与 H_c(LA) 的centroid embedding的余弦相似度。最后,取两个相似度的最大值作为EmbClickSim。如果 H_c 中的房源来自于两个以上城市,也是相同的计算方法。
下图表示了各个特征的重要性和覆盖率,可以看到,UserTypeListingTypeSim, EmbClickSim和EmbSkipSim的覆盖度较高。第3列显示了特征的重要程度,分母表示一共有104个特征,分子表示该特征的重要程度排名。
对User type和List type embedding的利用就是查询现在的用户的类别和Listing的类别,求出二者的相似性作为特征。
引入 embedding features后,线上NDCU提升2.27%,booking DCU增长2.58%
总而言之,
对Listing Embedding的使用:通过获取并实时更新用户历史两周的点击等信息,构造了不同的集合,再对需要排序的Listing,计算到各个集合中Listing的相似度,作为特征加入模型中。
对User/Listing Type Embedding的使用:获取当前用户的类型和要排序的Listing的类型,计算相似度,作为特征加入模型中
在实际应用时,都将embedding或相似度加载到后端中,便于快速计算,维度设置成32也是性能和成本trade-off的结果。
参考文献:
https://astro.temple.edu/~tua95067/kdd2018.pdf
https://zhuanlan.zhihu.com/p/57234648
https://www.zhihu.com/question/302288216/answer/530729525