一.引言

之前的文章中循序渐进的介绍过 LR,FM,WideAndDeep,有了这些模型的了解,接一下介绍当下比较流行的深度模型 DeepFm,WideAndDeep 结合了LR + DNN,DeepFM 结合了 FM + DNN,使得模型具备学习特征一阶,二阶以及高阶交叉的能力。

二.常见推荐系统

介绍DeepFM前,先看一下 LR,FM,DNN, WideAndDeep 以及 FM的演进过程:

1.LR

LR 是最早的线性模型,具备较强的记忆性,模型训练比较简单,因为只有一阶特征,所以有较好的解释性。

CSDN-BITDDD

2.FM

LR 一阶特征不能对交叉特征有较好的表征,FM 解决了这个问题,通过为每个特征训练隐向量,两个特征交叉的权重可以由隐向量内积得到,从而解决了特征二阶交叉的问题。

CSDN-BITDDD

3.DNN

LR 解决了一阶特征,FM 解决了二阶交叉特征,DNN 则解决了特征的高阶特征,随着层深度的增加,特征的交叉阶数不断地上升,模型有了更好的表征能力。

CSDN-BITDDD

4.WideAndDeep

WideAndDeep 结合了 LR 的记忆能力又综合了 DNN 的高阶特征组合,获得更加平滑的结果。

CSDN-BITDDD

5.DeepFM

既然 WideAndDeep 引入了一阶特征和高阶特征,那么也可以引入二阶特征,这就是 DeepFM。DeepFM 目的是同时学习低阶和高阶的特征交叉,弥补了 WideAndDeep 的表征能力不足,主要由 FM 与 DNN 两部分构成,二者共用同一份输入共同训练,输入模型可以看作 :

y = sigmoid(y_{FM} + y_{DNN})

CSDN-BITDDD

除了上述模型外,还有很多 FM,DeepFM 模型的衍生,例如 FFM,NFM,AFM,DIN,DIEN,DRN 等等,后续有时间可以研究~

三.DeepFM 自定义实现

上一篇文章已经对 FM 的具体公式,流程进行了详细分析,FM 侧相关问题可以参考 FM 自定义实现,下面基于 FM 层,在层内新增 DNN 单元,使得 Layer 可以同时训练 FM + DNN。

Tip:

导入类如下:

from tensorflow.keras import backend as K
from tensorflow.keras import layers, Model, optimizers, regularizers, losses
from tensorflow.keras.layers import Layer, Lambda, Dense, Input, Activation
import tensorflow as tf
import numpy as np

1.数据准备

    # 原始特征输入num_samples = 60000categoryA = np.random.randint(0, 100, (num_samples, 1))categoryB = np.random.randint(100, 200, (num_samples, 1))categoryC = np.random.randint(200, 300, (num_samples, 1))categoryD = np.random.randint(300, 400, (num_samples, 1))train = np.concatenate([categoryA, categoryB, categoryC, categoryD], axis=-1).astype('int32')print("训练数据样例与Size:")print(train[0:5])print(train.shape)labels = np.random.randint(0, 2, size=num_samples)labels = np.asarray(labels)print("样本labels:")print(labels[0:10])

num_samples 为训练样本数量,train 为训练数据,维度为 (None x 4),labels 为标签,取值为0/1,数据均为 random 随机构造。

训练数据样例与Size:
[[ 70 194 202 309][ 19 195 241 324][ 27 161 237 380][  6 196 237 374][ 43 191 219 316]]
(60000, 4)
样本labels:
[0 1 1 0 0 0 1 0 1 1]

2.DeepFM 层构建

DeepFM 层是 FM层 + DNN层,最后将二者的结果结合在一起 sigmoid 得到最终结果,所以 DeepFM层中需要单独实现 FM 与 DNN。这里按照 FM + 双隐层DNN 构造 DeemFm 模型。

(1) 输入参数含义 

feature_num : 特征数

output_dim : 隐向量输出维度

dense1_dim : 第一个隐层的维度

dense2_dim : 第二个隐层的维度

kernel_regularize : 正则化参数

activation : 激活函数

(2) 层内函数功能 

init : 根据传参初始化相关参数,其中 dense1_dim,dense2_dim 默认 128 维度。

