机器学习(ML)(十四) — 推荐系统探析

排序 - 多目标模型

我们先回顾一下推荐系统的链路,分为召回,粗排、精排、重排。有很多条召回通道,从几亿个物品选出几千个物品,做完召回之后,要从中选出用户最感兴趣的物品,这就要用到粗排和精排,粗排会给召回的物品逐一打分,保留分数最高的几百个物品,然后使用精排模型给粗排选中的几百个物品打分但不做截断,让几百个物品全都带着精排分数进入重排,最后一步是重排,做多样性抽样,并且把相似内容打散,最终由几十个物品被选中展示给用户。

排序的主要依据是用户对物品的兴趣,兴趣可以反映在用户与物品的交互上,对于每个物品,系统会记录下面几个统计量:曝光次数(number of impressions),就是一个物品被展示给多少用户,展示之后,才会有点击等行为;点击次数(number of clicks),就是一个物品被多少用户点开;点赞次数(number of likes)、收藏次数(number of collects)、转发次数(number of shares)。点击率 = 点击次数 / 曝光次数、点赞率 = 点赞次数 / 点击次数、收藏率 = 收藏次数 / 点击次数、转发率 = 转发次数 / 点击次数。排序的依据:排序模型通过机器学习预估点击率、点赞量、收藏率、转发率等,做完预估之后,要对这些预估分数做融合(比如加权和),最后按照融合的分数对物品做排序、截断,保留分数最高的物品。

多目标模型:排序模型的输入是各种各样的特征,用户特征主要是用户ID和用户画像;物品特征主要是物品ID、物品画像和作者信息;统计特征:包括用户统计特征物品统计特征,比如用户在过去30天曝光了多少物品,点击了多少物品,点赞了多少物品,比如物品在过去获得了多少次曝光、点击、点赞等等;场景特征:是随着用户请求传过来的,不如按当前的时间和用户所在的地点。这些信息对推荐很有用,把这些特征做融合(concatenation),输入神经网咯,神经网络可以是简单的全连接网络,也可以是更复杂的结构,神经网络会输出一个向量,这个向量在输入4个神经网络,每个神经网络有2-3个全连接层和输出层的激活函数Sigmoid4个神经网络分别输出点击率、点赞率、收藏率和转发率的预估值。4个预估值都是实数,介于0~1之间,推荐系统排序就主要靠这4个预估值,它们反映出用户对物品的兴趣。如下图所示:

把模型输出的点击率、点赞率、收藏率和转发率,分别记作。它们都是模型做出的预估,做训练的时候,要让这些预估值去拟合真实的目标。把真实的目标记作,分别对应:点击、点赞、收藏和转发的行为。要么是0、要么是1,举个例子,,表示用户对物品有点击、没点赞、没收藏和有转发。这些是用户的真实的行为,被记录下来。用这样的数据来训练模型,训练是要鼓励模型的预测接近目标,其实就是二元分类,就是判定用户是否会点击物品,有点击、点赞、收藏和转发4个任务,每个任务都是一个二元分类,可以使用交叉熵损失函数。对于点击这个任务使用交叉熵作为损失函数,记作越接近,那么交叉熵损失就越小。我们把4个函数的加权和作为总的损失函数,记作,其中权重是根据经验设置的。在收集的历史数据上训练神经网络的参数,最小化损失函数,损失函数越小,说明模型的预测越接近真实目标。做训练的时候,把损失函数关于神经网络的参数求梯度,做梯度下降更新神经网络的参数。

