文章作者:龙楚、丹鸥、晨宁、元涵

内容来源:阿里机器智能

导读: 用户建模是搜索与推荐模型的核心技术。我们力求从实际应用出发,和大家分享我们在搜索场景中用户建模的一些实践经验。同时将我们所观察到的现象、问题写出来,欢迎大家多讨论交流。

01背景与意义

用户建模是搜索与推荐模型的核心技术。淘宝搜索排序算分的对象是 <user, query, item> 三元组,我们从样本特征表达的角度上来看,item是比较稠密而且稳定的部分,在大样本的环境下,大部分信息都能够被id embedding所表达,相反user是三者中比较稀疏的部分,所以对于user的描述,需要大量的泛化特征。

从模型分类的角度上来看,用户与商品的静态特征作用在于增强模型的泛化性,而用户实时行为的引入与建模,可以大大增强样本之间的区分性,显著地提升模型的分类精度。我们把用户建模的过程看作是对用户的信息抽象和信息组织的过程。

信息抽象方面我们不断地优化与丰富建模方式:

  • user profile用来表征用户的静态属性信息;
  • 偏好标签的挖掘,从行为上预测用户的一般性偏好;
  • 实时行为建模,更细粒度的对当前请求下的兴趣刻画与描述。

信息处理方面,我们从行为周期和行为内容方面对用户行为数据进行合理的组织:

  • 从行为周期上,我们将行为序列划分成中短期和长期,分别使用不同的时间跨度,描述不同粒度的兴趣;
  • 从行为内容维度上,直接行为反馈商品和曝光商品分别被用来显式和隐式的表达用户意图,与此同时,我们也将用户行为数据从传统的电商商品,延伸到一些泛内容信息。

用户行为建模也是推荐,广告等很多团队在研究的方向(比如广告团队的DIN,DIEN,Practice on Long Sequential User Behavior Modeling,推荐团队的MIND,DSIN,等等非常好的工作),我们力求从实际应用出发,和大家分享我们在搜索场景中用户建模的一些实践经验。同时将我们所观察到的现象、问题写出来,欢迎大家多讨论交流。本文后续包含的内容如下:

  • 简要介绍大模型的整体模型结构
  • 用户数据与行为序列的组织与处理
  • 模型结构的改进
  • 模型的实验和分析,相关实际问题的研究与讨论

02模型结构

我们的模型结构大致所图所示,用户画像、多个用户行为序列特征、待打分的商品特征和一些其他的实时上下文特征(天气、网络、时间等特征),最终concat之后,进入DNN的分类器。用户行为序列建模是模型中最重要的部分之一,对于实时刻画用户兴趣尤其重要。我们这里采用self atten和atten pooling的方式来做序列建模,self atten刻画行为之间的相互关系,atten pooling对行为进行匹配激活并实现combine。这是我们一个通用化的序列建模组件。下面将基于该模型框架,进一步介绍我们今年的优化工作及其实现细节。

03用户数据与模型

user profile 仅仅是一些比较静态的用户特征,这些静态特征作为对user_id的补充和泛化。近来以session-based recommendation为代表的理解用户实时兴趣的模型,越来越受到广泛的研究,大量实验表明其能够显著提升推荐的准确率。特别是用户当前越短期的行为,越能代表用户目前的兴趣状态。使用用户有过行为的商品来表征用户,有助于我们实时的捕获用户兴趣的动态性。另外,以Graph的角度来看,由user-item组成的图中,item是稠密结点,user是稀疏结点,稠密结点适合用来对稀疏结点进行表达。

我们定义统一的行为schema如下图:

包含两个部分,商品自身的属性特征和用户对商品的行为特征。属性特征包括item_id, seller_id等一系列对商品进行描述的特征。行为特征包括用户对商品的行为类型,行为时间,序列位置等特征。

1. 中短周期

数据与特征: 在去年星舰项目中,我们针对用户中短期,不同行为类型的行为进行了全局建模,该序列包含了用户全网实时的点击 加购 收藏 购买等行为。鉴于用户历史行为非常丰富,而我们的序列长度有上限(L_max=50),因此我们通过query的预测类目来甄选出与当前意图类目更相关的历史行为。用户主动输入query,这是搜索和推荐最大的区别。关于query方面,query理解团队已经做了大量的工作。在此,我们利用query理解的结果,使用query的预测叶子类目,对用户行为序列做筛选。

模型结构:

