马斯克最近开源了部分 Twitter的代码,主要有两个仓库,
此次发布的大部分代码是推荐算法,包括给用户在时间线上推文的机制等等。并且看起来这个github会持续更新,本篇文章也尝试理一下这部分的推荐机制。
时间线推文(For You timeline)的整体框架如下图所示,
其主要分为三个模块:
最后实现Timeline、Who to follow、Ads的三个任务,即给用户推文、推用户、推广告。
下面分别简要介绍一下各个模块。
DATA
在推特这种社交属性明显的场景中,数据几乎就是由用户之间的互动、用户和推文之间的互动所构成的。因此DATA部分分为Follow graph、Tweet engagement、User data。
FEATRUES
FEATRUES指特征工程,包括embedding嵌入、社交图特征如聚类和社区发现、用户信用和违规检测等,这些特征后续可以用于召回、排序、安全等等具体模块(具体可见下一节的HOME MIXER)。
特征主要分为:GraphJet、SimClusters、TwHIN、RealGraph、TweepGred、Trust&Safety。
社交特征。GraphJet是社交图特征。通过分析用户已经关注的人或具有相似兴趣的人,如关注的人所浏览的内容,即社交图中的二跳关系U2U2I。因此为了实现高效动态图构造和游走,Twitter内部自研了GraphJet图引擎(VLDB 2016)。
嵌入特征。目标得到user embedding和item embedding,主要分为稀疏嵌入和稠密嵌入两种,前者通过聚类、后者基于图学习。具体是两种算法:
RealGraph用于偏好预测,主要进行边预测,即用户是否互动。这个特征主要用于粗排模块中,作为LR粗排的一个辅助,具体在粗排模型中进行介绍。
TweepGred用于信用预测,基于pagerank评价用户的声誉。
Trust&Safety用于检测不可信和不安全等违规内容。
HOME MIXER
HOME MIXER是推特推荐的核心服务(Scala框架),其分为Candidate Source、Heavy Ranker、Heuristics & Filtering三个大块(分别对应召回、粗/精排、重/混排),其中每一小块内有多种小组件,如上图所示。
Candidate Source(即召回)。目的是从不同的源(量级亿万)召回一些最新、质量高的推文,主要是利用社交图召回,有两个召回路,一路是已经关注的社交圈(in-network),和待探索的社交圈(out-of-network),理论比例是各50%出现在用户的时间流推文中,实际上这个比例会根据用户的兴趣而适配。
召回模块的各小组件主要有如下,其中Search Index和UTEG是社交图内的,CR Mixer和FRS是社交图网络外的内容。
Heavy Ranker(即粗/精排)。Candidate Source中的两路召回in-network、out-network得到的推文,会先进粗排再进精排。
负责粗排有两个模型,第一个是LR模型,预测用户和推文有互动的概率,如上图所示,具体特征有
不同特征会有不同的权重,如点击的权重为1,点赞的权重为2等,如下表所示。
INDEX_BY_LABEL = {
"is_clicked": 1,
"is_favorited": 2,
"is_open_linked": 3,
"is_photo_expanded": 4,
"is_profile_clicked": 5,
"is_replied": 6,
"is_retweeted": 7,
"is_video_playback_50": 8
}
第二个粗排模型是基于RealGraph: User Interaction Prediction at Twitter,如上图所示,本质是个链接预测任务,去预测用户和用户交互的概率。包括图构成、模型训练和应用。
过粗排模型后,两路召回会各自排出750条推文,然后将共1500的数量进精排。
精排模型来自新浪KDD 2021,MaskNet: Introducing Feature-Wise Multiplication to CTR Ranking Models by Instance-Guided Mask,如上图所示。主要提出了一种instance-guided mask方法将全局上下文信息进行动态融入。首先,所有输入的特征会被concat在一起, V e m b = c o n c a t ( e 1 , e 2 , … , e i , … , e f ) V_{emb}=concat(e_1,e_2,…,e_i,…,e_f) Vemb=concat(e1,e2,…,ei,…,ef)为了充分利用全局上下文,Instance-Guided Mask使用两层FC来投影,
V m a s k = W d 2 ( W d 1 V e m b + β d 1 ) + β d 2 V_{mask}=W_{d2}(W_{d1}V_{emb}+\beta_{d1})+\beta_{d2} Vmask=Wd2(Wd1Vemb+βd1)+βd2再利用element-wise product来融合全局上下文信息, V m a s k e d E M B = V m a s k ⊙ V e m b V_{maskedEMB}=V_{mask}\odot V_{emb} VmaskedEMB=Vmask⊙Vemb V m a s k e d H I D = V m a s k ⊙ V h i d d e n V_{maskedHID}=V_{mask}\odot V_{hidden} VmaskedHID=Vmask⊙Vhidden所以其实instance-guided mask可以被看作为一种gate,用于可以加强某些特征,减弱某些噪声对模型的影响。最后以多个这种MaskBlock作为基本单元,串行MaskBlock或者并行MaskBlock得到MaskNet。
而Twitter所用的MaskNet网络参数48M,特征6k,一个多目标模型,目标数量涵盖包括互动、时长和画风等10个方面,如下:
Heuristics & Filtering(即重/混排)。这一部分主要设计一些启发式的过滤策略(重排),和混排推文、推人、推广告等下端应用。
混排是最后一步,系统会将推文与其他非推文内容(如推广告、推关注人)混合在一起,然后再这些内容将返回到设备上进行显示。 上面的流程每天运行大约 50 亿次,平均完成时间不到 1.5 秒。单个管道执行需要 220 秒的 CPU 时间,几乎是在应用程序上看到的延迟的 150 倍。