实际的训练中会有很多困难:做训练的时候存在类别不平衡的问题,正样本少,负样本多。比如说每100次曝光,约有10次点击,90次无点击。点击的是正样本,没有点击的负样本。要太多的负样本用途不大,白白浪费计算资源。解决方案就是负样本的降采样(down-sampling),只保留其中一小部分负样本,让正负样本数量保持平衡,降低训练的计算代价。给定用户特征、物品特征,用神经网络预估出点击率、点赞率等之后,就要对这些预估分数做校准,做完校准之后才能把这些预估值做排序。为什么要做校准?首先设正样本、负样本的数量为,以点击为例,曝光之后有点击就是正样本,否则就是负样本,负样本数量通常远大于正样本,在训练的时候要对负样本做降采样,抛弃一部分负样本,这样会使正、负样本的差距不太悬殊,把采样率记作,它介于0~1之间,使用负样本的数量等于,由于减少了负样本的数量,模型预估点击率大于真实点击率,越小,负样本越少,模型对点击率高估就会越严重,把真实的点击率记作,样本的总数等于,预估的点击率记作,把上面两个公式合起来,记作,这个公式就是预估点击率的校准。等式左边的是校准之后的点击率,等式右边是对预估点击率做的变换,公式中用到了采样率,在线上排序的时候,首先让模型预估,然后使用做校准,最后拿校准之后的点击率作为排序的依据。

排序 - MMoE

MMoE(Multi-gate Mixture-of-Exports):模型的输入是一个向量,包含用户特征物品特征统计特征场景特征。把向量输入3神经网络,每个神经网络结构都相同,都是由很多全连接层组成,但是这3个神经网络不共享参数,这3个神经网络各输出一个向量,这3个向量记作,这3个神经网络代表3个”专家“。把下面的特征向量输入到另一个神经网络,这个神经网络也有多个全连层,神经网络的最后加入一个softmax激活函数,输出一个3维的向量。由于是softmax输出,向量的3个元素都大于0,而且相加等于1,向量的3个元素记作,分别对应3个专家神经网络,之后用这3个元素做权重,对向量加权平均;同样的方法,把下面的特征向量送入右边的神经网络,在神经网络的最后也是softmax激活函数,输出一个3个向量,分别记作,这三个元素也是之后做加权平均的权重。如下图所示:

如下图所示,都是权重,用于之后的加权平均,对向量做加权平均,权重是,得到左边的向量;用右边的向量对向量做加权平均,得到右边的向量。把左边的向量输入一个神经网络,神经网络可以有一个或多个全连接层,神经网络的输出取决于具体的任务,比如神经网络输出是对点击率的预估,是一个介于0~1之间的实数,把右边的一个向量输入另一个神经网络,这个神经网络会输出另一个指标的预估,比如对点赞率的预估,也是介于0~1之间的实数。这里假设多目标模型只有点击率、点赞率这两个目标,所以用了这两种权重,假如有10个目标,就要用10种权重。

在实践中MMoE模型有一个问题:softmax会发生极化现象(polarization)。上个例子中有2softmax函数,各自输出一个3维向量,每个向量都是概率分布,元素大于0,相加等于1极化现象(polarization)是softmax输出值1个接近1,其余接近0。举例左边的softmax输出值为,也就是说左边神经网络点击预估任务只使用了第3号专家网络,而没有使用其它的专家网络,这也就是没有使用MMoE,没有让3个专家网络输出融合,而是简单使用了一个专家;右边的softmax输出值为,也就是说左边神经网络点击预估任务只使用了第2号专家网络,也没有对3个专家做融合,而第1号专家网络没有被使用。那么MMoE就是一个简单的模型,不会对专家做融合,则失去了MMoE的优势。解决极化现象的方案:如果有个专家神经网络,那么每个softmax的输出都是维向量。不希望输出值中其中一个接近1,其余的接近0,在训练的过程中,对softmax输出使用dropoutsoftmax输出的个数值被mask的概率都是10%,也就是说每个专家被丢弃的概率都是10%,这会强迫每个任务根据部分专家做预测,如果用dropout,则不太可能发生极化。MMoE模型请参考论文:Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Experts,极化现象的解决方案请参考:Recommending What Video to Watch Next: A Multitask Ranking System

排序 - 排序模型的结构

