Actions Speak Louder than Words: Trillion-Parameter Sequential Transducers for Generative Recommendations
泛读后的问题
- 能打败传统的方法,核心点有哪些
- 样本和特征的组织方式
- 模型结构改进HSTU
- 训练加速的思路
聊聊整体的理解
It’s also worth remarking that there have been no successful applications of fully sequential ranking settings in industry, especially not at billion daily active users (DAU) scale, prior to this work.
这篇文章整体读下来,是非常接地气的,浓厚的工业风,如果是一篇试水的工作,写不出这样的底气。我最近也面试过几个meta的同学,reals已经完成了落地,还在内部推广,但是也有声音说不够solid。另一个场景的TL说,未必是生成式,但是8k序列肯定是ok的,他们做超长序列非常轻松,因为meta推荐和LLM训练和serving那一套生态是一致的,这个对我的影响是我们做超长序列的同时,必须切成torch。
我感觉这就像16-18年,大家知道可以用深度学习做推荐系统,但是能击败LR和协同过滤却很困难,这像极了那个时刻,经验在积累,等待迷雾散去,一丝天光到万丈的光芒。
阿里之前有一个做OCR的组,他们是基于SVM的,效果被CNN碾压,这个组没有升级技术的机会,直接解散了。应当以此自我警醒,过去的多年经验可能经受不住新技术的一击。我以第一性的态度来理解这篇文章,他未必能击败能轻松击败现有的方案,但是他里面的许多点能启发你,重组你自己的工作。
一句话理解,改变样本和特征的组织方式,把召回和排序任务变成用户序列转移的任务,具体为预测下一个内容和下一个行为的发生概率,融合了召回排序任务,序列的长度就是scaling law的突破点。剩下的问题就是怎么在GPU降低训练的复杂度,包括HSTU的序列处理结构,采样操作,利用输入序列稀疏性,随机长度(Stochastic Length, SL)算法,M - FALCON的方法。
重新组织样本和特征

这张图片展示了传统DLRMs的样本特征组织和GRs的差异与过度。
先看左侧,我们从上往下看,左侧的每一列代表一条样本,这条样本从上到下包含了它的数值统计特征,文章给的例子是一个match特征,很工业的特征了;绿色的是主事件特征,它都是在你推荐的内容上的不同类型的事件,传统我们会抽取为序列特征,附录A给出来的例子是,用户最近10个喜欢的图片,与当前候选item相比用户过去点击过的最相似的50个url,这不就是SIM超长序列search后的结果,再次说明了浓重的工业风,它们的基线不是一个玩具基线,或者至少作者对于传统方法基线的理解非常的solid;蓝色和黄色的部分,并不是用户和内容的交互,如用户的人口统计学画像,年龄、性别,最近关注的主播。这些几乎描述了传统的原始特征的构建。
再看右侧及样本特征组织方式的转换,还是从上到下。样本做了采样,是按照userr的维度设置的采样率,用户的历史行为丰富就采样率低,否则就高,这和我们常做的无偏采样是不同的;数值统计型的特征都被丢弃了,它的理由是通过超长的序列和target-aware cross attention能够捕捉到这部分丢弃的特征,这个也能给传统的建模一个topic,是不是序列足够长,序列处理足够复杂,人工的统计类特征都可以抛弃了;所有的内容维度的特征,合并到时间线维度上,组织方式是(内容,时间,行为)的3元组,行为是一个multi-hot的向量,这个其实也是传统的建模上对于序列组织的考量,是拆成多条不同行为的序列,还是组织成一条序列并把不同事件类型记录到上面,一般序列都很短,大家的选择更偏向于前者;非内容交互的特征,也按照发生的时间插入到主序列中。整个的特征形式就变成了一条只包含离散特征行为超长的序列了。
聊一下样本重新组织后的优势。
它在附录里提到了,传统的模型Ignorance of features other than user-interacted items。它是指如果主序列里没有其他非交互类型的离散特征,性能会大幅度下降,table 6和table 7中的GR(interaction only)就是去掉了这部分特征。而给传统的方法增加了这部分特征,增益也没有很大,传统的方法没有很好地利用这部分特征,DLRM(abl. features)就是去掉了这部分特征的。核心原因是这些特征没有用户的历史行为及target有充分的交互。但是这里也有一个点,就是看基线的处理会不会做一些工业上的trick比如大规模的笛卡尔积交叉特征,比如用户的性别交叉target id,历史的top行为类目交叉target id。不过这里能看出来这样的组织方式,因为后续序列的建模方式,很自然地完成了这一点。

因为所有的信息都放在了序列里面,后面的序列建模又是target-aware的,那么也就意味着所有的特征都是target-aware的,这在一般的基线中也是未必存在的设定。并且一条超长的序列,很多跨事件、跨领域的行为序列融合其中,他们之间的交叉也更为自然,现行方案里多条小的序列之间是没有直接信息交互处理的,一般都是pooling后在上层的tower完成特征交叉,这时已经丧失了非常多的信息了。
召回和排序任务重新表述



