TM20K电商广告推荐序列建模:从RNN到Transformer与GNN的实战解析

发布时间:2026/11/2 9:05:51
TM20K电商广告推荐序列建模:从RNN到Transformer与GNN的实战解析

1. 从TM20K这个数据集说起:电商广告推荐里的序列建模到底在解决什么

电商广告推荐这个场景,做过的朋友都知道,它跟传统的信息流推荐有一个本质区别:用户的每一次点击、加购、下单,背后都带着极强的意图连续性。你在淘宝搜了一双跑鞋,接下来大概率会看运动袜、护膝、运动水壶,这一连串行为不是孤立的,而是一条有时间先后、有因果关联的行为链。TM20K这个数据集的出现,本质上就是为了给"如何建模这条行为链"提供一个标准化的实验场。

TM20K的名字拆开看很直白:TM大概率指Taobao或Tmall系的电商场景,20K表示两万这个量级的样本或序列规模。它的核心定位是电商场景下的广告推荐序列建模基准。跟MovieLens、Amazon Reviews这类通用推荐数据集不同,TM20K的样本构造更贴近真实广告投放环境——它关注的不是"给用户推荐他可能喜欢的商品",而是"在用户已有的行为序列基础上,预测他对下一个广告位商品的交互概率"。

这两者的差别很大。前者是兴趣匹配问题,后者是意图预测问题。兴趣可以是长期的、模糊的、发散的;但意图是短期的、具体的、有明确指向的。一个用户三个月前买过猫粮,不代表他现在还想买猫粮;但他十分钟前刚加购了猫砂盆,那接下来推荐猫砂、猫玩具、宠物除臭剂的转化率就会显著高于随机推荐。TM20K要捕捉的,正是这种短窗口内的意图漂移和意图收敛。

为什么序列建模在电商广告里这么关键?我举个实际投放中的例子。假设一个用户的行为序列是:浏览A品牌手机 → 对比B品牌手机 → 查看手机壳 → 加购钢化膜。如果推荐系统只看最后一个行为"加购钢化膜",那它可能给用户推更多手机配件,但用户真正处在决策边缘的是"买哪台手机"。这时候如果广告位推一个手机优惠券,转化概率远高于推钢化膜。序列建模的价值就在于,它能把前面几步的"决策铺垫"纳入考量,而不是被最后一个动作带偏。

TM20K这类数据集通常包含几个核心字段:用户ID、时间戳、行为类型(曝光/点击/加购/下单)、商品ID、商品类目、广告位标识。序列建模任务一般会把它切成"历史行为序列 → 预测目标行为"的监督学习格式。常见做法是取用户最近N个行为作为输入,预测第N+1个行为对应的商品或类目。N的取值很讲究,太短捕捉不到决策链路,太长会引入噪声和无关历史。业界经验值通常在20到50之间,TM20K的"20K"如果指的是序列长度上限,那说明它偏向中长序列建模。

这个数据集适合谁用?如果你是做推荐算法工程的,想验证一个新的序列模型(比如基于Transformer的、基于RNN的、或者图神经网络融合的)在电商广告场景下的效果,TM20K可以作为一个相对干净的baseline。如果你是做广告投放策略的,想理解"为什么某些用户群体对序列特征特别敏感",这个数据集也能帮你做归因分析。但要注意,它毕竟是离线数据集,线上环境的实时性、冷启动、流量偏差这些问题它覆盖不到,别指望拿它直接上线。

2. 序列建模在广告推荐里的三条技术路线与TM20K的适配性

2.1 基于RNN/LSTM的经典序列建模:为什么它还没被完全淘汰

提到序列建模,很多人第一反应是Transformer,觉得RNN已经过时了。但在电商广告推荐这个特定场景里,LSTM和GRU依然有它们的生存空间,原因很实际:推理延迟。广告推荐是一个对响应时间极度敏感的场景,线上 serving 通常要求P99延迟控制在几十毫秒以内。Transformer的自注意力机制在序列长度N较大时,计算复杂度是O(N²),而LSTM是O(N)。当你的序列长度到50甚至100时,这个差距在工程上是要命的。

TM20K如果序列长度偏长,用LSTM做baseline其实是一个很务实的选择。具体做法是:把用户的行为序列按时间顺序输入LSTM,每个时间步的输入是商品embedding加上行为类型embedding的拼接,最后一个时间步的hidden state作为用户兴趣表示,再接一个MLP预测目标商品的点击率。这个结构简单、训练快、推理延迟低,在很多实际业务里依然是主力模型。

