作者:Wei
搜索推荐系统实战篇-中篇
1. 前言
一切源于炼丹笔记,我只是敲了敲代码。
2.模型优化
此处我们假设模型训练的大的框架已经固定,同时数据采样的方式也基本已经确定,接下来就是对模型结构进行深入的优化。关于模型结构的优化这块几乎是做不完的做不完的,从最新诸多论文结构来看,也可以划分为非常多块,此处仅仅列举下面三大模块的优化;
交叉模块优化
大部分内容摘自炼丹笔记之前的汇总.....实在是太懒了。
交叉模块是非常重要的模块,在早期序列化探索还没有那么强的时候,Poly2,FM,FFM这些模型都是在探索特征之间的交叉信息的,而这些统计信息是可以带来非常大提升的,
1. LR -> Poly2(特征交叉,基于点)
早期最早我们最为熟知的模型是LR,它的数学形式为:
我们知道LR其实是线性模型,所以很多非线性关系我们的LR模型是没法捕捉的,最典型的就是XOR,单条直线是没法直接分割的。

如果不做任何处理,LR是没法做到很好的区分的。那么怎么做呢?做些交叉特征。
这么看之前(0,0),(0,1),(1,0),(1,1)就被分配到了四个不同的bin中,对应位置的bin设置高的权重就可以解决上面的问题了。
2. Poly2 -> FM(升级特征交叉)
下面我们看一个特殊的场景,假设在我们的训练数据集中只有一个负样本(ESPN,Adidas),那么对于Poly2,(ESPN,Adidas)的组合特征对应的权重就会非常大,因为我们只能从该组合中学习它们的关系,这可能不是非常理想,那么如何缓解这样的问题呢?
我们将表示为两个向量的内积,每个向量的维度,这样做有什么好处呢?最明显的一点就是:我们可以只通过一个特征的出现去更新另外一个向量了,对应到上面的例子,我们可能还会有其他的组合(ESPN, Nike), (NBC, Adidas),而这些组合都可以用来更新我们的向量,所以我们的预测将会更加精确。
我们再看一个看电影的例子,

对于Poly2算法,如果出现了某个用户A没有看过的电影B,那么对应的(UserA,MovieB)的组合就是0,但是如果使用FM的话,结果就不一样了,因为UserA和MovieB的向量可以从其他的特征对中进行学习,所以(UserA,MovieB)的组合可能会非常有意义。
不管是Poly2,FM和FFM本质还是只学习了一阶和二阶的特征,那么高阶的特征怎么办?随着Deep模型的发展,我们尝试使用Deep模型去挖掘高阶交互特征,
1.传统 -> WDL

我们将Deep模型加入到原先的模型中来学习高阶的交叉,
其中:
2.WDS -> DeepFM(显示FM+隐式)
起初我们人为把特征embedding之后扔到MLP之中就可以很好地学习到高阶的交叉信息,但其实不然, MLP在特征组合的时候学习的并不是非常好,这个时候我们就需要找到之前我们的一些组合方法。将第一部分的内容加入进来。

其中:
3.WDS -> NFM(显示二阶+隐式)
做二阶特征,除了内积的形式外,我们还可以做element-wise的乘法, NFM提出了Bi-Interaction pooling,

在Bi-Interaction pooling之后连接上一层MLP学习高阶的特征交叉就可以得到:
其中:
NFM算另外一种结合两种将MLP与显示交叉结合的方式(之前是分两个分支),而实验中,我们发现后者可能效果更好一些。在模型的早期,加入Bi-interaction pooling并且拼接在之前的模型中一般是可以提升模型的效果的。
4.DeepFM/NFM -> TFNET(显示高级二阶+隐式)
之前的显示二阶特征交叉的形式都相对简单, 例如:
这么看我们其实每个元素在做内积的时候都乘上了一个1,我们是不是可以把这个1换成更加通用的呢,答案当然是可以的。
我们这么做忽略了两个向量不同元素之间的交叉,例如和此类的交叉,于是我们就想着能不能再扩展一下,所以我们就得到:
能不能再扩展一下(张量的思想),
最终我们得到,为我们模型的特征个数,这基本就是TFNET的核心。