上面的图和任务的定义联合看会清晰一些,它包含了排序和召回任务,将排序和检索重新定义为序列转移任务。序列和行为是交替输入的,能拆分出两个任务,对应两种概率过程。
- 召回,对应着Next content token prediction任务,描述了推荐出内容的概率过程。
- 排序,对应着Next action token prediction任务,描述了用户对推荐内容的行为反馈的概率过程。
排序上,主事件序列里是包含负样本的,所以有清晰的正负例,可以使用交叉熵来训练,学习p(ai+1|Φ0, a0, Φ1, a1, . . . , Φi+1)。按多目标的设定,在Φi+1的输出之上增加一个小网络进行Multi-task训练。
召回上,学习p(Φi+1|ui) 的分布,是next one predict问题。不同的是,序列里包含着负样本和离散特征节点,要通过mask来处理。召回任务具体怎么训练和推理,文章写的不够清晰,我觉得这里可以轻松地做一些发挥,不一定要follow原工作。比如给每一个content一个embedding,这个就是最终用于检索的,训练的时候通过batch sample softmax,把序列第i个位置的输出当成user tower,套用我们之前的各种认知即可。
传统模型里放超长的行为序列,最大的问题就是样本是impression-level的,如果用户有一个行为事件,它会出现在样本中N次,有N个这样的行为,它的存储和计算消耗必定是O(N^2)的。这个地方是我认为文章最有突破的点,它通过采样降低了样本的发出频率,把这个计算降低到了O(N),这里并不是说训练用到的监督信号减少了,因为序列中是带着actions的,它可以同时计算多个target的loss,encoder的计算量也在众多的target上有了分摊。
工业实践上,它是流式产生样本的,选择了一个request或者session结束。实际上,天级增量样本也是好的选择,每天产出一条样本。把需要训练的位置做好标记,保持one-epoch的设定。
序列网络结构HSTU

这里是HSTU结构和传统模型的对比,我们的重点在右侧。它是多层结构的,每一层的结构是重复的,和transformer encoder的是一致的。

每一层会包含3个子层。
- f函数是单层的MLP,也就是一层线性变化,Φ函数是一个非线性的变换,这里用的SiLU,即sigmoid(x)*x,它在防止死神经元上有很大作用,实践中有一些效果。split成4份,相比于传统self-attention,多一个U(x),它的作用先按下不表。
- QK计算加上一个位置和时间的bias,套上SiLU激活之后乘上V。这里核心的差异点是,激活函数不是softmax。
- Layer Norrm后做一次线性变换,乘以U(X)。
QKV计算,其实就是一个list target level上的DIN计算。额外的一个U,文章的解释是一种gate,这根我们今天在MLP里大量使用FM结构、LHUC gate等乘法交叉操作是异曲同工的。
下面实验表明,相比Softmax,SiLU的非线性变化拿到了更好的结果,这个和原始的DIN一样,都没有依赖Softmax作为激活。优势有两点,用户序列和物品相关的数量是能表明用户兴趣强度的,Softmax归一化会丧失这样的信息。另一个是,Softmax无法适应非稳定的词表变化,文章通过一个数据模拟实验证明了这一点,HSTU里面pointwise attention换成Softmax低了44.7%的性能。
线上服务
对于召回只要产出了next predict的表征,用于KNN检索即可。和一般的双塔user侧的serving没有本质区别。
排序的会相对复杂,为了降低超长序列的重复运算,候选的结果会拆成多个batch放入序列,只是它会断掉候选之间的attention。

加速运算
GPU attention kernel优化
利用了序列的稀疏性。
序列长度的稀疏性采样

ncj是用户行为序列长度,alpha在1-2之间,我们假设它是1,最大化稀疏性。Nc是所有用户最长的行为长度,我们假设是10000。
- 如果序列长度少于100,则完全保留用户序列
- 如果序列长度大于100,我们假设是1000的长度,以0.99的概率把序列截断到100,否则完全保留。
alpha不变的情况下,序列越长被截断的概率越高;其他不变的情况,alpha越大,保留的序列下限越长,保留概率越高。

蓝色代表它的设置带来的损失是微乎其微的。
优化器选择
100亿 512维的embedding,使用Adam优化器,fp32情况下向量和优化器状态需要60TB。通过按行的adamW来减少内存压力,并且把存储器状态 DRAM(Dynamic Random Access Memory)中,相比HBM(High Bandwidth Memory)每float从12byte减少到2byte。毛估计从60TB降低到了27TB。
M-FALCON算法优化大规模候选排序
M-FALCON全称是 Microbatched-Fast Attention Leveraging Cacheable OperatioNs
上面提到,为了降低超长序列的重复运算,候选的结果会拆成多个batch放入序列并行运算,它会断掉候选之间的attention。
除此之外,文章假设了要处理上万候选,才要切分batch。batch之间的数据也是可以共享的,重复使用已缓存的K(X)和V(X)。想想为啥,attention都是看到了前序,后面的候选放入序列并不影响计算,只有候选的Q和U在batch件
启发
scaling law 本质就在序列长度,传统的方法样本不做丢弃(出于性能考虑可能会丢弃曝光样本),样本长度叉乘上每个用户的超长序列,计算性能和样本的存储都是巨大的问题,它做了大比例的丢弃样本,换来的是8k的序列长度。
这篇文章是我最近阅读过的最受启发的推荐系统论文,别的工业论文可能有一个亮点,但是做了一堆额外的把字数凑到了10页。这一篇有非常多的闪光点,溢出到附录里都是精华。