推荐系统(九)SENet 双塔模型在推荐领域召回粗排的应用

在推荐领域,双塔模型是粗排/召回环节应用最为广泛的算法模型,各种改进型双塔模型层出不穷,本文介绍一种基于 SENet 的双塔模型。

1.双塔模型的鼻祖——DSSM 模型

所谓“双塔模型”,可以追溯到 UIUC(伊利诺伊大学厄巴纳-香槟分校)与微软于 2013 在 CIKM 上发表的论文,论文中提到了一种名为 DSSM(Deep Structured Semantic Models,深度结构化语义模型)的模型。其核心思想是将 query 和 doc 映射到到共同维度的语义空间中,通过最大化 query 和 doc 语义向量之间的余弦相似度,从而训练得到隐含语义模型,达到检索的目的。

提出 DSSM 的论文题目:《Learning Deep Structured Semantic Models for Web Search using Clickthrough Data》

经过多年演进,DSSM 被广泛应用到多个领域,比如:搜索引擎检索,广告相关性,问答系统,机器翻译等。当然,DSSM 主要用在召回和粗排阶段,基本上统治了召回/粗排阶段,呈现“垄断地位”。推荐中 DSSM 双塔模型结构如图 1 所示:
推荐系统(九)SENet 双塔模型在推荐领域召回粗排的应用_第1张图片

图1. 推荐领域常用 DSSM 模型结构

如图 1 所示,双塔模型结构非常简单,左侧是 User 塔,右侧是 Item 塔。在推荐领域,我们可将特征拆分为两大类:User 相关特征(用户基本信息、群体统计属性以及行为相关的 Item 序列等)与 Item 相关特征(Item 基本信息、属性信息等),原则上,Context 上下文特征可以放入 User 侧塔。对于这两个塔本身,则是经典的 DNN 模型,从特征 One-Hot 到特征 Embedding,再经过几层 MLP(multi-layer perceptron,网络多层感知器) 隐层,两个塔分别输出 User Embedding和 Item Embedding 编码。在训练过程中,User Embedding 和 Item Embedding 做内积或者 Cosine 相似度计算(注: Cosine 相当于对User Embedding 和 Item Embedding 内积基础上,进行了两个向量模长归一化,只保留方向一致性不考虑长度),使得 User 和正例 Item 在 Embedding 空间更接近,和负例 Item 在 Embedding 空间距离拉远。损失函数则可用标准交叉熵损失,将问题当作一个分类问题,或者类似 DSSM 采取 BPR 或者 Hinge Loss,将问题当作一个表示学习问题。

需要说明的是,User 侧特征和 Item 侧特征分别经过各自的 DNN(一般情况下,两个 DNN 结构是一样的,当然也可以不一样)后得到 User Embedding 和 Item Embedding。如果 User DNN 和 Item DNN 结构不一样,那么就必须保证输出维度一样,也就是最后一层全连接层隐藏单元个数相同,基于此,才能保证 User Embedding 和 Item Embedding 的维度相同,因为下一步要做相似度计算(常用内积或者 cosine)。

DSSM 模型虽好,但是根据笔者之前的关于特征的系列文章,可以很容易看出 DSSM 模型的缺点:无法使用 user x item 的交叉特征。

2.双塔模型的应用

双塔模型的应用场景很多,比如,在当代搜索引擎的召回环节,除了常见的经典倒排索引来对 Query 和 Document 进行文本字面匹配外,经常也会增加一路基于 Bert 模型的双塔结构,将用户查询 Query 和搜索文档,各自通过一个塔形结构来 Embedding,以此增加 Query 和Document 的深层语义匹配能力。

再比如,在自然语言处理的 QA 领域,一般也会在第一步召回环节,上一个基于 Bert 模型的双塔结构,分别将问题 Question 和可能包含正确答案的 Passage,通过双塔结构映射到同一个语义空间,并分别把 Question 和 Passage 打出各自的 Embedding。

