【推荐系统】专栏历史部分文章:

深入理解推荐系统:召回

深入理解推荐系统:排序

深入理解推荐系统:Fairness、Bias和Debias

深入理解推荐系统:推荐系统中的attention机制

深入理解推荐系统:特征交叉组合模型演化简史

深入理解推荐系统:十大序列化推荐算法梳理

作为【推荐系统】系列文章的第十五篇,将以“xDeepFM”作为今天的主角,中科大、北大与微软合作发表在 KDD’18 的文章:《xDeepFM: Combining Explicit and Implicit Feature Interactions for Recommender Systems》。本文主要对xDeepFM进行详细描述,并进行代码实现。

背景介绍

传统交叉特征工程主要有三个缺点,以下部分来自paper:

  • 获取高质量特征代价高昂

  • 大规模预测系统(比如:推荐系统),存在大量原始特征(raw features),很难人工抽取所有交叉特征

  • 人工交叉特征不能泛化到在训练数据中未见过的交叉上

FM会将每个特征i嵌入到一个隐因子向量





































上,pairwise型特征交叉可以被建模成隐向量的内积:




































。在本paper中,使用术语bit来表示在隐向量中的一个元素(比如:










)。经典的FM可以被扩展到专门的高阶特征交叉上,但一个主要缺点是:会建模所有的特征交叉,包括有用组合和无用组合。无用组合会引入噪声、以及效果的下降。最近几年,DNNs越来越流行。利用DNNs可以学习复杂和可选择的特征交叉。FNN用于学习高阶特征交叉,它会使用对于field embedding的预训练FM,然后应用于DNN。PNN则不依赖预训练的FM,而是在embedding layer和DNN layer之间引入了一个product layer。FNN和PNN的主要缺点是,它们主要更多关注高阶特征交叉,而非低阶交叉。Wide&Deep模型和DeepFM模型通过引入混合结构克服了上面的缺点,它包含了一个shallow组件以及一个deep组件,可以学到memorization和generalization。因而可以联合学习低阶和高阶特征交叉。

上面的所有模型都使用DNN来学习高阶特征交叉。然而,DNN可以以一个隐式的方式建模高阶特征交叉。由DNN学到的最终函数可以是任意形式,关于特征交叉的最大阶数(maximum degree)没有理论上的结论。另外,DNNs在bit-wise级别建模征交叉,这与FM框架不同(它会在vector-wise级别建模)。这样,在推荐系统的领域,其中DNN是否是用于表示高阶特征交叉的最有效模型,仍然是一个开放问题。在本paper中,我们提供了一个基于NN的模型,以显式、vector-wise的方式来学习特征交叉。论文的方法基于DCN(Deep&Cross Network)之上,该方法能有效捕获有限阶数(bounded  degree)的特征交叉,然而,DCN将带来一种特殊形式的交叉。论文设计了一种新的压缩交叉网络CIN(compressed interaction network)来替换在DCN中的cross network。CIN可以显式地学到特征交叉,交叉的阶数会随着网络depth增长。根据Wide&Deep模型和DeepFM模型的精神,论文会结合显式高阶交叉模块和隐式交叉模型,以及传统的FM模块,并将该联合模型命名为“eXtreme Deep Factorization Machine (xDeepFM)”。这种新模型无需人工特征工程,可以让数据科学家们从无聊的特征搜索中解放出来。总结一下,主要有三个贡献:

  • 提出了一种新模型xDeepFM,可以联合训练显式和隐式高阶特征交叉,无需人工特征工程

  • 设计了CIN来显式学习高阶特征交叉,论文展示了特征交叉的阶(degree)会在每一层增加,特征会在vector-wise级别进行交叉。

  • 论文在三个数据集中进行了实验,结果展示xDeepFM效果好于其它state-of-art模型

准备工作

Embedding Layer

在CV或NLP领域,输入数据通常是图片或文本信号,它们空间相关(spatially correlated)或时序相关(temporally correlated),因而DNN可以被直接应用到dense结构的原始特征上。然而,在推荐系统中,输入特征是sparse、高维、没有明显地空间相关或时序相关。因此,multi-field类别形式被广泛使用。例如,一个输入实例为:

[user_id=s02, gender=male, organization=msra, interests=comedy&rock]

通过field-aware one-hot进行编码成高维稀疏特征:

在原始特征输入上使用一个embedding layer,可以将它压缩到一个低维、dense、real-value vector上。如果field是一阶的(univalent),feature embedding被当成field embedding使用。以上述实例为例,特征(male)的embedding被当成field gender的embedding。如果field是多阶的(multivalent),feature embedding的求和被用于field embedding。embedding layer如下图所示。embedding layer的结果是一个wide concatenated vector:



























其中,m表示fields的数目,














表示一个field的embedding。尽管实例的feature长度可以是多变的,它们的embedding具有相同的长度 m x D, 其中D是field embedding的维数。下图中,field embedding layer。本例中embedding的维度是4

隐式高阶交叉

FNN, Deep&Cross,以及Wide&Deep的deep part会使用一个在field embedding vector e上的feed-forward神经网络来学习高阶特征交叉。forward process是:






























































其中,k是layer depth,




是激活函数,







是第k层的output。可视化结构与下图展示的非常像,但不包括FM layer或Product layer。该结构会以bit-wise的方式建模交叉。也就是说,相同field embedding vector中的元素也会相互影响。

PNN和DeepFM在上述结构上做了小修改。除了在embedding vector e上应用了DNNs外,它们在网络中添加了一个2-way interaction layer。因而,bit-wise和vector-wise的交叉都能在模型中包含。PNN和DeepFM中主要不同是,PNN会将product layer的输出连接到DNNs中,而DeepFM会直接将FM layer连接给output unit。

显式高阶交叉

Cross Network(CrossNet)的结构如下图所示:

它可以显式建模高阶特征交叉。不同于经典的fully-connected feed-forward network,它的hidden layers通过以下的cross操作进行计算:

其中,

























是第k层的weights,bias以及output。对于CrossNet能学到一个特殊类型的高阶交叉这一点我们有争论,其中,CrossNet中的每个hidden layer是一个关于







的标量乘积。

theorem: 考虑到一个k层cross network,第i+1层的定义为:


































。接着,cross network的output







是一个关于







的标量乘积。

证明如下:

k=1时,根据矩阵乘法的结合律和分配律,我们具有:

其中,标量



















实际上是关于







的线性回归。其中,







是关于







的一个标量乘。假设标量乘适用于k=i。对于k=i+1, 我们可以有:

其中,

































是一个标量。其中,











仍是一个关于







的标量乘。通过引入hypothesis,cross network的output







是一个关于







的标量乘。

注意,



标量乘


















并不意味着







是与







是线性关系的。系数











是与







敏感的。CrossNet可以非常有效地学到特征交叉(复杂度与一个DNN模型对比是微不足道的),然而,缺点是:

  • CrossNet的输出受限于一个特定的形式,每个hidden layer是关于







    的一个标量乘

  • 交叉是以bit-wise的方式进行

CIN模型

CIN

论文设计了一个新的cross network,命名为CIN(Compressed Interaction Network),具有如下注意事项:

  • 交叉是在vector-wise级别上进行,而非bit-wise级别

  • 高阶特征的交叉显式衡量

  • 网络的复杂度不会随着交叉阶数进行指数增长

由于一个embedding vector被看成是一个关于vector-wise 交叉的unit,后续会将field embedding公式化为一个矩阵:
















,其中,假设

















表示在第k层的(embedding)feature vectors的数量。对于每一层,







通过以下方式计算:

其中







































是第h个feature vector的参数矩阵,




表示Hadamard product,例如:。注意,







通过在



















间的交叉产生,其中,特征交叉会被显式衡量,交叉的阶数会随着layer depth增长。CIN的结构与RNN非常相似,其中下一个hidden layer的outputs取决于最近一个(the last)的hidden layer和一个额外的input。论文在所有layers上都持有embedding vectors的结构,这样,即可在vector-wise级别上使用交叉。

有意思的是,等式












与CNN具有很强的关联。如上图 a 所示,引入了一个内部张量(intermediate tensor)











,其中,它是hidden layer







和原始特征矩阵







的外积(outer products:沿着每个embedding维度)。











被看成是一个特殊类型的图片,