build : 构建 FM 参数矩阵,构造两个 Dense 层的 kernel 与 偏置 bias

call : 将 FM + DNN 得到的结果 concat ,送给最后的 sigmoid 处理

compute_output_shape : 计算输出样本维度,供 keras 自动推断

Tips : 这里需要注意的就是各个 weights 的维度,其他的逻辑都比较清晰,FM 层实现逻辑与前文一致,Dense 层实现逻辑为 activation(self.kernel * Tensor + self.bias),其中 activation 选择为 relu。

relu = Lambda(lambda x: K.relu(x))
class DeepFM(Layer):"""init: 初始化参数build: 定义权重call: 层的功能与逻辑compute_output_shape: 推断输出模型维度"""def __init__(self, feat_num, out_dim, dense1_dim=128, dense2_dim=128, **kwargs):self.feature_num = feat_numself.output_dim = out_dimself.dense1_dim = dense1_dimself.dense2_dim = dense2_dimself.kernel_regularize = regularizers.l2(0.1)self.activation = Activation(relu)super().__init__(**kwargs)# 定义模型初始化 根据特征数目def build(self, input_shape):# 特征隐向量矩阵self.kernel = self.add_weight(name='kernel',shape=(self.feature_num, self.output_dim + 1),initializer='glorot_normal',regularizer=self.kernel_regularize,trainable=True)# DNN Dense1self.dense1 = self.add_weight(name='dense1',shape=(input_shape[1] * self.output_dim, self.dense1_dim),initializer='glorot_normal',trainable=True)# DNN Bias1self.bias1 = self.add_weight(name='bias1',shape=(self.dense1_dim, ),initializer='glorot_normal',trainable=True)# DNN Dense2self.dense2 = self.add_weight(name='dense2',shape=(self.dense1_dim, self.dense2_dim),initializer='glorot_normal',trainable=True)# DNN Bias1self.bias2 = self.add_weight(name='bias2',shape=(self.dense2_dim, ),initializer='glorot_normal',trainable=True)super(DeepFM, self).build(input_shape)  # Be sure to call this at the enddef call(self, inputs, **kwargs):# input 为多个样本的稀疏特征表示# LRfirst_order = get_first_order(inputs, self.kernel)# FMseconder_order = get_second_order(inputs, self.kernel)# DNNdeep_order = get_deep_order(inputs, self.kernel)activation_1 = self.activation(tf.matmul(deep_order, self.dense1) + self.bias1)activation_2 = self.activation(tf.matmul(activation_1, self.dense2) + self.bias2)# Concatconcat_order = tf.concat([first_order, seconder_order, activation_2], axis=-1)return concat_orderdef compute_output_shape(self, input_shape):return input_shape(0)

(3) FM 部分

这里结合使用了 tf.nn 以及 keras.backend 的 Api,FM 公式与简化结果如下 :

y=w_0 + \sum_{i=1}^{n}w_i x_i + \sum_{i=1}^{n-1}\sum_{j=i+1}^{n}(v_i\cdot v_j)x_i x_j =\frac{1}{2}\sum_{1}^{k}((\sum_{i=1}^{n}v_{i,f}x_i)^2-\sum_{1}^{n}v_{i,f}^2x_i^2)

# LR线性部分
def get_first_order(feat_index, args):embedding = tf.nn.embedding_lookup(args, feat_index)[:, :, -1]linear = K.sum(embedding, axis=-1)sum_embedding = K.expand_dims(linear, axis=1)return sum_embedding# FM二阶交叉部分
def get_second_order(feat_index, args):embedding = tf.nn.embedding_lookup(args, feat_index)[:, :, :args.shape[-1] - 1]# 先求和再平方sum_embedding = K.sum(embedding, axis=1)sum_square = K.square(sum_embedding)# 先平方在求和squared = K.square(embedding)square_sum = K.sum(squared, axis=1)# 二阶交叉项second_order = 0.5 * tf.subtract(sum_square, square_sum)return second_order

(4) DNN 部分

外部 DNN 模块只 lookup 了对应特征的 Embedding 并 Flatten,Dense 层的逻辑在 call 函数内实现,因为需要在层内初始化 Dense 的权重,这里 Dense 层没有直接调用 layers 选择自己实现,效果大同小异。