就个人判断而言,未来,双塔结构会在更多应用领域获得应用,这是个非常有生命力的模型。理由很简单——在面临海量候选数据进行粗筛的场景下,它的速度太快了,即便它的效果谈不上极好,但是毕竟是个有监督学习过程,一般而言也不差,实战价值很高,这个是根本。若一个应用场景有如下需求:应用面临大量的候选集合,首先需要从这个集合里面筛选出一部分满足条件的子集合,缩小筛查范围。那么,这种应用场景就比较适合用双塔模型。

上面说的是双塔模型的优点,所谓 “凡事皆有两面性”,在追求速度快的同时,也是需要付出代价的,那么,代价是什么呢?就是要在一定程度上牺牲掉模型的部分精准性,而且这个代价是结构内生的,也就是说它这种结构必然会面临这样的问题。至于产生问题的具体原因,在后面介绍双塔模型的时候会讲。

3.双塔模型在推荐领域的应用

在图 1 中,关于两个塔的 DNN 模块,我们直接认为是是 MLP 结构,但是理论上这里可以替换成任意你想用的模型结构,比如 Transformer 或者其它模型,最简单的应该是 FM(Factorization Machines,因子分解机) 模型,如果这里用 FM 模型做召回或者粗排,等于把上图的 DNN 模块替换成了对特征 Embedding 进行“Sum”求和操作,貌似应该是极简的双塔模型了。所以说,双塔结构不是一种具体的模型结构,而是一种抽象的模型框架。

一般在推荐的模型召回环节应用双塔结构的时候,分为离线训练和在线应用两个环节。上面基本已描述了离线训练过程,至于在线应用,一般是这么用的:

  • step1,通过训练数据,训练好 User 侧和 Item 侧两个塔模型,我们要的是训练好后的这两个塔模型,让它们各自接受用户或者 Item 的特征输入,能够独立打出准确的 User Embedding 或者 Item Embedding。

  • step2,对于海量的候选 Item 集合,可以通过 Item 侧塔,离线将所有 Item 转化成Embedding,并存储进 ANN 检索系统,比如 FAISS,以供查询。为什么双塔结构用起来速度快?主要是类似 FAISS 这种 ANN 检索系统对海量数据的查询效率高。

  • step3,某个用户的 User Embedding,一般要求实时更新,以体现用户最新的兴趣。为了达成实时更新的目的,你有几种难度不同的做法,比如你可以通过在线模型来实时更新双塔的参数来达成这一点,这是在线模型的路子;但是很多情况下,并非一定要采取在线模型,毕竟实施成本高,而可以固定用户侧的塔模型参数,采用在输入端,将用户最新行为相关(如点击、购买)的 Item 做为用户侧塔的输入,然后通过 User 侧塔打出 User Embedding,这种模式。这样也可以实时地体现用户即时兴趣的变化,这是特征实时的角度,做起来相对简单。

  • step4,有了最新的 User Embedding,就可以从 FAISS 库里拉取相似性得分Top K 的Item,做为个性化召回结果。

以上内容介绍了双塔模型的结构以及训练及应用过程。在本文开始,提到过双塔结构有一个内生性的问题,就是它的结构必然会导致精度的损失,为什么这么说呢?

4.双塔模型的局限性

我们再审视下双塔的结构,它最大的特点是:首先对用户特征和 Item 特征分离,两组分离的特征,各自通过 DNN 网络进行信息集成,集成结果就是两个塔各自顶端的 User Embedding 和 Item Embedding。相比我们平常在精排阶段见到的 DNN 模型,这种特征分离的设计,会带来两个问题:

  • 问题-1:我们一般在做推荐模型的时候,会有些特征工程方面的工作,比如设计一些 User 侧特征和 Item 侧特征的组合特征,一般而言,这种来自 User 和 Item 两侧的组合特征是非常有效的判断信号。但是,如果我们采用双塔结构,这种人工筛选的,来自两侧的特征组合就不能用了,因为它既不能放在 User 侧,也不能放在 Item 侧,这是特征工程方面带来的效果损失。当然,我个人认为,这个问题不是最突出的,应该有办法绕过去,或者模型能力强,把组合特征拆成两个分离的特征,各自放在对应的两侧,可以让模型去捕获这种组合特征。

  • 问题-2:如果是精排阶段的 DNN 模型,来自 User 侧和 Item 侧的特征,在很早的阶段,比如第一层 MLP 隐层,两者之间就可以做细粒度的特征交互。但是,对于双塔模型,两侧特征什么时候才能发生交互?只有在 User Embedding 和 Item Embedding发 生内积的时候,两者才发生交互,而此时的 User Embedding 和 Item Embedding,已经是两侧特征经过多次非线性变换,糅合出的一个表征 User 或者 Item 的整体Embedding 了,细粒度的特征此时估计已经面目模糊了,就是说,两侧特征交互的时机太晚了。我们知道,User 侧和 Item 侧特征之间的交互,是非常有效的判断信号。而很多领域的实验已经证明,双塔这种过晚的两侧特征交互,相对在网络结构浅层就进行特征交互,会带来效果的损失。这个问题比较严重。

