我们以三个月内的站内发布作品为例,三个月内的站内发布作品大概会到十的九次方量级,然后我们通过一些内容挖掘跟优质内容发现的方式,从中找到更为优质的一部分内容,这部分内容仍然有十的七次方量级,相当于从百万量级的作品库做兴趣的召回。这是一个非常大的候选集场景,从优质内容的发现到召回,是整个UGC平台和推荐系统的连接,背后承载着我们对整个UGC的分发、内容生态的理解。这一部分我们会在第三个环节去做进一步详细的介绍。召回可以看到有十的七次方的候选集召回,通常完成召回过程之后仍然有十的五次方候选集,而精排通常只能去处理一个千级别的规模,所以我们看到这中间存在一个比较大的漏斗,很多时候会成为我们在效果或者一些收益上的瓶颈。这时,粗排模块的重要性就体现出来了。粗排模块的一个重要的作用就是防止召回到精排之间的漏斗过大,导致过多的信息损失。
大家可能比较了解的是,召回跟精排召回更像是一个集合,选择的过程更侧重于选择效率最高的方法,至于topk中item之间的先后顺序,其实不是最关心的因素;而精排环节相对来说它更强调次序,也就是说item A跟item B的先后顺序是非常敏感和关键的。
粗排夹在召回跟精排之间,它的定位是什么?相比于召回,粗排更强调排序性,也就是更强调topk内部的排序关系;相对于精排,粗排更强调性能,因为精排通常有非常复杂的网络结构,非常大的参数量,这也意味着它在实际应用的过程中比较难去处理一个较大规模量级的候选集的打分,这时粗排就必须要解决这个问题,所以它在性能上会相较于精排有更多的要求。现在主流的粗排方案有两条路线,这两条路线是基于两个出发点来思考的:
第一条路线是把粗排当成是召回的一种延伸,它的技术选型会像是一种集合,选择的方案和目标是选出效率最高的子集。常用的方式,简单的可以通过实时的serving或者一些实时的指标对召回排序的结果做一个选择。总体来说,这条技术路线最大的优点是算力消耗非常小、性能非常好,但是它的缺点是本身的表达能力是有限的,可以明显预估到它的天花板。
第二条路线是从精排的角度,把粗排当成是精排的迁移或压缩,也就是说这是一条排序的路线,它的建模目标是预估值。这种方法的好处是它的表达能力很强,因为通常会用到一些比较复杂的网络结构,而且它跟精排的联动性是更好的,可以让粗排跟精排的目标保持某种程度上的一致性。同时,它的缺点也凸显出来了,就是我们用到了复杂的方法,算力的消耗一定也会相应的提升。因此,需要着重解决的是如何在有限的算力下尽可能地突破表达能力上限。在这种路线下,我们通常会在架构选择上选择双塔结构模型,右下图所示。
接下来,介绍下粗排双塔模型实战相关细节。
2. 粗排双塔模型实践
我们通过把user和item的feature进行结构解耦与分开建模,然后完成整个架构的设计,在模型训练完毕之后,我们会通过user serving实时的产出user embedding,再通过索引服务把该用户所有的候选集合的ID给取出来,最后在user embedding跟item embedding之间做內积的运算,得到一个粗排的预估值,作为整个粗排阶段的排序依据。
这么做的优势是user/item 结构是解耦的,内积计算的算力消耗小。
同时,它的缺点也非常的明显:
- 第一个是它在特征表达上是缺失的,因为user跟item解耦之后,很难使用一些交叉特征,一旦用了交叉特征,有多少item就得进行多少次预估,这违背了我们使用双塔模型的初衷。
- 第二个是它在结构上也是有缺陷的,我们回忆一下上面这幅框架图,可以看到user跟item的交互非常少,这会限制它的表达能力的上限。
如果我们选择了这种技术方案,我们可以保障它的性能,但是我们需要进一步的考虑如何避免这种简易的结构所带来的效果上的损失。在这种情况下,我们通常会使用一些模型蒸馏的方式。
模型蒸馏有两个关键词,第一个是它本质上是一种迁移学习,也就是transfer learning,第二个是transfer的方式是通过所谓的label,区别于我们平时理解的样本label离散值,变为了0到1之间的一个连续值。左下角是一个常见的蒸馏模型架构图,这个里面会有涉及到两个模型,第一个模型叫做教师模型,叫做teacher,第二个模型是学生模型,叫做student。这两个模型的总体思路是teacher模型是一个非常大、非常复杂、学习到的东西非常多的模型,teacher模型会把学习到的知识传导给student模型,受限于某些原因,该模型没有办法做得很复杂,或者它的规模必须限制在一定范围内的子模型。
具体流程如下:
- 准备训练样本,对teacher模型预训练,即得到了teacher模型;
- 把teacher模型最后一层或倒数第二层的输出结果,作为传递给student模型的信息,这部分通常是logits或softmax的形式,也叫做soft labels;
- 把soft labels传导到student模型,作为模型loss的一部分,因为student模型除了要拟合teacher模型传递的信息,也要去拟合样本真实的分布。
针对上述流程里涉及到了几个概念,有如下的进一步解释:
- 关于logits:它是teacher模型层层映射后的一个抽象度很高且信息浓度很大的结果,是整个知识传递的媒介。在logits后,通常会接一个softmax,但是softmax会放大logits的两极差异,造成细节损失,而这些细节恰恰是帮助student模型更好学习的关键。为了克服以上问题,我们选用了改进的softmax,即softmax with temperature这里,引入一个超参数T控制整个softmax分布的陡峭或平滑程度,间接控制蒸馏的强度。通常,T要设置成多少没有一个定论,与实际场景相关,依赖相应场景下的一些实验设计。
- 关于loss:预训练好teacher模型后,转而关注student模型,它的最小化loss由两部分构成,一部分是尽可能拟合teacher模型的输出结果,另一部分是尽可能拟合真实样本。由于student模型的表达能力有限,直接用student模型拟合真实样本可能学不好或者学偏;teacher模型传递过来的信息对student模型做了约束和纠正,指导student模型的优化方向,进而加强了student模型的学习能力。
整个模型蒸馏的收益表现如下:
引入soft labels的概念,不再是原本的非零即一状况,需要考虑正样本有多正和负样本有多负。这看起来类似把分类问题转换成回归问题,但实质并不是。如果构建样本时,用回归的方式构建,通常会基于作品的完播率或规则组合等,人工敲定样本的回归值,这种方式过于主观,没有一个非常合理或可矫正的指标进行后续比对;而模型蒸馏的soft labels是基于teacher 模型,即由teacher 模型对真实样本进行充分训练后给出,包含更多的隐含信息且不受人为主观因素影响。
具体的,来看看我们如何做粗排模块的蒸馏,主要是分为两个大的方向:
- 模型蒸馏,主要适用于模型不同但特征相同的情况,比如,包含多个场景的框架里,某些场景对性能有要求;由于有一些额外的外部限制,使某场景无法用很复杂参数量非常大的模型,可以用一个子模型使用全部特征。此时,模型蒸馏主要是弥补子模型缺少复杂结构或交互结构导致的部分收益损失,本质上是一种模型压缩方案。
- 特征蒸馏,主要适用于模型相同但特征不同的情况,比如,在某些场景,无法使用全量特征 ( 如交叉特征 ) 或部分特征必须是剪裁过的,即特征没被完全利用,存在一部分损失。这时,通过一个更大的teacher模型学习全量特征,再把学到的知识迁移到子模型,即弥补了上述的部分特征损失。
基于以上描述可知,粗排模块可以通过蒸馏的方式,补足双塔模型在结构和特征上的缺陷。接下来的问题就是如何找到一个合适的teacher模型?精排模型通常是一个被充分训练的、参数量很大、表达能力很强的模型,如果通过蒸馏精排模型获取粗排模型,那么目标的一致性和学习能力的上限都符合我们预期的。具体操作方式如上图右侧所示:
- 左侧的teacher模型是精排模型,该模型使用全量的特征,包括三大类,即user侧特征、item侧特征及它们的交叉特征;曲线框里是一些复杂的拓扑结构;最后的softmax with temperature就是整个精排模型的输出内容,后续会给到粗排模型进行蒸馏。
- 中间的粗排模型,user tower只用user features,item tower只用item features,即整体上看,模型未使用交叉特征。在user tower和item tower交互后,加上精排模型传递过来的logits信息,共同的构成了粗排模型的优化目标。整个粗排模型的优化目标,同时对真实样本和teacher信息进行了拟合。
- 右侧展示的是训练完粗排模型后,在线上产出user serving,通过user serving产出user embedding,再与item embedding做内积运算,完成整个排序的过程。上述流程即实现了粗排和精排的联动过程,并且训练完粗排模型就可以进行一个非常高效的serving,进行粗排排序。业界也有相关的一些工作,上图最下方给出了一篇阿里在这方面的论述。
3. 线上的粗排双塔模型
实践中,粗排模型训练时,依赖的精排输出结果来自上报精排日志。如果在离线重新对样本进行预估再输出,其实是对线下资源的浪费,所以通常在线上精排预估时,就把一些结果作为日志进行上报。粗排模型异步训练,产出模型提供给Serving。
Serving环节主要包括异步Serving和User Serving两部分,具体功能如下:
- 异步Serving,主要通过刷库Item Serving捕获所有的item embedding,以异步的方式反复刷库。大家经常会问的一个问题:如果模型更新了,item embedding有的是新的,有的是旧的,版本不一致怎么办?如果更新周期比较短,item embedding的分布不会发生较明显的偏移,即相邻版本比较接近,这间接保障了一致性,不需要版本是强一致性的,只要更新周期比较短就可以。
- User Serving,当用户请求推荐引擎后,获取该用户的user features,然后请求User Serving产出user embedding;同时,会拿到该用户的所有召回item集合,基于刷库结果产出的索引服务,取到所有的item embedding。由此可见,User Serving的最大优势是可以做实时计算且只需计算一次,效率非常高。并且,双塔粗排Serving阶段是做内积运算,这种高效的计算方式也使它更适合大规模的预排序场景。
4. 粗排的线上收益