文章链接:https://arxiv.org/pdf/2508.20900
机构:快手
发布时间:2025.08
参考文献:
Copyright (c) Wang-Luning. All Rights Reserved.
OneRec存在如下问题:
Encoder-decoder架构的资源利用率低,绝大部分资源消耗在了encode长序列用户历史上(97%的资源被用于序列上下文编码),而真正在decoder用于生成推荐结果的资源消耗比例很小(或者说在训练中用于计算loss的部分),这限制了模型的扩展到更大规模的潜力
RL仅依赖于奖励模型,会导致采样效率低的问题。在OneRec-v1的流式训练过程中需要额外的计算资源进行在线生成和打分,计算资源的限制使得采样仅能局限于少部分(1%)用户,难以近似全局行为分布。另外,基于reward model的proxy reward signal的RL还可能有reward hacking的问题,难以反映真实的用户体验偏好。
OneRec-v2通过如下主要的优化点来改进:
Lazy Decoder-Only模型架构:通过decoder only架构消除了encoder的瓶颈并简化了交叉注意力,使得总体计算量降低94%,训练资源消耗减少90%,这也使得模型成功被扩大到8B,且在训练中能持续看到loss降低,符合scaling law。
基于真实用户交互的偏好对齐:一个由用户反馈驱动的框架,有效利用来自真实世界的用户反馈信号——视频观看时长(而不是奖励模型的代理信号)作为奖励,来更好地对齐用户偏好,主要包括:
时长感知的奖励塑形:为了避免视频本身的长短带来的偏差(短的视频即使质量很高,用户观看时长上限也就是视频长度,如果比绝对观看时间的话很难比得过本身就长的视频),在考虑视频本身长度差异的基础上对用户观看时长信号进行矫正,从而让奖励信号更准确地反映内容质量而非视频本身的时长
自适应的ratio剪裁:在策略优化过程中稳定训练
这样即可有效利用现实世界反馈来更好地对齐用户偏好,使得用户使用app的时间更长。
Lazy Decoder-Only模型架构:
首先考虑在流式训练场景下,模型训练样本的组织形式:
在流式训练中,传统上训练样本通常按照时间顺序排列,直接在整个序列上将下一个token预测作为训练目标,每次曝光都产生一条训练样本,但由于多次曝光可能共享同一部分历史序列(由同一段历史增量扩展而成),导致这样训练会带来大量冗余。
如下图(a)所示,设一共对用户进行了3次曝光,第一次曝光了物品A、第二次曝光了物品B、第三次曝光了物品C,这3次曝光产生了3条训练样本:A、A-B、A-B-C,那么样本2的训练目标就是预测A->B,样本3的训练目标是预测A->B和[A,B]->C,可见A->B这个共享的历史模式在2条样本中被重复学习,造成了冗余。
一种解决方案是不再每次曝光就产生一条训练样本,而是以用户为中心,把每个用户的完整交互历史作为一条训练样本。但这样存在时间信息泄露和流行度偏差问题。如下图(b)所示,设用户1、2产生的2条训练样本分别为A-B-C、B-C-D,则在样本1上训练后模型就学到了B->C这种模式,再在样本2上训练时还会碰到B->C模式,相当于发生了信息泄露。另外在流式训练场景下,用户的历史序列是在不断增长的,因此这种把每个用户的历史序列当成一个静态样本的方式也不太适合。
OneRec-v2通过改进方法1得到“New impression Only Organization”,解决共享历史冗余的问题。其仍为每次曝光就产生一条样本,但这条样本用于训练时并不是在整个序列上都做NTP loss,而是只对最后一个物品的token(对应本次曝光的最新物品)算loss。具体而言,在每条视频SID长度为3的情况下,每条训练数据只在最后3个token上算loss(上文的全文概览图中也能体现出来)。这样就避免了把它的历史序列数据再重新训一遍,历史序列早已在之前的老样本中就被拿来训过了。
接下来考虑Lazy Decoder-only架构的细节。
OneRec-v1中使用Encoder-Decoder架构的动机在于,用户上下文特征(包括历史物品序列、用户画像特征等)和目标推荐物品之间存在较大差异,因此使用Encoder专门用于处理用户上下文特征,Decoder专门用于基于处理后的上下文特征来做目标SID生成。但这样会使得大部分计算资源花费在了Encoder处理巨大的用户上下文特征序列上,而真正用于生成SID和计算loss的资源比例就很小了,使得在固定总算力下真正用在生成上的比例很小,某种程度上属于浪费了算力,且难以实现模型规模的扩展。
为了将计算集中在真正和目标生成相关的SID token上,这里提出了Lazy Decoder-Only模型架构,它和传统的Encoder-Decoder架构和Decoder-Only架构都有所区别。它将context信息当成一种静态的条件信息,且只能通过cross-attention来访问到这些信息,从而避免context序列内部进行大量冗余的计算,同时保留了模型对于复杂context信息的有效捕捉。另外,decoder的cross-attention模块中去除了K/V projection层,直接拿context张量(的一部分)作为各层的K/V参与attn计算,从而避免在每层都单独对于巨大的context张量做projection产生KV的资源消耗,再结合GQA可以大幅减少处理用户context的资源消耗(“Lazy”这个名字含义也就是免去每层内使用kv projection算kv)。
Context Processor:
用于处理用户上下文信息的模块,作用其实就相当于Encoder。
将不同来源的异构信息(如用户画像特征、用户历史行为序列等)连接成一个统一的序列作为context序列。context表征张量中的每个token都被处理成如下feature维数,以便在后续直接拿来作为KV算attention:
其中,
然后,将上述context表征张量沿feature维度切分成
然后,在每层
最终,context processor即可输出由context张量转化得到的,为decoder各层准备好的KV数据,它包含了:
可见,相比于Encoder-Decoder架构中Encoder花费大量计算产生供decoder生成使用的kv,context processor以非常轻量的方式编码了context信息,并同样将其提供给decoder作为kv。
Lazy Decoder Block:
decoder的目标是预测训练样本中最后一个视频(目标视频)。训练时,decoder的输入为BOS+目标视频SID的前2位:
每个decoder block具有一个cross-attn、一个self-attn、一个FFN。对于第
基于真实用户交互的偏好对齐:
在后训练中,RSFT和OneRec-v1保持一致,持续拿线上数据使用和预训练相同的NTP loss做微调。而RL部分不同于v1中仅基于奖励模型获得reward,v2使用了用户反馈信号(视频观看时长)作为reward。
在短视频场景下,每个视频的播放时长(Playtime)是最dense的反馈信号,且和app留存率等关键线上指标高度相关。因此这里基于视频播放时长设计了一个简单但有效的reward,而没有使用参数化的奖励模型。
由于视频播放时间(Playtime)受到视频时长(Duration)的影响导致偏差,因此本身时长差异巨大的视频的播放时间是没什么可比性的(短的视频即使质量再高,它的播放时长最高也超不过它本身的时长,很难比得过那些本身很长的视频)。因此,首先将用户历史交互视频按本身时长进行分桶,时长接近的视频放到一个桶中,然后衡量视频在桶中的相对质量高低。由于视频时长遵从长尾分布,因此使用对数策略来进行分桶,随着时长增大桶的大小按指数递增,使得每个桶里的视频数量尽可能均衡。
具体而言,对于一个时长为
其中
设用户历史交互序列为
对于某目标视频
可见
若
可见,这种策略下筛选出来的正样本和负样本都是很突出的,能够代表很强的正向或负向偏好信号。
具体到RL算法上,使用了新提出的GBPO(Gradient-Bounded Policy Optimization):
可见,GBPO移除了
对于OneRec生成的曝光样本,可以使用其在曝光时刻的生成概率为
在GRPO等算法中,比例为1的样本被视为非常稳定的训练样本,因此不会对它进行截断处理。但是在实践中这种样本也有可能带来梯度爆炸。对于某个token
问题出在梯度中的
借鉴BCELoss的梯度表达式,其形式和上述ECPO loss类似,且也存在对于负样本的惩罚,但区别在于负样本的梯度的系数由
因此,参考BCELoss的梯度形式设计了GBPO,从而约束了RL的梯度: