本文要介绍的论文题目是《AutoInt: Automatic Feature Interaction Learning via Self-A entive Neural Networks》 论文下载地址为:t.cn/AipG8aXz
这篇文章使用Multi-Head self-Attention进行自动的特征提取,整体思路相对而言比较简单易懂,但是论文结构比较完整。除介绍论文外,最后本文介绍了如何使用Python绘制热力图,一起来看一下吧。
点击率预估问题对推荐系统来说比较重要,但是目前存在许多挑战: 1)特征数量巨大,离散特征多,存在特征稀疏问题。 2)高阶特征组合对于提升点击率预估的性能至关重要,但发现一些有实际意义的特征组合需要依靠专业知识,这一过程费时费力,需要通过模型自动去学习高阶特征组合。 3)现有的方法如FM,它只能学习低阶的特征组合,而DeepFM等通过神经网络的方法往往进行隐式的特征组合,缺乏一定的可解释性。
基于上述问题,本文提出了AutoInt,通过目前比较火热的Multi-Head Attention来自动进行特征组合。一起来看一下。
AUTOINT框架的整体框架比较简单,如下图:
接下来,我们逐层进行介绍。
这里咱们的目标是预测用户u点击某个物品i的概率,因此输入层包含用户相关的特征和物品相关的特征:
上面的M是特征域的个数,一个离散特征和一个连续特征都属于一个单独的特征域。
在Embedding层,我们对三种不同的特征分别进行了处理,这三种特征分别是单值离散特征、多值离散特征和连续特征。
对于单值离散特征,直接通过Embedding词表得到对应的Embedding表示:
对于多值离散特征,通过Embedding词表得到对应Embedding之后,还需要通过avg-pooling的方式对同一个field的Embedding进行平均:
上面的q就是多值离散特征中取值的个数。对于离散特征来说,上面的xi是one-hot向量或者multi-hot向量,取值非0即1,而对于连续特征,直接就是一个标量,我们将标量的取值直接与其对应的Embedding相乘:
交互层是Transformer的encoder部分,由多层进行堆叠来学习特征之间的高阶组合。Transformer中最重要的是multi-head attention,其简单的示意图如下:
有关Transformer,咱们这里也不讲了,可以参考之前的文章。
输出层的计算公式如下:
首先将交互层得到的输出进行对位相加,然后经过一层全连接层并进行sigmoid变换得到点击率的预估值。
而模型的损失采用的是logloss:
接下来,我们来解释一下,模型是如何来学习高阶特征之间的组合的。假设我们有4个field的输入,分别是x1、x2、x3、x4。这里重点介绍二阶和三阶特征组合。
在第一层的交互层,通过attention map我们可以学习不同特征的相关性,并通过加权求和的方式进行组合。假设第一个field的输出为e1,e1中就包含了第一个field和4个field之间的交互。
对于三阶特征组合,在第二层的交互层就可以学习到。我们知道,在transformer中encoder的每一个block中,存在residual connection的过程,这样输出e1中不仅包含了第一个field和其他field组合的信息,还包含第一个field自身的信息,这样在与e3(第三个field在第一个交互层的输出)进行multi-head attention时,就可以得到第一个field和第二三个field的交互结果。
文中使用了不同的数据集,与一些base模型进行了效果的对比,结果如下:
可以看到,AutoInt在所有的数据集上,AUC都是最优的。
最后再来看看如何对推荐过程中的特征组合进行一定的解释性分析,这主要需要观察multi-head attention过程中的attention map:
上图中,左边是针对一条电影推荐数据的结果,对于该条数据,通过attention map可以得到的结论是18-24岁的年轻人比较喜欢看恐怖片或者动作片。
而右图是对所有训练数据集中对应field的attention score的一个平均值,可以看到性别和电影类别、年龄和电影类别等都具有更高的相关性。
论文整体上就介绍完了。有一说一,整体上的创新点不是很足,不过相比于其他的论文,对于特征组合的构建、以及可解释性的分析比较充分,论文结构相对来说更加完整。最后,咱们也一起来学习一下3.2节中提到的热力图的绘制:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
# cmap(颜色)
np.random.seed(20180316)
x = np.random.randn(4, 4)
f, (ax1, ax2) = plt.subplots(figsize=(6,6),nrows=2)
sns.heatmap(x, annot=True, ax=ax1)
sns.heatmap(x, annot=True, ax=ax2, annot_kws={'size':9,'weight':'bold', 'color':'blue'})
plt.show()
上面结果的如下:
其中,最重要的函数是sns.heatmap函数,这里我们用到了四个参数,第一个参数是我们的输入数据,也就是热度矩阵,这里是4*4大小的;第二个参数是annot,代表是否要标注热力值大小,默认为false;第三个参数ax是指定我们的画布;第四个参数annot_kws是对显示的字体进行一定的设定。
好了,今天就到这里了,大伙假期注意劳逸结合哇!