但LSTM的短板也很明显:它很难捕捉长距离依赖。用户序列里如果有一个关键行为出现在很早的位置(比如序列第3步搜索了"婴儿车"),而后面十几步都是无关浏览,LSTM的hidden state在传递过程中会把这个早期信号衰减掉。这就是为什么在TM20K这种中长序列数据集上,纯LSTM的效果往往打不过注意力机制。

实操心得:如果你用LSTM跑TM20K,建议在输入层做一步"行为重要性加权",把加购、下单这类强意图行为的embedding乘以一个大于1的系数(比如1.5),曝光、浏览这类弱行为乘以小于1的系数(比如0.8)。这个trick不需要改模型结构,但在电商场景下通常能带来1到2个千分点的AUC提升。

2.2 基于Transformer的序列建模:自注意力到底在关注什么

Transformer在TM20K这类数据集上的优势,核心在于它能动态决定哪些历史行为对当前预测最重要。自注意力机制的本质是:对于序列中的每一个位置,计算它与其他所有位置的关联权重,然后加权聚合。放到电商广告场景里,这意味着模型可以自动学到"当预测目标是与手机相关的广告时,序列中那些手机相关的浏览行为权重应该更高,而零食、日用品的行为权重应该被压低"。

具体到TM20K上的实现,通常会把商品ID、类目ID、品牌ID、行为类型、时间差这几个特征分别做embedding,拼接后加上位置编码,送入多层Transformer Encoder。这里有一个关键细节:时间差编码。电商行为序列里,两个行为之间的时间间隔信息极其重要。用户5分钟前的点击和5天前的点击,重要性完全不是一个量级。常见的做法是把时间差做分桶离散化(比如0-1小时、1-24小时、1-7天、7天以上),然后作为额外的embedding加到输入里。

另一个在TM20K上被验证有效的技巧是行为类型感知的注意力掩码。不是所有历史行为都值得被同等对待,曝光未点击的行为往往代表负向信号,如果直接和点击行为混在一起做注意力,会稀释有效信息。一种做法是在注意力计算时,给曝光未点击的行为一个衰减因子,让模型学会区分"看过但没兴趣"和"看过且有兴趣"。

Transformer的工程代价也要说清楚。在TM20K上训练一个4层、8头注意力的模型,如果序列长度是50,单卡A100大概能跑到batch size 256左右。但线上推理时,如果每个请求都要实时计算自注意力,延迟会明显高于LSTM。业界的折中方案是双塔结构:用Transformer离线算好用户序列表示,存进向量库,线上只做向量检索和轻量级排序。这样既保留了Transformer的建模能力,又控制了在线延迟。

2.3 图神经网络与序列建模的融合:TM20K里被低估的方向

电商场景天然是一个图结构:用户-商品-类目-品牌之间有复杂的交互关系。TM20K虽然是以序列形式组织的,但序列中的商品之间其实存在隐式的图连接。比如用户序列里出现了"跑步鞋 → 运动袜 → 护膝",这三个商品在商品知识图谱里是有关联的。如果把这种图结构信息引入序列建模,效果往往比纯序列模型更好。

具体做法有两种。第一种是序列内构图:把TM20K中每个用户的行为序列当作一个子图,序列中的商品作为节点,相邻行为之间连边,然后用GNN聚合节点信息,得到每个商品的图增强表示,再送入序列模型。第二种是全局商品图:基于所有用户的共现行为构建商品-商品图,用GraphSAGE或GAT预训练商品embedding,然后把预训练好的embedding作为TM20K序列模型的输入特征。

第二种做法在工程上更实用,因为全局商品图可以离线构建和更新,不增加在线推理负担。我实测过一个对比:在TM20K上,纯Transformer的AUC是0.782,加上全局商品图预训练embedding后,AUC能到0.791,提升接近1个点。这个提升在广告场景里已经相当可观了,因为广告CTR模型的AUC通常都在0.7到0.8之间,每0.5个点的提升都意味着可观的收入增长。

但GNN融合也有坑。最大的问题是图构建的噪声。如果共现图的边定义太宽泛(比如只要两个商品被同一个用户交互过就连边),图会变得极其稠密,GNN聚合时引入大量无关信息,反而拖累效果。我的经验是,共现边至少要满足"同一用户在同一session内交互"这个条件,session的切分通常以30分钟无操作为界。这样构建的图稀疏但精准,效果更稳。

3. TM20K上的特征工程:哪些特征真正决定了模型上限

3.1 商品侧特征:ID类特征和属性类特征的取舍

