2.1 召回、粗排、精排——各有所长

A/B实验几乎是推荐系统改进的不二法则,推荐算法工程师做A/B实验,开发人员做A/B实验,产品经理做A/B实验,运营人员更要做A/B实验。

召回有点像一个“甩锅侠”,其不管推荐得准不准,只管把潜在的、能推荐的都放进来。

其他环节想要提升,除了自身确实有改进,也要和精排相似,因为精排掌握着最终呈现的出口。

粗排非常容易照本宣科,明明实际结果已经说明不需要粗排,内心的惯性还是让人想留着它。

第1章大体讲解了推荐系统做什么,以及发展历程。从这一章开始,我们会逐渐进入推荐系统具体运转的技术环节。

推荐系统一般包含索引池、特征服务、排序模块、展示逻辑、日志系统、分析系统等主要环节。推荐系统的主要模块及交互关系如图2-1所示。

(1)索引池是对当前所有合法物料的汇总。这里需要注意“合法”二字,因为并不是所有物料都可以出现在“推荐”的大逻辑下的。举个例子,对某广告的推荐,如果广告主的预算花完了,或者广告主中途退出,那就需要从索引池里面拿掉;或者广告主不想把他的广告投放给20~30岁的人群,那么这一年龄段的索引池也不应包含此物料。

图2-1 推荐系统的主要模块及交互关系

(2)特征服务是指在用户发生请求[1]时,计算出该用户信息所对应的特征和历史行为,如年龄、性别、购买记录等。在计算推荐结果时,既需要计算用户的特征,又需要计算物料的特征。但物料的大多数特征都相对固定,而且更新频率较低,可以事先计算存储。相反,用户的行为特征变化得很快,需要专门的服务来处理,因此图2-1所示的特征服务主要指计算用户特征的服务。

(3)排序模块,这既是推荐系统的主导,又是机器学习模型最密集的部分。它包括下面要讲的召回、精排、粗排、打压、保送策略,其作用就是从很多候选的物料中挑出最好的一个或多个进入展示逻辑。

(4)展示逻辑主要指广告和内容的混排,或者是视频和文章的混排。广告和文章在各自的排序阶段是互不影响的,也就是说,上面的排序系统是双份的。当双方都排好之后,需要对广告进行判定,如果广告的质量很高[预估的点击率(Click-Trough Rate,CTR)、转化率(ConVersion Rate,CVR)都很高],或者之前展示的广告比较少使得门槛下降,那么符合这两种情况就可以选择合适的位置投放广告。

(5)日志系统记录推送前后系统发生的一切事情。在图2-1中有一个日志系统返回排序模块的箭头,此处箭头的含义是,用户的行为要落盘(记录下来),形成新的训练数据,提供给排序模块继续训练,不断学习。

(6)分析系统依赖于日志系统,此处主要指A/B实验系统。A/B实验就是指对用户进行随机划分,一部分用户应用对照组(A组,也就是原来的系统),另一部分用户应用实验组(B组,也就是我们想添加的改进点)。通过对比A组和B组之间的差异,来验证改进点是否有效,所以整个系统的迭代都是非常依赖A/B实验的。迭代一般是这样的流程:想到一个好想法→做线下实验→做A/B实验→有效就推广到全量。当然A/B实验也不是万能的,里面也存在问题,我们在决策篇会讲到。另外要注意的是,虽然这里叫作A/B实验,但是实际上对照组的用户不是都只有一组,实践中也可以是AA/BB实验,即对照组也有多组,实验组也有多组。这么做是为了观察组内的方差和组间的方差,假如两个对照组之间的观看时长的差距有3%,对照组和实验组的差距只有2%,那就很难说明这个实验引起的改变是置信的。

上面是对于整个推荐系统框架的梳理,下面细化到排序模块具体是如何工作的。在整体上,排序是一个多层漏斗,每层完成各自的任务,逐渐缩小候选范围,一直到最后透出结果。排序模块中的主要模型如图2-2所示。

图2-2 排序模块中的主要模型

在图2-2中的链路中,从左到右,输入/输出规模越来越小,因此,模型的负担越来越小。那么可想而知,从左往右,模型会越来越复杂、越来越强,个性化程度也会越来越高。