# DNN高阶交叉部分
def get_deep_order(feat_index, args):# FM Args Shape: Feature_num * (K + 1)# Embedding Shape: Samples_num * Feature_num * Kembedding = tf.nn.embedding_lookup(args, feat_index)[:, :, :args.shape[-1] - 1]# Flatten Shape: Samples_num * (Feature_num * K)embedding_flatten = layers.Flatten()(embedding)return embedding_flatten
# DNN
deep_order = get_deep_order(inputs, self.kernel)
activation_1 = self.activation(tf.matmul(deep_order, self.dense1) + self.bias1)
activation_2 = self.activation(tf.matmul(activation_1, self.dense2) + self.bias2)

3.DeepFM 模型编译

这里选择与上文 FM 相同的 feature_num 与 output_dim,由于是 CTR 问题,loss 依旧选择交叉熵,优化器可以自定义学习率等参数,其他参数也可自定义。

    # 构建模型feature_num = 400output_dim = 8deep_input = Input(shape=4, name='input', dtype='int32')deepFm_layer = DeepFM(feature_num, output_dim, name='DeepFM')(deep_input)result = Dense(1, activation='sigmoid', name='sigmoid')(deepFm_layer)deepFm_model = Model(deep_input, result)# 模型编译deepFm_model.compile(optimizer=optimizers.RMSprop(learning_rate=0.01),loss=losses.binary_crossentropy,metrics='accuracy')deepFm_model.summary()

4.模型训练与预测

epoch=10,batch_size=128训练模型,样本量为 60000。

    # 模型训练deepFm_model.fit(train, labels, epochs=10, batch_size=128)# 模型预测print("模型预测结果:")test_sample = [[1, 101, 201, 301], [7, 110, 222, 323], [81, 114, 270, 342], [63, 139, 204, 323],[33, 173, 201, 396]]print(deepFm_model.predict(test_sample))

由于样本随机,训练结果近似于随机预测。

5.隐向量权重获取

通过 layerName 获取对应 DeepFM 层,再根据索引获取对应权重即可,如果想获取 Dense 层和 Bias 权重,修改索引即可。

    # 获取线性权重与隐向量index = 100weights = deepFm_model.get_layer(name='DeepFM').get_weights()[0]vector = weights[index]print("V-隐向量")v = vector[:8]print(v)print(" W-线性:")w = vector[-1]print(w)

6.不同隐向量维度,Dense层维度,正则化系数对模型的影响

(1) 去掉FM层 L2 正则化参数 

去掉正则化参数模型的精度会提升,但是也会有过拟合。

(2) 增加隐向量维度 

增加隐向量维度,不修改 FM 正则化系数,模型效果变化不大。

(3) 增加 Dense 层维度 

Dense1_dim 和 Dense2_dim 扩大,不修改 FM 正则化系数,模型效果变化不大。

四.总结

有上一节 FM 的铺垫,这里在 FM 的基础上添加 DNN 并不困难,keras Api 的实现比较友好,但是有 bug 不好定位所以有利有弊,有问题欢迎交流~

更多推荐算法相关深度学习:深度学习导读专栏

