文章目录
概念
推荐系统是什么?每天被短视频平台控制,没法专注学习的朋友都对推荐算法深恶痛绝。虽然笔者没有接触过相关系统的设计,但还是决定浅学习一下推荐系统相关的知识。
对比
常与推荐系统相提并论的包括搜索和广告系统,对比三者:
从业务角度看:
- 广告:一个公司要搭建广告系统,它的商业目的非常直接,就是要解决公司的收入问题。所以广告算法的目标就是为了直接增加公司收入。
- 推荐:推荐算法虽然本质上也是为了增加公司收入,但其直接目标是为了增加用户的参与度。只有用户的参与度高了,才能让广告系统有更多的 inventory,进而增加公司营收。
- 搜索:搜索要解决的关键问题全部是围绕着用户输入的搜索词展开的。虽然现在搜索越来越强调个性化的结果,但是一定要清楚的是,推荐算法强调的个性化永远只是搜索算法的补充。“围绕着搜索词的信息高效获取问题“才是搜索算法想解决的根本问题。
从优化目标来看:
- 广告:各大公司广告算法的预估目标非常统一,就是预估CTR(Click-Through-Rate 点击率)和 CVR(Conversion Rate 转化率)。这是跟当前效果类广告的产品形态密切相关的。因为CPC和CPA计价仍是效果类广告系统的主流计价方式。所以只有预估出CTR和CVR,才能反向推导出流量的价值,并进一步给出合理的出价。所以针对这样的目标,广告算法非常看重把预估偏差当作首要的评价指标。
- 推荐:推荐算法的预估目标就不尽相同,视频类更多倾向于预测观看时长,新闻类预测CTR,电商类预估客单价等等这些跟用户参与度最相关的业务指标。而且由于推荐系统的推荐场景是生成一个列表,所以更加关注 item 间的相对位置,因此评估阶段更倾向于用 AUC (area under curve),gAUC(group AUC),mAP(mean Average Precision 平均准确度均值)这些指标作为评价标准。
- 搜索:搜索的预估目标又有所不同,因为相比广告和推荐,搜索某种意义上说是存在着“正确答案”的。所以搜索非常看重能否把这些正确答案给召回回来(广告和推荐也关注召回率,但重要性完全不同)。所以搜索系统往往会针对召回率,mAP,NDCG(Normalized Discounted cumulative gain 归一化折损累计增益)这些指标进行优化。
总的来看,广告算法是要“估得更准”,推荐算法是要整体上“排的更好”,搜索算法是要“搜的更全”。
推荐系统架构
系统架构
系统架构设计思想是大数据背景下如何有效利用海量和实时数据,将推荐系统按照对数据利用情况和系统响应要求出发,将整个架构分为离线层、近线层、在线层三个模块。
由于大数据量和实时性的矛盾,因此这三个层面分别用于解决不同的问题:
- 离线层:不用实时数据,不提供实时响应;
- 近线层:使用实时数据,不保证实时响应;
- 在线层:使用实时数据,保证实时在线服务;
这种设计思想最经典的就是Netflix在2013年提出的架构:
作用划分:
- 在线层
客户端和服务端之间的交互,用于记录用户真实行为,即埋点。比如用户看到了哪些内容,和哪些内容发生了交互,和哪些没有发生了交互。如果再精细一点,还会记录用户停留的时间,用户使用的设备等等。除此之外还会记录行为发生的时间,行为发生的session等其他上下文信息。
既然我们要做推荐系统,要分析用户行为,还要训练模型,显然需要数据。需要数据,就需要记录。
-
近线层
流处理平台准实时数据处理,也是记录用户行为数据,但会由于更加复杂、数据量大等元素,因此需要计算。例如用户在观看这个内容之前还看过哪些内容,和哪些内容发生过交互。理想情况这部分数据也需要做成实时,但由于这部分数据量比较大,并且逻辑也相对复杂,所以很难做到非常实时,一般都是通过消息队列加在线缓存的方式做成准实时。
-
离线层
离线处理是数据处理的大头。所有“脏活累活”复杂的操作都是在离线完成的,比如说一些join操作。后端只是记录了用户交互的商品id,我们需要商品的详细信息怎么办?需要去和商品表关联查表。显然数据关联是一个非常耗时的操作,所以只能放到离线来做。
离线层
- 数据处理、数据存储;
- 特征工程、离线特征计算;
- 离线模型的训练;
近线层
离线层无法反应用户的实时兴趣变化,这就促使了近线层的产生。
它适合处理一些对延时比较敏感的任务,比如:
- 特征的事实更新计算:例如统计用户对不同type的ctr,推荐系统一个老生常谈的问题就是特征分布不一致怎么办,如果使用离线算好的特征就容易出现这个问题。近线层能够获取实时数据,按照用户的实时兴趣计算就能很好避免这个问题。
- 实时训练数据的获取:比如在使用DIN、DSIN这行网络会依赖于用户的实时兴趣变化,用户几分钟前的点击就可以通过近线层获取特征输入模型。
- 模型实时训练:可以通过在线学习的方法更新模型,实时推送到线上;
在线层
最大的特点是对响应延时有要求,因为它是直接面对用户群体的。
- 模型在线服务;包括了快速召回和排序;
- 在线特征快速处理拼接::根据传入的用户ID和场景,快速读取特征和处理;
- AB实验或者分流:根据不同用户采用不一样的模型,比如冷启动用户和正常服务模型;
- 运筹优化和业务干预:比如要对特殊商家流量扶持、对某些内容限流;
在线服务的数据源就是我们在离线层计算好的每个用户和商品特征,我们事先存放在数据库中,在线层只需要实时拼接,不进行复杂的特征运算,然后输入近线层或者离线层已经训练好的模型,根据推理结果进行排序,最后返回给后台服务器,后台服务器根据我们对每一个用户的打分,再返回给用户。
算法架构
算法架构设计思想就是对数据层层建模,层层筛选,帮助用户从海量数据中找出其真正感兴趣的部分。主要分为召回、粗排、排序、重排四个环节。
召回
召回层的主要目标时从推荐池中选取几千上万的item,送给后续的排序模块。由于召回面对的候选集十分大,且一般需要在线输出,故召回模块必须轻量快速低延迟。由于后续还有排序模块作为保障,召回不需要十分准确,但不可遗漏(特别是搜索系统中的召回模块),保证多样性。
目前基本上采用多路召回解决范式,分为非个性化召回和个性化召回。个性化召回又有content-based、behavior-based、feature-based等多种方式。
召回主要考虑的内容有:
- 考虑用户层面:用户兴趣的多元化,用户需求与场景的多元化:例如:新闻需求,重大要闻,相关内容沉浸阅读等等
- 考虑系统层面:增强系统的鲁棒性;部分召回失效,其余召回队列兜底不会导致整个召回层失效;排序层失效,召回队列兜底不会导致整个推荐系统失效
- 系统多样性内容分发:图文、视频、小视频;精准、试探、时效一定比例;召回目标的多元化,例如:相关性,沉浸时长,时效性,特色内容等等
- 可解释性推荐一部分召回是有明确推荐理由的:很好的解决产品性数据的引入;
粗排
粗排的原因是有时候召回的结果还是太多,精排层速度还是跟不上。是精排前的一轮过滤机制,减轻精排模块的压力。
粗排主要考虑三个方面:
- 根据精排模型中的重要特征,来做候选集的截断。
- 有一些召回设计,比如热度或者语义相关的这些结果,仅考虑了item侧的特征,可以用粗排模型来排序跟当前User之间的相关性,据此来做截断,这样是比单独的按照item侧的倒排分数截断得到更加个性化的结果,
- 最后是算法的选型要在在线服务的性能上有保证,因为这个阶段在pipeline中完成从召回到精排的截断工作,在延迟允许的范围内能处理更多的召回候选集理论上与精排效果正相关
精排
获取粗排模块的结果,对候选集进行打分和排序。精排需要在最大时延允许的情况下,保证打分的精准性,是整个系统中至关重要的一个模块,也是最复杂,研究最多的一个模块。
精排和粗排层的基本目标是一致的,都是对商品集合进行排序,但是和粗排不同的是,精排只需要对少量的商品(即粗排输出的商品集合的topN)进行排序即可。因此,精排中可以使用比粗排更多的特征,更复杂的模型和更精细的策略(用户的特征和行为在该层的大量使用和参与也是基于这个原因)。
重排
重排序的原因是因为多个物品之间往往是相互影响的,而精排序是根据 PointWise 得分,容易造成推荐结果同质化严重,有很多冗余信息。而重排序面对的挑战就是海量状态空间如何求解的问题,一般在精排层我们使用AUC作为指标,但是在重排序更多关注NDCG等指标。
重排序在业务中,获取精排的排序结果,还会根据一些策略、运营规则参与排序,比如强制去重、间隔排序、流量扶持等、运营策略、多样性、context上下文等,重新进行一个微调。重排序更多的是List Wise作为优化目标的,它关注的是列表中商品顺序的问题来优化模型,但是一般 List Wise 因为状态空间大,存在训练速度慢的问题。
混排
多个业务线都想在Feeds流中获取曝光,则需要对它们的结果进行混排。比如推荐流中插入广告、视频流中插入图文和banner等。可以基于规则策略(如广告定坑)和强化学习来实现。
推荐系统技术栈
算法方面笔者不了解,就不列了(蓝瘦)。
工程部分基本需要的技术栈:
- 编程语言:Python、Java(scala)、C++、sql、shell;
- 机器学习:Tensorflow/Pytorch、GraphLab/GraphCHI、LGB/Xgboost、SKLearn;
- 数据分析:Pandas、Numpy、Seaborn、Spark;
- 数据存储:mysql、redis、mangodb、hive、kafka、es、hbase;
- 相似计算:annoy、faiss、kgraph
- 流计算:Spark Streaming、Flink
- 分布式:Hadoop、Spark
推荐系统算法
简单总结基于协同过滤的召回算法以作为入门了解。
协同过滤(Collaborative Filtering)推荐算法是最经典、最常用的推荐算法。基本思想是:
- 根据用户之前的喜好以及其他兴趣相近的用户的选择来给用户推荐物品。
- 基于对用户历史行为数据的挖掘发现用户的喜好偏向, 并预测用户可能喜好的产品进行推荐。
- 一般是仅仅基于用户的行为数据(评价、购买、下载等), 而不依赖于项的任何附加信息(物品自身特征)或者用户的任何附加信息(年龄, 性别等)。
- 目前应用比较广泛的协同过滤算法是基于邻域的方法,主要有:
- 基于用户的协同过滤算法(UserCF):给用户推荐和他兴趣相似的其他用户喜欢的产品。
- 基于物品的协同过滤算法(ItemCF):给用户推荐和他之前喜欢的物品相似的物品。
UserCF 和 ItemCF 算法重点是计算用户之间(或物品之间)的相似度。
UserCF
基于用户的协同过滤(UserCF):
- 例如,我们要对用户 A 进行物品推荐,可以先找到和他有相似兴趣的其他用户。
- 然后,将共同兴趣用户喜欢的,但用户 A 未交互过的物品推荐给 A。
User-based算法存在两个重大问题:
- 数据稀疏性
- 一个大型的电子商务推荐系统一般有非常多的物品,用户可能买的其中不到1%的物品,不同用户之间买的物品重叠性较低,导致算法无法找到一个用户的邻居,即偏好相似的用户。
- 这导致UserCF不适用于那些正反馈获取较困难的应用场景(如酒店预订, 大件物品购买等低频应用)。
- 算法扩展性
- 基于用户的协同过滤需要维护用户相似度矩阵以便快速的找出 TopN 相似用户, 该矩阵的存储开销非常大,存储空间随着用户数量的增加而增加。
- 故不适合用户数据量大的情况使用。
由于UserCF技术上的两点缺陷, 导致很多电商平台并没有采用这种算法, 而是采用了ItemCF算法实现最初的推荐系统。
ItemCF
基于物品的协同过滤(ItemCF):
- 预先根据所有用户的历史行为数据,计算物品之间的相似性。
- 然后,把与用户喜欢的物品相类似的物品推荐给用户。
举例来说,如果用户 1 喜欢物品 A ,而物品 A 和 C 非常相似,则可以将物品 C 推荐给用户1。ItemCF算法并不利用物品的内容属性计算物品之间的相似度, 主要通过分析用户的行为记录计算物品之间的相似度, 该算法认为, 物品 A 和物品 C 具有很大的相似度是因为喜欢物品 A 的用户极可能喜欢物品 C。
协同过滤算法存在的问题之一就是泛化能力弱:
- 即协同过滤无法将两个物品相似的信息推广到其他物品的相似性上。
- 导致的问题是热门物品具有很强的头部效应, 容易跟大量物品产生相似, 而尾部物品由于特征向量稀疏, 导致很少被推荐。
比如下面这个例子:
http://ryluo.oss-cn-chengdu.aliyuncs.com/JavaxxhHm3BAtMfsy2AV.png!thumbnail
- 左边矩阵中,A,B,C,D 表示的是物品。
𝐴,𝐵,𝐶,𝐷
-
可以看出,D 是一件热门物品,其与 A、B、C 的相似度比较大。因此,推荐系统更可能将 D 推荐给用过 A、B、C 的用户。
- 但是,推荐系统无法找出 A,B,C 之间相似性的原因是交互数据太稀疏, 缺乏相似性计算的直接数据。
所以这就是协同过滤的天然缺陷:推荐系统头部效应明显, 处理稀疏向量的能力弱。
为了解决这个问题, 同时增加模型的泛化能力。2006年,矩阵分解技术(Matrix Factorization, MF)被提出:
- 该方法在协同过滤共现矩阵的基础上, 使用更稠密的隐向量表示用户和物品, 挖掘用户和物品的隐含兴趣和隐含特征。
- 在一定程度上弥补协同过滤模型处理稀疏矩阵能力不足的问题。
什么时候使用UserCF,什么时候使用ItemCF?为什么?
(1)UserCF
- 由于是基于用户相似度进行推荐, 所以具备更强的社交特性, 这样的特点非常适于用户少, 物品多, 时效性较强的场合。
- 比如新闻推荐场景, 因为新闻本身兴趣点分散, 相比用户对不同新闻的兴趣偏好, 新闻的及时性,热点性往往更加重要, 所以正好适用于发现热点,跟踪热点的趋势。
- 另外还具有推荐新信息的能力, 更有可能发现惊喜, 因为看的是人与人的相似性, 推出来的结果可能更有惊喜,可以发现用户潜在但自己尚未察觉的兴趣爱好。
(2)ItemCF
- 这个更适用于兴趣变化较为稳定的应用, 更接近于个性化的推荐, 适合物品少,用户多,用户兴趣固定持久, 物品更新速度不是太快的场合。
- 比如推荐艺术品, 音乐, 电影。
参考
排得更好VS估得更准VS搜的更全「推荐、广告、搜索」算法间到底有什么区别?
https://github.com/datawhalechina/fun-rec