此处,作者认为不同层的语义应该是不一样的,所以又加入了attention 来学习。
其中,

TFNET的输出为:
其中:
5.DeepFM -> ONN/NFFM(显示二阶+隐式)

在FM和FFM中,我们发现了FFM的表示相较于FM的几种好处,而且早期实验中也显示了FFM比FM却是要好很多。
所以类似的,既然FM和FFM都可以认为是Embedding,一个映射为单个dense向量,一个映射为多个dense向量,所以ONN就是将Embedding部分的特征修改,从FM的形式转化为FFM,后面仍然是一样的做cross的内积。
其中:
其中:
ONN是第一届腾讯赛冠军提出来的,在后两届的腾讯赛中,第一名也都有用到该模型,所以FFM的embedding是非常值得借鉴的。
此处还有一个小细节就是作者将embedding的特征和cross的特征进行concat输入MLP。
6.DeepFM -> xDeepFM(显示高阶+ 隐式)

上面所有的模型要么是直接用embedding之后用MLP模型进行隐式高阶特征在于显示的二阶交叉相加,要么就是二阶显示交叉之后再与一阶的embedding进行concat后加入MLP进行隐式学习。却还没有一个是显式学习高阶特征交叉的,那么这么做会有提升吗?xDeepFM告诉我们是的!!!
其中是CIN层的输出(显示特征交叉),

注意:xDeepFM还多来一层原始层的信息,这边一般也是可以带来提升的。剩下的就是显示的高阶特征交叉与隐式的相加,和之前的类似。
7. ONN/NFFM VS xDeepFM
ONN和xDeepFM是目前在数据竞赛中经常用到的模型(据本人所知,2020年之前的CTR竞赛最多的处理categorical的特征还是这两类模型),19年的腾讯赛冠军也是用的NFFM模型,二者的对比如下(18年的腾讯数据),整体来看,NFFM的效果要略好于xDeepFM,但二者融合效果还是极棒的!

1. FM -> AFM(噪音信息处理)
枚举式特征交叉的问题1:从上面所有模型的构建我们可以看到,所有的模型都是枚举式的二阶交叉,枚举的话毫无疑问就会带来非常大的问题,特征冗余,会带出非常多的无用的特征(Noise),这在实践中也是类似的,随机加入多个高斯噪音,模型的效果可能会下降(虽然很多时候下降不是非常多,但基本都是下降的),那怎么办呢?
所以我们就看到了最早的AFM模型。

AFM的数学表示形式为:
其中,
其中就是我们特征i和特征j交叉的attention分数,用来评估每个交叉特征的重要性。
注意如果全部为1,删去我们就还原得到了FM,所以此处认为是FM到AFM的衍生。
2. FM/DeepFM/PNN -> AutoFIS

Step1:寻找到不重要的特征交叉,
Step2:重新训练:,
我们发现和AFM的方案不同之处是,我们不需要通过attention的方式计算得到的,而且AutoFIS是两步训练,在第一部分先过滤,第二步重新训练,个人感觉效果会更好一点。AFM的思想和AotuFIS的思想都非常通过都可以直接嵌入到存在二阶交叉的模块中。
3. AFM/FFM -> AoAFFM(噪音+冗余信息处理)
枚举式特征交叉的问题2:除了枚举带来的噪音数据会导致我们的模型的效果下降之外,还有一类信息,就是冗余信息也会带来模型效果的下降,此处的冗余我们指:比如有一个交叉特征A非常重要,是非常强的特征,但是又有一个交叉特征B也非常重要,但是A特征和B特征的相关性几乎为1,也就是说A特征基本上已经包含了B特征的信息,其实只保留一个特征就好了,保留两个不仅会带来内存的消耗,还会导致我们的模型效果下降。实践中,最为常见,而且很多时候冗余信息带来的模型性能下降的程度比噪音数据会大。
所以我们就看到了最早的AoAFFM模型中的AoA希望处理的事情,当然此处作者不是基于FM做的,是基于FFM做的。

