type
status
date
slug
summary
tags
category
icon
password
priority
从精排切换成深度学习以来,工业界一直会把排序的模型结构研究切分成基本的两部分,序列处理和特征交叉,甚至有一些公司的排序组,下面都拆成两个Team分别处理行为序列和特征交叉。从最早的时候,比如序列用DIN来处理,序列就被压成了一个或多个向量表征,再参与与其他特征的交叉。我们可以理解成MLP(concat(DIN, Features)),发展到今天大多数的模型研究,还是分立地把MLP换成DCN,增加个LHUC,复杂化为Rank Mixer或Transformer,把DIN叠加MHA,直接换成Transformer,可以写成RankMixer(concat(Transformer, Features))。
从MLP(concat(DIN, Features))到RankMixer(concat(Transformer, Features)),本质没有变,就是序列处理和特征交叉是一个隐式的两阶段处理,序列被压缩到Vector Space才和特征发生交叉。而LLM的有趣之处,就是在Next Token Prediction利用到的交叉发生在词序列的Token Space之中,它能启发推荐排序模型的,就是每一个特征的交叉应该发生在用户序列的Token Space之中。

OneTrans的核心思路很清晰,把用户序列和用户物品特征统一成tokens,作为主体模型的输入。然后主体模型选择一个decoder only Transformer。至此,这篇工作80%的价值已经体现了。至于特征怎么转成token,用户序列怎么排布,Transformer做哪些变体,可能每一部分都有多种做法,工作里展示出来的未必是最好的一种。
类似的思路,年中的时候,美团发了MTGR。从下面这张架构图上,核心思想是非常一致的,所以我们以上谈到的观点并非独有,实际也有其他人在选择突破瓶颈。不过即便今天来看,无论是公司内还是业界,把统一序列和特征并采用简洁的单一网络结构落地全量的,还是屈指可数的。

和美团的MTGR思路不太一样的,它选择把交叉特征也变成token,并且消融了这些交叉特征的作用,这像是之前wide&deep那种新老交替的妥协。从年初开始,我们确定了OneTrans的主体架构,系统里原本那些巨大维度的FM隐式交叉向量特征,海量存储的稀疏笛卡尔积显式交叉特征,就被我们塞在了Non-Seq Features部分,作为一个一个的token,避免了效果损失。但随着模型的Scaling Up,即拉宽d_model,增加层数,增加序列长度,在一两个版本的迭代中,逐步下掉了这批旧时代的手工交叉特征。而且很有意思的是,当初这些带来很大增益的手工交叉,在模型Scaling Up后,它反而在伤害模型的泛化性,带不来AUC的提升,这种略显作弊的记忆性特征大概有着梯度抢占的影响,模型交叉还在DCN/LHUC的水平,它们发挥巨大的作用;在Scaling Up的Transformer面前,它们作用已经不大。

