DeepFM:融合因子分解机与深度学习的CTR预测模型

server/2025/2/9 5:19:00/

引言

点击率(Click-Through Rate, CTR)预测是推荐系统和计算广告领域的核心任务。传统方法通常依赖人工特征工程或单一模型架构,难以同时捕捉低阶与高阶特征交互。为了克服这些限制,研究者们不断探索新的模型架构,以更有效地学习特征间的复杂交互关系。2017年,由Huifeng Guo、Ruiming Tang、Yunming Ye、Zhenguo Li 和 Xiuqiang He 提出的 DeepFM 模型,为这一领域带来了新的突破

DeepFM 是一种创新的混合模型,通过无缝集成 因子分解机(Factorization Machine, FM)深度神经网络(Deep Neural Network, DNN) ,实现了端到端的特征交互学习。它不仅能够捕捉低阶特征交互(如线性和二阶交互),还能学习高阶特征交互,而无需复杂的特征工程。这种设计使得 DeepFM 在处理高维稀疏数据时表现出色,且无需预训练,曾经是工业界广泛采用的解决方案之一

DeepFM可以看做是Wide&Cross的扩展,与Deep&Cross模型一样都是将wide部分进行修改,以进行更充分的特征交叉

1.1 CTR预测任务

假设训练数据集包含n个实例(χ, y),其中χ是一个包含多个字段的数据记录,通常涉及用户和商品的配对,y ∈ {0, 1} 是与该配对相关的标签,表示用户的点击行为(y = 1表示用户点击了该商品,y = 0表示没有点击)。χ可以包括类别字段(如性别、位置)和连续字段(如年龄)。

  • 对于类别字段,采用one-hot编码表示,
  • 而连续字段则可以直接使用数值表示,或通过离散化后用one-hot编码表示

每个实例将被转换为 (x, y),其中 x = [ x f i e l d 1 , x f i e l d 2 , . . . , x f i e l d j , . . . , x f i e l d m ] x = [x_{field1}, x_{field2}, ..., x_{fieldj}, ..., x_{fieldm}] x=[xfield1,xfield2,...,xfieldj,...,xfieldm]是一个d维向量,其中 x f i e l d j x_{fieldj} xfieldj x x x的第j个字段的向量表示。通常,x是高维且稀疏的。CTR预测的任务是构建一个预测模型 y ^ = C T R m o d e l ( x ) \hat{y} = CTR model(x) y^=CTRmodel(x),用于估计用户在特定场景下点击某个商品的概率。

给定用户-物品交互记录数据集,CTR预测旨在建模用户对物品的点击概率。输入特征通常包含类别型字段(如性别、位置)和连续型字段(如年龄),经编码后形成高维稀疏向量。模型的输出为概率值:

y ^ = CTR_model ( x ) ∈ ( 0 , 1 ) \hat{y} = \text{CTR\_model}(x) \in (0,1) y^=CTR_model(x)(0,1)

其中 x ∈ R d x \in \mathbb{R}^d xRd为稀疏特征向量, d d d为特征维度。

1.2 核心挑战

  1. 特征交互复杂性:低阶(如一阶、二阶)与高阶(三阶及以上)交互均对预测有贡献。
  2. 数据稀疏性:类别型特征的独热编码导致输入维度极高且稀疏(如用户ID字段可达十亿维)。
  3. 端到端学习需求:传统方法依赖人工设计特征交互(如Wide & Deep),限制了模型泛化能力。

2. DeepFM模型架构

DeepFM由FM组件深度组件构成,二者共享输入嵌入层,实现低阶与高阶特征交互的联合学习(见图1)。模型输出为:

y ^ = sigmoid ( y FM + y DNN ) \hat{y} = \text{sigmoid}(y_{\text{FM}} + y_{\text{DNN}}) y^=sigmoid(yFM+yDNN)

其中 y FM y_{\text{FM}} yFM为FM组件的输出, y DNN y_{\text{DNN}} yDNN为深度组件的输出。
在这里插入图片描述

2.1 FM组件:低阶特征交互建模

FM通过隐向量内积建模二阶特征交互,解决了传统方法在稀疏数据下的参数估计问题。其数学形式为:

y FM = ⟨ w , x ⟩ + ∑ j 1 = 1 d ∑ j 2 = j 1 + 1 d ⟨ V i , V j ⟩ x j 1 x j 2 y_{\text{FM}} = \langle w, x \rangle + \sum_{j_1=1}^d \sum_{j_2=j_1+1}^d \langle V_i, V_j \rangle x_{j_1} x_{j_2} yFM=w,x+j1=1dj2=j1+1dVi,Vjxj1xj2

  • 一阶项 ⟨ w , x ⟩ \langle w, x \rangle w,x:捕获线性特征重要性。
  • 二阶项 ∑ ⟨ V i , V j ⟩ x j 1 x j 2 \sum \langle V_i, V_j \rangle x_{j_1}x_{j_2} Vi,Vjxj1xj2:通过隐向量 V i ∈ R k V_i \in \mathbb{R}^k ViRk内积建模特征对 ( i , j ) (i,j) (i,j)的交互强度。