融合预估分数:最简单的分数融合方法就是预估值的加权和,记作,其中就是模型预估的点击率,对应的权重是1是模型预估的点赞率,对应的权重的是模型预估的收藏率,对应的权重是。另一种融合方式:点击率乘以其它项的加权和,。另一种融合方式:,其中代表预估短视频的观看时长,比如预测用户会观看10秒,是超参数,需要自己调整,代表预估用户的点赞率。

视频播放建模:视频排序的依据还有播放时长完播。直接使用回归拟合播放时长效果不好,建议使用YouTube的时长建模(论文请参考:Deep Neural Networks for YouTube Recommendations)。

  • 对播放时长的预估:这是排序模型使用的特征:用户特征物品特征统计特征场景特征。把它输入多层神经网络,这个神经网络被所有任务共享,在这个神经网络之上有多个全连接层,一个全连接层对应1个目标,比如点击、点赞、收藏、播放时长等,这里只关注播放时长的预估,全连接层输出的实数,记作,对sigmoid变换得到,记作,然后让拟合是自己定义的,记作,其中是实际观看时长,越大,则也越大),为了让拟合,我们使用的交叉熵作为损失函数,记作。最小化交叉熵损失,记作,会让接近于,如果,那么,也就是说,可以用作为播放时长的预估,对做指数变换,输出的就是对播放时长的预估。
  • 对完播的预估:一种方法是回归,例如视频长度为10分钟,实际播放是4分钟,则实际播放率是。做训练的时候,让预估播放率去拟合,记作,其中的大小介于0~1之间,用的交叉熵作为损失函数,在线上用作为完播率的预估,比如说模型输出,意思是预计播放73%。视频的完播率会作为融分公式的一项,影响视频的排序。另一种视频完播的建模方法是二元分类,需要自己定义完播指标,比如完播80%,例如视频的长度是10分钟,那么播放超过8分钟就是正样本,否则作为负样本。训练要做二元分类,播放 >= 80%属于正样本、播放 < 80%属于负样本。做完训练之后,可以在线上预估完播率,例如模型输出,意思是,预估的播放率会跟点击率一起作为排序的依据。

不能直接把预估的完播率用到融分公式中,视频越长,完播率越低。使用预估的完播率适用于短视频,而不适用于长视频。线上预估完播率之后,然后对其做调整,记作,其中是视频长度的函数,视频越长,值越小。把作为融分公式的一项,与点击率、点赞率一起作为指标决定视频的排序。

排序 - 排序模型的特征

召回和排序的模型中都有用户属性,用户属性都记录在用户画像中,用户ID是排序中最重要的特征之一,用户ID本身不携带任何有用的信息,但是模型学习到的Embedding向量对召回、排序模型有很重要的影响。召回和排序都会对用户做Embedding,通常用32为或64位向量。人口统计学属性包括性别、年龄等,不同年龄、不同性别年龄段的用户兴趣差别很大。用户的账号信息:包括注册时间、活跃度。新用户和老用户、高活和低活用户区别很大。模型需要专门针对新用户、低活用户做优化。再就是用户感兴趣的类目、关键词、品牌。这些信息可以是用户填写的,也可以是算法提取的。这些用户兴趣的信息对排序也是很有用的。与用户画像相对应的是物品画像,物品ID Embedding在召回、排序中的重要性非常的高,物品的发布时间和物品的年龄也是很重要的特征,GeoHash(经纬度编码)、所在城市对召回、排序都很有用。物品的内容:包括类目、标题、关键词、品牌等信息。通常对离散的内容做embedding变成向量。字数、图片数、视频清晰度、标签数这些都是物品自带的属性,反映出物品的质量,物品的点击和交互指标跟这些相关。内容信息量、图片美学是算法打的分数。事先使用人工标注的数据训练CVNLP模型,当物品要发布的时候让模型给物品打分,将内容信息量和图片美学写入物品画像中。这些分数可以作为排序模型的特征,除了用户画像和物品画像,还有用户统计特征,比如会统计用户最近30天(7天、1天、1小时)的点击率、点赞率、收藏率等等。用各种时间粒度可以反映出用户的实时兴趣、短期兴趣、长期兴趣,除此之外还有分桶统计各种指标,比如图文的点击率和视频的点击率,可以反映出用户对两类的偏好,按照类目分桶;还要物品的统计特征,比如会统计物品最近30天(7天、1天、1小时)的点击数、点赞数、收藏数等等。这些统计量反映出物品的受欢迎程度。可按照物品的受众做分桶,按照用户性别分桶、按照用户年龄分桶等。最后一类特征是场景特征,它们随着推荐请求传来的,不用从用户画像、物品画像数据库中取得,当前用户定位的GeoHash、定位的城市属于场景特征,当前的时刻对推荐很有用,一个人在同一天不同时刻的兴趣也不相同,比如是否是周末、是否是节假日,再就是设备信息:包括手机品牌、手机型号、操作系统等,设备信息也是有用的特征。