这就是为何我们说,双塔结构的内生性问题。归纳起来,就是说:为了速度快,必须对 User 和 Item 进行特征分离,而特征分离,又必然导致上述两个原因产生的效果损失。

5.SENet 双塔模型

SENet 由自动驾驶公司 Momenta 在 2017 年提出,在当时,是一种应用于图像处理的新型网络结构。它基于 CNN 结构,通过对特征通道间的相关性进行建模,对重要特征进行强化来提升模型准确率,本质上就是针对 CNN 中间层卷积核特征的 Attention 操作。SENet 是 2017 ILSVR 竞赛的冠军,错误率比 2016 年的第一名要低 25%,效果非常显著。即使到今天,SENet 仍然是效果最好的图像处理网络结构之一。

推荐系统(九)SENet 双塔模型在推荐领域召回粗排的应用_第2张图片

图 2 SENet

我们知道,推荐领域里面的特征有个特点,就是海量稀疏 ——即大量长尾特征是低频的(例如购买行为,用户浏览、点击商品可能比较多,但购买通常十分少),而这些低频特征,去学一个靠谱的 Embedding 是基本没希望的,但是你又不能把低频的特征全抛掉,因为有一些又是有效的。既然这样,如果我们把 SENet 用在特征 Embedding 上,类似于做了个对特征的 Attention,弱化那些不靠谱低频特征 Embedding 的负面影响,强化靠谱低频特征以及重要中高频特征的作用,从道理上是讲得通的。

那么,怎么把 SENet 引入推荐系统呢?如下图所示, 标准的 DNN 模型一般有一个特征 Embedding 层,我们可以把 SENet 放在Embedding 层之上,目的是通过 SENet 网络,动态地学习这些特征的重要性 a i a_{i} ai ——即对于每个特征学会一个特征权重,然后再把学习到的权重乘到对应特征的 Embedding 里,这样就可以动态学习特征权重,通过小权重抑制噪音或者无效低频特征,通过大权重放大重要特征影响的目的。
推荐系统(九)SENet 双塔模型在推荐领域召回粗排的应用_第3张图片
具体而言,SENet 分为两个步骤:Squeeze 阶段和 Excitation 阶段。在 Squeeze 阶段,我们对每个特征的 Embedding 向量进行数据压缩与信息汇总,如下:
z i = F s q ( v i ) = 1 / k ∑ t = 1 k v i t z_{i}=F_{s}q(v_{i})=1/k\sum^{k} _{t=1}v_{i}^{t} zi=Fsq(vi)=1/kt=1kvit

如上面的公式,假设某个特征 v i v_{i} vi 是 k 维大小的 Embedding,那么我们对Embedding 里包含的 k 维数字求均值,得到能够代表这个特征汇总信息的数值 z i z_{i} zi ,也就是说,把第 i 个特征的 Embedding 里的信息压缩到一个数值。

原始版本的 SENet,在这一步是对 CNN 的二维卷积核进行 Max 操作的,我们这里等于对某个特征 Embedding 元素求均值。在推荐领域的实践表明,均值效果比 Max 效果好,这也很好理解,因为图像领域对卷积核元素求 Max,等于找到最强的那个特征,而推荐领域的特征 Embedding,每一位的数字都是有意义的,所以求均值能更好地保留和融合信息。通过 Squeeze 阶段,对于每个特征 v i v_{i} vi ,都压缩成了单个数值 z i z_{i} zi ,假设特征 Embedding 层有 f 个特征,就形成了 Squeeze 向量 Z,向量大小为f。

