CTR 系列文章:

  1. 广告点击率(CTR)预测经典模型 GBDT + LR 理解与实践(附数据 + 代码)
  2. CTR经典模型串讲:FM / FFM / 双线性 FFM 相关推导与理解
  3. CTR深度学习模型之 DeepFM 模型解读
  4. 【CTR模型】TensorFlow2.0 的 DeepFM 实现与实战(附代码+数据)
  5. CTR 模型之 Deep & Cross (DCN) 与 xDeepFM 解读
  6. 【CTR模型】TensorFlow2.0 的 DCN(Deep & Cross Network) 实现与实战(附代码+数据)
  7. 【CTR模型】TensorFlow2.0 的 xDeepFM 实现与实战(附代码+数据)

本篇文章讲解 xDeepFM 的 tensorflow2.0 实现,并使用 Criteo 数据集的子集加以实践。如果在看本文时有所困惑,可以看看 xDeepFM 的相关理论:CTR 模型之 Deep & Cross (DCN) 与 xDeepFM 解读。

本文使用的数据下载地址于代码获取地址在文末获取。

首先了解一下 Criteo数据集,它由有39个特征,1个label列,其中以I开头的为数值型特征,以C开头的为类别特征:

可以看到数据中有缺失值需要填充,并且类别变量需要进行类别编码(onehot 编码的任务交给模型),这部分预处理的代码不详细讲了。

为了方便后面建立模型,先将特征划分为 dense 特征与 sparse 特征两个类别:

# 数值型
dense_feats = [f for f in cols if f[0] == "I"]
# 类别型
sparse_feats = [f for f in cols if f[0] == "C"]

xDeepFM 网络结构如下:

构造模型输入

对于 dense 特征,按下面的代码构造输入:

# 构造每个 dense 特征的输入
dense_inputs = []
for f in dense_feats:_input = Input([1], name=f)dense_inputs.append(_input)# 将输入拼接到一起
concat_dense_inputs = Concatenate(axis=1)(dense_inputs)  # ?, 13# 对dense特征加权求和
fst_order_dense_layer = Dense(1)(concat_dense_inputs)

上面代码的注释中 ? 表示输入数据的 batch_size。

对于每一个 sparse 特征,一般都是进行one-hot以后再转化为embedding特征,但实际上由于稀疏性的存在,很多位置的 xix_ixi 取0时,对应的 wixiw_i x_iwixi 也为0。因此,可以将 sparse 特征 embedding 到 1维,然后通过 embedding lookup 的方式来找到对应的 wiw_iwi

这里举个例子:假设我们的性别特征取值有-1,0,1三种,某个样本的取值为1,则其one-hot以后为[0, 0, 1]向量,我们进行线性回归时会得到 w1×0+w2×0+w3×1w_1 \times 0 + w_2 \times 0 +w_3 \times 1w1×0+w2×0+w3×1 ,仅仅只有 w3w_3w3 被保留下来。因此,可以对性别构造一个 3*1 的 embedding 向量,然后通过 embedding lookup 得到系数。

对于 sparse 特征,按下面的代码构造输入:

# 这里单独对每一个 sparse 特征构造输入,
# 目的是方便后面构造交叉特征
sparse_inputs = []
for f in sparse_feats:_input = Input([1], name=f)sparse_inputs.append(_input)sparse_1d_embed = []
for i, _input in enumerate(sparse_inputs):f = sparse_feats[i]voc_size = total_data[f].nunique()# 使用 l2 正则化防止过拟合reg = tf.keras.regularizers.l2(0.5)_embed = Embedding(voc_size, 1, embeddings_regularizer=reg)(_input)# 由于 Embedding 的结果是二维的,# 因此如果需要在 Embedding 之后加入 Dense 层,则需要先连接上 Flatten 层_embed = Flatten()(_embed)sparse_1d_embed.append(_embed)# 对sparse特征加权求和
fst_order_sparse_layer = Add()(sparse_1d_embed)

然后将 dense 特征与 sparse 特征加权求和结果相加,完成模型最左侧的 Linear 部分:

linear_part = Add()([fst_order_dense_layer, fst_order_sparse_layer])

Compressed Interaction Network

终于来到最核心的 CIN 部分,此部分的网络结构如下图所示:

CIN 的输入来自 embedding 层,假设有 m 个 field,每个 field 的 embedding 维度为 D ,则输入可以表示为矩阵 X0∈Rm∗DX^0 \in \mathbb R^{m * D}X0RmD。为了得到 X0X^0X0,在进入 CIN 网络之前,需要先将 sparse 特征进行 embedding 并构建 X0X^0X0

# embedding size
D = 8sparse_kd_embed = []
for i, _input in enumerate(sparse_inputs):f = sparse_feats[i]voc_size = data[f].nunique()reg = tf.keras.regularizers.l2(0.7)_embed = Embedding(voc_size+1, D, embeddings_regularizer=reg)(_input)sparse_kd_embed.append(_embed)# 构建feature mmap X0
input_feature_map = Concatenate(axis=1)(sparse_kd_embed)

CIN 内部有 k 层,每一层都会输出一个矩阵 Xk∈RHk∗DX^k \in \mathbb R^{H_k * D}XkRHkD ,k 表示第 k 层的输出, HkH_kHk 表示第 k 层有 HkH_kHk 个维度为 D 的向量。要得到 XkX^{k}Xk ,需要接收两个矩阵作为输入,一个是 Xk−1X^{k-1}Xk1 ,另一个是 X0X^0X0 ,具体的计算公式如下:
Xh,∗k=∑i=1Hk−1∑j=1mWijk,h(Xi,∗k−1∘Xj,∗0)∈R1∗D,where 1≤h≤Hk\boldsymbol{X}_{h, *}^{k}=\sum_{i=1}^{H_{k-1}} \sum_{j=1}^{m} \boldsymbol{W}_{i j}^{k, h}\left(\boldsymbol{X}_{i, *}^{k-1} \circ \boldsymbol{X}_{j, *}^{0}\right) \in \mathbb{R}^{1 * D}, \quad \text { where } 1 \leq h \leq H_{k} Xh,k=i=1Hk1j=1mWijk,h(Xi,k1Xj,0)R1D,where1hHk
其中 Wk,h∈RHk−1∗mW^{k, h} \in \mathbb R^{H_{k-1} * m}Wk,hRHk1m,表示要得到第 k 层第 h 个向量所需要的权重矩阵, Hk−1H_{k-1}Hk1 表示第 k−1k-1k1 层的输出矩阵 Xk−1X^{k-1}Xk1Hk−1H_{k-1}Hk1 个维度为 D 的向量组成。∘\circ 表示Hadamard乘积。式子中 Xi,∗k−1∘Xj,∗0\boldsymbol{X}_{i, *}^{k-1} \circ \boldsymbol{X}_{j, *}^{0}Xi,k1Xj,0 是表示取出 Xk−1X^{k-1}Xk1 的第 iii 个向量与输入层 X0X^{0}X0 中第 jjj 个向量进行 Hadamard 乘积运算。这个部分的计算过程如下图所示:

此公式的实现代码如下:

def compressed_interaction_net(x0, xl, D, n_filters):"""@param x0: 原始输入@param xl: 第l层的输入@param D: embedding dim@param n_filters: 压缩网络filter的数量"""# 这里设x0中共有m个特征,xl中共有h个特征# 1.将x0与xl按照k所在的维度(-1)进行拆分,每个都可以拆成D列x0_cols = tf.split(x0, D, axis=-1)  # ?, m, Dxl_cols = tf.split(xl, D, axis=-1)  # ?, h, Dassert len(x0_cols)==len(xl_cols), print("error shape!")# 2.遍历D列,对于x0与xl所在的第i列进行外积计算,存在feature_maps中feature_maps = []for i in range(D):# transpose_b=True 将 x0_cols[i] 转置feature_map = tf.matmul(xl_cols[i], x0_cols[i], transpose_b=True)  # 外积 ?, h, mfeature_map = tf.expand_dims(feature_map, axis=-1)  # ?, h, m, 1feature_maps.append(feature_map)# 3.得到 h × m × D 的三维tensorfeature_maps = Concatenate(axis=-1)(feature_maps)  # ?, h, m, D# 3.压缩网络x0_n_feats = x0.get_shape()[1]  # mxl_n_feats = xl.get_shape()[1]  # hreshaped_feature_maps = Reshape(target_shape=(x0_n_feats * xl_n_feats, D))(feature_maps)  # ?, h*m, Dtransposed_feature_maps = tf.transpose(reshaped_feature_maps, [0, 2, 1])  # ?, D, h*m# Conv1D:使用 n_filters 个形状为 1 * (h*m) 的卷积核以 1 为步长,# 按嵌入维度 D 的方向进行卷积,最终得到形状为 ?, D, n_filters 的输出new_feature_maps = Conv1D(n_filters, kernel_size=1, strides=1)(transposed_feature_maps)  # ?, D, n_filters# 为了保持输出结果最后一维 为嵌入维度 D ,需要进行转置操作new_feature_maps = tf.transpose(new_feature_maps, [0, 2, 1])  # ?, n_filters, Dreturn new_feature_maps