深度学习 - 18.TF x Keras DeepFM 原理与实现相关推荐

  1. 深度学习 - 35.TF x Keras FM、WideAndDeep、DeepFM、DeepFwFM、DeepFmFM 理论与实战

    目录 一.引言 二.浅层模型概述 1.LR 2.FM 3.FMM 4.FwFM 5.FmFM 三.常用推荐算法实现 Pre.数据准备 1.FM 2.WideAndDeep 3.DeepFM 4.Dee ...

  2. 深度学习 - 9.TF x Keras 基于 Processing 与 Embedding 的文本处理

    一.引言: 处理 IMDB 数据集 demo 时,用到了很多文本转 onehot,文本转 embedding 的方法,下面整理一下. 本文后续样例测试数据集采用 IMDB 原始数据集,代表了用户对电影 ...

  3. 常用深度学习框——Caffe/TensorFlow / Keras/ PyTorch/MXNet

    常用深度学习框--Caffe/TensorFlow / Keras/ PyTorch/MXNet 一.概述 近几年来,深度学习的研究和应用的热潮持续高涨,各种开源深度学习框架层出不穷,包括Tensor ...

  4. 2_初学者快速掌握主流深度学习框架Tensorflow、Keras、Pytorch学习代码(20181211)

    初学者快速掌握主流深度学习框架Tensorflow.Keras.Pytorch学习代码 一.TensorFlow 1.资源地址: 2.资源介绍: 3.配置环境: 4.资源目录: 二.Keras 1.资 ...

  5. 深度学习(神经网络) —— BP神经网络原理推导及python实现

    深度学习(神经网络) -- BP神经网络原理推导及python实现 摘要 (一)BP神经网络简介 1.神经网络权值调整的一般形式为: 2.BP神经网络中关于学习信号的求取方法: (二)BP神经网络原理 ...

  6. 【深度学习系列】卷积神经网络CNN原理详解(一)——基本原理(1)

    上篇文章我们给出了用paddlepaddle来做手写数字识别的示例,并对网络结构进行到了调整,提高了识别的精度.有的同学表示不是很理解原理,为什么传统的机器学习算法,简单的神经网络(如多层感知机)都可 ...

  7. 推荐系统与深度学习(二)——FFM模型原理​

    作者:livan 来源:数据python与算法 前言 上一篇我们讲解了FM模型: 推荐系统与深度学习(一)--FM模型原理 从FM的公式我们可以看出: FM中每个特征所对应的向量是唯一的: Vi是Xi ...

  8. 【深度学习】1:感知器原理,以及感知器解决异或问题

    前言: 写完上一篇<KNN算法实现手写数字识别>到现在已经过去了十天,2018年伊始几天同学同事都是各种浪,自己坚持学习实在是痛苦啊! 不悲不气,闲话不多说了,开始自己神经网络的学习旅程吧 ...

  9. 手把手写深度学习(18):finetune微调CLIP模型的原理、代码、调参技巧

    前言:在前面的博客<手把手写深度学习(16):用CILP预训练模型搭建图文检索系统/以图搜图/关键词检索系统>中介绍了如何在图文检索.以图搜图.关键词检索等任务中使用CLIP.这篇博客重点 ...

最新文章

  1. Java线程有哪些不太为人所知的技巧与用法?
  2. 网传阿里一总裁 PPT 被员工拍照泄漏,新规划遭曝光
  3. RPi 2B UART作为调试口或者普通串口
  4. 如何写windbg高级脚本---以访问文件的windbg脚本为例说明
  5. win10下git的配置教程
  6. 服务器和操作系统怎么看,服务器和操作系统怎么看
  7. (原创)RHEL/CentOS 5.x使用yum快速安装MySQL 5.5.x
  8. 天玑800处理器支持鸿蒙系统吗,为何Redmi Note 9选择天玑800U处理器?和骁龙750G差距多大...
  9. [转载] Python 3 集合方法 remove( )
  10. MyBatis -- 对表进行增删改查(基于注解的实现)
  11. NVIDIA控制面板闪退
  12. DICOM worklist工作原理?
  13. 用手机打开word图表位置很乱_原来Word还可以自动生成图片和图表目录!
  14. 如何查找计算机密码cmd,教你如何查看计算机所连wifi密码
  15. Python环境下数据处理常用命令
  16. 程序设计算法竞赛高级——练习1解题报告
  17. 通过K-means对iris数据集进行处理 Kmeans聚类算法实例
  18. 如何在 iPhone 上设置整点报时提醒?
  19. 美团 python_Python | 美团差评数据分析
  20. 只会用Excel吗?这套全面的数据分析工具打包送你,拿走不谢

热门文章

  1. 加密市场进入寒冬,是“天灾”还是“人祸”?
  2. Linux下禁用T440s,X240的一体化触摸板(touchpad)
  3. Ant Design Pro 使用proxy无法设置cookies
  4. windows10永久禁用驱动强制签名
  5. 宁海县妇幼保健医院灾备建设
  6. ofstream的用法
  7. unbuntu14.04安装mxnet遇到的一些问题(未整理)
  8. python计算均方根误差_scikit学习:如何计算均方根误差(RMSE)的百分比?
  9. pr视频剪辑必备的6个音效、配乐素材网站。
  10. Burp Suite中intruder爆破模块四种模式的区别