优势

  • 隐向量共享机制允许在特征共现极少时仍能有效学习交互参数。
  • 计算复杂度优化至 O ( k d ) O(kd) O(kd),适用于大规模稀疏数据。

在这里插入图片描述

2.2 深度组件:高阶特征交互建模

深度组件为前馈神经网络,通过多层非线性变换捕获高阶特征交互。其关键设计包括:

嵌入层(Embedding Layer)
  • 将每个字段映射为定长稠密向量 e i ∈ R k e_i \in \mathbb{R}^k eiRk,解决输入稀疏性与维度爆炸问题。
  • 权重共享:FM的隐向量 V i V_i Vi直接作为嵌入层参数,实现两组件联合训练。
前向传播过程

a ( l + 1 ) = σ ( W ( l ) a ( l ) + b ( l ) ) a^{(l+1)} = \sigma\left(W^{(l)} a^{(l)} + b^{(l)}\right) a(l+1)=σ(W(l)a(l)+b(l))

其中 a ( 0 ) = [ e 1 , e 2 , … , e m ] a^{(0)} = [e_1, e_2, \dots, e_m] a(0)=[e1,e2,,em]为嵌入层输出, σ \sigma σ为激活函数(如ReLU), W ( l ) W^{(l)} W(l) b ( l ) b^{(l)} b(l)为第 l l l层参数。最终输出为:

y DNN = σ ( W ∣ H ∣ + 1 a H + b ∣ H ∣ + 1 ) y_{\text{DNN}} = \sigma\left(W^{|H|+1} a^{H} + b^{|H|+1}\right) yDNN=σ(WH+1aH+bH+1)

在这里插入图片描述

3. 创新点与技术优势

3.1 共享嵌入的联合学习机制

  • 参数共享:FM与DNN共享嵌入层,避免预训练并增强特征表示一致性。
  • 端到端训练:通过反向传播联合优化所有参数,提升模型收敛效率。

3.2 对比现有模型

模型特征交互类型需要预训练特征工程需求
FNN仅高阶是(FM初始化)
PNN高阶(乘积层)
Wide & Deep低阶+高阶高(需设计Wide部分)
DeepFM低阶+高阶

关键区别

  • FNN依赖FM预训练,导致嵌入表示受限于FM初始化。
  • Wide & Deep需人工设计Wide部分的交叉特征,而DeepFM通过FM自动实现。

3.3 实验结论

在这里插入图片描述

从表格可以看到,各种指标的提升都很小,但是引用原文的话:

  • “具体来说,DeepFM在AUC和Logloss两个关键指标上分别比竞争对手高出0.37%和0.42%。虽然这些提升看似微小,但在CTR预测领域,即使是微小的改进也可能带来巨大的商业价值。”
  • 根据Cheng等人(2016)的报告,与逻辑回归(LR)相比,Wide & Deep模型在AUC上提高了0.275%(离线),而在线CTR的提升达到了3.9% 考虑到Company*的应用商店每天的营业额高达数百万美元,即使是CTR的微小提升也能带来额外的数百万美元收益。因此,DeepFM模型在商业应用中的潜力巨大。

4. 代码实现

注意这里为了简化,考虑的是将数值型进行离散化ont-hot处理

class DeepFM(nn.Module):def __init__(self, feature_sizes, embedding_dim=10, hidden_dims=[64, 32], num_classes=1,dropout = 0.2):"""feature_sizes: 每个特征的唯一值数量列表embedding_dim: 嵌入维度hidden_dims: DNN隐藏层维度列表num_classes: 输出维度(二分类为1)"""super(DeepFM, self).__init__()self.feature_sizes = feature_sizesself.num_fields = len(feature_sizes)self.embedding_dim = embedding_dim#FM 一阶项self.linear = nn.Embedding(sum(feature_sizes) + 1, 1)#FM/DNN 共享嵌入层self.embedding = nn.ModuleList([nn.Embedding(dim, embedding_dim)for dim in feature_sizes])#DNN 部分dnn_input_dim = self.num_fields * embedding_dimself.dnn = nn.Sequential()for i, hidden_dim in enumerate(hidden_dims):self.dnn.add_module(name = f"fc_{i}",module = nn.Linear(dnn_input_dim, hidden_dim))self.dnn.add_module(name = f"bn_{i}",module = nn.BatchNorm1d(hidden_dim))self.dnn.add_module(name = f"relu_{i}",module = nn.ReLU())self.dnn.add_module(name = f"dropout_{i}",module = nn.Dropout(dropout))dnn_input_dim = hidden_dim#最终输出层self.dnn_output = nn.Linear(hidden_dims[-1], num_classes)#初始化权重self._initialize_weights()def _initialize_weights(self):for m in self.modules(): if isinstance(m, nn.Embedding):nn.init.xavier_normal_(m.weight) #使用Xavier初始化elif isinstance(m, nn.Linear):nn.init.xavier_normal_(m.weight)#原地修改nn.init.constant_(m.bias, 0) def forward(self,x):"""x: 输入特征 [batch_size, num_fields] (LongTensor)"""#FM 一阶项linear_part = torch.sum(self.linear(x), dim = 1) #[batch_size, 1]#获取嵌入向量embeds = []for i in range(self.num_fields):embed = self.embedding[i](x[:, i]) #[batch_size, embedding_dim]embeds.append(embed)#FM 二阶段项,注意这里采用化简公式计算fm_second_order = 0sum_embed = torch.stack(embeds, dim = 1) #[batch_size, num_fields, embedding_dim]sum_embed = torch.sum(sum_embed, dim = 1) #[batch_size, embedding_dim],其实就是将所有的特征与给加起来square_of_sum = sum_embed.pow(2) #[batch_size, embedding_dim]sum_of_square = torch.stack([e.pow(2) for e in embeds],dim = 1).sum(dim = 1) #[batch_size, embedding_dim]fm_second_order = 0.5 * (square_of_sum - sum_of_square).sum(dim = 1, keepdim = True) #[batch_size, 1]#DNN部分dnn_input = torch.cat(embeds, dim = 1) #[batch_size, num_fields * embedding_dim]dnn_output = self.dnn(dnn_input) #[batch_size, hidden_dims[-1]]dnn_final_output = self.dnn_output(dnn_output) #[batch_size, num_classes(二分类为1)]#输出output = linear_part + fm_second_order + dnn_final_output #[batch_size, num_classes(二分类为1)]return torch.sigmoid(output).squeeze(1)

