Twitter推荐系统概览

Twitter去年开源推荐系统代码到现在一年多了,一直没时间去看一看,今天想起来瞄了会,本文简单记录下。 开源: 系统代码:https://github.com/twitter/the-algorithm 算法代码:https://github.com/twitter/the-algorithm-ml 博客:https://blog.twitter.com/engineering/en_us/topics/open-source/2023/twitter-recommendation-algorithm 我先读的博客,基本了解其推荐系统的概况,总体来说,算法相比国内阿里电商首猜/小红书feed流的推荐是更初级很多。 整个系统基本就是召回 + 精排,可以理解没有粗排,在In-Network召回时也就是RealGraph那里会有一个LR模型类似粗排的功能。 数据: 因为Twitter是社交app,所以: 主要是用户交互数据,包括用户-用户Follow的社交图,Tweet engagement通常指用户和内容的的交互,比如点赞、分享、关注等等; 用户的profiles数据:语言、地理位置等 召回 召回是本次开源里面的重头部分。Twitter召回包括In-Network的召回和Out-of-Network的召回。In-Network指从用户的Follow用户的内容中召回,Out-of-Network指从未Follow的其他用户中召回,两者占比大概各50%。召回最终返回1500个候选集给到精排(Twitter叫Heavy Rank)打分排序。 In-Network召回,占比50% 从Follow的用户中召回所有的内容,然后通过一个LR模型对这些内容进行排序。这部分叫Real Graph,看了下这个是2014的工作了,博客中也提到要对LR模型重构。 RealGraph核心逻辑就是构建User间的有向图,然后通过LR学习Edges的权重,权重高的用户的内容多推荐一些。 Out-of-Network召回,占比50% 包括直接从U2U2I召回、Sparse Embedding召回、Dense Embedding召回。 U2U2I召回:即从关注的用户喜欢的内容中召回,占比15%。有个问题,这里如果U2U2I内容数量超过15%怎么截断呢? Sparse Embedding召回:也是U2U2I,只不过是通过Sparse Embedding找相似用户。首先通过SimClusters社区发现算法,找到用户的社区representation embedding,然后通过ANN找到相似用户。 Sparse Embedding可解释性强,虽然Sparse Embedding从技术上来说是相比下面的Dense Embedding简单,但是基本所有的公司都还是会保留该路召回的。 Dense Embedding召回:相比用社区向量表征用户,Dense Embedding采用了TwHIN模型学习用户的向量表征,得到的向量结果可用于其他模型作为特征。 TwHIN思路和其他的U2U/U2I召回算法类似: 正样本:和目标用户有engagement的用户作为正样本 负样本:batch内采样负样本 优化:通过binary_cross_entropy_with_logits loss函数train一个Model。模型离线Train完之后,离线存储user vector,然后线上通过ANN索引查找最相似的用户。 采用的Graph数据:提到了大致是类似于"User follows User" “User favorites Tweet” “User clicks Advertisement”,但是由于隐私原因没法公开数据,由于存在不同的关系类型,所以TwHIN应该是训练的异构图,数据格式是:左节点id, 关系类型,右节点id。 工程上,TwHIN采用了pytorch开源的torchrec来实现该算法,torchrec适合高维稀疏特征的场景,也被用在Meta自己的DLRM的模型训练中。 召回里面的算法其实都比较中规中矩,没有很fancy的模型,对于图模型训练感兴趣的可以研究下TwHIN的详细代码。除了算法上,召回会有很多工作在推荐工程上,比如设计GraphJet去维护user-tweet-entity-graph (UTEG)即用户的交互图,比如follow-recommendation-service (FRS)推荐服务的工程实现等等。有兴趣的可以深入研究下twitter的工程实现,比如: 相似性检索,user/item embedding的存储,ANN的实现 图数据的存储 训练的规模和配置等等。 精排 召回的1500个候选送到大概48M参数的MaskNet中打分。国内的推荐系统,通过各种工程优化,中等公司一般也能做到差不多3000左右了,所以twitter进到精排的量并不算太大。 MaskNet是微博21年发表的一篇paper,其主要是为了解决输入特征(尤其是特征交叉)学习不充分的问题,作者也说过,MaskNet是微博摸索过的几个模型里面(FiBiNet,GateNet,MaskNet,ContextNet)综合效果最好的一个。MaskNet由多个MaskBlock构成,多个MaskBlock可以组成Serial Model或者Parallel Model的形式。Parallel其实就是输入Embedding经过多个不同的特征权重计算后concat起来,最终输入DNN的Embedding维度会变成N倍。 对于每个MaskBlock,它的输入都是全量的Embedding,计算方式大概如下, LN-EMB:计算Embedding的Layer Norm,$LN_{EMB}(Vemb)=concat(LN(e_1),LN(e_2),..,LN(e_f))$, 对于Parallel Model,其中Vemb都是原输入Embeddings=$[e_1,e_2,…,e_f]$,而对于Serial Model,第二个MaskBlock之后就是上一个MaskBlock特征加权后的输出; Instance-Guided Mask: Mask计算:2层全连接层,$𝑉𝑚𝑎𝑠𝑘 =𝑊_2(ReLU(𝑊_1*𝑉𝑒𝑚𝑏 + b_1)) + b_2$,注意Vmask的输出维度是F X K,F是特征Fields数量,K是每个Field的Embedding数量。所以输入Embedding的每个元素的mask weight都不同,而不只是每个Field不同。 Mask输出:$Voutput=ReLU(LN(W_i(Vmask⊙𝐿𝑁_{𝐸𝑀𝐵}(V𝑒𝑚𝑏))))$,Vmask点乘LN-EMB,再经过一个线性层+LN+ReLU输出。几个点,一个为什么这里Vmask没有像Attention一样softmax归一化?第二个,输出这里的线性层只有一个weight没有bias项? 重排和混排 重排就是一些基于业务的规则和策略,主要就是过滤和打散操作:...