在 Excitation 阶段,引入了中间层比较窄的两层 MLP 网络,作用在 Squeeze 阶段的输出向量 Z 上,如下: S = F e x ( Z , W ) = δ ( W 2 δ ( W 1 Z ) ) S=F_{ex}(Z,W)=\delta (W_{2}\delta (W_{1}Z)) S=Fex(Z,W)=δ(W2δ(W1Z))

δ \delta δ 是非线性函数,一般取 Relu。本质上这是在做特征的交叉,也就是说,每个特征以一个 Bit 来表征,通过 MLP 来进行交互,通过交互,得出这么个结果:对于当前所有输入的特征,通过相互发生关联,来动态地判断哪些特征重要,哪些特征不重要。其中,第一个 MLP 的作用是做特征交叉,第二个 MLP 的作用是为了保持输出的大小维度。因为假设 Embedding 层有 f 个特征,那么我们需要保证输出 f 个权重值,而第二个 MLP 就是起到将大小映射到 f 个数值大小的作用。这样,经过两层 MLP 映射,就会产生 f 个权重数值,第 i 个数值对应第 i 个特征 Embedding 的权重 图片 。我们把每个特征对应的权重 a i a_{i} ai ,再乘回到特征对应的 Embedding 里,就完成了对特征重要性的加权操作。 a i a_{i} ai 数值大,说明 SENet 判断这个特征在当前输入组合里比较重要, a i a_{i} ai 数值小,说明 SENet 判断这个特征在当前输入组合里没啥用。如果非线性函数用 Relu,你会发现大量特征的权重会被 Relu 搞成 0,也就是说,其实很多特征是没啥用的(或者说贡献很小,可忽略不计)。

如此一来,就可以将 SENet 引入推荐系统,用来对特征重要性进行动态判断。注意,所谓动态,指的是比如对于某个特征,在某个输入组合里可能是没用的,但是换一个输入组合,很可能是重要特征。它重要不重要,不是静态的,而是要根据当前输入,动态变化的。SENet 的代码已经做为一个构件集成在 DeepCTR 框架里,对于实做细节感兴趣的,可以看下 DeepCTR 里的相关代码。
推荐系统(九)SENet 双塔模型在推荐领域召回粗排的应用_第4张图片

图 4 SENet双塔模型

上面讲了那么多,其实都是做个知识铺垫作用,主要想讲的其实是怎么做 SENet 双塔模型。不过,讲到这里,SENet 怎么做,也就呼之欲出了。参考上图,其实很简单,就是在 User 侧塔和 Item 侧塔,在特征 Embedding 层上,各自加入一个 SENet 模块就行了,两个 SENet 各自对 User 侧和 Item 侧的特征,进行动态权重调整,强化那些重要特征,弱化甚至清除掉(如果权重为 0 的话)不重要甚至是噪音的特征。其余部分和标准双塔模型是一样的。推荐领域的实践表明,加入 SENet 的双塔模型,与标准双塔模型比,在多个业务指标都有提升,在个别指标有较大的效果提升。而且,如果引入 ID 类特征,这种优势会更明显。

那么,为什么 SENet 双塔模型是有效的呢?—— 在前面,我们谈过双塔模型有个内生性的问题,就是为了速度快,这种两侧分离结构,必然会导致效果损失。而如果归因的话,比较重要的一个原因,是 User 侧特征和 Item 侧特征交互太晚,在高层交互,会造成细节信息,也就是具体特征信息的损失,影响两侧特征交叉的效果。站在这个前提下,我们再审视下 FM 模型和 DNN 双塔模型各自的特点。