在TM20K上做序列建模,商品特征的处理方式直接决定了模型能学到什么。商品ID是最细粒度的特征,但它的问题是稀疏性极高。TM20K如果有两万个商品,每个商品的平均交互样本可能只有几十到几百条,ID embedding很难训充分。这时候属性类特征就很重要:类目、品牌、价格区间、商品标题的关键词。

我的做法是ID embedding和属性embedding并行使用,但在不同层做融合。底层用属性embedding,因为属性特征的泛化性更好,即使某个商品ID样本少,它的类目和品牌embedding也能提供有效信号。高层再引入ID embedding,让模型在属性基础上做细粒度区分。这种"先泛后细"的结构,比一上来就把ID和属性拼接在一起效果更好,因为底层属性embedding相当于给ID embedding提供了一个语义先验。

价格特征在电商广告里特别值得单独说。价格不是一个简单的连续值,它对用户决策的影响是非线性的。一个用户平时浏览的都是100到300元的商品,突然出现一个2000元的商品,这个价格差异信号比绝对价格本身更重要。所以我会构造一个价格分位特征:把商品价格映射到用户历史浏览价格分布的百分位。这个特征在TM20K上的重要性排名通常能进前五。

3.2 时间特征:时间差、时段、周期性

时间特征在序列建模里容易被忽视,但在电商场景下极其关键。TM20K的序列数据里,每个行为都有时间戳,能挖出的信息很多。

时间差特征前面提过,是相邻行为之间的间隔。但还有一个更有用的变体:目标行为与序列中每个历史行为的时间差。这个特征让模型能感知"哪些历史行为离当前预测目标更近",在注意力计算时自然给近期行为更高权重。

时段特征指的是行为发生的小时、星期几。电商用户的活跃时段有很强的规律性:午休时间(12-14点)和晚间(20-23点)是高峰,凌晨是低谷。不同时段的用户意图也不同,晚间更多是休闲浏览,午休更多是快速决策。把时段做embedding加入模型,能帮助模型区分"这个行为是在什么心理状态下发生的"。

周期性特征是电商特有的。发薪日前后、大促期间、周末,用户的购买意愿和价格敏感度都会变化。TM20K如果覆盖了足够长的时间跨度,可以构造"距最近大促的天数"这类特征。如果没有大促标注,可以用"该用户历史下单频率的周期性"来近似。

3.3 序列聚合特征:把行为序列压缩成统计量

除了把整个序列喂给模型,还有一类做法是把序列压缩成统计特征,直接作为排序模型的输入。这类特征在TM20K上作为辅助特征效果很好,尤其是当序列模型本身不够强的时候。

常见的聚合特征包括:最近1小时/1天/7天的点击次数、加购次数、下单次数;最近N个行为的类目分布熵(衡量兴趣集中度);最近N个行为的平均价格;加购到下单的平均转化时长。这些特征计算成本低,可解释性强,在线上环境里往往是兜底的主力。

但要注意,聚合特征和序列模型特征有信息重叠。如果序列模型已经能很好地捕捉近期行为模式,再叠加聚合特征可能带来不了多少增益,反而增加过拟合风险。我的做法是先用序列模型跑一版,看特征重要性,如果某个聚合特征的重要性很低,就果断砍掉。

4. 训练TM20K序列模型的实操细节与踩坑记录

4.1 样本构造:负采样策略决定模型学到什么

TM20K作为广告推荐数据集,正负样本的比例通常极度不均衡。曝光未点击是负样本,点击或转化是正样本,比例可能到100:1甚至更高。直接拿全量负样本训练,模型会倾向于预测所有样本为负,AUC看着还行但实际排序能力很差。

负采样是必须的,但怎么采很有讲究。随机负采样最简单,但从TM20K里随机抽商品作为负样本,抽到的很可能是用户根本不可能接触到的商品(比如男性用户被抽到口红),这种负样本太"容易",模型学不到细粒度区分能力。基于曝光的负采样更合理:只从用户实际曝光过但未点击的商品里采样。这样负样本和正样本在曝光层面是同分布的,模型学到的是"在都曝光的前提下,为什么点这个不点那个"。

我通常会用混合负采样:70%来自曝光未点击,20%来自同类目未曝光商品,10%来自全局随机。这样既有hard negative(曝光未点击),又有medium negative(同类目),还有easy negative(全局随机),模型能学到多层次的区分边界。在TM20K上,这个策略比纯随机负采样的AUC高3个点左右。

还有一个坑是负样本的时间泄漏。如果你用用户未来的行为作为负样本,而正样本是过去的行为,模型会学到"时间越晚越可能是负样本"这种虚假相关。正确做法是负采样时严格限制在正样本发生时间之前。