参考文献

  1. Rendle, S. (2010). Factorization Machines. ICDM.
  2. Cheng, H. et al. (2016). Wide & Deep Learning for Recommender Systems. DLRS.
  3. Zhang, W. et al. (2016). Deep Learning over Multi-field Categorical Data. ECIR.
  4. Qu, Y. et al. (2016). Product-based Neural Networks for User Response Prediction. ICDM.
  5. Guo, H., Tang, R., Ye, Y., Li, Z., & He, X. (2017). DeepFM: A Factorization-Machine based Neural Network for CTR Prediction. arXiv preprint arXiv:1703.04247.
  6. 王喆 《深度学习推荐系统》

http://www.ppmy.cn/server/166129.html

相关文章

基于ArcGIS的SWAT模型+CENTURY模型模拟流域生态系统水-碳-氮耦合过程研究

流域是一个相对独立的自然地理单元,它是以水系为纽带,将系统内各自然地理要素连结成一个不可分割的整体。碳和氮是陆地生态系统中最重要的两种化学元素,而在流域系统内,水-碳-氮是相互联动、不可分割的耦合体。随着流域内人类活动…

ansible自动化运维

ansible自动化运维 1、实现远程连接主机 2、批量配置,批量操作,ansible可以对主机进行组划分,也可以把名下所有的主机进行划分,进行批量的操作。 3、远程自动化运维(脚本-------------playbook剧本) an…

自定义飞书Webhook机器人api接口

自定义飞书Webhook机器人api接口 使用方法: 在网站目录新建一个名为api.php的文件,将以上代码粘贴进去即可 然后访问域名/api.php?title洛小柒 - QQ沐编程&content小柒祝大家新年快乐!&urlwww.qqmu.com&type1 title是标题 con…

用 HTML、CSS 和 JavaScript 实现抽奖转盘效果

顺序抽奖 前言 这段代码实现了一个简单的抽奖转盘效果。页面上有一个九宫格布局的抽奖区域,周围八个格子分别放置了不同的奖品名称,中间是一个 “开始抽奖” 的按钮。点击按钮后,抽奖区域的格子会快速滚动,颜色不断变化&#xf…

基于ssm的药店管理系统

一、系统架构 前端:jsp | bootstrap | jquery | css | ajax 后端:spring| springmvc | mybatis 环境:jdk1.8 | mysql | maven | tomcat 二、代码及数据 三、功能介绍 01. 注册 02. 登录 03. 管理员-药品基础信息 04.…

DeepSeek 的含金量还在上升

大家好啊,我是董董灿。 最近 DeepSeek 越来越火了。 网上有很多针对 DeepSeek 的推理测评,除此之外,也有很多人从技术的角度来探讨 DeepSeek 带给行业的影响。 比如今天就看到了一篇文章,探讨 DeepSeek 在使用 GPU 进行模型训练…

团体程序设计天梯赛-练习集——L1-034 点赞

前言 20分的题目题目不难,理解也不难,做起来有点问题 L1-034 点赞 微博上有个“点赞”功能,你可以为你喜欢的博文点个赞表示支持。每篇博文都有一些刻画其特性的标签,而你点赞的博文的类型,也间接刻画了你的特性。本…

自定义数据集 使用pytorch框架实现逻辑回归并保存模型,然后保存模型后再加载模型进行预测,对预测结果计算精确度和召回率及F1分数

自定义数据集:继承 torch.utils.data.Dataset 类创建自定义数据集,并重写 __len__ 和 __getitem__ 方法。 定义逻辑回归模型:继承 nn.Module 类,定义一个线性层,并在 forward 方法中应用sigmoid激活函数。 训…