.. _higher_order_feature_crossing: 高阶特征交叉 ============ 在掌握了二阶特征交叉的各种技术后,我们发现这些模型虽然能够显式地处理二阶交互,但对于更高阶的特征组合,它们主要依赖于深度神经网络(DNN)部分来隐式学习。然而,这种“隐式”学习的过程如同一个黑盒,我们很难解释模型具体学习到了哪些特征的组合,以及这些组合是如何影响最终预测的。因此,研究者们开始探索能否设计出像FM处理二阶交叉一样,能够\ **显式地、可控地捕捉高阶交叉**\ 的网络结构,从而在提升模型性能的同时,增强模型的可解释性。 DCN: 残差连接的高阶交叉 ----------------------- 为了解决上述问题,Deep & Cross Network (DCN) :cite:`wang2017deep` 通过一个创新的Cross Network来替代Wide & Deep模型中的Wide部分。该网络的核心思想是在每一层都与原始的输入特征进行交叉,从而以一种显式且可控的方式,自动构建更高阶的特征交互,而无需繁琐的人工特征工程。 .. figure:: ../../img/deepcross.png DCN模型结构 DCN的整体结构由并行的Cross Network和Deep Network两部分组成,它们共享相同的Embedding层输入。首先,模型将稀疏的类别特征转换为低维稠密的Embedding向量,并与数值型特征拼接在一起,形成统一的输入向量 :math:`\mathbf{x}_0`\ 。 .. math:: \mathbf{x}_0 = [\mathbf{x}_{\text{embed}, 1}^T, \ldots, \mathbf{x}_{\text{embed}, k}^T, \mathbf{x}_{\text{dense}}^T] 这个初始向量 :math:`\mathbf{x}_0` 会被同时送入Cross Network和Deep Network。 Cross Network是DCN的核心创新。它由多个交叉层堆叠而成,其精妙之处在于每一层的计算都保留了与原始输入 :math:`\mathbf{x}_0` 的直接交互。第 :math:`l+1` 层的计算公式如下: .. math:: \mathbf{x}_{l+1} = \mathbf{x}_0 \mathbf{x}_l^T \mathbf{w}_l + \mathbf{b}_l + \mathbf{x}_l 其中\ :math:`\mathbf{x}_l, \mathbf{x}_{l+1} \in \mathbb{R}^d` 分别是第 :math:`l` 层和第 :math:`l+1` 层的输出列向量,\ :math:`\mathbf{x}_0 \in \mathbb{R}^d` 是Cross Network的初始输入向量,\ :math:`\mathbf{w}_l, \mathbf{b}_l \in \mathbb{R}^d` 分别是第 :math:`l` 层的权重和偏置列向量。 .. figure:: ../../img/cross_network.png Cross Network 我们可以观察到,这个结构本质上是一个残差网络。每一层都在上一层输出 :math:`\mathbf{x}_l` 的基础上,增加了一个交叉项 :math:`\mathbf{x}_0 \mathbf{x}_l^T \mathbf{w}_l` 和一个偏置项 :math:`\mathbf{b}_l`\ 。这个交叉项非常关键,它让原始输入 :math:`\mathbf{x}_0` 与当前层的输入 :math:`\mathbf{x}_l` 进行了显式的特征交叉。随着层数的加深,\ **特征交叉的阶数也随之增加**\ 。例如,在第一层(\ :math:`l=0`\ ),\ :math:`\mathbf{x}_1` 包含了与 :math:`\mathbf{x}_0` 相关的二阶交叉项;在第二层(\ :math:`l=1`\ ),由于 :math:`\mathbf{x}_1` 已经包含了二阶信息,它与 :math:`\mathbf{x}_0` 的再次交叉就会产生三阶的交叉项。因此,Cross Network的深度决定了它能显式捕获的最高特征交叉阶数。这种设计使得参数量只随着输入维度呈线性增长,非常高效。 与Cross Network并行的Deep Network部分是一个标准的全连接神经网络,用于隐式地学习高阶非线性关系,其结构与我们熟悉的DeepFM中的DNN部分类似。最后,模型将Cross Network的输出 :math:`\mathbf{x}_{L_1}` 和Deep Network的输出 :math:`\mathbf{h}_{L_2}` 拼接起来,通过一个逻辑回归层得到最终的预测概率。 .. math:: \mathbf{p} = \sigma([\mathbf{x}_{L_1}^T, \mathbf{h}_{L_2}^T] \mathbf{w}_{\text{logits}}) DCN通过Cross Network提供了一种有效且高效的显式高阶特征交叉方案,并结合DNN的隐式交叉能力,为推荐模型的设计提供了新的思路。 xDeepFM: 向量级别的特征交互 --------------------------- 尽管DCN能够显式地构建高阶特征,但它的交叉方式是在 **元素级别(bit-wise)** 上进行的。这意味着Embedding向量中的每一个元素都会独立地与其他特征的Embedding元素进行交互,这在一定程度上忽略了Embedding向量作为一个整体所代表的特征场的概念。为了解决这个问题,xDeepFM模型被提了出来,其核心是设计了一个全新的压缩交互网络(Compressed Interaction Network, CIN) :cite:`lian2018xdeepfm` ,以 **向量级别(vector-wise)** 的方式进行特征交互,这更符合我们进行特征工程时的直觉。 xDeepFM的整体架构同样由三部分组成:一个传统的线性部分、一个用于隐式高阶交叉的DNN,以及创新的CIN网络用于显式高阶交叉。这三部分的输出最终被结合起来进行预测。 .. figure:: ../../img/xdeepfm.png xdeepfm模型架构 CIN的设计目标是实现向量级别的显式高阶交互,同时控制网络复杂度。它的输入是一个\ :math:`m \times D`\ 的矩阵 :math:`\mathbf{X}_0`\ ,其中 :math:`m` 是特征域(Field)的数量,\ :math:`D` 是Embedding的维度,矩阵的第 :math:`i` 行就是第 :math:`i` 个特征域的Embedding向量 :math:`\mathbf{e}_i`\ 。 CIN的计算过程在每一层都分为两步。在计算第 :math:`k` 层的输出 :math:`\mathbf{X}_k` 时,它依赖于上一层的输出 :math:`\mathbf{X}_{k-1}` 和最原始的输入 :math:`\mathbf{X}_0`\ 。 第一步,模型计算出上一层输出的 :math:`H_{k-1}` 个向量与原始输入层的 :math:`m` 个向量之间的所有成对交互,生成一个中间结果。具体来说,是通过哈达玛积(Hadamard product)\ :math:`\circ` 来实现的。这个操作会产生 :math:`H_{k-1} \times m` 个交互向量,每个向量的维度仍然是 :math:`D`\ 。 第二步,为了生成第 :math:`k` 层的第 :math:`h` 个新特征向量 :math:`\mathbf{X}_{h,*}^k`\ ,模型对上一步产生的所有交互向量进行加权求和。这个过程可以看作是对所有潜在的交叉特征进行一次“压缩”或“提炼”。 综合起来,其核心计算公式如下: .. math:: \mathbf{X}_{h,*}^k = \sum_{i=1}^{H_{k-1}} \sum_{j=1}^{m} \mathbf{W}_{i,j}^{k,h} (\mathbf{X}_{i,*}^{k-1} \circ \mathbf{X}_{j,*}^0) 其中: - :math:`\mathbf{X}_k \in \mathbb{R}^{H_k \times D}` 是CIN第 :math:`k` 层的输出,可以看作是一个包含了 :math:`H_k` 个特征向量的集合,称为“特征图”。\ :math:`H_k` 是第 :math:`k` 层特征图的数量。 - :math:`\mathbf{X}_{i,*}^{k-1}` 是第 :math:`k-1` 层输出的第 :math:`i` 个 :math:`D` 维向量。 - :math:`\mathbf{X}_{j,*}^0` 是原始输入矩阵的第 :math:`j` 个 :math:`D` 维向量(即第 :math:`j` 个特征域的Embedding)。 - :math:`\circ` 是哈达玛积,它实现了\ **向量级别的交互**\ ,保留了 :math:`D` 维的向量结构。 - :math:`\mathbf{W}_{k,h} \in \mathbb{R}^{H_{k-1} \times m}` 是一个参数矩阵。它为每一个由 :math:`(\mathbf{X}_{i,*}^{k-1}, \mathbf{X}_{j,*}^0)` 产生的交互向量都提供了一个权重,通过加权求和的方式,将 :math:`H_{k-1} \times m` 个交互向量的信息“压缩”成一个全新的 :math:`D` 维向量 :math:`\mathbf{X}_{h,*}^k`\ 。 这个过程清晰地展示了特征交互是如何在向量级别上逐层发生的。第 :math:`k` 层的输出 :math:`\mathbf{X}_k` 包含了所有 :math:`k+1` 阶的特征交互信息。 在计算出每一层(从第\ :math:`1`\ 层到第\ :math:`T`\ 层)的特征图 :math:`\mathbf{X}_k` 后,CIN会对每个特征图 :math:`\mathbf{X}_k` 的所有向量(\ :math:`H_k`\ 个)在维度 :math:`D` 上进行求和池化(Sum Pooling),得到一个池化后的向量 :math:`\mathbf{p}_k \in \mathbb{R}^{H_k}`\ 。最后,将所有层的池化向量拼接起来,形成CIN部分的最终输出。 .. math:: \mathbf{p}^+ = [\mathbf{p}_1, \mathbf{p}_2, \ldots, \mathbf{p}_T] 这个输出 :math:`\mathbf{p}^+` 捕获了从二阶到 :math:`T+1` 阶的所有显式、向量级别的交叉特征信息。最终,xDeepFM将线性部分、DNN部分和CIN部分的输出结合起来,通过一个Sigmoid函数得到最终的预测结果。 .. math:: \hat{y} = \sigma(\mathbf{w}_{\text{linear}}^T \mathbf{a} + \mathbf{w}_{\text{dnn}}^T \mathbf{x}_{\text{dnn}}^k + \mathbf{w}_{\text{cin}}^T \mathbf{p}^+ + \mathbf{b}) 其中\ :math:`\mathbf{a}` 表示原始特征,\ :math:`\mathbf{x}_{\text{dnn}}^k` 表示DNN的输出,\ :math:`\mathbf{b}` 是可学习参数。 通过引入CIN,\ **xDeepFM成功地将显性的、向量级别的特征交互与隐性的、元素级别的特征交互结合在同一个模型中**\ ,为自动学习高阶特征交互提供了又一个强大且更具解释性的解决方案。 AutoInt: 自注意力的自适应交互 ----------------------------- DCN通过残差连接实现了元素级别的高阶交互,xDeepFM通过CIN网络实现了向量级别的高阶交互,但这两种方法都有一个共同的局限性:它们对高阶特征交互的构建方式是相对固定的。DCN的每一层都必须与原始输入进行交叉,而xDeepFM的CIN网络则按照预定义的方式进行向量交互。那么,\ **能否设计一种更加灵活、智能的高阶特征交互机制,让模型自主地决定哪些特征应该参与交互,以及交互的强度如何?** AutoInt (Automatic Feature Interaction) :cite:`song2019autoint` 模型回答了这个问题。它借鉴了自然语言处理领域中 Transformer 架构的核心思想,\ **通过多头自注意力机制来自动、自适应地学习任意阶数的特征交互**\ 。与前面介绍的方法不同,AutoInt 不依赖于固定的交互模式,而是让模型在训练过程中学习出最有效的特征交互组合。 .. figure:: ../../img/autoint_overview.png AutoInt模型原理示意图 AutoInt 的整体架构相对简洁,它将所有输入特征(无论是类别型还是数值型)都转换为相同维度的嵌入向量 :math:`\mathbf{e}_m \in \mathbb{R}^d`\ ,其中 :math:`m` 代表第 :math:`m` 个特征域。这些嵌入向量构成了自注意力网络的输入,类似于 Transformer 中的 token embeddings。 **多头自注意力机制** AutoInt 的核心是其交互层,该层由多头自注意力机制构成。对于任意两个特征的嵌入向量 :math:`\mathbf{e}_m` 和 :math:`\mathbf{e}_k`\ ,自注意力机制会计算它们之间的相关性得分。这个过程在每个“注意力头” (head) :math:`h` 中独立进行。具体来说,对于特征 :math:`m` 和特征 :math:`k`\ ,它们在第 :math:`h` 个注意力头中的相关性得分 :math:`\alpha_{m,k}^{(h)}` 计算如下: .. math:: \alpha_{m,k}^{(h)} = \frac{\exp(\psi^{(h)}(\mathbf{e}_m, \mathbf{e}_k))}{\sum_{l=1}^{M}\exp(\psi^{(h)}(\mathbf{e}_m, \mathbf{e}_l))} 这里的 :math:`M` 是特征域的总数,而 :math:`\psi^{(h)}(\mathbf{e}_m, \mathbf{e}_k)` 是一个用于衡量两个嵌入向量相似度的函数,通常是缩放点积注意力: .. math:: \psi^{(h)}\left(\mathbf{e}_{\mathbf{m}}, \mathbf{e}_{\mathbf{k}}\right)=\left\langle\mathbf{W}_{\text {Query }}^{(h)} \mathbf{e}_{\mathbf{m}}, \mathbf{W}_{\text {Key }}^{(h)} \mathbf{e}_{\mathbf{k}}\right\rangle 其中 :math:`\mathbf{W}_{\text{Query}}^{(h)} \in \mathbb{R}^{d' \times d}` 和 :math:`\mathbf{W}_{\text{Key}}^{(h)} \in \mathbb{R}^{d' \times d}` 是可学习的投影矩阵,它们分别将原始嵌入向量映射到“查询”(Query)和“键”(Key)空间。\ :math:`d'` 是投影后的维度。 在计算出所有特征对之间的相关性得分后,模型会利用这些得分来对所有特征的“值”(Value)向量进行加权求和,从而为特征 :math:`\mathbf{e}_m` 生成一个新的、融合了其他特征信息的表示 :math:`\mathbf{\tilde{e}}_m^{(h)}`\ : .. math:: \mathbf{\tilde{e}}_m^{(h)} = \sum_{k=1}^{M} \alpha_{m,k}^{(h)} (\mathbf{W}_{\text{Value}}^{(h)} \mathbf{e}_k) 其中 :math:`\mathbf{W}_{\text{Value}}^{(h)} \in \mathbb{R}^{d' \times d}` 同样是一个可学习的投影矩阵。这个新的表示 :math:`\mathbf{\tilde{e}}_m^{(h)}` 本质上就是一个通过自适应学习得到的新组合特征。 .. figure:: ../../img/autoint_attention.png 自注意力机制示意图 **多层交互与高阶特征学习** “多头”机制允许模型在不同的子空间中并行地学习不同方面的特征交互。模型将所有 :math:`H` 个头的输出拼接起来,形成一个更丰富的特征表示: .. math:: \mathbf{\tilde{e}}_m = \mathbf{\tilde{e}}_m^{(1)} \oplus \mathbf{\tilde{e}}_m^{(2)} \oplus \cdots \oplus \mathbf{\tilde{e}}_m^{(H)} 其中 :math:`\oplus` 表示拼接操作。为了保留原始信息并稳定训练过程,AutoInt 还引入了残差连接(Residual Connection),将新生成的交互特征与原始特征相结合: .. math:: \mathbf{e}_m^{\text{Res}}= \text{ReLU}(\mathbf{e}_m + \mathbf{W}_{\text{Res}} \mathbf{\tilde{e}}_m) 其中 :math:`\mathbf{W}_{\text{Res}}` 是一个用于匹配维度的投影矩阵。 **AutoInt 的关键创新在于其高阶特征交互的构建方式**\ 。通过堆叠多个这样的交互层,AutoInt 能够显式地构建任意高阶的特征交互。第一层的输出包含了二阶交互信息,第二层的输出则包含了三阶交互信息,以此类推。每一层的输出都代表了更高一阶的、自适应学习到的特征组合。与 DCN 和 xDeepFM 不同,AutoInt 中的高阶交互不是通过固定的数学公式构建的,而是通过注意力权重动态决定的,这使得模型能够学习到更加灵活和有效的特征交互模式。 最终,所有层输出的特征表示被拼接在一起,送入一个简单的逻辑回归层进行最终的点击率预测: .. math:: \hat{y}=\sigma\left(\mathbf{w}^{\mathrm{T}}\left(\mathbf{e}_{1}^{\mathbf{Res}} \oplus \mathbf{e}_{2}^{\mathbf{Res}} \oplus \cdots \oplus \mathbf{e}_{\mathbf{M}}^{\text {Res}}\right)+b\right) AutoInt 的一个巨大优势是其可解释性,通过可视化注意力权重矩阵 :math:`\alpha^{(h)}`\ ,我们可以直观地看到模型认为哪些特征组合是最重要的。这种基于自注意力机制的高阶特征交互不仅提升了模型的表达能力,还为高阶特征交互的学习提供了一个全新的、更加灵活的范式。 代码实践 -------- .. raw:: latex \diilbookstyleinputcell .. code:: python import sys import funrec from funrec.evaluation import compare_models models = ['dcn', 'xdeepfm', 'autoint'] results, table = compare_models(models) print(table) .. raw:: latex \diilbookstyleoutputcell .. parsed-literal:: :class: output +---------+--------+--------+---------------+ | 模型 | auc | gauc | valid_users | +=========+========+========+===============+ | dcn | 0.6078 | 0.572 | 928 | +---------+--------+--------+---------------+ | xdeepfm | 0.6 | 0.574 | 928 | +---------+--------+--------+---------------+ | autoint | 0.5919 | 0.5695 | 928 | +---------+--------+--------+---------------+