召回也叫触发,它从百万甚至上亿的物料中挖掘出当前用户可能感兴趣的东西,这个环节是入口。由于这里挑选候选的压力最大,模型也最简单,单独的召回可能难以照顾到所有方面,此时就需要多路召回,即多个召回路共同决定哪些候选进入下一个环节。比如,可以用一路召回专门根据用户过往的兴趣来筛选候选,再加一路召回专门输出近一段时间的热门视频。每一路召回的侧重点都不一样,共同组成下一级的输入。

粗排接受的输入就少很多,如几千个,压力大大降低。粗排的存在与算力的平衡有关,这几千个候选还不能全部交给精排来计算,但量不大,还可以使用更复杂的模型预估。此时,多层感知机(Multi-Layer Perceptron,MLP)就可以用上了。粗排在链路中的模型范式要么接近召回,要么接近精排,一般而言,输出小于1000个。

精排大体上是模型的最后一个环节,可以采用目前机器学习中非常复杂的结构,输出的是本次推荐的最终候选,可以是一个或多个。

举个例子,在电商场景下,首先计算用户的画像信息(年轻女性)和历史行为信息(曾经购买过高端女装),然后开始推荐流程。根据用户的年龄和性别,可以由“用户画像召回”提供和该用户同性别、同年龄段的其他人所喜欢的物料。根据用户历史购买的记录,“历史行为召回”发掘一些其他品牌的高端女装加入候选。这些召回按照自己的侧重点,汇总出一套全面的候选递交给粗排。粗排根据用户和候选物料的特征,把一些明显不符合要求的候选筛除,如用户画像召回可能召回了一些大众喜欢,但并不高端,与用户兴趣不符的女装。最后,精排模型把最有可能购买的一个或多个结果展示出去。

由于在每一步中要处理的候选规模不同,上述流程实际上是计算压力从大到小,模型复杂度从低到高的过程。正因为如此,它们的角色也有差别。

精排:最纯粹的排序,也是最纯粹的机器学习模块。它的目标只有一个,就是根据手头所有的信息输出最准的预测。在学术界,关于精排的文章也是最多的(当然要在前人的基础上改进也更难)。

研究精排,其他环节的干扰最少。精排训练所需要的数据本身就是它自己产生的,没有其他环节的影响。精排也是整个流程中的霸主,如果在召回上做一个改进点,但它在精排上不适配,那改进点就难以在最终候选中体现出来。精排之前的环节想要做出收益,都需要精排的“认可”。

召回:由于召回所要面对的物料量是最大的,因此召回也是时延压力最大的。简单来说,就是推理要快。这也意味着它的模型结构最简单,甚至有时候不是模型,而是规则。

对于召回来说,最经典的模型莫过于双塔(一个MLP输出用户的表示嵌入,一个MLP输出物料的表示嵌入,后面详细介绍[2])。双塔的输出,通常建模在向量的近似搜索里面,可以极大地提升搜索的效率。因此,双塔几乎可以说是为召回而生的。

召回有一个原则是多样化,多个召回路在它们所要涵盖的地方应该有差异。召回对象有差异最好,模型结构有差异次之,如果仅仅是训练数据有差异可能不会有什么提升。但是召回不像精排和粗排那样关注准确性,一方面,后面有粗排、精排来决策;另一方面,最终结果是后面环节决定的,召回这里的结果有多精准不一定能反映到最终结果上。但召回也有自己的指标,在机器学习中有一个指标叫“召回率”,就是模型认为的正样本占所有正样本的比例。这里的环节称之为召回也有这个意思:不在乎是不是把错的放进来了,只在乎它是否把对的全部放进来了。

粗排:相比于召回和精排,粗排的定位比较尴尬。在有的推荐系统里,粗排可以很好地平衡计算复杂度和候选数量的关系;但是在有的场景中,粗排可能只是精排甚至召回的一个影子。所以,粗排的模型结构在大多数情况下都很像精排或召回。

粗排不是必需的环节。如果候选数量非常少,那连召回都不需要了;如果精排能承载所有召回的输出,那可以考虑做实验对比是不是需要粗排。有的地方甚至出现过粗排输出的候选变少,整个推荐系统反而有提升的情况。如果这样的情况出现,就说明整个链路的设计存在不合理的地方。

同理,也不是所有的场景都只能有3个排序模型。如果面对的场景中还需要更多的环节来进行过渡,那么在时延允许的情况下是可以添加的。只要理解上面的模型之间是互相分担压力的关系,灵活处理即可。