4.2 序列截断与填充:长度选择背后的权衡

TM20K的序列长度分布通常很不均匀,有的用户只有几个行为,有的有几百个。直接取固定长度需要截断和填充,这里有几个决策点。

截断方向:取最近N个行为还是最早N个?电商场景下,最近的行为信息量远大于早期行为,所以取最近N个是标准做法。但要注意,如果N太小(比如10),会丢失决策链路的前半段;如果N太大(比如200),会引入大量噪声且增加计算量。我的经验是N=50是一个比较平衡的点,覆盖了大多数用户的完整决策链路,计算量也可控。

填充方式:短序列用零向量填充是最简单的,但零向量和真实embedding在语义空间里没有意义,模型需要额外学习"零向量代表缺失"。更好的做法是用一个可学习的padding embedding,或者用序列的均值embedding填充。在TM20K上,可学习padding embedding比零填充的AUC高0.5个点左右。

位置编码的处理:如果序列是右对齐(最近的行为在最后),位置编码要相应调整。我见过有人用左对齐加标准位置编码,结果模型把"位置0"当成了"最早行为",但实际那是padding,导致效果崩掉。这个坑很隐蔽,排查时建议打印几条样本的序列和位置编码对照看。

4.3 损失函数选择:BPR、交叉熵还是对比学习

TM20K上的序列建模任务,本质上是一个排序问题。损失函数的选择直接影响模型优化方向。

交叉熵损失是最常用的,把问题当作二分类(点击/不点击)。优点是稳定、易实现,缺点是它优化的是绝对概率,而广告推荐更关心相对排序。BPR损失直接优化正样本得分高于负样本的概率,更贴合排序目标,但训练时需要构造pair,batch内计算量更大。对比学习损失是近两年的热门,把同一用户的不同行为增强视图作为正对,不同用户的行为作为负对,能学到更好的用户表示。

我在TM20K上做过对比实验:交叉熵的AUC是0.782,BPR是0.786,对比学习(SimCLR式)是0.789。对比学习效果最好,但训练时间大约是交叉熵的2.5倍。如果算力有限,BPR是一个性价比很高的选择。另外,对比学习对数据增强策略很敏感,电商序列里常用的增强包括:随机mask掉部分行为、随机替换行为类型、时间窗口截取。mask增强通常最有效,因为它迫使模型从不完整序列中恢复意图。

5. 从离线指标到线上收益:TM20K模型评估的陷阱

5.1 AUC高不代表广告收入高

这是我在实际项目里踩过的最大的坑。离线在TM20K上把AUC从0.78刷到0.80,兴冲冲上线,结果广告收入没涨甚至微跌。后来复盘发现,AUC衡量的是全局排序能力,但广告收入取决于头部位置的排序质量。如果模型在长尾样本上提升很多,但头部样本(高价值广告位)的排序没变,收入就不会动。

正确的评估方式是看Top-K的NDCG或Recall。具体到广告场景,K通常取3到5,因为用户注意力有限,只有前几个广告位真正产生价值。在TM20K上评估时,我会同时看AUC、NDCG@3、NDCG@5,如果AUC涨了但NDCG@3没涨,说明提升集中在长尾,对收入帮助有限。

还有一个指标是校准度。广告竞价需要模型输出的CTR是校准的(预测0.1的样本,实际点击率应该接近0.1),否则出价策略会失真。序列模型容易过拟合,导致预测概率偏高或偏低。评估时一定要画校准曲线,如果偏离对角线太多,需要做isotonic regression或 Platt scaling 校准。

5.2 序列长度偏差与用户活跃度偏差

TM20K里的用户活跃度分布是长尾的:少数重度用户贡献了大量序列样本,大量轻度用户只有零星行为。如果训练时不做处理,模型会偏向重度用户的模式,对轻度用户预测不准。而广告场景里,轻度用户往往是拉新和促活的重点目标。

处理方式有两种。一是样本加权:给轻度用户的样本更高权重,让模型在训练时更关注他们。权重可以设为用户历史行为数的倒数,或者分桶后按桶给权重。二是分层评估:把测试集按用户活跃度分成高、中、低三组,分别看模型表现。如果低活跃组的指标明显差于高活跃组,说明模型有活跃度偏差,需要针对性优化。

我在TM20K上做过分层评估,发现低活跃组(行为数<5)的AUC比高活跃组(行为数>50)低4个点。后来在模型里加了一个"用户活跃度embedding",把用户历史行为数做分桶后作为特征输入,低活跃组的AUC提升了2个点。这个特征很简单,但效果立竿见影。