代码中分为三步:

  • 第一步将输入的两个需要交互的 feature maps 分成 D 列
  • 第二步计算交互的三维 tensor,即在每个维度上进行向外积操作
  • 第三步使用一维的卷积操作得到当前层的输出

这里 n_filters 是经过该 CIN 层后,输出的 feature map 的个数,也就是说最终生成了由 n_filters 个 D 维向量组成的输出矩阵。

有了单层的 CIN 实现,我们紧接着可以实现多层的CIN网络,这里要注意的是 CIN 网络的输出是将每一层的 feature maps 进行 sum pooling,然后 concat 起来。相关代码实现如下:

def build_cin(x0, D=8, n_layers=3, n_filters=12):"""构建多层CIN网络@param x0: 原始输入的feature maps: ?, m, D@param D: 特征embedding的维度@param n_layers: CIN网络层数@param n_filters: 每层CIN网络输出的feature_maps的个数"""# 存储每一层cin sum pooling的结果pooling_layers = []xl = x0for layer in range(n_layers):xl = compressed_interaction_net(x0, xl, D, n_filters)# sum poolingpooling = Lambda(lambda x: K.sum(x, axis=-1))(xl)pooling_layers.append(pooling)# 将所有层的pooling结果concat起来output = Concatenate(axis=-1)(pooling_layers)return output
# 生成 CIN
cin_layer = build_cin(input_feature_map)

经过 3 层的 CIN 网络,每一层的 filter 是12,意味着会产出 3 个 12*D 的 feature maps,再经过 sum-pooling 和 concat 操作后,就得到 3*12=36 维的向量。

DNN 部分

这部分好理解,直接上代码吧:

embed_inputs = Flatten()(Concatenate(axis=-1)(sparse_kd_embed))fc_layer = Dropout(0.5)(Dense(128, activation='relu')(embed_inputs))
fc_layer = Dropout(0.3)(Dense(128, activation='relu')(fc_layer))
fc_layer_output = Dropout(0.1)(Dense(128, activation='relu')(fc_layer))

输出部分

代码如下:

concat_layer = Concatenate()([linear_part, cin_layer, fc_layer_output])
output_layer = Dense(1, activation='sigmoid')(concat_layer)
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["binary_crossentropy", tf.keras.metrics.AUC(name='auc')])

完善模型

model = Model(dense_inputs+sparse_inputs, output_layer)
model.compile(optimizer="adam", loss="binary_crossentropy", metrics=["binary_crossentropy", tf.keras.metrics.AUC(name='auc')])

训练模型

train_data = total_data.loc[:500000-1]
valid_data = total_data.loc[500000:]train_dense_x = [train_data[f].values for f in dense_feats]
train_sparse_x = [train_data[f].values for f in sparse_feats]
train_label = [train_data['label'].values]val_dense_x = [valid_data[f].values for f in dense_feats]
val_sparse_x = [valid_data[f].values for f in sparse_feats]
val_label = [valid_data['label'].values]model.fit(train_dense_x+train_sparse_x, train_label, epochs=5, batch_size=128,validation_data=(val_dense_x+val_sparse_x, val_label),)

最后,本文的代码链接在:https://github.com/zxxwin/tf2_xDeepFM 。

数据下载地址为:链接:https://pan.baidu.com/s/1Qy3yemu1LYVtj0Wn47myHQ 提取码:pv7u

参考文章:

CTR预估模型:DeepFM/Deep&Cross/xDeepFM/AutoInt代码实战与讲解

NELSONZHAO/zhihu/ctr_models/xDeepFM