Transformer模型在NLP领域取得了非常好的效果,它通过使用self atten机制,捕捉到了序列内部的依赖关系,同时它可以并行计算,提高训练和预测的速度。在CTR模型中,我们广泛地使用self atten来处理商品sequence。我们在现有self-atten的基础上进行如下两点改进。

  • 我们采用了cosine + scale up代替原来的点乘+scale down(也可以通过加入layer norm),来计算K和Q的相似度,提升softmax logits输出值的区分度。因为在套用原来的self-atten时,我们发现了一些问题:(1). softmax logits值非常小,导致atten的权重一直处于均值状态;(2). atten结构出现梯度弥散,导致几乎不能被学习。我们的CTR模型embedding从0初始化,而不是随机初始化,过小的梯度导致self atten很难被学习。为此,我们使用cosine值代替点乘,计算K与Q的距离。如下图所示:

  • 对self-atten的输出结果我们进行了一个query_atten_pooling。虽然我们的中短期序列尽量保证了与当前意图的类目一致性,但为了进一步保证query一致性,这里对中短期序列进行一个query_atten_pooling,激活与当前query意图和语义一致的历史行为;后续实验部分也会进一步分析为什么这里不使用通用的target attention。

整个中短期行为建模的模型结构如下图所示,self atten + query atten pooling:

其中,Context Masked Embedding作e1+c1的操作。

2. 长周期

数据与特征:中短周期的行为序列, 在有限长度的行为里,兼顾了用户在全网中短期的多种行为。很自然的我们可以想到,对于用户早期的行为很可能不在该序列中。在去年星舰的项目中,我们通过离线统计一个用户长期偏好的静态特征来补充这部分信息,但这种方法无法结合用户当前的意图和上下文来选出相关的偏好信息。

我们希望能end2end的对用户长期的行为进行建模,一方面能引入用户的长期偏好;二是基于当前意图来对长期行为建模,而不是静态的抽取偏好标签;三是长期行为能引入去年同季数据 解决换季个性化冷启动等问题。

我们对用户长周期行为作如下定义:用户最近两年的成交行为;点击等其他类型暂不考虑,一是相对成交数据而言,其他类型的行为置信度较低,噪音较大,例如一般来说用户只会记得去年买过什么,而不记得去年点过什么,二是其他类型数据过多。

具体地,我们对两年的行为数据按照季度划分成8个季度序列,每个季度序列是长度为N的子序列,确保每个季度的行为都能被保留,如果直接按时间和个数进行截断,都有可能导致某个季度的行为信息被全部过滤掉,不能尽可能保留用户多方位的信息;同时我们并没有对序列做一个类目相关的过滤,相对短期行为而言,长期行为更着重在对品牌 店铺 term等上的偏好。

模型结构:

  • 如下图所示,首先对长期行为item_level embedding特征用context_level embedding进行add_mask,即e1+c1。然后用一个多层建模方式,先在季度序列内通过优化后的self atten进行特征抽取和子序列的atten_pooling,得到当前季度的用户偏好表达。最后对不同季度进行concat(也尝试过atten_pooling,效果比concat稍微差一点),得到用户最终的长期偏好表达。这样做的好处在于,对于季节敏感的搜索意图,能更好的抽取与当前季度更匹配的偏好信息。
  • 这里的atten_pooling是用shortseq_vec来作为查询Query的; Shortseq_vec是一个综合了用户意图和用户实时偏好的表达,比直接用原始搜索词(仅能表达用户搜索意图), 能更加全面评估历史trigger对当前搜索的重要性;同时short seq也属于序列,向量空间上也比较接近。

3. 端上点击

前面两部分分别从长、短期捕获用户的行为商品以及对应的上下文信息,但实际用户的行为远远不止点击、购买这些;在搜索结果页面,商品列表曝光,用户发生浏览、滑屏;在商品详情页,用户观看视频,对比参数等;用户有非常丰富的行为没有被我们关注到,一方面某些特征通过服务端日志无法获取,另一方面某些特征通过ut日志延迟很多,使得在线比较难以利用;因此我们利用端计算的优势,在客户端把这些数据特征收集到,传给服务端,同时也能把rt降低到ms以内;后面两部分我们将分别介绍端上的点击序列和端上的曝光序列建模。

数据与特征: 端上点击序列的建模相对中短期序列中的点击行为有几个差异,一是获取用户的点击行为更加实时,平均rt从分钟级降到ms级;二是端上能获取到更加详细的用户行为,用户在详情页各个区块的停留时间,点击了哪些按钮;三是没有对该序列做query相关性的过滤,是希望从跨类目行为引入一些有用信息,作为做中短期序列的进一步补充,而不是重复;用户的行为从instance_level来讲,每一个行为都有一定的重要性,但是从feature_level来讲,每个行为的重要性也取决于品牌、店铺、term等特征与目标商品的匹配程度,不仅仅在于强调行为与query的类目预测一致。

