本文是推荐算法实战系列第四篇文章。
前面文章包括:
- 推荐系统简介
- 特征工程
- embedding
推荐系统最关键的部分是精排模型,它也是最“卷”的领域。
本节主要从特征交叉和用户行为序列建模两个角度介绍推荐系统的精排模型。
1、特征交叉
面对众多的输入特征,精排模型的重要功能之一是做特征交叉。特征交叉越充分,越能挖掘到输入数据中的不同pattern。
特征交叉有两类。
第一类,输入侧,即传统的特征工程,利用人工经验做特征交叉。
第二类,模型侧,通过设计网络结构自动特征交叉。
1.1、LR——手动特征交叉,无法模型交叉
上篇文章已经提到LR其实是一个评分卡模型。它强于记忆。它本质是给每一个特征或者特征组合学习到一个权重(评分)。预测时,看当前样本命中了哪些特征,就把这些特征对应的评分相加,再经过sigmoid得到排序分。
LR在模型侧没有特征交叉能力。完全依赖于输入特征人工做特征交叉,即特征工程。LR的模型预测能力完全由特征工程决定。
LR模型,只有特征取值不为0的样本才能参与该特征参数的训练。
由于推荐系统的特征高维稀疏,如果每个特征都保存一个评分,评分卡无疑十分庞大,存储计算效率变低。
因此,通常要求模型学习到的参数尽可能稀疏,让一些小的参数尽量为0,这样能减少评分卡的大小。
传统的SGD优化算法无法满足参数的稀疏性要求,google提出了FTRL优化算法。本篇暂不做介绍。
1.2、FM——先embedding化再自动二阶交叉
LR无法在模型侧做特征交叉,FM在模型侧加入自动二阶交叉。其公式如下:
\[{logit_{FM} = b + \sum^n_iw_ix_i + \sum_i^n\sum_j^nw_{ij}x_ix_j}\]- ${x_i}$代表第i个特征。
- ${w_{ij}}$代表二阶交叉的特征权重。
但是,这种形式的交叉存在两个问题:
- 二阶权重项有$O(N^2)$个,参数量膨胀厉害,容易过拟合。
- 只有${x_i}$和${x_j}$都不为0的样本,才能训练更新二阶权重,导致它可能得不到充分的训练。
为了解决这个问题,提出了FM算法,其公式如下:
\[{logit_{FM} = b + \sum^n_iw_ix_i + \sum_i^n\sum_j^n(v_i \cdot v_j)x_ix_j}\]其改进点包括:
- 将二阶权重拆解成两个隐向量的点乘。
- 每个特征学习一个隐向量${v_i}$。
- 隐向量其实就是后来的embedding向量。
- 只要${x_i \neq 0}$的样本都能训练${v_i}$,${x_j \neq 0}$的样本都能训练${v_j}$,也都能间接训练${w_{ij}}$。
- LR中,样本中没有出现过的特征组合,其权重无从学起,剥夺了小众模式发挥作用的机会,降低了模型的泛化性。
- FM中,即便这种特征组合没有共现过,只要各自单独出现,就有机会训练。在预测时,模型可以通过各自的隐向量预估出二阶权重,从而为小众模式提供了发挥作用的机会,提高了模型的泛化性。
- FM除了用于精排,还可以用于召回和粗排,堪称推荐模型届的瑞士军刀。
1.3、wide&deep——兼顾记忆与扩展
记忆与扩展是推荐系统永恒的主题,google在2016年提出了wide&deep模型,分别解决这两个问题。
1.3.1、deep侧-侧重扩展
deep侧采用经典的embedding+MLP范式,可以表示成: \({logit_{DNN} = MLP(Concat(Emb({x_{deep}})))}\)
- Emb表示将输入的稀疏特征(通常是onehot或者multihot表示),映射成稠密向量的操作,参见上一节中embedding实现的描述。
- Deep侧使用embedding和MLP的高阶隐式交叉,增强了模型的扩展性,有利于满足低频、小众、个性化的需求。
1.3.2、wide侧-侧重记忆
wide侧用LR,主打“记忆性”,有利于记住高频、大众的模式。
deep侧是主力,wide侧是辅助,喂入其中的是被先验知识认定非常重要的精华特征。
另外,position bias这类bias特征,只能喂入wide侧,避免与其它特征交叉。
训练时,wide侧和deep侧一同训练。
模型的预测结果是: \({CTR_{pred} = sigmoid(logit_{wide} + logit_{deep})}\)
1.4、deepFM——在wide侧增加自动二阶交叉
在前述wide&deep中,deep侧负责高阶隐式交叉,wide侧无交叉。在此基础上,华为提出deepFM,在wide侧增加FM,自动进行二阶交叉。
其原理可以表示为:
$$
\begin{aligned}
logit_{dnn} &= DNN(Concat(emb(x_{dnn})))
logit_{fm} &= FM(x_{fm}, emb(x_{fm}))
logit_{lr} &= w_{lr} x_{lr}
CTR_{pred} &= sigmoid(logit_{lr} + logit_{fm} + logit_{DNN})
\end{aligned} $$
- LR的输入是一些被先验认为重要的特征,比如position bias等;
- DNN的输入可以是除bias以外的所有特征。
- FM的输入可以与DNN相同,也可以不同。
- FM和DNN都要用到embedding,原论文中,二者公用embedding。注意,FM要求emb的维度一样。
- 实践中,可以自由设计并组合LR、FM、DNN以及各自特征输入。
1.5、DCN —— 在deep侧增加显式任意高阶交叉
DNN只能做隐式特征交叉,交叉维度未知。
DCN由google提出,意在补充deep侧,做任意指定阶数的显示特征交叉。
1.5.1、DCN v1
DCN定义了CrossLayer,每个cross layer定义如下: \({x_{l+1} = x_0x_l^tw_l + b_l + x_l}\)
- x0是第一层的输入,通常是emb向量的拼接。
- 层数L控制交叉的阶数。
- 对于一个包含L个crosslayer的DCN,其最终结果包含了原始输入$x_0=[f_1,f_2,f_d]$所有d个元素之间小于等于L+1阶的交叉,即包含了所有$f_1^{\alpha_1}…f_d^{\alpha_d}$的可能组合,其中$0<=\sum_{i=1}^d alpha_i <= (L+1)$
1.5.2、DCN v2
作者认为DCN v1中可学习的参数是d维向量,容量有限。于是,在DCN v2中,用一个d * d的矩阵W代替了d维向量w。
\({x_{l+1} = x_0\odot(W_lx_l + b_l) + x_l}\) 由于,d很大,矩阵W的参数很多,进一步提出将其拆成两个小矩阵相乘的形式。 \({x_{l+1} = x_0\odot(U_l(V_l^Tx_l) + b_l) + x_l}\)
1.6、autoInt——引入transformer做特征交叉
autoInt采用transformer做特征交叉。
和DCN一样,transformer只做交叉,不做压缩。
在实践中,我们通常不让autoINT独立预测ctr,而是把它作为一个特征交叉模块,嵌入更大的推荐模型中,只选择一部分重要的特征喂入autoInt做交叉。
2、行为序列
用户的行为序列最能体现用户的个性化兴趣,因此行为序列建模是推荐系统中一个重要的环节。
行为序列本质上是一类特征,特殊性在于它的维度和其它特征不一样。其余的特征可以embedding化后拼接在一起,再经过上层DNN网络。
序列特征多了一个维度(序列长度),无法直接拼接,通常需要pooling,压缩掉一个维度,才能和其它特征拼接。
既然是压缩,必然有信息损失,序列建模就是用不同的pooling方式生成一个用户的embedding向量表征,然后再与其它特征拼接。
其原理表示如下:
\[{emb_{seq} = NN([s_1,s_2,...s_n]})\]2.1、行为序列信息的构成
序列中的每个元素$s_i$可以由多种类型的信息组成,例如item id、时间差信息等等。
这些信息都会送入NN压缩,提取用户表征。
2.2、简单pooling
Youtube的初代论文中,采用了简单的pooling方式压缩序列特征。
一些简答的pooling包括:
- average pooling
- sum pooling
- weighted pooling
简单pooling提取的用户兴趣是固定的,与候选物料无关。
对于召回、粗排等用户、物料解耦的场景,可以采用简单pooling。
对于精排模型,有其它更精细化的建模方式。
2.3、DIN——千物千面
阿里妈妈2018年提出了DIN,将attention引入序列建模。
以候选item做target(query),以序列做key、value,做target attention运算,得到序列的表征。
target attention成为序列建模的标准做法。
当没有候选item作为target时,可以拿序列中最后一个item当作query对整个序列做attention。
(备注:query和key/value必须来自同一个物料空间吗?例如query来自店铺id,key来自商品id?)
2.4、建模序列内的依赖关系
DIN只刻画了历史序列和候选item的关系,忽略了历史序列内部的依赖关系。
例如,一个用户购买过macbook和ipad,这两个行为的组合将产生强烈的信号,表明用户可能是苹果粉丝。
目前,较为常用的建模用户行为序列依赖关系的是双层attention。
第一步,用multi-head self- attention建模序列内部关系。其输出和输入维度相同,是一个长度相同的序列。只不过每个序列元素融合了原始序列中其它元素的信息。
第二步,在上一步基础上,再叠加一个DIN的target attention,得到最终的用户向量。
2.5、长序列建模
考虑序列建模的时间复杂度:
- 假设一个batch的大小为B,序列长度为L,每个embedding的长度为d
- DIN的时间复杂度为$O(B \times L \times d)$
- 双层attention的时间复杂度为:$O(B \times L^2 \times d)$
可见,序列建模的复杂度与序列长度呈线性甚至平方的关系。当L非常大时,无法满足在线预测和离线训练的时效要求。
为了实现超长序列建模,业界提出了一些方案。
2.5.1、在线提取用户兴趣-SIM
既然序列长度影响attention的时间复杂度,我们想办法把序列变短。
- 第一步,从超长序列过滤(搜索)出与候选物料最相关的一个短序列。
- 第二步,对短序列应用DIN。
第一步的搜索过滤有两种情况,hard search和soft search。
- hard search
在原始的长序列中,搜索与候选物品的某个属性(例如类目)相同的子序列。
为了加速搜索过程,SIM设计了一个特殊的双层hash存储格式。外层hash的key是userid,内层hash的key是属性。
通过hash查表,非常快速的找到候选物品最相关的子序列。
SIM论文说,这种方式虽然简单,但是效果和soft search差不多。
- soft search
soft search拿候选物品的embedding,在超长序列中做“近似近邻搜索(ANN)”,找到与之最相似的k个历史物料,作为子序列。
SIM原论文拿候选物料和超长序列构建了一个小模型预测CTR,得到item embedding。
也可以尝试用双塔召回的item embedding,或者word2vec得到的embedding。具体效果可以通过线上ab对比。
2.5.2、离线预测用户兴趣
SIM这类在线实时调用超长序列进行用户兴趣建模的方式,实现起来比较复杂,需要工程配合,做超长序列检索。
还有另一种方式,离线挖掘用户长期兴趣,作为特征供模型线上调用。
一种方法,比如用户对物品的长期统计特征,作为用户的兴趣表征。这种方法比较基础、简单,信息损失比较大。
另一种方式,离线训练一个辅助模型,提取用户长期兴趣,输入用户超长期序列,输出一个embedding作为用户兴趣表征。再结合DIN提取短期兴趣特征。
“离线派”的优点是在线预测简单,耗时低;缺点是无法实现“千物千面”,各个候选物品的向量一样。
美团采用这种“离线派”方式建模超长行为序列。
如何构建这种预训练模型,一种方法是,用同一个用户的长期行为序列,预测它的短期行为序列。例如:
- 模型采用双塔结构。
- 模型输入三元组$(LS_A,SS_A,SS_B)$。其中,$LS_A$与$SS_A$是同一个用户的长期序列和短期序列,$SS_B$是随机采样的另一个用户的短期序列。
- $LS_A$喂入左塔得到长期兴趣向量$UL_A$,$SS_A$和$SS_B$喂入右塔得到A、B两用户的短期行为兴趣$US_A$、$US_B$。
- 建模目标是,同一个用户的长短期兴趣向量应该相近,而不同用户的长短期兴趣向量应该较远。
- 训练完成后,将老用户的长期行为序列喂入左塔,得到用户长期兴趣向量。
本文总访问量次