其实,FM 召回模型本身是个很强的模型召回基准,但是因为深度学习时代,大家出来讲,或者实际工作的时候,喜欢拿深度模型也就是 DNN 双塔来说,要不然可能感觉不好意思见人,这个可以理解。说 FM 效果比较强,这里给个证据,可以参考图 5,这是微信的召回方面的工作(可以参考论文:Internal and Contextual Attention Network for Cold-start Multi-channel Matching in Recommendation),其中 Enhanced FM 其实就是 FM 模型召回,从实验数据可以看出,除了论文提出的模型外,相对 Youtube DNN 等很多双塔 DNN 模型,在多个指标上,FM 模型的效果基本是最强的。
推荐系统(九)SENet 双塔模型在推荐领域召回粗排的应用_第5张图片

图 5 不同召回模型效果对比

我们还是更深入地审视下 FM 和 DNN 双塔各自的特性。相对 FM 模型,双塔 DNN 的优点是引入了非线性,但是因为这种非线性是在 User 侧特征之间,或者 Item 侧特征之间做的,所以可能发挥的作用就没有期待中那么大,因为 User 侧和 Item 侧之间的特征交互会更有效一些。而单侧特征的多层非线性操作,可能反而会带来上面说的两侧特征交互太晚,细节信息损失的问题。而 FM 模型,感觉特性和 DNN 双塔正好相反,它在 User 侧和 Item 侧交互方面比较有优势,因为没有深层,也没有非线性对单侧特征的深度融合,只在两侧特征 Embedding 层级发生交互作用,所以在特征 Embedding 层级能够更好地表达 User 侧和 Item 侧特征之间的交叉作用,当然,缺点是缺乏非线性。所以,如果仔细分析的话,会发现 FM 和 DNN 双塔,是各有擅长之处的。

在这个基础上,我们再来看为何把 SENet 引入双塔模型会是有效的——一种解释是:它很可能集成了 FM 和 DNN 双塔各自的优点,在 User 侧和 Item 侧特征之间的交互表达方面增强了 DNN 双塔的能力。SENet 通过参数学习,动态抑制 User 或者 Item 内的部分低频无效特征,很多特征甚至被清零,这样的好处是,它可以凸显那些对高层 User Embedding 和 Item Embedding 的特征交叉起重要作用的特征,更有利于表达两侧的特征交互,避免单侧无效特征经过 DNN 双塔非线性融合时带来的噪声,同时,它又带有非线性的作用。这貌似能同时吸收了 FM 和 DNN 各自的优势,取得一个折衷效果。当然,上述解释只是一种推测。

6.推荐系统几个环节的目标一致性问题

我们知道,一般推荐系统会包含召回、粗排以及精排几个环节。这几个环节优化目标保持一致,其实是个很重要的问题,但是容易在平常工作中忽视。精排环节最靠后,一般没有这个问题,因为可以理解为精排的优化目标,一般就体现为 业务指标。容易被忽略的是召回和粗排环节,这两个环节是精排环节的前置环节,为精排输送合适的候选 Item 集合,如果不能在优化目标上和精排保持一致,会导致物料库里比较适合精排的推荐项,无法通过前置环节,导致推荐效率的损失。

举个极端的例子,虽然不容易出现,但是比较容易说清楚道理。假设精排优化目标是时长目标,但是召回或者粗排的目标是互动或点击目标,这意味着很多高时长的候选推荐项,很可能精排环节根本看不到,因为前置两个环节并不倾向于把高时长的内容往前排。

我们这里说的召回环节,指的是模型召回,因为传统的多路召回,比如热点路等,很多是非个性化,或者个性化因素很弱的,基本不可能针对最终业务指标设立优化目标,也就根本无法讨论目标是否一致的问题。当然,召回除了和最终目标保持一致,还要有多样性等目标,这个可以通过增加其它召回路来实现。

那么,怎么能够尽量使得前置环节的优化目标,和精排目标保持一致呢?一般而言,有两种做法,一种是保持多个环节的多目标优化,各个子目标尽量一致;另外一个是采用知识蒸馏(Teacher-Student 模型)的思路。