模型结构: 端上点击序列的建模方式和中短期序列的建模方式类似,都是通过优化过的self atten+atten pooling捕获用户的偏好表达;同样我们获取到的详情页行为也可以作为context信息,对item_level embedding进行add_mask;这里的atten_pooling同样也采取shortseq_vec作为查询Query。

4. 端上曝光

前面我们介绍了对用户偏好的建模,基本都是从用户的主动行为出发,用用户喜欢的商品去描述、理解一个陌生的用户。那么,我们能不能从用户不喜欢的方面出发,来描述用户呢。于是我们对用户的曝光但未点击的商品进行采集,建模,融入到我们的大模型中。区别于其他商品序列,曝光商品有一个非常重要的性质,它是当前user + query + context 下,所能实际搜出的最准确的商品。从某种程度上来说,曝光商品综合了此次搜索丰富的信息,能够有效的对user / query进行强有力的表达。

数据与特征:相比于用户的点击和购买,pv曝光数据的体量非常之大,于是我们没有选择将其实时写入igraph,然后进行读取,而是分布在端上存储,由端上请求搜索的时候直接发送,绕开了存储问题,也保证了数据的实时性。具体地,当一个用户搜索“连衣裙”时,客户端会把该用户最近搜索”连衣裙“时,曝光但未点击过的50个商品信息,上传到服务端,例如在进行第二页的排序时,就会拿到第一页的曝光商品。

模型结构: 曝光序列的建模方式比较简单,通过mean pooling得到曝光表达。但是为了让正向表达和曝光表达有所区分,我们先分别计算正向表达和曝光表达与目标商品的距离d1和d2,并添加辅助loss使得两个距离之间符合以下条件:当目标商品对应是正样本时 d1 + M < d2;当目标商品对应是负样本时 d1 > d2 + M。建模方式类似下图方式。

04实验与分析

数据集:以线上的曝光、点击数据为样本,以前N天的样本为训练样本,训练至收敛,以后一天的样本为测试样本。

评价指标:以后一天的样本为测试样本,主要评比在训练集上的AUC,同时也观测在训练集上的AUC等指标。这里的auc gap都是全量线上模型的auc提高。

效果比较:我们与一些baseline进行比较实验,其中 LSTM with Q/U/P Attention 为DUPN(kdd ‘18)。结果如下表所示:

效果分析:这里的auc gap都是在线上收敛版本上的提高。行为序列模型的优化能带来接近0.3%的auc提高;针对不同问题,引入新的序列特征,并进行对应的建模优化,带来接近0.7%的auc提高。

1. 中短周期序列

Attention Weight分析:我们在tensorboard中,打印出Atten Map,方格(i, j)表示第i个商品,对第j个商品的atten权重。我们可以观察到以下现象:

如图所示,方格颜色越浅,表示权重越大,训练的开始并不能体现self atten能够捕获商品序列内部关联的作用,仅仅学到了一些行为信息,即前面的商品(最近行为的商品)重要。随着训练的进行,商品之间的关联性逐渐体现,直接表现为对角线附近权重变大。最终呈现的是同时受到商品关联性和行为信息影响的attention map图。另外,对于atten pooling层,我们监测序列在各个位置上的权重信息,整体看来,商品序列位置从近到远,依次递减,符合预期。

Self Atten的作用:我们尝试去掉Self Atten层,对seq直接做Atten Pooling,AUC绝对值稳定降0.001。我们理解Self Atten,从两个方面:1. 如一般的解释,它确实对商品序列内部的依赖关系进行了建模,使得商品表达更为准确;2. 在Self Atten过程中,用户最近行为的商品,作为用户意图最贴近的表示,作为Key,对整个序列进行了Atten,其得到的向量成为了在最后Atten Pooling中占比成份最大的信息。

Why Not Target Atten in Search:Target Atten是在推荐场景中普遍使用的方法,在搜索中我们也尝试过,但最后还是没有使用,有两个原因:1.搜索场景中用户会主动输入query,已经能够很强的表示了用户当前的意图(比如类目意图),这个时候再加入target item收益会变小很多,auc提升微弱。另外我们的用户sequence也使用了query预测的行业/类目作了初步的筛选。2. 最后在精排时,Target Atten需要把Atten Pooling对每个doc计算一遍,会额外增加一定的计算开销,而query atten只用计算一次,性能更好。虽然在搜索场景中收益较少,但在推荐场景,Target Atten依然是最有效的方式。

2. 其他序列建模

① 长周期序列实验:

为了分析长周期是否能达到去年同季个性化冷启动的作用,我们做一个简单的实验:把长周期的8个季度序列拼在一起,作为一个sequence序列,用self atten来观察季度之间所有序列的的关联性。如图所示:横轴是seq_index,颜色越