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

本文详细介绍了如何在TensorFlow2.0中实现DeepFM模型,包括FM部分的一、二阶特征组合,以及DNN部分的结构。通过实例展示了在Criteo数据集上的应用,并提供了完整的代码实现。此外,还提及了CTR预测模型的系列文章,以及数据和代码的获取途径。
摘要由CSDN通过智能技术生成

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 实现与实战(附代码+数据)

本篇文章讲解 DeepFM 的 tensorflow2.0 实现,并使用 Criteo 数据集的子集加以实践。如果在看本文时有所困惑,可以看看DeepFM的相关理论: CTR深度学习模型之 DeepFM 模型解读

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

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

在这里插入图片描述

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

而下面这张图是 DeepFM 的网络结构:

在这里插入图片描述

FM 部分

一阶特征

要构建立此模型,第一步是要构造模型的输入并且对各个输入进行加权求和,如下图绿色箭头所示:

在这里插入图片描述

在 CTR 任务中,数据主要分为两个类型,一种是数值型的连续变量(Dense type),另一种是类别型的离散数(Sparse type)。为了更方便的构造模型的输入,我们先提取出不同类型的特征:

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

对于数值型特征,构造其模型输入与加权求和的代码如下:

# 构造每个 dense 特征的输入
dense_inputs = []
for f in dense_feats:
    _input = Input([1], name=f)
    dense_inputs.append(_input)
# 将输入拼接到一起,方便连接 Dense 层
concat_dense_inputs = Concatenate(axis=1)(dense_inputs)  # ?, 13
# 然后连上输出为1个单元的全连接层,表示对 dense 变量的加权求和
fst_order_dense_layer = Dense(1)(concat_dense_inputs)  # ?, 1

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

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

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

相关 embedding 与加权求和的代码如下:

# 这里单独对每一个 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)
# 对每个 embedding lookup 的结果 wi 求和
fst_order_sparse_layer = Add()(sparse_1d_embed)

到这里为止,分别完成了对 Dense 特征与 Sparse 特征的加权求和,接下来就是将二者的结果再求和:

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

到这里,上图中绿色箭头表示的加权求和的功能就实现了。

二阶特征组合

对于 FM 模块而言,在进行特征组合之前,每个 sparse 特征需要先进行 embedding,如下图中绿色方框所示:

在这里插入图片描述

相关代码如下:

# embedding size
k = 8

# 只考虑sparse的二阶交叉
sparse_kd_embed = []
for i, _input in enumerate(sparse_inputs):
    f = sparse_feats[i]
    # 注意,nan 不会被 nunique() 所统计
    voc_size = total_data[f].nunique()
    reg = tf.keras.regularizers.l2(0.7)
    _embed = Embedding(voc_size, k, embeddings_regularizer=reg)(_input)
    sparse_kd_embed.append(_embed)

接下来就是要进行特征组合,如果对 n 个 sparse 特征两两组合,那么复杂度应该是 O ( n 2 ) O(n^2) O(n2) ,但是可以对特征组合的公式加以化简:
∑ i = 1 n ∑ j = i + 1 n < v i , v j > x i x j = 1 2 ∑ i = 1 n ∑ j = 1 n < v i , v j > x i x j − 1 2 ∑ i = 1 n < v i , v i > x i x i = 1 2 ( ∑ i = 1 n

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值