所谓知识蒸馏,其实就是,召回和粗排环节做为 Student,学习精排 Teacher 的排序偏好,等于说前置环节,直接学习精排的优化目标,打通整个通路。当然,知识蒸馏除了能够引导推荐系统各个环节优化目标保持一致,还可以通过复杂 Teacher 传播复杂模型和特征给前置环节,提高前置环节模型效果。知识蒸馏具体做法有很多,这里不再赘述。

7.召回及粗排模型的负例选择问题

我们训练精排模型的时候(假设是优化点击目标),一般会用 “用户点击” 实例做为正例,“曝光未点击” 实例做为负例,来训练模型,基本大家都是这么干的。现在,模型召回以及粗排,也需要训练模型,意思是说,也需要定义正例和负例。一般正例,也都是用 “用户点击” 实例做为正例,但是怎么选择负例,这里面有不少学问。

推荐系统(九)SENet 双塔模型在推荐领域召回粗排的应用_第6张图片

我们先来看下不同阶段模型面对的输入数据情况,对于召回模型来说,它面临的输入数据,是所有物料库里的物品;对于粗排模型来说,它面对的输入数据,是各路召回的结果;对于精排模型来说,它面临的输入是粗排模型的输出结果。如果我们仍然用“曝光未点击”实例做为召回和粗排的负例训练数据,你会发现这个训练集合,只是全局物料库的一小部分,它的分布和全局物料库以及各路召回结果数据,这两个召回和粗排模型面临的实际输入数据,分布差异比较大,所以根据这种负例训练召回和粗排模型,效果如何就带有疑问,我们一般把这个现象称为 “Sample Selection Bias” 问题。

6.1 可能的负例选择方法

为了解决 “Sample Selection Bias” 问题,我们在召回或者粗排模型训练的时候,应该调整下负例的选择策略,使得它尽量能够和模型输入的数据分布保持一致。这里我简单归纳下可能的做法。

  • 选择1:曝光未点击数据

这就是上面说的导致 Sample Selection Bias 问题的原因。我们的经验是,这个数据还是需要的,只是要和其它类型的负例选择方法,按照一定比例进行混合,来缓解Sample Selection Bias 问题。当然,有些结论貌似是不用这个数据,所以用还是不用,可能跟应用场景有关。

  • 选择2:全局随机选择负例

就是说在原始的全局物料库里,随机抽取做为召回或者粗排的负例。这也是一种做法,Youtube DNN 双塔模型就是这么做的。从道理上讲,这个肯定是完全符合输入数据的分布一致性的,但是,一般这么选择的负例,因为和正例差异太大,导致模型太好区分正例和负例,所以模型能学到多少知识是成问题的。

  • 选择3:Batch 内随机选择负例

就是说只包含正例,训练的时候,在 Batch 内,选择除了正例之外的其它 Item,做为负例。这个本质上是:给定用户,在所有其它用户的正例里进行随机选择,构造负例。它在一定程度上,也可以解决 Sample Selection Bias 问题。比如 Google 的双塔召回模型,就是用的这种负例方法。

  • 选择4:曝光数据随机选择负例

就是说,在给所有用户曝光的数据里,随机选择做为负例。该方法在某些场景下是有效的。

  • 选择5:基于 Popularity 随机选择负例

这种方法的做法是:全局随机选择,但是越是流行的 Item,越大概率会被选择作为负例。目前不少研究证明了,负例采取 Popularity-based 方法,对于效果有明显的正面影响。它隐含的假设是:如果一个例子越流行,那么它没有被用户点过看过,说明更大概率,对当前的用户来说,它是一个真实的负例。同时,这种方法还会打压流行 Item,增加模型个性化程度。

  • 选择6:基于Hard选择负例

它是选择那些比较难的例子,做为负例。因为难区分的例子,很明显给模型带来的loss和信息含量比价多,所以从道理上讲是很合理的。但是怎样算是难的例子,可能有不同的做法,有些还跟应用有关。比如 Airbnb,还有不少工作,都是在想办法筛选 Hard 负例上。

7.参考文献

1-《SENet双塔模型在推荐领域召回粗排的应用及其它》

你可能感兴趣的:(推荐系统,推荐系统,机器学习,DNN,双塔模型,SENet,DSSM)