看成是一个filter。如上图 b 所示跨











沿着该embedding dimension(D)滑动该filter,获得一个hidden vector
















,这在CV中通常被称为一个feature map。在CIN命名中所使用的术语"compressed"表示了第k个hidden layer会将













向量的隐空间压缩到







向量中。

上图中,提供了CIN的一个总览。假设T表示网络的深度。每个hidden layer















具有一个与output units的连接。首先在hidden layer的每个feature map上使用sum pooling:





























其中,













。这样,就可以得到一个pooling vector:,对于第k个hidden layer相应的长度为







。hidden layers的所有polling vectors在连接到output units之前会被concatenated:。如果直接使用CIN进行分类,output unit是在







上的一个sigmoid节点:
































其中,







是回归参数。

CIN详解

论文对CIN进行分析,研究了模型复杂度以及潜在的效果。

空间复杂度

在第k层的第h个feature map,包含了













个参数,它与











具有相同的size。因而,在第k层上具有


















个参数。考虑到对于output unit的当前最近(the last)的regression layer,它具有
















个参数,CIN的参数总数是































。注意,CIN与embedding dimension D相互独立。相反的,一个普通的T-layers DNN包含了个参数,参数的数目会随着embedding dimension D而增长。

通常,m和







不会非常大,因而,











的规模是可接受的。当有必要时,我们可以利用一个L阶的分解,使用两个小的矩阵



























以及




















来替换













































其中






以及






。出于简洁性,论文假设每个hidden layer都具有相同数目(为H)的feature maps。尽管L阶分解,CIN的空间复杂度从












下降到

















。相反的,普通DNN的空间复杂度是















,它对于field embedding的维度D是敏感的。

时间复杂度

计算tensor











的开销是O(mHD)。由于在第一个hidden layer上具有H个feature maps,计算一个T-layers CIN会花费













时间。相反的,一个T-layer plain DNN,会花费















时间。因此,CIN的主要缺点是在时间复杂度上。

多项式近似(Polynomial Approximation)

接下来,作者检查了CIN的高阶交叉属性。出于简洁性,论文假设,在hidden layers上的feature maps数目,等于fields m的数目。假设[m]表示小于或等于m的正整数集。在第1层上的第h个feature map,表示为













,通过下式计算:

因此,在第1层的每个feature map会使用










个系数来建模pair-wise特征交叉。相似的,在第2层的第h个feature map为:

注意,l和k相关的所有计算在前一个hidden layer已经完成。在等式








扩展的因子是为了清晰。可以观察到,在第二层的每个feature map会使用










新参数来建模3-way交叉。

一个经典的k阶多项式具有










系数。展示了CIN会逼近这类型多项式,根据一个feature maps链,只需要











个参数。通过引入hypothesis,我们可以证明,在第k层的第h个feature map为:

为了更好地演示,假设

























表示一个multi-index,其中




















。会从








中忽略原始的上标,使用







来表示它,因为对于最终展开的表达式,只关心来自第0层(等同于field embedding)的feature maps。现在,使用一个上标来表示向量操作,比如























。假设











表示一个multi-vector 多项式的阶数k:

在该类中的每个向量多项式都具有










个系数。接着,我们的CIN接似系数









其中,





























是一个multi-index,







是索引(






















)的所有排列。

与隐式网络的组合

我们知道plain DNNs可以学到隐式高阶特征交叉。由于CIN和plain DNNs可以互补,一个直观的做法是,将这两种结构进行组合使模型更强。产生的模型与Wide&Deep和DeepFM非常像。结构如下图所示,新模型命名为eXtreme Deep Factorization Machine(xDeepFM),一方面,它同时包含了低阶和高阶特征交叉;另一方面,它包含了隐式特征交叉和显式特征交叉。它产生的output unit如下:

其中,a是原始特征。



















分别是是plain DNN和CIN的outputs。







和b是可学习的参数。对于二分类,loss函数为log loss:

其中,N是训练实例的总数。Optimization过程是最小化下面的目标函数:


















其中









表示正则项,




表示参数集,包含linear part,CIN part,DNN part。

与FM和DeepFM的关系