于是我们有:
其中为特征层的attention, 为交互层的attention权重。
如果忽略embedding层的操作,我们发现相较于AFM,AoAFFM多了一层Interaction-Level的Attention。而它的作用就是希望降低冗余特征的影响 :
在Feature-level的Attention网络中,我们可以学习每个特征的权重,但是却没法降低我们冗余特征带来的影响。所以两个类似的特征最终会有类似的attention,为了判别这种冗余的交互特征,我们使用interaction-level的attenion来处理,Q \in R^|\mathcal{F||} 从上面的网络框架图中,我们发现因为我们的Q是不依赖于前面的信息,所以即使对于相似的embedding向量,我们也有可能会有不同的权重,所以这个方法可以缓解特征冗余的问题。
一些实验
首先为了验证特征交叉是有价值的,我们在模型中删去了特征交叉的模块,发现在早期的版本中模型的预估,不管是CTR还是CVR的预估效果都会有较大幅度的下降,这也验证了网络层进行特征交叉的价值。那么问题来了,究竟哪种类型的交叉效果是最好的呢?
1. FM + NFM + TFNET特征交叉思路的组合尝试
这里希望验证的内容主要是:
当然如果是搜索任务可能还需要考虑Query的情况,我们默认将Query当做User侧的embedding加入。而在大量的实验结果中,我们基本可以得到下面的结论:我们将UI的所有emebdding信息进行拼接, 我们将拼接之后的信息用UI表示,
这一块的实验结论大致可以归纳为:
简单总结就是,U和I分开进行Bilinear的操作可以为我们的CTR带来些许帮助,但是对最终我们期望的曝光到转化的预估没能带来太大的正向收益。
2.模仿ONN思路
在大量的数据竞赛中,19年及之前有较大优势的是ONN以及xDeepFM两种,考虑到xDeepFM时间计算代价较大,我们尝试往ONN的思路迁移。因为目前我们线上的Embedding维度不能太大,但是又希望有类似于FFM这种的效果怎么办?
此处偷个懒,不细分field,而是每个Item的特征都对应一个field,同样的每个User的特征也都对应一个,等价于暴力转换
# [U, d] * Tensor(like:[d, d, V]) = [U, d, V]
# [V, d] * Tensor(like:[d, d, U]) = [V, d, U]
得到上面的形式之后,再用下面的方式做cross:
IF_trans = tf.transpose(IF,perm=[0, 3, 2, 1]) # [?, U, d, V]
UIF = tf.reduce_sum(UF * IF_trans, axis=-2) # [?, U, V]
Tensor因为是自行设计的,中间的*也可以自定义为其他操作,最终我们就得到一个形式上类似的新的"embedding"....
这么做的话,我们发现实验在CTR和曝光到转化的预估上可以带来一些收益,不过非常小。受限于资源等的问题,我们没法直接和ONN以及FFM中,直接在初始的过程中就执行转化,相信后面资源扩充了这么做肯定还是能有帮助的。
3.模仿TFNET细化embedding内积操作
UI的Cross内积,, 然后把所有的内积结果concat输入到下一层,接入MLP等,但是我们看MLP的形式是, 也就是说最后我们的输出其实是:,从表面来看,我们不会再深入到embedding的内部进行操作,都是在内积的基础上做,所以我们模仿一些NFM,TFNET,FiBiNET等文章思路先做内部交叉。
然后在此基础上加入张量的思想,将扩充成张量的形式。
这个思路在论文中也存在。
该思路在实验中效果还不错,基本在CTR和曝光到转化的预估中基本都能带来一定幅度的提升。
3. 序列相关模块优化
关于序列模块数据的使用是近几年才开始探索的,能更好地挖掘当前商品和用户历史点击商品之间的关系,这也是用户的近期和长期的兴趣爱好,充分挖掘各个阶段的信息,关于序列化建模因为涉及到数据的构建,所以这块要做好,需要至少做到两点:
序列构建
在电商搜索推荐的问题中,因为问题的不同,所以构建的序列也就不再仅限于简单的用户点击序列,例如在DMT中,使用到的序列就有:
这些序列反映了用户的不同的实时兴趣,当前大量的研究都会优化点击序列,但是却会忽略用户的其他行为,例如购买等;而从作者的实验结果来看,