特征处理

  • 离散特征:离散特征处理很简单,做Embedding。离散特征包括:用户ID、笔记ID、作者ID、类目、关键词、城市、手机品牌等。
  • 连续特征:连续特征的第一种处理方式是做分桶转变成离散特征。连续特征包括:年龄、文本字数、视频长度等。连续特征的第二种处理方式是做变换,还可以把点击数、点赞数、收藏数转化为点击率、点赞率、收藏率,并做平滑处理。

两种变换的特征都作为模型的输入,比如等。拼花之后点击率、点赞率也会被用到。推荐系统会用到3个数据源,包括用户画像、物品画像、统计数据,3个数据源都存储在内存数据库之中,在线上服务的时候,排序服务器会从3个数据源取回所需的数据,然后把读取的数据做处理,作为特征喂给模型,模型就能预估出点击率、点赞率等指标。系统架构是:用户发起请求到主服务器上,主服务器会把请求发到召回服务器上,做完召回之后,召回服务器会把几十路召回的结果做归并,几千个物品ID返回给主服务器,主服务器会把用户ID、物品ID、场景特征发送到排序服务器上,这里有一个用户ID和几千个物品ID,物品ID是召回的结果,用户ID和场景特征都是从请求中获取的,场景特征包括:时刻、所在的位置、手机的型号和操作系统。接下来,排序服务器会从3个数据源中取回排序所需的特征,主要是这3个数据源:用户画像、物品画像、统计数据。取回的特征分别是用户特征、物品特征、统计特征。用户画像数据库压力比较小(每次只读取1个用户的特征),而物品画像数据库压力特别巨大,粗排要给几千个物品做排序,读取几千个物品的特征,同样的道理,存用户统计数据的数据库压力比较小,存物品统计数据的数据库压力比较大。工程实现的时候,用户画像里面存什么都可以,特征可以很多、很大,尽量不要在物品画像中放很大的向量,否则物品画像会承受很大的压力,用户画像较为静态,物品画像可以说是完全静态的,对于用户画像、物品画像主要考虑读取速度,而不用考虑其时效性。统计数据不能在本地缓存,统计数据是动态变化的,时效性很强。在收集到所需的特征之后,排序服务器对特征打包,传递给TF ServingTF会给物品打分,并把分数返回给排序服务器,排序服务器会用融合的分数、多样性分数和业务规则对物品做排序,把排名最高的几十个物品返回给主服务器,这些就是最终给用户曝光的物品。如下图所示:

排序 - 粗排模型