假设所有field是一阶的(univalent)。如上图所示(xDeepFM的结构),当depth和CIN part的feature maps同时设为1时,xDeepFM就是DeepFM的一个泛化,通过为FM layer学习线性回归权重实现(注意,在DeepFM中,FM layer的units直接与output unit相连,没有任何系数)。当我们进一步移去DNN part,并同时为该feature map使用一个constant sum filter(它简单采用输入求和,无需任何参数学习),接着xDeepFM就变成了传统的FM模型。

CIN 源码浅析

详细注释写在了代码中, 其中不太直观的地方有两处, 这里写了很简单的测试用例, 可以用于后续的参考:dot_result_m = tf.matmul(split_tensor0, split_tensor, transpose_b=True)

import tensorflow as tfB = 2
D = 3
m = 2
H = 2 ## 理解为 H_{k-1}
a = tf.reshape(tf.range(B * D * m, dtype=tf.float32),(B, m, D))
b = tf.split(a, D * [1], 2)
c = tf.matmul(b, b, transpose_b=True)with tf.Session() as sess:print(sess.run(tf.shape(c))) ## shape 为 [D, B, m, H_{k-1}]

curr_out = tf.nn.conv1d(dot_result, filters=self.filters[idx], stride=1, padding='VALID')

import tensorflow as tfB = 2
D = 3
E = 4  ## 代表 m * H_{k-1}
F = 5  ## 代表 H_{k}
a = tf.reshape(tf.range(B * D * E, dtype=tf.float32),(B, D, E))
b = tf.reshape(tf.range(1 * E * F, dtype=tf.float32),(1, E, F))
curr_out = tf.nn.conv1d(a, filters=b, stride=1, padding='VALID')with tf.Session() as sess:print(sess.run(tf.shape(curr_out))) ## 结果为 [B, D, H_{k}]

CIN 模块的代码如下:

class CIN(Layer):"""Compressed Interaction Network used in xDeepFM.This implemention isadapted from code that the author of the paper published on https://github.com/Leavingseason/xDeepFM.Input shape- 3D tensor with shape: ``(batch_size,field_size,embedding_size)``.Output shape- 2D tensor with shape: ``(batch_size, featuremap_num)`` ``featuremap_num =  sum(self.layer_size[:-1]) // 2 + self.layer_size[-1]`` if ``split_half=True``,else  ``sum(layer_size)`` .Arguments- **layer_size** : list of int.Feature maps in each layer.- **activation** : activation function used on feature maps.- **split_half** : bool.if set to False, half of the feature maps in each hidden will connect to output unit.- **seed** : A Python integer to use as random seed.References- [Lian J, Zhou X, Zhang F, et al. xDeepFM: Combining Explicit and Implicit Feature Interactions for Recommender Systems[J]. arXiv preprint arXiv:1803.05170, 2018.] (https://arxiv.org/pdf/1803.05170.pdf)"""def __init__(self, layer_size=(128, 128), activation='relu', split_half=True, l2_reg=1e-5, seed=1024, **kwargs):if len(layer_size) == 0:raise ValueError("layer_size must be a list(tuple) of length greater than 1")self.layer_size = layer_sizeself.split_half = split_halfself.activation = activationself.l2_reg = l2_regself.seed = seedsuper(CIN, self).__init__(**kwargs)def build(self, input_shape):if len(input_shape) != 3:raise ValueError("Unexpected inputs dimensions %d, expect to be 3 dimensions" % (len(input_shape)))self.field_nums = [int(input_shape[1])]self.filters = []self.bias = []for i, size in enumerate(self.layer_size):## layer_size 对应着论文中的 H_{k}, 表示 CIN 每层中 feature map 的个数## self.filters[i] 的 shape 为 [1, m * H_{k-1}, H_{k}]self.filters.append(self.add_weight(name='filter' + str(i),shape=[1, self.field_nums[-1] * self.field_nums[0], size],dtype=tf.float32, initializer=glorot_uniform(seed=self.seed + i),regularizer=l2(self.l2_reg)))## self.bias[i] 的 shape 为 [H_{k}]self.bias.append(self.add_weight(name='bias' + str(i), shape=[size], dtype=tf.float32,initializer=tf.keras.initializers.Zeros()))if self.split_half:if i != len(self.layer_size) - 1 and size % 2 > 0:raise ValueError("layer_size must be even number except for the last layer when split_half=True")self.field_nums.append(size // 2)else:self.field_nums.append(size)self.activation_layers = [activation_layer(self.activation) for _ in self.layer_size]super(CIN, self).build(input_shape)  # Be sure to call this somewhere!def call(self, inputs, **kwargs):## inputs 的 shape 为 [B, m, D], 其中 m 为 Field 的数量,## D 为 embedding size, 我注释的符号尽量和论文中的一样if K.ndim(inputs) != 3:raise ValueError("Unexpected inputs dimensions %d, expect to be 3 dimensions" % (K.ndim(inputs)))dim = int(inputs.get_shape()[-1]) # Dhidden_nn_layers = [inputs]final_result = []## split_tensor0 表示 list: [x1, x2, ..., xD], 其中 xi 的 shape 为 [B, m, 1]split_tensor0 = tf.split(hidden_nn_layers[0], dim * [1], 2)for idx, layer_size in enumerate(self.layer_size):## split_tensor 表示 list: [t1, t2, ..., tH_{k-1}], 即有 H_{k-1} 个向量;## 其中 ti 的 shape 为 [B, H_{k-1}, 1]split_tensor = tf.split(hidden_nn_layers[-1], dim * [1], 2)## dot_result_m 为一个 tensor, 其 shape 为 [D, B, m, H_{k-1}]dot_result_m = tf.matmul(split_tensor0, split_tensor, transpose_b=True)## dot_result_o 的 shape 为 [D, B, m * H_{k-1}]dot_result_o = tf.reshape(dot_result_m, shape=[dim, -1, self.field_nums[0] * self.field_nums[idx]])## dot_result 的 shape 为 [B, D, m * H_{k-1}]dot_result = tf.transpose(dot_result_o, perm=[1, 0, 2])## 牛掰啊, 还可以这样写, 精彩!## self.filters[idx] 的 shape 为 [1, m * H_{k-1}, H_{k}]## 因此 curr_out 的 shape 为 [B, D, H_{k}]curr_out = tf.nn.conv1d(dot_result, filters=self.filters[idx], stride=1, padding='VALID')## self.bias[idx] 的 shape 为 [H_{k}]## 因此 curr_out 的 shape 为 [B, D, H_{k}]curr_out = tf.nn.bias_add(curr_out, self.bias[idx])## curr_out 的 shape 为 [B, D, H_{k}]curr_out = self.activation_layers[idx](curr_out)## curr_out 的 shape 为 [B, H_{k}, D]curr_out = tf.transpose(curr_out, perm=[0, 2, 1])if self.split_half:if idx != len(self.layer_size) - 1:next_hidden, direct_connect = tf.split(curr_out, 2 * [layer_size // 2], 1)else:direct_connect = curr_outnext_hidden = 0else:direct_connect = curr_outnext_hidden = curr_outfinal_result.append(direct_connect)hidden_nn_layers.append(next_hidden)## 先假设不走 self.split_half 的逻辑, 此时 result 的## shape 为 [B, sum(H_{k}), D] (k=1 -> T, T 为 CIN 的总层数)result = tf.concat(final_result, axis=1)## result 最终的 shape 为 [B, sum(H_{k})]result = reduce_sum(result, -1, keep_dims=False)return result

往期精彩回顾适合初学者入门人工智能的路线及资料下载机器学习及深度学习笔记等资料打印机器学习在线手册深度学习笔记专辑《统计学习方法》的代码复现专辑
AI基础下载机器学习的数学基础专辑温州大学《机器学习课程》视频
本站qq群851320808,加入微信群请扫码:

【推荐系统】深入理解推荐系统:无需人工特征工程的xDeepFM相关推荐

  1. 大数据:“人工特征工程+线性模型”的尽头

    大数据:"人工特征工程+线性模型"的尽头 作者:李沐 来源:http://qing.blog.sina.com.cn/1953709481/74733da9330036o7.htm ...

  2. “人工特征工程+线性模型”的尽头

    11年的时候我加入百度,在凤巢使用机器学习来做广告点击预测.当时非常惊讶于过去两年内训练数据如此疯狂的增长.大家都在热情的谈特征,每次新特征的加入都能立即得到AUC的提升和收入的增长.大家坚信特征才是 ...

  3. 【王喆-推荐系统】(task4)Graph Embedding(特征工程篇)

    学习总结 (1)本次task学习Embedding中的Deep Walk和Node2vec算法,和Embedding在推荐系统的三种应用:直接应用.预训练应用和End2End训练应用. (2)Deep ...

  4. 【王喆-推荐系统】(task3)Embedding基础(特征工程篇)

    学习心得 (1)Word2vec 的研究中提出的模型结构.目标函数.负采样方法.负采样中的目标函数在后续的研究中被重复使用并被屡次优化.掌握 Word2vec 中的每一个细节成了研究 Embeddin ...

  5. 2.2w字长文详解推荐系统之数据与特征工程,码起来慢慢看

    作者丨gongyouliu 编辑丨lily 来源 | 大数据与人工智能(ID:ai-big-data) [导读]推荐系统是机器学习的一个子领域,并且是一个偏工程化.在工业界有极大商业价值的方向.大量应 ...

  6. 「构建企业级推荐系统系列」推荐系统之数据与特征工程

    作者 | gongyouliu 编辑 | auroral-L 推荐系统是机器学习的一个子领域,并且是一个偏工程化.在工业界有极大商业价值的方向.大量应用于提供toC类产品的互联网企业服务中,通过推荐系 ...

  7. 推荐系统之数据与特征工程

    点击上方"大数据与人工智能","星标或置顶公众号" 第一时间获取好内容 作者丨gongyouliu 编辑丨lily 这是作者的第25篇文章,约2.2w字,阅读需 ...

  8. 【转】【重要】推荐系统之数据与特征工程

    原文链接: 推荐系统之数据与特征工程 原文作者丨gongyouliu  来自 大数据与人工智能 推荐系统是机器学习的一个子领域,并且是一个偏工程化.在工业界有极大商业价值的方向.大量应用于提供toC类 ...

  9. 推荐系统特征工程的万字理论

    作者丨gongyouliu 编辑丨lily 这是作者的第25篇文章,约2.2w字,阅读需120分钟   推荐系统是机器学习的一个子领域,并且是一个偏工程化.在工业界有极大商业价值的方向.大量应用于提供 ...

最新文章

  1. Anacanda的安装
  2. js返回上一页并刷新代码整理
  3. Java集合框架:ArrayList扩容机制解释
  4. /proc/meminfo文件内容详解
  5. JSP 九大内置对象及四个作用域详解
  6. [云原生专题-11]:容器 - 如何构建自己的docker镜像:Docker Dockerfile
  7. 【Software】动软代码生成器
  8. 计算年龄:DATEDIF函数
  9. C Primer Plus(6) 中文版 第11章 字符串和字符串函数 11.1 表示字符串和字符串I/O
  10. 如何通过知识付费盈利,实现内容变现?
  11. 设计模式---002适配模式(转载自我的老师 Alley-巷子)
  12. 一键重装系统工具和U盘重装工具有什么区别?
  13. 【21.00%】【vijos P1018】智破连环阵
  14. find vba 模糊_利用VBA代码实现多重查找、模糊查找、清除值的方案
  15. 高德地图-添加路线规划(自驾、步行...)
  16. 【转】最全网上纳税申报流程
  17. 交易委托账本 order book
  18. 一键解决Windows照片查看器故障
  19. Gent OS7乱码
  20. inno setup怎么检测系统是否安装了vcredist_x86 exe

热门文章

  1. java多线程总结五:线程池的原理及实现
  2. 《幸福就在你身边》第七课、工作着,快乐着【哈佛大学幸福课精华】
  3. 鸡肋工具-Oracle建表工具
  4. unity_小功能实现(敌人巡逻功能)
  5. ThinkPHP5显示数据库字段内容
  6. Anaconda3中Python3.5和Python2.7共存
  7. 【代码笔记】iOS-在导航栏中显示等待对话框
  8. android手机短信拦截器,垃圾短信退订套路深 手机上装拦截软件是可行方法
  9. mano安全_爱立信:O-RAN存在的安全风险
  10. 30个数据可视化超级工具_Python5个数据可视化工具