【CTR模型】TensorFlow2.0 的 xDeepFM 实现与实战(附代码+数据)相关推荐

  1. 【CTR模型】TensorFlow2.0 的 DeepFM 实现与实战(附代码+数据)

    CTR 系列文章: 广告点击率(CTR)预测经典模型 GBDT + LR 理解与实践(附数据 + 代码) CTR经典模型串讲:FM / FFM / 双线性 FFM 相关推导与理解 CTR深度学习模型之 ...

  2. 【CTR模型】TensorFlow2.0 的 DCN(Deep Cross Network) 实现与实战(附代码+数据)

    CTR 系列文章: 广告点击率(CTR)预测经典模型 GBDT + LR 理解与实践(附数据 + 代码) CTR经典模型串讲:FM / FFM / 双线性 FFM 相关推导与理解 CTR深度学习模型之 ...

  3. Tensorflow2.0深度学习入门与实战(日月光华)(学习总结1)

    Tensorflow2.0深度学习入门与实战(学习总结1) 我是刚学的,网易云课堂跟着日月光华老师,现在对每节课的学习课程做一下记录,总结,仅仅作为总结. 1.使用快捷键 shift+enter执行代 ...

  4. tensorflow2.0 循环神经网络--情感分类实战

    tensorflow2.0 循环神经网络–情感分类实战代码 本文主要是情感分类单层实战RNN Cell代码 import os import numpy as np import tensorflow ...

  5. tensorflow 保存训练loss_tensorflow2.0保存和加载模型 (tensorflow2.0官方教程翻译)

    最新版本:https://www.mashangxue123.com/tensorflow/tf2-tutorials-keras-save_and_restore_models.html 英文版本: ...

  6. ​TensorFlow2.0系列教程集合版(附PDF下载)

    文章来源于机器学习算法与Python实战,作者奥辰 TensorFlow2.0(1):基本数据结构--张量 TensorFlow2.0(2):数学运算 TensorFlow2.0(3):张量排序.最大 ...

  7. 生成式对抗网络GAN之实现手写字体的生成(基于keras Tensorflow2.0实现)详细分析训练过程和代码

  8. T-S模糊模型与状态反馈控制及Matlab仿真 (附代码)

    目录 (一) 仿射非线性系统建模 (二) 计算T-S模糊模型子系统 (三) 建立推理,验证开环特性 (四) 极点配置,验证闭环特性 (五) 使用LMI验证稳定性 (一) 仿射非线性系统建模 以over ...

  9. tensorflow2.0实现DeepFM

    文章目录 数据预处理 模型的构建与训练 FM部分 一阶特征 二阶(交叉)特征 DNN部分 组合FM和DNN 模型训练 本文基于tensorflow2.0实现的DeepFM 结构.数据集: Criteo ...

最新文章

  1. u盘复制不进去东西_限制电脑只能识别自己指定的U盘
  2. hdoop(2)——hdfs一些常用的配置文件
  3. CodeForces - 1213E Two Small Strings(暴力+构造)
  4. matlab高斯滤波跟中值滤波区别,matlab图像滤波处理代码讲解 均值滤波 中值滤波 高斯滤波...
  5. SpringCloud之RestTemplate,几种常见的请求方式
  6. local class cannot see outer class defined type, even if it is public
  7. CyclicBarrier-同步辅助类
  8. 两条信号之间加电容_模电总结:第七章、波形的发生和信号的转换,正弦波振荡的电路...
  9. 楼主,不知道为什么这么流行
  10. kali linux中文版安装
  11. 阿里巴巴未来十年使命、愿景和价值观
  12. Android音频数据格式概述
  13. Microsoft Office SharePoint Designer 2007 宣布免费
  14. 浅谈微信活码架构及其简易实现
  15. 电脑显示器屏幕看不清灰色,灰色部分都几乎呈现白色状态的解决办法。
  16. 一文带你了解步进电机的相关知识:相、线、极性和步进方式
  17. 不想被甲方折磨?移动互联网的9大趋势知道一个算你牛
  18. 记录一个换了intel+主板换成 AMD 5800X之后蓝屏问题
  19. Docker安装Weblogic
  20. 5G 帧结构、物理资源与物理信道

热门文章

  1. stanford python中文分词
  2. Matlab-OpenCV-VC-混合编程配置
  3. 一个numpy报错——ValueError: Object arrays cannot be loaded when allow_pickle=False
  4. 7.4.5 鲁棒主成分分析 PCA
  5. produces在@requestMapping中的使用方式和作用
  6. VS中生成时“sgen.exe”已退出,代码为 1解决办法
  7. 有关字符编码学习记录
  8. Redis基础知识之————如何处理客户端连接
  9. 20145237 《信息安全系统设计基础》第2周学习总结
  10. MySQL 5.6 Threadpool(优先队列)介绍及性能测试【转】