关于推荐系统的技术架构,我认为应该是作为一个初学者首先需要认识的。
1 推荐系统架构图——baseline4![图1](https://i-blog.csdnimg.cn/blog_migrate/0dcc9a109b07c6ee2f4ffe8cb5110d7d.png)
根据以上的很简单的架构图可以看出,一个推荐系统可以概括为 f ( U , I , C ) f(U, I, C) f(U,I,C):基于用户(User)+物品(Item)+场景(Context)信息,从系统中的物品库中,给对应的用户推荐相应的物品,也即实现所谓的”千人千面“。
基于图文1.1,我们可以看到的推荐系统完成一次推断的流程为:
- 读取数据(ETL)
- 读取用户数据
- 读取物品数据
- 读取场景数据(实时上下文数据)
- 读取候选物品库数据(这里有很多召回的知识)
- 算法模型打分
- 有算法模型,意味着存在模型训练的过程推荐结果展示
- 按打分结果排序
2 Netflix的推荐系统架构图
这是Netflix发布了8年(2013年发布)之久的推荐系统架构。
从上至下依次是离线(offline),近线(nearline)和在线(online)
2.1 离线
存储离线数据,利用大数据查询工具进行数据查询和处理,离线模型训练。离线部分对于数据数量和算法复杂度限制很少,以批量方式完成数据处理,但是数据处理的实时性非常差,无法做到数据和模型的即使更新。
可以看到当时还是hive,pig等工具的天下,现在spark 是主流,但也有越来越多的offline job被合并到near line之中,可以说当前的offline和nearline的界限日渐模糊了。
2.2 近线
基于数据消息队列,利用一些流计算平台进行数据的准实时处理。它居于离线和在线之间,既可以以分钟级别甚至秒级的延时来准实时地处理数据,也有一定的数据批量处理能力。
- 把算法模型所需要的特征数据,存储到读取时延更低的Cassandra/MySQL等中,在数据获取上减少推断时延。
- 定期更新(1分钟、半小时)算法模型所需要的特征数据,保证特征的实时性。
- 近线更新算法模型,提高模型实时性。
nearline可以说是近几年大数据架构发展的重中之重了。当时Netflix开发了自己的流处理框架Manhattan,但现在已经是Flink一统天下的时候,Netflix内部的Flink平台每天会运行上千个不同的流处理任务。涵盖了特征实时计算、数据监控、BI、模型实时训练等等。越来越多的offline任务被替代,也许Kappa架构彻底替代Lambda架构的日子不太远了。
2.3 在线
online部分的主要任务是进行用户请求的实时处理,模型的在线服务。在线部分需要更快地响应最近的事件和用户交互,因此对于延迟的要求比较苛刻,一般都要求在100ms以内完成所有处理,这会限制所用算法的复杂性和可处理的数据量。
正是online部分极高的响应延迟要求和相比离线、近线较弱的数据处理能力,要求online部分采用不同的高效的model serving方法去支持个性化推荐服务。
对于在线系统,一般要经过几个阶段,分别是召回,粗排和精排。
对于大多数推荐系统而言,在线系统的主体有召回(Recall)和精排(Ranking)。召回强调快,精排重视准。
- 召回:从千万量级的候选物品里,采取简单模型将推荐物品候选集合快速筛减到千级别甚至百级别
- Ranking: 在候选集中,融入更多特征,使用复杂模型进行精确的个性化推荐。
进一步细分就有四个阶段:
四个环节分别是:召回、粗排、精排和重排。
召回目的如上所述;有时候因为每个用户召回环节返回的物品数量还是太多,怕排序环节速度跟不上,所以可以在召回和精排之间加入一个粗排环节,通过少量用户和物品特征,简单模型,来对召回的结果进行个粗略的排序,在保证一定精准的前提下,进一步减少往后传送的物品数量,粗排往往是可选的,可用可不同,跟场景有关。
之后,是精排环节,使用你能想到的任何特征,可以上你能承受速度极限的复杂模型,尽量精准地对物品进行个性化排序。排序完成后,传给重排环节,传统地看,这里往往会上各种技术及业务策略,比如去已读、去重、打散、多样性保证、固定类型物品插入等等,主要是技术产品策略主导或者为了改进用户体验的。
2.4 推断流程
基于以上架构,我们可以对上文总结的推断过程进行一个扩充
- 读取数据(ETL)
- 读取用户数据(离线+近线+在线)
- 读取物品数据(离线+近线+在线)
- 读取场景数据(离线+在线)
- 读取候选物品库数据(在线)
- 算法模型训练
- 离线训练
- 近线迭代
- 算法模型打分
- 在线
- 推荐结果展示
- 在线
- 存储数据
- 记录用户和推荐系统的交互日志(在线+近线+离线)
至此,我们基本得到了一个工业级的推荐系统的推断流程。
3 技术栈
根据以上逻辑架构,我们可以构建一个推荐系统的技术栈
在数据ETL方面:
- 在数据采集上,可以采用流行的是Flink;
- 在离线批量计上,可以采用流行的是Spark;
- 在底层数据存储上,HDFS仍不过时;
- 在存储(U,I,C)的近线在线特征时,Redis能扛能打;
在模型推断方面:
- 算法层:
- 召回+排序
- 重排层
打散,在精排给出的准确性因子上增加多样性、新鲜度、流行度等因子冷启动推荐策略
- 算法工具层:
- TensorFlow,算法开发成本直线下降
- Spark MLlib,分布式计算你值得拥有
- 模型性能预估:
- 离线 AUC/Recall/RMSE
- 在线AB Testing
3.1 召回阶段
推荐系统的召回阶段是很关键的一个环节,但是对比如今的技术而言,该阶段的技术含量并不高,主要是偏策略导向的。如今推荐模型主流还是在研究排序阶段。
传统的召回阶段主要就是多路召回,下图所示。每一条策略就代表一个召回路线,所以说该阶段主要是偏策略方向。常用的召回策略基本都包括兴趣标签,兴趣Topic,兴趣实体,协调过滤,热门物品等等。多者高达几十路召回。
对于每一路召回,会拉回K条相关物料,这个K值是个超参,需要通过线上AB测试来确定合理的取值范围。如果你对算法敏感的话,会发现这里有个潜在的问题,如果召回路数太多,对应的超参就多,这些超参组合空间很大,如何设定合理的各路召回数量是个问题。
另外,如果是多路召回,这个超参往往不太可能是用户个性化的,而是对于所有用户,每一路拉回的数量都是固定的,这里明显有优化空间。按理说,不同用户也许对于每一路内容感兴趣程度是不一样的,更感兴趣的那一路就应该多召回一些,所以如果能把这些超参改为个性化配置是很好的,但是多路召回策略下,虽然也不是不能做,但是即使做,看起来还是很Trick的。
如果我们根据召回路是否有用户个性化因素存在来划分,可以分成两大类:
- 一类是无个性化因素的召回路
比如热门商品或者热门文章或者历史点击率高的物料的召回; - 另外一类是包含个性化因素的召回路
比如用户兴趣标签召回。
我们应该怎么看待包含个性化因素的召回路呢?其实吧,你可以这么看,可以把某个召回路看作是:单特征模型排序的排序结果。意思是,可以把某路召回,看成是某个排序模型的排序结果,只不过,这个排序模型,在用户侧和物品侧只用了一个特征。比如说,标签召回,其实就是用用户兴趣标签和物品标签进行排序的单特征排序结果;再比如协同召回,可以看成是只包含UID和ItemID的两个特征的排序结果….诸如此类。我们应该统一从排序的角度来看待推荐系统的各个环节,这样可能会更好理解本文所讲述的一些技术。
如果我们换做上面的角度看待有个性化因素召回路,那么在召回阶段引入模型,就是自然而然的一个拓展结果:无非是把单特征排序,拓展成多特征排序的模型而已;而多路召回,则可以通过引入多特征,被融入到独立的召回模型中,找到它的替代品。如此而已。所以,随着技术的发展,在embedding基础上的模型化召回,必然是个符合技术发展潮流的方向。
在召回阶段,使用模型替换多路召回:链接
3.2 排序阶段
召回针对的是全部item,而精排针对的是召回输出的item。因此召回一般是在全部item集合上构建训练样本,而精排一般是基于展现样本来构建训练样本,解决基于单目标或者多目标的模型排序问题。最常见的就以CTR作为预测的预估算法。各行业也有不同的预测指标,比如电商的CVR(用户的转化率),阿里的一个主要排序目标就是gmv(ctr×cvr×price)。对于内容推荐,业务关心的除了CTR,还有阅读/观看时长、转发、评论等指标。
排序模型的发展史:
如果归纳下工业界CTR模型的演化历史的话,你会发现,特征工程及特征组合的自动化,一直是推动实用化推荐系统技术演进最主要的方向,而且没有之一。最早的LR模型,基本是人工特征工程及人工进行特征组合的,简单有效但是费时费力;再发展到LR+GBDT的高阶特征组合自动化,以及FM模型的二阶特征组合自动化;再往后就是DNN模型的引入,纯粹的简单DNN模型本质上其实是在FM模型的特征Embedding化基础上,添加几层MLP隐层来进行隐式的特征非线性自动组合而已。所谓隐式,意思是并没有明确的网络结构对特征的二阶组合、三阶组合进行直接建模,只是通过MLP,让不同特征发生交互,至于怎么发生交互的,怎么进行特征组合的,谁也说不清楚,这是MLP结构隐式特征组合的作用,当然由于MLP的引入,也会在特征组合时候考虑进入了特征间的非线性关系。