引言
点击率(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),其中是一个d维向量,其中 是的第j个字段的向量表示。通常,x是高维且稀疏的。CTR预测的任务是构建一个预测模型,用于估计用户在特定场景下点击某个商品的概率。
给定用户-物品交互记录数据集,CTR预测旨在建模用户对物品的点击概率。输入特征通常包含类别型字段(如性别、位置)和连续型字段(如年龄),经编码后形成高维稀疏向量。模型的输出为概率值:
其中为稀疏特征向量,为特征维度。
1.2 核心挑战
- 特征交互复杂性:低阶(如一阶、二阶)与高阶(三阶及以上)交互均对预测有贡献。
- 数据稀疏性:类别型特征的独热编码导致输入维度极高且稀疏(如用户ID字段可达十亿维)。
- 端到端学习需求:传统方法依赖人工设计特征交互(如Wide & Deep),限制了模型泛化能力。
2. DeepFM模型架构
DeepFM由FM组件与深度组件构成,二者共享输入嵌入层,实现低阶与高阶特征交互的联合学习(见图1)。模型输出为:
其中为FM组件的输出,为深度组件的输出。
2.1 FM组件:低阶特征交互建模
FM通过隐向量内积建模二阶特征交互,解决了传统方法在稀疏数据下的参数估计问题。其数学形式为:
- 一阶项:捕获线性特征重要性。
- 二阶项:通过隐向量内积建模特征对的交互强度。
优势:
- 隐向量共享机制允许在特征共现极少时仍能有效学习交互参数。
- 计算复杂度优化至,适用于大规模稀疏数据。
2.2 深度组件:高阶特征交互建模
深度组件为前馈神经网络,通过多层非线性变换捕获高阶特征交互。其关键设计包括:
嵌入层(Embedding Layer)
- 将每个字段映射为定长稠密向量,解决输入稀疏性与维度爆炸问题。
- 权重共享:FM的隐向量直接作为嵌入层参数,实现两组件联合训练。
前向传播过程
其中为嵌入层输出,为激活函数(如ReLU),与为第层参数。最终输出为:
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_sizes
self.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_dim
self.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 = 0
sum_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)
参考文献
- Rendle, S. (2010). Factorization Machines. ICDM.
- Cheng, H. et al. (2016). Wide & Deep Learning for Recommender Systems. DLRS.
- Zhang, W. et al. (2016). Deep Learning over Multi-field Categorical Data. ECIR.
- Qu, Y. et al. (2016). Product-based Neural Networks for User Response Prediction. ICDM.
- 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.
- 王喆 《深度学习推荐系统》