先从输入讲起,左侧Seq Tokenizer输入就是用户行为序列,推荐系统的行为序列往往是多种的,比如包括隐式曝光、用户的正向行为(点击、购买)、其他域的正向行为(点赞、关注、搜索),在上面说的那种把序列压缩成向量再交叉的两阶段模式中,往往是每一种行为压缩成一个向量。现在是一条序列,怎么排布是会影响效果的,因为Transformer采用了单向的casual attention,也就是右侧的行为的叠层计算能感知到左侧的行为,反过来则不然。早期摸索出来的规律是,越靠近系统的行为放在右侧,就是从左到右依次是其他域的行为(点赞、关注、搜索)、本域的正向行为(点击、购买)、推荐系统的曝光,这么排布下测试和full attention的效果基本一致。
我理解这种tricky的序列排布是一种并不普适的方法,可能换一个业务就不一样了,但是从旧有架构的多sequence切换到one sequence,可以有所适配和参考。后续的版本,对序列特征重新做了组织,按照时间先后排布,这是最自然的一种方案。就是时间上更靠近的行为,视野更广,能看到历史上全部的行为。前者必然是一种中间状态,因为不按照时间排布,虽然可以做KV Cache,但当用户有新增行为时是无法处理KV Cache增量更新的。
右侧的Non-seq tokens,最初是分组的原始特征,逐步演变成所有特征拼接好做一层变换再Split成多个token。
接下来是Transformer的一些“优化”,但在我看来这些“优化”更像是trick,它可能是特定条件下的一种妥协,我相信随着架构的推理能力提升、Transformer的宽度、层数提升,这些“优化”会逐步被消灭掉,整个结构蜕变成标准的Transformer。
第一个”优化“就是per-token的Transformer参数,左侧蓝色部分是标准的Transformer共享参数,右侧的橘黄色则是给每一个特征token分配了独立的参数,类似于RankMixer,这么干确实在效果上更好了,我们的解释是每一个特征token的异质性,需要独立参数来处理,但这么做有非常多潜在的危害。
首先是模型参数量暴涨,我想有人会问,这未必是坏事,这不正好是在做Scaling Up么?我的理解是,Scaling Law本质是算力的Scaling,研究的是算力在参数维度和数据量上的最优分配,并不是单纯地把参数量搞大,因为本质算力没有变化,无法共享的参数实际带来了访存量的提升,使得计算强度下降,GPU的利用率变低。其次,我认为LLM能突破是依靠足够强的压缩,压缩产生智能,推荐系统的数据量实际是优先的,有限的训练机会分散给了多组参数,未必是最优分配。所以,我看到那种per-token加上sparse MOE扩展出来的几B的模型都会吐槽一番,实际算力和GPU利用率虚的狠,举个例子,4B的模型深度只有6层,但是qwen 0.5B的模型却有24层和更宽的dmodel。
关于scaling law和计算强度的讨论,可以参考:
zhuanlan.zhihu.com
未来的方向一定是想办法消灭掉这些per-token的参数,比如不做per-token的Sparse MOE,可能要设计更好的tokenizer,或者继续scaling到一定程度会自然地解决掉。
另一个是金字塔的设计,它设计的思考是不必每一层都处理几K的token,相当于token在长度上的算力缩减,以支撑更大的深度,但是启发式地总是保留最近的token,潜在可能导致每次层都被最近的同质化行为主导,最标准地做法还是动态地逐层丢弃token,例如LazyLLM:Dynamic Token Pruning。
工程上的训练推理优化,就是围绕着标准Transformer的经验而展开,比如最重要的是当序列长度逐步增加,为了避免掉重复的attention计算,就需要借助KV Cache。包括request和session级别,request内训练和推理都只做一次计算,跨刷复用历史计算。
.png?table=block&id=2cc0131b-d915-8053-bb9d-cb5281d5a3b1&t=2cc0131b-d915-8053-bb9d-cb5281d5a3b1)
接下来讲讲,为什么选择尽可能标准的Transformer。推荐领域实际很喜欢从其他领域借鉴然后修改形成一套模型结构,深度学习框架的灵活性也给了足够的自由度,即便有几篇工作强调了序列和特征的统一建模,也会发现模型结构的改造是五花八门的,更不用说众多的模型复杂化(Scaling Up)工作。最早我们的基线也一度切到过RankMixer,后来才调整到One Transformer,这里面不只是说某一个结构的强弱差距。经验主义的判断总是你来AB下,哪个好就保留哪个,但是我们当时的思路就是,必须是朝着OneTrans方向做,不够好就分析改进,这背后的思考源于认清自己的渺小,甚至推荐领域的渺小。
我们的技术判断是要用标准的Transformer,那么我们就和LLM拉齐了基础。在任何情况下我都倾向于选择Transformer,不再做其他基本结构的探索,并不是说在任何情况下他都更强,而是相信绝大多数闭源和开源LLM的基础模型选择。并且因为选择了和LLM相同的基础模型结构,LLM领域的学术和业界会提供源源不断的对模型的理解和增量创新。举个例子,DeepMind MoR工作尝试在token的深度上进行控制,进行参数的递归和计算的早停,节省一半的内存和计算量,如果我们基础模型结构是Decoder Only的Transformer,是可以直接尝试和复用的。再如DeepSeek的稀疏attention(DSA,NSA)工作,LLM生态的flex attention组件,都是我们做技术增量的源泉。使用Transformer作为基础,对齐LLM做问题映射,相当于免费雇佣了大量LLM的研究者帮你分析理解问题、提供创新思路和帮助构建开源生态工具。

更多可以参考:
zhuanlan.zhihu.com![zhuanlan.zhihu.com]()
zhuanlan.zhihu.com
再发一下招聘,欢迎对LLM和推荐系统感兴趣,想把利用LLM的技术革新推荐系统的同学: