3-2 排序模块:推荐系统的目标是什么?
大家一想到推荐系统,可能第一个脑海中的概念就是,“喜欢这个商品的用户也喜欢”。没错,这一句由亚马逊发扬光大的广告词实际上是推荐系统应用最直观的一种体现。
但首先,我们要定义清楚,什么是用户喜欢,学名叫做用户的偏好。
- 最简单的用户喜欢,可以是用户的点击。所以有了基于点击率预估的推荐系统的模型。
- 后来产品形态发生了改变,用户除了点击表达喜欢之外,也可以通过点赞评论收藏关注等等表达自己的偏好。这时候我们出现了,一个item对一个用户可能会有多个维度的喜欢的表达。
我们在定义清楚用户的偏好之后,自然要把所有的候选,按照用户的偏好进行排序。这也是推荐系统排序模块最主要的任务。
一、单目标预估:点击率
点击率这个目标大家其实都已经比较熟悉了,点或不点其实是一个经典的二分类问题。
那么当今推荐系统是如何解决这个问题的呢,而其他的二分类问题的模型结构有什么区别呢?
首先我们来看排序阶段的模型结构。这个部分可能是推荐系统在线模块中,与在学校学习的机器学习课程中最为类似的一个部分了。我们可以按照自己学校中对机器学习的理解,按照进行模型的training & serving
,我们主要来看模型结构。
一句话简单说明,现在排序阶段的模型整体架子都是在Wide & Deep
的框架下的一些变体和调整。
什么是Wide & Deep框架呢?这源于Google在16年的一篇论文,Wide & Deep Learning for Recommender Systems。这篇论文非常短,只有4页,核心思想就是这样一张图:
所谓Wide Models,就是所有的特征直接预估得到最终的结果,说穿了就是我们机器学习的第一课:逻辑回归。而Deep Models,就是我们常见的,从最开始的稀疏特征,到变换成Embedding层,到最终的全连接隐藏层,再到最终的输出层。
而Wide & Deep Models,就是把这两个模型结构简单粗暴的融合在一个模型结构里,变成一个大的网络结构。在这个网络结构中,既有Wide的部分,也有Deep的部分。这样的效果通常比我们单独使用Wide 或者单独使用Deep的网络效果要好:比只有Wide的网络结构效果好比较显然,毕竟有deep的部分,拟合的效果自然会好很多;比只有Deep的网络结构效果好,可能的解释性在于,feature直接作用于最终的输出结果,会强化原始的feature在最终预估结果的解释性,尤其会使模型呈现出一种“记忆性”(同样的feature再度出现时,wide部分的网络更容易直接学到结果。)
Wide & Deep只是一个网络的框架,一般而言我们会在网络结构中做一些调整和变换,这一点在王喆的《深度学习推荐系统》中有比较系统且准确的介绍。我们在这里先插一张王喆在书中总结出来的图,感兴趣的同学可以深入研究一下。
说几个常用的Wide & Deep 模型的变体:
- Deep部分加入Attention (DIN)
- Deep部分加入用户的点击/购买序列,引入Sequence信息,使用类似RNN的操作方式处理Sequence序列等等 (DIEN)
排序模型整体上没有特别深的模型。我个人总结下来有两个原因:
- 原始的信息输入都是离散特征,比如user_id或者item_id。在这种特征场景下,Embedding层结合三五层全连接已经可以足够表征离散特征的信息了,更深层的网络的优势体现不出来。
- 深层的网络inference的速度太慢。而inference的速度与效果是呈现反比的。事实上,整个推荐系统在线的部分,模块的延时都可以和最终效果进行换算。因为如果可以在整体耗时给定的情况下,如果排序的候选增加,一般是肯定增加延时但提升效果的。相当于其他模块的延时增加,都可以通过同样的方式进行效果的机会成本的兑换。有时候,因为更多的网络结构带来的耗时的增加所带来的收益,可能敌不过简单的扩大排序候选带来的收益。
模型方面的发展方向是:模型结构使用auto ML的方式搜索出一个合适的模型结构和模型size等等(这个方向叫做NAS, Neural Architecture Search),而不是再依赖于人手工对模型结构进行调整,就像集成电路设计最终会取代手工设计一样。这个方向目前有一些简单的尝试,但可能距离大规模的工业界的应用,还需要几年的发展时间。
二、多目标预估
以上我们假定的模型预估目标,是单一目标的预估场景,通常都是以点击率为目标做预估的。但是实际上,在推荐系统落地的主要场景中,一般不只有一个目标。比如:
- 在今日头条这样的新闻类app中,一般除了考虑点击率之外,还会考虑用户在这个文章的停留时长。
- 在广告推荐领域,一般除了考虑点击率之外,还会考虑广告自身的转化率。
- 在抖音快手这样的短视频App中,因为产品本身是自动播放的,所以就没有点击率的概念,这时考虑的就是用户是否点赞,是否会看完整个视频等等。
这时候就涉及到两个问题:一是多个目标如何做模型,建模和预估;二是当需要考虑多个模型输出结果的时候,如何确定多个输出结果的权重。
我们分开来看。
多目标建模
首先,多个目标的建模。最简单的解法当然是,多个目标,每一个目标单独建模。比如我们同时预估点击率和时长:就先单独搞一个模型预估点击率,再单独搞一个模型预估时长。
这样的搞法有两个问题:
- 资源问题,如果每一个模型单独一个模型,需要的资源消耗肯定是比较多的,出于控制成本的角度,我们考虑模型是否可以进行合并。
- 效果问题,对于比如稀疏的目标,比如广告转化,可能转化率是在千分位左右。这时候如果单独训练一个转化的模型,可能效果欠佳。这时候如果有一个稍微稠密的目标,且表达的信息和用户点击率类似,比如点击率(转化相对点击来说是用户喜好更强的表达),这时候就可以把两个目标一起训练,可能在效果上还会有一些增益。
这是一个相对来说比较通用的问题,有一个专门研究这个问题的方向叫做Multitask Learning。我这里先说一个有代表性的场景:
假设我们这里有三个目标ABC,彼此目标类似,可以用类似下图的模型结构进行学习。即三个目标有共同的shared的部分,然后又有一些specific的网络结构。ABC三个task的样本,会共同更新shared部分的网络结构,同时也会更新各自独立的网络结构。如果效果好的话,有时候可以起到一个模型,效果比分别三个模型效果还要好的程度。
Multitask Learning 可以玩的花样比较多,具体还是需要在实际的使用中具体调优得到。比如以下几个点:
- 哪个结构share,哪个结构不share? 除了直接这样hard share之外,也可以使用一些比如软性的约束条件来进行share。
- 对于有一些目标,我觉得比较重要,我只是想让这个目标去引导另一个目标的学习,而不想让另外那个目标影响我原本这个目标的预估。这是一种teacher & student的模式,通过合理的loss处理以及stop gradient的应用就可以达到目标了
- 可以设计出更为复杂的网络结构来处理multitask问题。比如MoE or MMoE,就是把门控结构引入Multitask 模型训练。有点类似于把boosting的思想引入网络结构的设计。
以上是一些网络结构的上面的想法,我这里就不具体展开了。感兴趣的同学可以通过我提出的这些关键词,来进行进一步的搜索和学习。简单而言,我们还是预期多个目标每个目标至少可以学准。
多目标融合
接下来我们来看下多个目标的融合。假设我们现在有了比较准确的目标的预估值,比如点击率、点赞率、关注率,那怎么样可以把这两个预估结果比较科学的融合在一起作为最终的排序结果的依据呢?
这个问题没有统一的回答,因为这实际上是一个产品的决策。
比方说,A这个产品的核心指标就是vv(视频播放量,video view),那么其实可以不关心用户对某一个视频的观看时长。只需要让点击率高的多出就行了。再比方说,B这个产品的核心指标就是让用户尽可能的沉浸,尽量不进行文章之间的切换,那我就需要让用户最终的排序按照用户的停留时长去排序即可,这样用户在每一个文章之中都可以停留足够长的时间。
更多的情况是,产品需要在多个目标之中做一个权衡。比方说,点击率高的文章,有可能是会遇到标题党,这时候停留时长就不长,用户体验也不好;而停留时长高的文章,可能因为标题封面不吸引人,用户就根本不点进来看。所以我们需要一个方式把多个目标的预估结果平衡起来。
解决问题的办法就是拍一个公式,把点击率和停留时长按照某种方式配比平衡起来。
比如0.3 * 点击率 + 0.8 * 点赞率
或者是 (1 + 0.3 * 点击率) * (0.5 + 0.6 * 点赞率)
等等。这样可以通过一个统一的公式,既考虑点击率,又考虑停留时长。
而如何决定多个目标之间的配比,其实就是一个产品决策问题了。除了要看线上的统计指标之外,可能也需要思考这些内容是不是符合整体的产品生态等等。这个问题就太大了,脱离了入门的范畴了。