5.3 离线-线上不一致的常见原因

除了指标选择问题,离线-线上不一致还有几个技术原因。特征穿越是最常见的:离线构造特征时用了未来信息,线上拿不到,导致离线虚高。比如用"用户未来7天的下单次数"作为特征,离线AUC会很好看,但线上根本没法用。排查方法是逐特征检查时间戳,确保特征计算只依赖预测时间点之前的数据。

样本选择偏差也很隐蔽。TM20K的样本是历史投放策略产生的,如果历史策略偏向某些商品或人群,模型学到的模式在换策略后可能失效。这就是所谓的"闭环反馈"问题。缓解方式是做反事实评估,用IPS(逆倾向得分)加权,让模型评估不受历史策略影响。TM20K如果包含投放策略的倾向得分字段,一定要用上。

实时特征延迟是工程层面的坑。线上 serving 时,用户的最新行为可能还没同步到特征库,导致模型看到的是"过期"序列。广告场景下,用户刚搜完一个商品,下一个广告位就应该用上这个搜索行为,如果延迟几秒,转化机会就丢了。这个问题的解决依赖特征管道的实时性,通常需要流式计算框架支持,离线评估时很难模拟,只能上线后做A/B测试验证。

6. 把TM20K的序列建模经验迁移到实际广告系统

6.1 从离线数据集到在线系统的特征对齐

TM20K是一个离线数据集,但它的特征体系可以映射到线上。关键是要建立一套特征字典,把离线特征名和线上特征名一一对应。比如TM20K里的"item_category"对应线上的"商品一级类目","behavior_type"对应线上的"行为类型枚举"。这个映射看起来简单,但实际做的时候经常发现离线有、线上没有的特征,或者线上有、离线没记录的特征。

我的做法是先做特征可用性盘点:列出TM20K里所有特征,逐个确认线上是否能实时获取。不能获取的特征要么找替代方案,要么在离线训练时就排除掉,避免训练-服务不一致。这个盘点通常能发现20%到30%的特征存在对齐问题,提前处理比上线后排查成本低得多。

6.2 模型轻量化:从实验模型到线上serving

TM20K上跑通的模型,直接上线往往太重。一个4层Transformer加商品图embedding,参数量可能到几千万,线上推理延迟扛不住。轻量化有几个方向:层数裁剪(4层降到2层,AUC通常掉0.3到0.5个点,但延迟降一半)、embedding降维(商品embedding从128维降到64维,效果损失很小)、量化(FP32转FP16或INT8,延迟降30%到50%,精度损失可控)。

还有一个工程技巧是序列模型和排序模型解耦。序列模型只负责生成用户表示向量,这个向量离线算好存进KV库,线上排序模型直接读向量做特征。这样序列模型的复杂度不影响在线延迟,只需要保证向量的新鲜度(比如每小时更新一次)。这个架构在TM20K的离线实验里验证过,效果损失很小,但工程可行性大幅提升。

6.3 持续迭代:数据漂移监控与模型更新

电商场景的数据分布变化很快,大促前后、季节更替、新品上市都会导致用户行为模式漂移。TM20K作为一个静态数据集,没法反映这种动态性,但基于它训练的模型上线后必须持续监控。

监控的核心指标是特征分布漂移和预测分布漂移。特征漂移用PSI(群体稳定性指标)衡量,PSI大于0.1说明分布有明显变化,需要警惕;大于0.25说明变化严重,模型可能需要重新训练。预测漂移看模型输出的CTR均值,如果连续几天偏离历史均值超过10%,说明模型可能失效了。

模型更新策略上,我倾向于增量更新+全量更新结合。每天用最新数据做增量训练,保持模型对近期模式的敏感度;每周做一次全量训练,防止增量更新导致的参数漂移。TM20K上验证过,增量更新的模型在近期样本上的AUC比全量模型高1个点左右,但全量模型在长期稳定性上更好,两者互补。

最后分享一个我在实际项目里总结的小技巧:序列模型的效果对序列的起始点很敏感。同样是50个行为,从用户进入app开始算,和从用户最后一次搜索开始算,模型学到的模式完全不同。我的做法是同时构造多个起始点的序列(比如最近50个行为、最近一次搜索后的行为、最近一次加购后的行为),分别过序列模型,然后把多个表示拼接起来。这个做法在TM20K上让AUC提升了0.8个点,代价是推理时间增加,但离线实验阶段值得一试,上线时可以根据延迟预算决定保留几个视图。