赞
踩
本文为王树森老师《小红书推荐系统公开课》的课程笔记
由于篇幅较长,分为【上】【下】两篇文章来记录。其中【上】包括推荐系统基础、召回、排序,【下】包括特征交叉、行为序列、重排、物品冷启动、涨指标的方法
【上】部分,内容导航如下:
打开小红书APP,默认打开 “发现” 页面,展示推荐系统分发给你的内容,即用户自己创作的笔记,将它们展示给其他用户,形成陌生人社交的社区
推荐系统决定给用户曝光什么内容,用户自己决定是否点击、滑动到底、...
抖音没有曝光和点击,用户下滑一次只能看到一个视频
反映出用户对推荐是否满意
短期消费指标容易竭泽而渔,用户很快会失去兴趣,不再活跃。故还需关注多样性(用户没看过的话题),有助于提高用户黏性,留住用户,让用户更活跃
衡量推荐系统好坏最重要的指标,根本标准
推荐系统的目标是从物品的数据库中选出几十个物品展示给用户
从物品的数据库中快速取回一些物品
几十条召回通道,每条召回通道取回几十~几百个物品,一共取回几千个物品作为候选集
让排序决定该把哪些物品曝光给用户,以及展示的顺序。为了解决计算量的问题,将排序分为粗排和精排(二者非常相似,但精排模型更大,用的特征更多)
用规模较小的机器学习模型给几千个物品逐一打分,按照分数做排序和截断,保留分数最高的几百个物品送入精排(也会用一些规则,保证进入精排的笔记具有多样性)
用大规模深度神经网络给几百个物品逐一打分,做排序和截断(截断可选)
根据精排分数和多样性分数做随机抽样,得到几十个物品。用规则把相似内容打散,并插入广告和运营推广内容,根据生态要求调整排序,即为最终展示给用户的结果
整条链路上,召回和粗排是最大的漏斗(候选物品从几亿->几千->几百)
目的:
离线实验结果正向,下一步是做线上的小流量AB测试(一般10%用户)
若用户数量足够大,每个桶的DAU/留存/点击率等指标都是相等的
例:召回团队实现了一种GNN召回通道,离线实验结果正向。下一步是做线上的小流量A/B测试,考虑新的召回通道对线上指标的影响。模型中有一些参数,比如GNN的深度取值∈{1, 2, 3},需要用A/B测试选取最优参数
目标:解决流量不够用的问题
分层实验:召回、粗排、精排、重排、用户界面、广告...(例如GNN召回通道属于召回层)
互斥 vs 正交:
若业务指标的diff显著正向,则可以推全实验。如重排策略实验,取一个桶作为实验组,一个桶作为对照组,实验影响了20%用户,若观测到显著正向的业务收益,则可以推全
- 分层实验:同层互斥(不允许两个实验同时影响同一位用户)、不同层正交(实验有重叠的用户)
- Holdout:保留10%的用户完全不受实验影响,可以考虑整个部门对业务指标的贡献
- 实验推全:扩大到90%流量上,新建一个推全层,与其它层正交
- 反转实验:为了在尽早推全新策略的同时还能长期观测各种指标,在新的推全层上,保留一个小的反转桶,反转桶使用旧策略。反转桶可以保留很久,长期观测新旧策略的diff
我喜欢看《笑傲江湖》,《笑傲江湖》与《鹿鼎记》相似,我没看过《鹿鼎记》——> 给我推荐《鹿鼎记》
推荐系统如何知道《笑傲江湖》与《鹿鼎记》相似?
假设点击、点赞、收藏、转发四种行为各1分
逐一计算用户对候选物品的兴趣分数,返回分数高的topn个物品
两个物品的受众重合度越高,两个物品越相似
上述公式只要是喜欢就看作1,不喜欢就看作0,没有考虑用户喜欢的程度
考虑用户喜欢的程度,如点击、点赞、收藏、转发各自算1分,用户对物品的喜欢程度最多是4分
ItemCF的基本思想:根据物品的相似度做推荐
- 如果用户喜欢物品Item1,而且物品Item1和Item2相似
- 那么用户很可能喜欢物品Item2
预估用户对候选物品的兴趣:
计算两个物品的相似度:
- 把每个物品表示为一个稀疏向量,向量每个元素对应一个用户
- 相似度sim就是两个向量夹角的余弦
为了能在线上实时推荐,必须要事先做离线计算,建立两个索引
建立 “用户->物品” 的索引:
建立 “物品->物品” 的索引:
索引的意义在于避免枚举所有的物品
用索引,离线计算量大(需要更新2个索引),线上计算量小(不需访问上亿个物品)
ItemCF召回通道的输出,会跟其他召回通道的输出融合起来做排序
如果取回的物品ID有重复的,就去重,并把分数加起来
ItemCF的原理:
- 用户喜欢物品i1,那么用户喜欢与物品i1相似的物品i2
- 物品相似度:
- 不是根据物品的内容判定物品相似,而是根据用户行为
- 如果喜欢i1、i2的用户有很大的重叠,那么i1与i2相似
ItemCF召回通道:
- 维护两个索引:
- 用户->物品列表:用户最近交互过的n个物品
- 物品->物品列表:相似度最高的k个物品
- 线上做召回:
- 利用两个索引,每次取回nk个物品
- 预估用户对每个物品的兴趣分数:
- 返回分数最高的100个物品,作为召回结果
与ItemCF非常像,区别就是如何定义物品的相似度
ItemCF:
ItemCF的问题:两篇笔记受众不同,但由于被分享到一个小圈子,导致很多用户同时交互过这两篇笔记。需要降低小圈子用户的权重
Swing模型即给用户设置权重,解决小圈子问题
α是个人工设置的参数;overlap为u1和u2的重叠,重叠大说明两个人是一个小圈子,对相似度的贡献应减小
Swing与ItemCF唯一的区别在于物品相似度
- ItemCF:两个物品重合的用户比例高,则判定两个物品相似
- Swing:额外考虑重合的用户是否来自一个小圈子
- 同时喜欢两个物品的用户记作集合v
- 对于v中的用户u1和u2,重合度记作overlap(u1, u2)
- 两个用户重合度大,则可能来自一个小圈子,权重降低
有很多跟我兴趣非常相似的网友,其中某个网友对某笔记点赞、转发,而我没看过这篇笔记,那么可能给我推荐这篇笔记
推荐系统如何找到跟我兴趣非常相似的网友呢?
0代表用户没有看过物品,或对物品不感兴趣
用户有共同的兴趣点,即喜欢的物品有重合
上述公式同等对待热门和冷门的物品,需降低热门物品的权重
物品越热门, 越大,分子(即物品的权重)越小
UserCF的基本思想:
- 如果用户user1跟用户user2相似,而且user2喜欢某物品,那么用户user1也很可能喜欢该物品
预估用户user对候选物品item的兴趣:
计算两个用户的相似度:
- 把每个用户表示为一个稀疏向量,向量每个元素对应一个物品
- 如果用户对物品不感兴趣,向量元素为0;若感兴趣,元素为1,或1除以物品的热门程度
- 相似度sim就是两个向量夹角的余弦
为了能在线上实时推荐,必须要事先做离线计算,建立两个索引
建立 “用户->物品” 的索引:
建立 “用户->用户” 的索引:
若取回的物品有重复的,去重,并把分数加起来
UserCF的原理:
- 用户u1跟用户u2相似,而且u2喜欢某物品,那么u1也可能喜欢该物品
- 用户相似度:
- 如果用户u1和u2喜欢的物品有很大的重叠,那么u1和u2相似
- (分母是做归一化,让相似度分数介于0~1之间)
UserCF召回通道:
- 维护两个索引:
- 用户->物品列表:用户近期交互过的n个物品
- 用户->用户列表:相似度最高的k个用户
- 线上做召回:
- 利用两个索引,每次取回nk个物品
- 预估用户user对每个物品item的兴趣分数:
- 返回分数最高的100个物品,作为召回结果
--------------------------------------------- 分割线,上面都是协同过滤召回 ---------------------------------------
如性别、国籍、英文单词、物品ID、用户ID
处理:
性别:男、女两种类别
国籍:中国、美国、印度等200种类别
局限:类别数量太大时,通常不用one-hot编码
把每个类别映射为一个低维的稠密向量
参数数量 = 向量维度 × 类别数量
编程实现:TensorFlow、Pytorch提供Embedding层
离散特征处理:One-hot编码、embedding
类别数量很大时,用embedding,如:
- word embedding
- 用户ID embedding
- 物品ID embedding
------------------------------------------------- 分割线,下面都是向量召回 ------------------------------------------
矩阵补充(Matrix Completion)是向量召回最简单的一种,已经不太常用,是为了帮助理解双塔模型
输出是一个实数(用户对物品兴趣的预估值),越大表示用户对物品越感兴趣
(1)基本想法:
(2)数据集:是很多三元组的集合
(3)训练:让模型的输出拟合兴趣分数
(4)直观解释:
拿绿色位置的数据训练模型,预估所有灰色位置的分数。给定一个用户,选出用户对应行中分数较高的物品,推荐给用户
矩阵补充在实践中效果不好,在工业界不work
模型存储:
线上服务:
避免暴力枚举(暴力枚举计算量正比于物品数量),近似最近邻查找的结果未必最优,但不会比最优差多少
支持最近邻查找的系统:
有些系统不支持余弦相似度,可以把所有向量都做归一化,让它们的二范数等于1,那么内积就等于余弦相似度
在做线上服务前,把数据划分为很多区域:
划分后,每个区域用一个向量表示,这些向量的长度都是1。划分区域后,建立索引,key为每个区域的向量,value为区域中所有点的列表
首先计算用户a与索引向量的相似度,通过索引找出该区域内的所有点,再计算用户a与该区域所有点的相似度
矩阵补充:
- 把物品ID、用户ID做embedding,映射成向量
- 两个向量的内积<au, bi>作为 用户u 对 物品i 兴趣的预估
- 让<au, bi>拟合真实观测的兴趣分数,用回归的方式学习模型的embedding层参数
- 矩阵补充模型有很多缺点,效果不好。工业界不用矩阵补充,而是用双塔模型
线上召回:
- 把用户向量a作为query,查找使得<a, bi>最大化的物品i(内积最大的 top k 物品i)
- 暴力枚举速度太慢,实践中用近似最近邻查找
- Milvus、Faiss、HnswLib等开源向量数据库支持近似最近邻查找
双塔模型可以看做是矩阵补充模型的升级
用户离散特征:
用户连续特征:年龄、活跃程度、消费金额
神经网络可以是简单的全连接网络,也可以是更复杂的深度交叉网络
物品的表征类似处理
双塔模型使用了ID之外的多种特征作为输入,输出介于-1~1的余弦相似度(余弦相似度相当于先对两个向量做归一化,再求内积,比内积更常用)
pairwise:Jui-Ting Huang et al. Embedding-based Retrieval in Facebook Search. In KDD, 2020.(Facebook)
listwise:
Xinyang Yi et al. Sampling-Bias-Corrected Neural Modeling for Large Corpus ItemRecommendations. In RecSys, 2019.(YouTube)
输入一个三元组,用户的特征向量为a,两个物品的特征向量为b+和b-。两个物品塔共享参数
让用户对正样本的兴趣分数尽量高(最好接近+1),对负样本的兴趣分数尽量低(最好接近-1)
(1)Triplet Hinge Loss:孪生网络
(2)Triplet Logistic Loss:让cos(a, b-)尽量小,让cos(a,b+)尽量大
最大化正样本的余弦相似度,最小化负样本的余弦相似度
上图为粗排/精排的模型,不能应用于召回
前期融合的模型不适用于召回,否则要把所有物品的特征挨个输入模型,预估用户对所有物品的兴趣,无法使用近似最近邻查找来加速计算。通常用于排序(从几千个物品中选出几百个)
双塔模型:
- 用户塔、物品塔各输出一个向量
- 两个向量的余弦相似度作为兴趣的预估值,越大,用户越有可能对物品感兴趣
- 三种训练方式:
- pointwise:每次用一个用户、一个物品(可正可负)
- pairwise:每次用一个用户、一个正样本、一个负样本。训练目标是最小化triplet loss,即让正样本余弦相似度尽量大,负样本余弦相似度尽量小
- listwise:每次用一个用户、一个正样本、多个负样本。训练时用softmax激活+交叉熵损失,让正样本余弦相似度尽量大,负样本余弦相似度尽量小
选对正负样本的作用 > 改进模型结构
正样本:
负样本:用户不感兴趣的物品,或链路上每一步被淘汰的物品
(1)全体物品:从全体物品中做非均匀抽样,作为负样本
未被召回的物品,大概率是用户不感兴趣的。几亿个物品里只有几千个被召回,故未被召回的物品 ≈ 全体物品
使用非均匀抽样,热门物品成为负样本的概率大
(2)batch内负样本
图中是一个batch内的样本。训练时要鼓励正样本的余弦相似度尽量大,负样本的余弦相似度尽量小
一个物品成为负样本的概率越大,模型对这个物品打压就会越狠
这样理解Batch内负样本的修正:p越小,-logp越大,softmax结果s更高。如果是正样本(s>0.5),那导数会偏小(输出已经很接近正确标签,不希望模型做出太大的调整);如果是负样本,那导数会偏大。就形成了对低频物品(p小)更强的负样本的倾向,相当于是放大了冷门负样本的梯度
-logp算是物品的先验,模型实际上是非常容易拟合先验的,所以要debias掉
注意,线上召回时,还是用原本的余弦相似度,不用做这种调整,不用减掉 logpi
训练双塔模型,其实是对正负样本做二元分类:
混合几种负样本,50%的负样本是从全体物品随机非均匀抽样得到(简单负样本),50%的负样本是没通过粗排精排的物品,即从粗/精排淘汰的物品中随机抽样得到(困难负样本)
选择负样本的原理:
正样本:曝光而且有点击的用户-物品二元组
简单负样本:
- 全体物品中做非均匀随机抽样
- batch内负样本
困难负样本:被召回,但是被排序淘汰(跟正样本很像,做分类会有困难)
错误:曝光但是未点击的物品做召回的负样本。这类负样本只能用于排序,不能用于召回
训练好的两个塔,分别提取用户特征和物品特征
离线存储:把物品向量b存入向量数据库
线上召回:查找用户最感兴趣的k个物品
训练好双塔模型之后,在开始线上服务之前,先要做离线存储,在向量数据库建好索引之后,可以做线上召回
跟ItemCF、Swing、UserCF等召回通道的结果融合
今天凌晨,用昨天全天的数据训练模型
做online learning更新模型参数,每隔几十分钟就要把新的模型参数发布出去,刷新线上的用户塔Embedding层参数
今天凌晨的全量更新,是基于昨天凌晨全量训练出来的模型,而不是用下面增量训练出来的模型。在完成这次全量之后,下面增量训练出来的模型就可以扔掉了
全量训练的模型更好,而增量训练可以实时捕捉用户的兴趣
双塔模型:
用户塔、物品塔各输出⼀个向量,两个向量的余弦相似度作为兴趣的预估值,越大越好 三种训练的方式:pointwise、pairwise、listwise 正样本:用户点击过的物品 负样本:从全体物品中随机抽样 (简单负样本)、被排序淘汰的物品 (困难负样本)召回:
做完训练,把物品向量存储到向量数据库,供线上最近邻查找 线上召回时,给定用户ID、用户画像,调用训练好的用户塔神经网络 现算用户向量a 把a 作为query,查询物品的向量数据库,找到余弦相似度最高的k个物品向量,返回k个物品ID更新模型:定期全量+实时增量
全量更新: 今天凌晨,用昨天的数据训练整个神经网络,做 1 epoch 的随机梯度下降(每条数据只用一遍) 增量更新:用实时数据训练神经网络,只更新 ID Embedding,锁住全连接层不更新- 实际的系统:全量更新(每天) & 增量更新(实时) 相结合。每隔几十分钟,发布最新的用户 ID Embedding,供用户塔在线上计算用户向量(好处:捕捉用户的最新兴趣点)
自监督学习:改进双塔模型的方法,能提升业务指标,目的是把物品塔训练的更好
用batch内负样本
让模型给正样本打的分数尽量高,给负样本打的分数尽量低
损失函数:考虑batch内第i个用户和全部n个物品
batch内负样本会过度打压热门物品,造成偏差。如果用batch内负样本,需要纠偏,使热门物品不至于被过分打压。训练结束,在线上做召回时,还是用原本的余弦相似度
Tiansheng Yao et al. Self-supervised Learning for Large-scale Item Recommendations. In CIKM, 2021. 【Google】
尽管对应不同的特征变换,但同一物品的两个向量表征应有较高的相似度
不同物品的向量表征的分布应尽量分散开
四种方法:
(1)Random Mask
一个物品可以有多个类目
(2)Dropout(仅对多值离散特征生效)
多值离散特征:离散特征 + 一个物品可以有多个该特征的取值
random mask是对整个类目特征的取值都丢掉,dropout只丢掉类目特征取值的50%
(3)互补特征(complementary)
正常的做法是把四种特征的值分别做embedding,然后拼起来输入物品塔,最终得到物品的向量表征
(4)mask一组关联的特征
特征之间有较强的关联,遮住一个特征并不会损失太多的信息,模型可以从其他强关联特征中学到遮住的特征
两个特征关联越强,p(u,v)就比较大,它们的互信息就越大
这里冷热门物品被抽样到的概率是相同的(注意跟训练双塔的区别。训练双塔得到的数据是根据点击行为抽样的,热门物品被抽到的概率大。双塔抽的是用户-物品二元组,这里只抽物品)
考虑batch中第i个物品的特征向量bi',和全部m个物品的特征向量b'':
训练时希望向量si接近yi,说明物品塔训练的好,即使做随机特征变换,对物品的向量表征也影响不大。用yi和si的交叉熵作为损失函数
双塔模型存在的问题:
- 双塔模型学不好低曝光物品的向量表征(其实这是数据的问题,而不是双塔模型的问题。真实推荐系统都存在头部效应,小部分物品占据了大部分的曝光和点击)
Google提出一种自监督学习的方法,用在双塔模型上效果很好(低曝光物品、新物品的推荐变得更准)
- 对一个物品用两种特征变换,物品输出两个特征向量
- 同一物品的两个不同特征变换得到的向量应该有高相似度
- 不同物品应让物品的向量表征尽量分散在整个特征空间上
训练:
对点击做随机抽样,得到n对用户-物品二元组作为一个batch。这个batch用来训练双塔,包括用户塔和物品塔。根据点击做抽样,热门物品被抽到的概率高 从全体物品中均匀抽样,得到m个物品作为另一个batch。热门和冷门物品被抽到的概率是相同的,这个batch用来做自监督学习,只训练物品塔 做梯度下降使损失函数减小。α决定自监督学习起到的作用
Deep Retrieval(字节):
Weihao Gao et al. Learning A Retrievable Structure for Large-Scale Recommendations. InCIKM , 2021.TDM(阿里): Han Zhu et al. Learning Tree-based Deep Model for Recommender Systems. In KDD , 2018.
Deep Retrieval和TDM都用深度学习,但都不做向量最近邻查找
L1~L3表示结构的3层(深度depth),每一层里面有K个节点(宽度width)
路径就是几个节点连接起来,路径可以有重合的节点
物品->路径的索引:训练神经网络时要用到
路径->物品的索引:线上做召回时要用到
给定用户特征,预估用户对路径的兴趣分数(根据用户特征,召回多条路径)
预估用户对路径的兴趣:
假设结构有3层
过程:
给定用户特征,召回一批物品
用Beam Search召回一批路径:
beam size(每层选的节点数量)越大,计算量越大,但同时search的结果也会越好(最简单的情况即beam size=1)
Beam Search相当于贪心算法,选中的节点分别最大化p1、p2、p3,但独立对p1、p2、p3求最大化,未必会最大化这三项的乘积
size大一些,结果会比贪心算法好一些,但计算量也变大
步骤:
神经网络可以判断用户对物品的兴趣,物品表征则是把物品映射到路径
训练时只用正样本,用户-物品二元组,只要用户点过物品就算正样本
判断用户对路径有多感兴趣
解释:图中的用户都点击过左边的物品,如果其中很多用户也对路径感兴趣(兴趣分数是神经网络预估出来的),我们就判断物品和路径有很强的关联,可以把路径作为物品的表征
最小化损失,相当于根据score对path做排序,排序结果的top j,即对于每个物品item,选择score最高的j条路径,作为物品的表征
为了防止非常多的物品集中在一条路径上的情况,希望每条path上的item数量比较平衡,需要用正则项约束path。如果某条path上已经有了很多item,这条path就会受到惩罚,避免关联到更多物品
物品与J条路径的相关性越高,损失函数就越小;正则reg控制路径l上的物品不要太多
训练神经网络时,把物品当做中介,将用户和路径关联起来
线上召回:用户->路径->物品(两阶段,先用神经网络寻找用户感兴趣的路径,路径长度与神经网络层数相关;再取回路径上的物品)
这里也说明了为什么要用正则项控制一条path上的item不能太多,否则有时候召回的物品数量会特别多,有时候会特别少
Deep Retrieval召回的本质是用路径作为用户和物品之间的中介
双塔模型召回的本质是用向量表征作为用户和物品之间的中介
离线训练:同时学习 用户-路径 和 物品-路径 的关系
避免让索引失去平衡
用户可能对附近发生的事感兴趣
召回纯粹只看地理位置,完全不考虑用户兴趣(就是因为没有个性化,才需要考虑优质笔记。笔记本身质量好,即使没有个性化,用户也很可能会喜欢看;反之,既没有个性化,又不是优质笔记,召回的笔记大概率通不过粗精排)
用户可能对同城发生的事感兴趣
这条召回通道没有个性化
用户对关注的作者发布的笔记感兴趣
即使没关注作者,如果推送有交互作者发布的笔记也可能会感兴趣而继续看
如果用户对某笔记感兴趣(点赞、收藏、转发),那么用户可能对该作者的其他笔记感兴趣
作者列表需要定期更新,保留最新交互的作者,删除一段时间没有交互的作者
如果用户喜欢某作者(感兴趣的作者包括用户关注的作者+用户有交互的作者),那么用户喜欢相似的作者。取回每个作者最新的一篇笔记
相似性的计算类似于ItemCF:如果两个作者的粉丝有很大重合,那么两个作者相似
想法:复用前n次推荐精排的结果(精排前50但是没有曝光的,缓存起来,作为一条召回通道)
问题:缓存大小固定(比如最多存100篇笔记),需要退场机制。有很多条规则作为退场机制,如
还能再细化规则,如想要扶持曝光比较低的笔记,那么可以根据笔记的曝光次数来设置规则,让低曝光的笔记在缓存中存更长时间
三大类、六条召回通道:
- 地理位置召回:用户对自己附近的人和事感兴趣
- GeoHash召回、同城召回
- 作者召回:
- 关注的作者、有交互的作者、相似的作者
- 缓存召回:把精排中排名高、但是没有成功曝光的笔记缓存起来,再多尝试几次
曝光过滤通常在召回阶段做,具体的方法就是用Bloom Filter(给用户曝光过等价于用户看过)
实验表明,重复曝光同一个物品会损害用户体验(抖音、小红书);但YouTube这样的长视频就没有曝光过滤,看过的可以再推荐
在小红书,n和r的量级都是几千,暴力对比的计算量太大。实践中不做暴力对比,而是用Bloom Filter
判断一个物品ID是否在已曝光的物品集合中
概括一下:根据Bloom Filter的判断做曝光过滤,肯定能干掉所有已经曝光的物品,用户绝对不可能重复看到同一个物品;但是有一定概率会误伤,召回的物品明明没有曝光过,却被Bloom Filter给干掉了
Burton H. Bloom. Space/time trade-offs in hash coding with allowableerrors. Communications of the ACM, 1970.
Bloom Filter是一种数据结构
最简单的情况:k=1(只有1个哈希函数)
k=3,用3个不同的哈希函数把物品ID映射到3个位置上,把3个位置的元素都置为1。同样地,如果向量的某个位置元素已经是1,不需要修改数值
如果物品已经曝光,那么其3个位置肯定都是1,如果其中某个位置为0,说明该物品实际未曝光
Bloom Filter误伤的概率:
用户历史记录上有n个曝光物品,只需要 m=10n bits,就可以把误差概率降低到1%以下
APP前端有埋点,所有曝光的物品都会被记录下来。但这个落表的速度要足够快,在用户推荐界面下一刷之前,就要把本次曝光的结果写到Bloom Filter上,否则下一刷很可能会出重复的物品,所以要用实时流处理,比如把曝光物品写入Kafka消息队列,用Flink做实时计算
Flink实时读取Kafka消息队列,计算曝光物品的哈希值,把结果写入Bloom Filter的二进制向量。用这样的实时数据链路,在曝光发生几秒之后,这位用户的Bloom Filter就会被修改,之后就能避免重复曝光
曝光过滤用在召回完成之后。召回服务器请求曝光过滤服务,曝光过滤服务把用户的二进制向量发送给召回服务器,在召回服务器上用Bloom Filter计算召回物品的哈希值,再跟二进制向量对比,把已经曝光的物品过滤掉,剩余的物品都是未曝光的,发送给排序服务器
只需要计算出k个哈希值(k是哈希函数的数量)
删除物品,不能简单把这个物品对应的k个元素从1改为0,否则会影响其他物品。这是因为向量的元素是所有物品共享的,如果把向量的一个元素改为0,相当于把很多物品都移除掉了。想要删除一个物品,需要重新计算整个集合的二进制向量
推荐系统的曝光过滤问题、Bloom Filter数据结构
粗排、精排原理基本相同,只是粗排模型小,特征少,效果差一些,粗排的目的是做快速的初步筛选(如果不用粗排,直接把很大的精排模型用在几千篇候选笔记上,计算代价大)
以小红书为例,排序的主要依据是用户对笔记的兴趣,兴趣可以反映在用户与笔记的交互上。对于每篇笔记,系统记录以下统计量:
可以用点击率之类的消费指标衡量一篇笔记受欢迎的程度
排序依据:
排序模型的输入是各种各样的特征
输出4个预估值,都介于0~1之间,排序主要依靠这4个预估值
模型训练:
4个任务,每个任务都是一个二元分类,如判断用户是否会点击物品。用交叉熵损失函数
实际训练中会有很多困难,如类别不平衡(正样本少,负样本多)
解决方案:负样本降采样(down-sampling)
给定用户特征和物品特征,用神经网络预估出点击率、点赞率等分数之后,要对这些预估分数做校准,做完校准之后才能把预估值用于排序
为什么要做校准?
α(采样率)越小,负样本越少,模型对点击率的高估就会越严重
Xinran He et al. Practical lessons from predicting clicks on ads at Facebook. In the 8th International Workshop on Data Mining for Online Advertising.
对预估点击率的校准公式:左边的 表示校准之后的点击率,右边是对预估点击率 做的变换,α为采样率
在线上做排序时,首先让模型预估点击率,然后用上述公式做校准,拿校准之后的点击率做排序的依据
排序的多目标模型,用于估计点击率、点赞率等指标。做完预估之后,要根据负采样率对预估值做校准
Google的论文提出MMoE模型:Jiaqi Ma et al. Modeling Task Relationships in Multi-task Learning with Multi-gate Mixture-of-Experts. In KDD, 2018.
模型的输入是一个向量,包含用户特征、物品特征、统计特征、场景特征
神经网络可以有一个或多个全连接层,其输出取决于具体的任务,比如输出对点击率的预估,是一个介于0~1之间的实数
这里假设多目标模型只有点击率和点赞率两个目标,所以只有两组权重。
对神经网络输出的向量做加权平均,用加权平均得到的向量去预估某个业务指标。若多目标模型有n个目标,就要用n组权重
YouTube的论文提出极化问题的解决方案:Zhe Zhao et al. Recommending What Video to Watch Next: A Multitask Ranking System. In RecSys, 2019.
softmax会发生极化(Polarization):softmax输出值一个接近1,其余接近0
如左边softmax输出值 ≈ [0,0,1],说明左边的预估点击率任务只使用了第三号专家神经网络(没有让三个专家神经网络的输出融合,只是简单使用了一个专家)
那么MMoE就相当于一个简单的多目标模型,不会对专家做融合,失去了MMoE的优势
解决极化问题:
如果有n个专家神经网络,那么每个softmax的输入和输出都是n维向量。不希望看到其中一个输出的元素接近1,其余n-1个元素接近0
在训练时,对softmax的输出使用dropout,这样会强迫每个任务根据部分专家做预测
如果用dropout,不太可能会发生极化,否则预测的结果会特别差。假如发生极化,softmax输出的某个元素接近1,万一这个元素被mask,预测的结果会错得离谱。为了让预测尽量精准,神经网络会尽量避免极化的发生,避免softmax输出的某个元素接近1。用了dropout,基本上能避免极化
用MMoE不一定会有提升,有可能是实现不够好,也有可能是不适用于特定的业务场景
多目标模型输出对点击率、点赞率等指标的预估。怎么融合多个预估分数?介绍工业界排序的几种融分公式
Pclick表示模型预估的点击率,权重为1;其他以此类推
Pclick*1就是预估的点击率,Pclick*Plike是曝光之后用户点赞的概率
Ptime是指预估短视频的观看时长(比如预测用户会观看10s),w1和α1都是超参数,通过线上ab选出合适的值
不是直接用预估的分数,而是用每个分数的排名
α和β都是需要调的超参数。预估的播放时长越长,排名越靠前,越小,最终得分就越高
指数α1~α4是超参数,需要调。若都为1,该公式就表示电商的营收,有很明确的物理意义
播放时长&完播率2个指标
视频播放时长是连续变量,但直接用回归拟合效果不好,建议用YouTube的时长建模
Paul Covington, Jay Adams, & Emre Sargin. Deep Neural Networks for YouTube Recommendations. In RecSys, 2016.
神经网络叫做Share Bottom(被所有任务共享),每个全连接层对应一个目标(比如点击、点赞、收藏、播放时长),这里只关心播放时长的预估:
对z(实数,可正可负)做sigmoid变换得到p=sigmoid(z),让p拟合y = t / (1+t)( t表示用户实际观看视频的时长,t越大,y也越大),训练中用p和y的交叉熵作为损失函数【训练完毕后,p就没有用了】
CE(y, p) = y*logp + (1-y)*log(1-p)
可以用exp(z)作为播放时长的预估【线上做推理时,只用z的指数函数,把它作为对播放时长t的预估】
总结一下,右边的全连接层输出z,对z做sigmoid变换得到p,在训练中用p;
用y(= t / (1+t),其中t为播放时长)和p的交叉熵作为损失函数训练模型,训练完成后p就没有用了;
线上做推理时,只用z的指数函数,把它作为对播放时长t的预估
实践中把分母1+t去掉也没问题,相当于给损失函数做加权,权重是播放时长
最终把exp(z)作为融分公式中的一项,它会影响到视频的排序
2种建模方法:回归;二元分类
y的大小介于0~1之间
需要算法工程师自己定义完播指标
预估的播放率会跟点击率等指标一起作为排序的依据
有利于短视频,而对长视频不公平
视频越长,函数值f越小,把调整之后的分数记作,可以反映出用户对视频的兴趣,而且对长、短视频是公平的
与播放时长、点击率、点赞率等指标一起,决定视频的排序
视频的排序;视频有两个独特的指标:播放时长和完播率
召回和排序的模型中都有用户属性,用户属性记录在用户画像中
(1)用户统计特征:
(2)笔记统计特征:
随着推荐请求传来的,不用从用户画像、笔记画像等数据库中获取
离散特征:做embedding
连续特征:做分桶,变成离散特征
连续特征:其他变换
特征工程需要注重特征覆盖率
提高特征覆盖率,可以让精排模型更准;另外还要考虑,当特征缺失时,用什么作为默认值
以上3个数据源都存储在内存数据库中。线上服务时,排序服务器会从3个数据源取回所需的数据,然后把读取的数据做处理,作为特征喂给模型,模型就能预估出点击率、点赞率等指标
当用户刷小红书时,用户请求会被发送到推荐系统的主服务器上,主服务器会把请求发送到召回服务器上。做完召回后,召回服务器会把几十路召回的结果做归并,把几千篇笔记的ID返回给主服务器(召回需要调用用户画像)
主服务器把笔记ID、用户ID、场景特征(1个用户ID+几千个笔记ID。笔记ID是召回的结果,用户ID和场景特征都是从用户请求中获取的,场景特征包括当前时刻、用户所在地点以及手机的型号和操作系统)发送给排序服务器
接下来,排序服务器要从多个数据源中取回排序所需的特征,主要是这3个数据源:用户画像、物品画像、统计数据
对用户画像和物品画像最重要的是读取速度快,而不太需要考虑时效性,因为它们都是静态的,甚至可以储存在排序服务器本地,让读取变得更快
在收集到排序所需的特征之后,排序服务器把特征打包传给TF Serving。TensorFlow会给笔记打分,把分数返回给排序服务器,排序服务器会用融合的分数、多样性分数、业务规则给笔记排序,把排名最高的几十篇笔记返回给主服务器,这就是最终给用户曝光的笔记
粗排牺牲准确性,以保证线上推理的速度快(目的是做初步筛选,从几千篇笔记中选出几百篇,而不是真正决定把哪些笔记曝光给用户);精排的模型足够大,牺牲更多的计算,确保预估的准确性足够高
Shared Bottom含义为被多个任务共享【精排模型的代价主要在这,因为它很大,神经网络也很复杂】
精排模型属于前期融合(先对所有特征做concatenation,再输入神经网络),但线上推理代价大(如果有n篇候选笔记,整个大模型要做n次推理)
两个向量的余弦相似度表明用户是否对物品感兴趣
在训练好模型之后,把物品向量b存储在向量数据库,在线上不需要用物品塔做计算。线上推理只需要用到用户塔,每做一次推荐,用户塔只做一次推理,计算出一个向量a【双塔模型的计算代价很小,适合做召回】
双塔模型属于后期融合(把用户、物品特征分别输入不同的神经网络,不对用户、物品特征做融合,直到最后才计算a和b的相似度),线上计算量小(用户塔只需要做一次线上推理,计算用户表征a;物品表征b事先储存在向量数据库中,物品塔在线上不做推理),但预估准确性不如精排模型
小红书的粗排是三塔模型,效果介于双塔和精排之间
借鉴【阿里妈妈】Zhe Wang et al. COLD: Towards the Next Generation of Pre-Ranking System. In DLP- KDD , 2020
交叉特征是指用户特征和物品特征做交叉
训练粗排模型的方法就是正常的端到端训练,跟精排完全一样
三塔模型介于前期融合(把底层特征做concatenation)和后期融合之间,是把三个塔输出的向量做concatenation
模型的上层结构:
模型上层做n次推理,代价大于交叉塔的n次推理
粗排大部分的计算量都在上层网络
粗排模型的设计理念:尽量减小推理的计算量,使得模型可以在线上给几千篇笔记打分
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。