粗排与精排对比:粗排给几千个物品打分单次推理的代价必须很小,预估的准确性不高;而精排只给几百个物品打分,单次推理的代价很大,预估的准确性更高。精排模型属于前期融合前期融合的意思是先对所有特征做concatenation,在输入神经网络,这样的模型线上推理代价大,如果有个物品,整个大模型要做次推理。双塔模型,左边是用户塔,右边是物品塔,两个塔各输出一个向量,两个向量的余弦相似度表示用户是否对物品感兴趣,在训练好模型之后,把物品向量存储在向量数据库,在线上不需要用物品塔做计算,线上推理只需要用到用户塔,每做一次推荐,用户只做一次推理,计算出一个向量,所以双塔模型的计算代价很小,适合做召回,双塔模型是典型的后期融合,把用户、物品特征输入不同的神经网络,不对用户、物品特征做融合。直到最后才计算向量和向量的相似度。后期融合的好处是线上计算量小,用户塔只需要做一次线上推理,计算用户表征,物品表征事先存储在向量数据库中,物品塔在线上不做推理。但是后期融合模型不如前期融合模型准确,因此前期融合模型用于召回,后期融合模型用于精排。粗排可以使用三塔模型,性能介于双塔和精排之间。三塔模型相关论文请参考COLD: Towards the Next Generation of Pre-Ranking System

三塔模型顾名思义,就是有3个塔:用户塔、物品塔、交叉塔。用户塔的输入是用户特征和场景特征;物品塔的输入只有物品特征;交叉塔的输入包括包括统计特征和交叉特征。交叉特征是指将用户特征与物品特征做交叉。三个塔分别输出3个向量,对3个向量做concatenation & Cross得到一个向量,把这个向量分别输入到多个神经网络(全连接层 + sigmoid),这些神经网络分别输出点击率、点赞率、收藏率、转发率的预估。训练粗排模型的方法就是正常的端到端训练,跟精排完全一样,这个模型看起来与精排模型不大,最主要的区别就是下面的3个塔,这个模型介于前期融合与后期融合之间,前期融合就是把这些底层的特征做concatenation,而三塔模型则是把三塔输出的向量做concatenation。三塔模型结构如下图所示:

  • 用户塔:只有一个用户,用户塔只做一次推理,即使用户塔很大,总计算量也不大。
  • 物品塔:有个物品,理论上物品塔需要做次推理,给所有个候选物品打分,好在物品的属性相对稳定,短期之内不会发生变化。可以把物品塔输出向量缓存在Parameter Server,隔一段时间刷新一次,由于做了缓存,物品塔在线上不用做推理。只有遇到新物品的时候,物品塔才要做推理。粗排给几千个物品打分,物品塔实际上只要做几十次推理,所以物品塔的规模可以比较大。
  • 交叉塔:它的输入,使用户、物品的统计特征,还有用户和物品的交叉,每当一个用户发生一个点击行为,他的统计特征就会发生变化,每当一个物品获得曝光和交互,它的点击次数、点击率就会发生变化。由于交叉塔的输入会实时发生变化,不应该缓存交叉塔的输出的向量,有个物品,交叉塔必须做次推理。所以交叉塔必须足够小,计算够快,通常来说交叉塔只有一层,宽度也比较小。

3个塔各输出一个向量,3个向量融合起来做为上层多个头(Head)的输入。粗排给物品打分,模型上层需要做次推理,无法用缓存方式避免计算,粗排模型的大部分计算量在模型上层,模型上层做次推理,代价大于交叉塔的次推理。

给一个用户做推荐,需要他的用户画像和统计特征,每次有个候选物品,需要取个物品的画像、统计特征。不论有多少个候选物品,用户塔只做一次推理。物品塔输出的向量,事先缓存在Parameter Server上,只有物品塔的缓存没有命中时,物品塔才要做推理。最坏的情况下,物品塔需要做次推理,但实际上缓存的命中率非常高,99%的物品都能命中缓存,给几千个物品做粗排,物品塔只需要做几十次推理。交叉塔的输入都是动态特征,不能做缓存,必须做次推理,3个塔各输出一个向量,3个向量做融合,作为上层网络的输入。上层网络必须做次推理,给个物品打分。没有办法通过缓存,减少推理次数。粗排大部分的计算量都是在上层网络。