October 11, 2024 · 1 min · Monkeyzx

CVR建模技术梳理

在之前的工作中负责过一段时间转化率的建模,这里对转化率建模的技术作一个简单梳理。 点击,一般意义上就是点了商品,转化,一般意义上是指下单/购买。但在电商或直播的漏斗中,中间可能还会经历一长串的链路: 传统电商:加购,收藏,店铺关注,收银台落地页,等等 直播电商:观看时长,点赞,吸粉,收藏,商品落地页 等等 通过优化中间的一长串漏斗,能一定程度使得最终的转化目标更大化。因此,多目标建模是转化建模必备技术。 多目标建模 说到多目标建模,为什么不采用多个单目标的模型呢?主要原因是商品的转化是一个极度稀疏的信号(有些场景<1%甚至0.1%量级),通过引入中间目标,不同目标的模型共享部分参数比如Embedding,有助于给转化模型的Embedding学习,缓解转化本身的稀疏问题。 一旦涉及到多目标,无外乎就是知识冲突和知识迁移两个维度(如下图,绘制于2022年左右)。多目标除了共享参数带来信息增益之外,有些情况也会存在目标间冲突的问题,典型的就是CTR和CVR一起建模,一些猎奇商品点击率很高,但是转化很低。 为了解决知识冲突: 一方面做法是调整多目标的网络结构:比如MMoE是针对不同的任务用不同的Gate(虽然MMoE设计考虑了共享信息,但为了归类方便,我且将他要解决的主要问题定位为冲突解决,因为要共享Share Bottom就能很好共享);腾讯的PLE则进一步不同的目标不仅用不同的Gate,而且不同目标还有自己独有的Experts达到冲突进一步解耦;如果从Task Specific的视角看,MMoE的Specific是Gate,PLE的Specific是Gate和Experts;那是不是还可以Task Specific的Features,Kuanshou的PEPNet就是Specific的Feature,对输入加权,在模型的更浅层把冲突问题解决。 另一种解决冲突的思路优化梯度,从模型角度来说,所有冲突的来源都来自于梯度的影响。如PCGrad在训练时把梯度冲突部分裁剪掉,保证不同目标间的梯度正交。 当然两种解决冲突的方式可以一起用,但从个人实践的经验来看,从网络结构上进行信息解耦,这种从本质上进行冲突信息分流的方式一般效果会更好些。保证每个任务有一个自己的与其他任务毫不相关的信息通路,保证冲突信息能从Task-specific的通路传递到loss。 为了实现知识迁移(即一个任务受益于另一个任务带来额外的提升): 根据业务先验信息,进行Bayesian转移概率建模:ESSM/ESM2这种,复杂些的比如DBMTL; 不直接建模转移概率,隐式建模目标间关系:典型的比如GMSL,以及美团AITM都可以认为是类似这种,利用目标间存在的序关系建模; 在建模关系的基础上,考虑偏置问题:比如针对CVR的曝光空间bias,引入因果推断IPW,以及刚看到RecSys24 Tecent最近的NISE NAS自动搜索模型结构:典型的AutoHERI在阿里妈妈场景下拿到了些效果,这种方向一般适合业务体量足够大的场景才去考虑,中小场景性价比不高。 有趣的是,大部分知识迁移的Paper都是考虑在Tower之后怎么进行融合,而知识冲突的研究基本考虑Tower之前怎么进行目标间信息的解耦。所以,上面列的,有很多知识迁移和知识冲突的方法是互补的,两者可以同时使用,比如PLE + ESSM,PLE + IPW等。 思考: 其实仔细去想,冲突信息在模型的越浅层解决越好。循着这个思路,参考PLE的思想,对于存在较大冲突目标的情况,是不是可以在更浅层Embedding层解决冲突,即每个task除了共享的embedding,还有自己独立的embeddig,即实现task specific embedding(TSE)?我在直播电商的多目标中简单尝试过这种做法(含观看时长/完播、点赞、吸粉、店铺收藏目标,主要考虑时长和其它目标有些情况不完全一致),在PLE的基础上有额外的提升,只是上线时Embedding需要更多的存储空间,Inference计算量相比不变。 有同学可能了解过MaskNet,它是否能用在多目标中实现Task-specific features? 样本有偏的问题 转化建模还有一个大的问题时样本有偏,其中又有很多情况,常见的是延迟反馈偏差和选择偏差。 延迟反馈:即曝光-转化可能发生在几天之后,这就导致近几天的数据不能直接拿来训练,因为负样本是不准的,可能在未来转化为正样本。在Online Learning场景下,该问题尤为严重。业界也有不少方案在想办法缓解该问题。 1. Modeling Delayed Feedback in Display Advertising DFM,业界最早关注该问题的,利用数据先验,将延迟转化的衰减过程建模成指数分布,考虑延迟反馈问题值得细读该Paper作为一个baseline。具体的,确定转化的情况下C=1,延迟天数D=d表示成下面的指数分布, $$ Pr(D=d|X=x,C=1)=\lambda(x) \exp(-\lambda(x) d) $$ 其中$\lambda(x)$是hazard function,$\lambda(x)=\exp(w_d*x)$。根据该先验信息,就能推导出观察正样本的概率和观察到负样本的概率,最后通过极大似然估计得到模型的Loss Function,从原来的Binary Cross Entropy Loss变成如下: 从Loss看,其中两项和BCE Loss很像,在BCE Loss基础上分别对正负样本有个loss调整。具体看负样本: 当 $\lambda$ 很大或elapsed time $e_i$ 很大的时候,$p(x_i)\exp(-\lambda(x_i)e_i$ 接近0,表示这种情况下基本确定性的负样本; 当 $\lambda$ 和elapsed time $e_i$ 都很小的时候,$p(x_i)\exp(-\lambda(x_i)e_i$ 接近$p(x_i)$,这个时候负样本还有很大概率正样本; DFM在DNN很容易实现:...

May 28, 2024 · 1 min · Monkeyzx

机器学习建模——如何融入先验信息

背景 想要用ML模型拟合业务,但实际中经常会遇到类似下面的场景: 二手车价格预估:同一辆车,预估的价格与里程应该是严格负相关的; 保费预估:保额越高,保费越高; 理财产品中,比如余额宝,用户的利率敏感度预估(利率敏感度=用户余额变化/利率变化):同一用户,理财产品利率越高,购买金额越高,余额越高; 如果直接用比如xgb或dnn模型拟合 X -> Y, $$ p_y=f(x), where\ x = [x_c, x_p] $$ 其中f为xgb或dnn等具体模型,x_c为先验无关的特征(比如二手车里面的品牌和里程特征无关),x_p为先验相关的特征。由于噪声数据的存在以及模型中没有任何的相关性约束,模型最终的打分输出很难保证满足上面案例中的约束关系。 自然想到的方法 一种自然想到的方法是,将f拆解成2部分: $$ p_y=f_c(x_c) + f_p(x_c,x_p) $$ 其中: $f_c$主要建模先验无关特征,可以是任意复杂模型,其输入只能是$x_c$; $f_p$单独建模先验信息,必须是满足先验约束的模型,一般是满足单调性的模型,比如LR、IsotonicRegression等,其输入包含$x_p$; 根据这个思路,二手车价格的建模就可以表达为:predicted car_value = 基础平均价格(baseclean_trade) + 里程相关的价格(predicted mieage_adjustment)。 这种方法建模有个问题,数据集怎么构造?针对二手车预估这个问题,标签一般只有最终的车价,basecleantrade model和averagemileage模型的标签怎构造呢? basecleantrade model:除里程相关特征(odometer,mileage等)外,其他特征group by计算平均价格作为标签,即同款车在不同里程下的平均价格作为标签; averagemileage:里程特征的平均作为标签,其他特征作为模型的输入; 从数据构造过程也可以看出,要采用这种方法的话,就一定得保证同款车有多个不同里程下的数据,这样效果才会好。 进一步——End2End 上面需要建模多个模型,是否能把多个模型融合做到End 2 End训练呢?答案是在DNN中加入先验信息。 同样对于二手车价格的建模,如下图,可以在DNN中针对里程这一项加入先验约束(mileageadjust module)。 图里画的是线性约束,当然,线性约束效果最中预估效果上可能会有一点折扣,可以考虑survival/cox function作为先验约束函数能达到更平滑的效果。具体用什么约束函数,是通过数据分析得到的。 根据这个思路,如果我要预估理财中的用户利率敏感度可以怎么做呢?把上面的思路顺一顺: 分析历史数据中“利率变化"和“余额变化"的关系,如果是接近线性,那就可以用线性先验,如果只是单调则可以考虑survival/cox function;也可以结合一些业务/经济规律来定义先验,比如需求价格弹性; DNN建模,在模型中加入步骤1中得到的先验约束; 最终,利率敏感度建模可以类似下面这样(先验有点类似于需求价格弹性先验)。其中$Q_t$是用户在t日的余额,$r_t$是产品在t日的利率,$Q_{t->t+N}$用户余额变化,$x_{t^+}$是用户利率变化,模型训练完后的$E_d$即可输出作为利率敏感度。 扩展 其实了解过uplift因果模型的同学,应该很容易发现这里的建模方式和uplift中的s-learner很像,只是s-learner中一般treatment是二元变量,但是这里例子中的变量(比如利率,里程等)是连续型变量。 所以要继续深入可以研究将uplift中的方法引入到先验建模场景中。

May 5, 2024 · 1 min · Monkeyzx

重读经典——word2vec

为什么需要重读word2vec Word2vec原论文: Tomas Mikolov, Kai Chen, Greg Corrado, and Jeffrey Dean. Efficient estimation of word representations in vector space. CoRR, abs/1301.3781,2013. Tomas Mikolov, Ilya Sutskever, Kai Chen, Gregory S. Corrado, and Jeffrey Dean. Distributed representations of words and phrases and their compositionality. NIPS 2013. 其中1主要是描述CBOW和Skip-Gram相关方法,2描述了Negative Sampling以及训练word2vec的方法。为什么想要重读word2vec: 推荐系统中,可以把item或user类比与word2vec中的word,很多i2i和u2i的方法都是借鉴的word2vec,以及召回中常用的NCE Loss和Sampled Softmax Loss都和word2vec相关;熟悉word2vec对了解召回,对如何像Aribnb KDD18和阿里EGES一样将word2vec改进应用到具体业务中,会非常有帮助; 召回热门样本的处理,也可以借鉴word2vec中热门词的处理思路; GPT的输入词是字符串,怎么表征输入到NN?当然,现在大家都很熟悉了embedding lookup table,embedding lookup table的其实最早差不多就是来自word2vec(更早影响没那么大暂且不提); word2vec是老祖级别的语言模型,那么最新的GPT和它主要区别在哪里? 初次看GPT代码时,发现GPT的输出是softmax,word2vec其实loss也是softmax loss。但为什么在word2vec里面的softmax就需要Negative sampling,而GPT里却不需要? 基于上下文的Embedding学习:CBOW和Skip-Gram 在word2vec之前,主要还是根据词频信息来表征词的特征。举个例子,每个词在不同的文章中出现的次数作为词的表征,然后通过PCA和Topic Models等无监督学习的方法学习词的Embedding,总体效果不够好。 doc1 doc2 doc3 这 5 2 1 北京 1 0 0 天安门 2 1 0 游客 1 2 2 word2vec核心思想是通过训练神经网络来预测上下文,利用上下文的监督信号学习word的Embedding,这样Embedding中就隐含了上下文信息。word2bec训练embedding的思想对推荐系统、以及Bert/GPT等都影响深远。Word2vec一般有两种训练方法:...

March 31, 2024 · 3 min · Monkeyzx

超长行为序列建模SDIM

SIM和ETA的问题 SIM通过类目从长序列中检索相关的items(hard-search)或者通过embedding inner product计算从长序列中检索最相似的topK个item;SIM的问题在 ETA 中讲过,主要是离线索引可能带来的在线target item embedding和离线的item embeddings不一致的问题; ETA在SIM基础上,通过对Long Behavior Sequence的item embeddings进行SimHash(LSH)之后,然后就可以将inner product的耗时计算转化为Hamming distance计算。从而大大降低了计算量,可以把检索topK的过程放到线上模型中,解决了SIM在离线不一致的问题;但是ETA依然需要通过一个Multi Head Target Attention得到最终的Long Behavior Sequence Embedding表达; 不管是SIM还是ETA,都是基于检索的方法从长序列(>1000)的候选items中选出最相关的topK,美团的这篇文章Sampling Is All You Need on Modeling Long-Term User Behaviors for CTR Prediction 则是吸收了ETA中Hash函数的特点,但不使用检索的方法,不通过Multi Head Target Attention,直接得到用户Long Behavior Sequence的embedding表达——SDIM(Sampling-based Deep Interest Modeling)。 Hash-Based Sampling的用户行为建模 SimHash有Local Sentitive特性,也就是说空间距离相近的两个vector在Hash之后距离也 大概率 相近。SDIM就是利用这个原理: 将序列的所有Item Embeddings和Target Embedding通过m个Hash函数进行Hash(比如下图m=4) Item Embedding每次Hash之后和Target Embedding落在同一个桶(Hash的LSH特性),则记为一次贡献; 进行m次Hash之后,统计每个item embedding的贡献,最后用L2 normalization进行归一化得到每个item embedding的权重 weights(按理L1也可以,但是作者说L2效果更好) 最后只需要将长序列的item embeddings通过weighted sum pooling求和就得到了Long Behavior Sequence的Embedding表达,完美避开了Multi Head Target Attention的操作; 当然,为了降低Hash冲突的风险,实际中需要将hash function数量m和Hash width设置得大一些。...

March 24, 2024 · 1 min · Monkeyzx