而序列的设计也是有非常多种形式的,最简单的例子就是下面的这种形式,
1.基于用户/查询的XX序列
基础的商品序列:
当然商品仅仅只是一种表示,还可以更加的泛化,于是我们又可以得到下面的一列序列;
2. 基于商品的属性序列
关于商品类型的序列:
关于商品品牌的序列:
关于商品店铺的序列:
商品其它属性,例如城市等等信息。
当然除了上面的信息的序列,还有一类序列,我把其称之为:
3. 基于上下文的序列
按照上面的三种序列构建的策略来看,我们大概可以构建几十几百条不同的序列。而在实践中,我们也会发现序列带来的提升是非常巨大的。至于哪些序列能带来的提升是比较大的,我不能给出直接的答案,但是用户/Query和商品的点击序列等都是可以带来不错提升的,这在最近搜索相关的论文中也都是有提到的,所以不再做过多的阐述。
序列模型比较
序列按照结构使用的核心模块不一样,又可以分为下面几种:
1.基于CNN模块的序列模型
典型的例如CosRec,CosRec是第一篇用于下一个商品推荐的基于二维CNN的方法, CosRec用于处理序列化的数据, CosRec将历史的商品进行枚举式的concat然后组成pair,最终使用二维的CNN提取序列特征。CosRec在数据集上的表现都明显优于最近的序列方法,表现了它作为顺序推荐任务的通用模型的有效性。
CosRec会先将单个序列变化为组合形式,然后再直接使用二维卷积进行处理。

2.基于RNN模块的序列模型
典型的如DIEN,DIEN是DIN的改进,因为用户兴趣会随着时间的推移而动态演化。之前的模型缺乏对具体行为背后潜在兴趣的专门建模。此外,很少有研究考虑兴趣的变化趋势。DIEN设计了兴趣提取层来从历史行为序列中捕捉时间兴趣。DIEN引入一个辅助损失来抽取每一步的时间兴趣信息。针对用户兴趣的多样性,特别是在电子商务系统中,我们提出了兴趣演化层来捕捉与目标商品相关的兴趣演化过程。

使用的序列辅助Loss如下:
3.基于Attention模块的序列模型
基于Attention系列的序列网络非常多,典型的有DIN,SASRec,DMT,DMIN,SSE-PT等等。
DIN是最早一批对用户序列进行挖掘的工作。它通过设计一个局部激活单元来自适应地学习用户对某个广告的历史行为的兴趣表示。这种表示向量在不同的广告中是不同的,大大提高了模型的表达能力。此外,我们还开发了两种技术:min-batch感知的正则以及数据自适应激活函数,它可以帮助训练具有数亿个参数的工业深层网络。

SASRec是最早将自我注意机制用于序列的模型, SASRec对整个用户序列进行建模(没有任何递归或卷积操作),并自适应地考虑消耗的项目进行预测,相较于之前的RNN/CNN的网络,不仅快,而且效果更好,算是最早基于Self-Attention的模型。

DMT加入了多条的序列,不再是简单的点击序列,还有加购/下单等序列,使用多条序列来多方面捕捉用户的历史兴趣爱好,最后使用Bias深度网络来减少隐式反馈的选择偏差。

用户经常在某个时间点拥有大量的兴趣, 与此同时, 潜在的主导兴趣是通过行为表现出来的。潜在主导兴趣的切换会导致最终的行为变化。因此,建模和跟踪潜在的多重兴趣将是有益的。

本文最大的一个特色还在于加入了辅助Loss来帮助我们获得更好的表示,
$$L_{aux} = - \frac{1}{N}(\sum_{i=1}^N \sum_{t} log \sigma()) + log( 1- \sigma()) $$
和很多工作不一样,本文在序列中加入了用户的emebdding来获得个性化,以及位置编码,最后使用随机emebdding的正则策略。

一些实验
关于序列的实验相信很多朋友不说也都知道了。目前效果相对最好的都是基于Attention系列的那一套,有的时候为了捕捉时间信息会在Attention之后加入LSTM等模块,用来弥补Attention模块忽略位置信息的缺点等等。
关注我们!