1. DeepFM模型的核心思想
第一次听说DeepFM是在一个推荐系统的技术分享会上。当时主讲人提到这个模型在点击率预测任务中的表现非常出色,我立刻被它巧妙的设计吸引了。DeepFM最大的特点就是把因子分解机(FM)和深度神经网络(DNN)结合在了一起,让模型既能捕捉低阶特征组合,又能学习高阶特征交互。
传统模型要么像逻辑回归那样只能处理线性关系,要么像Wide&Deep那样需要人工设计特征交叉。而DeepFM完全端到端,自动学习所有阶数的特征组合。我在电商平台的推荐系统项目里实测过,相比单纯的FM模型,DeepFM的AUC能提升2-3个百分点。
2. 模型架构详解
2.1 输入层设计
在实际项目中,输入数据通常包含连续型和离散型特征。比如用户年龄是连续值,而用户性别是离散值。离散特征需要先做One-Hot编码,这会导致特征空间变得高维稀疏。为了解决这个问题,DeepFM引入了嵌入层(Embedding Layer)。
举个例子,假设有个"城市"特征,取值有北京、上海、广州。One-Hot编码后会变成3维向量。通过嵌入层,我们可以把它压缩到一个固定长度的稠密向量(比如4维)。这样不管原始特征有多少取值,嵌入后的维度都是固定的。
2.2 FM组件实现
FM部分负责捕捉二阶特征交互。它的核心思想是为每个特征学习一个隐向量,通过隐向量的内积来计算特征组合的权重。这样即使某些特征组合在训练数据中很少出现,也能得到合理的预测。
在PyTorch中实现时有个小技巧:FM的计算可以优化为线性复杂度。原始公式需要计算所有特征两两组合,但通过数学变换可以改写成:
sum_square = (所有特征和)^2
square_sum = 所有(特征^2)的和
FM = 0.5*(sum_square - square_sum)
这样计算量从O(n^2)降到了O(n),对大规模数据特别重要。
2.3 DNN组件实现
DNN部分是全连接网络,负责学习高阶特征交互。它的输入是嵌入层输出的拼接向量。这里有个关键点:DNN和FM共享同一个嵌入层。这种设计不仅减少了参数量,还能让两部分互相促进学习。
我在实现时通常会加一些技巧:
- 使用BatchNorm加速收敛
- 添加Dropout防止过拟合
- 使用LeakyReLU替代普通ReLU
- 网络深度一般3-4层,每层维度逐渐减小
3. PyTorch完整实现
3.1 数据预处理
先看一个实际的数据处理例子。假设我们有以下特征:
- 连续特征:用户年龄、商品价格
- 离散特征:用户性别、商品类别
import torch
from sklearn.preprocessing import LabelEncoder, MinMaxScaler
# 连续特征归一化
scaler = MinMaxScaler()
continuous_features = ['age', 'price']
data[continuous_features] = scaler.fit_transform(data[continuous_features])
# 离散特征编码
label_encoders = {}
categorical_features = ['gender', 'category']
for feat in categorical_features:
le = LabelEncoder()
data[feat] = le.fit_transform(data[feat])
label_encoders[feat] = le
3.2 模型定义
下面是模型的核心代码:
import torch.nn as nn
class DeepFM(nn.Module):
def __init__(self, feature_sizes, embedding_size=4,
hidden_dims=[64,32], dropout=0.2):
super().__init__()
# 特征信息
self.field_size = len(feature_sizes)
self.feature_sizes = feature_sizes
# FM部分
self.fc = nn.Embedding(sum(feature_sizes), 1) # 一阶项
self.embeddings = nn.Embedding(sum(feature_sizes), embedding_size)
# DNN部分
self.dnn = nn.Sequential(
nn.Linear(self.field_size*embedding_size, hidden_dims[0]),
nn.BatchNorm1d(hidden_dims[0]),
nn.LeakyReLU(),
nn.Dropout(dropout),
nn.Linear(hidden_dims[0], hidden_dims[1]),
nn.BatchNorm1d(hidden_dims[1]),
nn.LeakyReLU(),
nn.Dropout(dropout),
nn.Linear(hidden_dims[1], 1)
)
# 初始化权重
self._initialize_weights()
def _initialize_weights(self):
for m in self.modules():
if isinstance(m, nn.Embedding):
nn.init.normal_(m.weight, mean=0, std=0.01)
elif isinstance(m, nn.Linear):
nn.init.xavier_normal_(m.weight)
def forward(self, x):
# FM一阶项
first_order = self.fc(x).sum(dim=1)
# FM二阶项
emb = self.embeddings(x)
square_of_sum = torch.sum(emb, dim=1)**2
sum_of_square = torch.sum(emb**2, dim=1)
second_order = 0.5*(square_of_sum - sum_of_square).sum(dim=1, keepdim=True)
# DNN部分
dnn_input = emb.view(-1, self.field_size*self.embedding_size)
dnn_output = self.dnn(dnn_input)
# 组合输出
output = torch.sigmoid(first_order + second_order + dnn_output)
return output
3.3 训练技巧
训练时我发现这些技巧很有效:
- 学习率设为0.001,使用Adam优化器
- Batch size设为1024效果不错
- 早停法防止过拟合
- 使用学习率衰减策略
model = DeepFM(feature_sizes=[2, 10, 2, 5]) # 假设有4个特征,每个特征的取值数量分别为2,10,2,5
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
criterion = nn.BCELoss()
for epoch in range(100):
model.train()
for batch_x, batch_y in train_loader:
optimizer.zero_grad()
outputs = model(batch_x)
loss = criterion(outputs, batch_y.float())
loss.backward()
optimizer.step()
# 验证集评估
model.eval()
with torch.no_grad():
val_preds = model(val_x)
val_loss = criterion(val_preds, val_y.float())
auc = roc_auc_score(val_y.numpy(), val_preds.numpy())
print(f'Epoch {epoch}, Loss: {loss.item():.4f}, Val AUC: {auc:.4f}')
4. 实际应用中的经验
在电商推荐系统项目中,我总结了以下几点经验:
-
特征工程:虽然DeepFM能自动学习特征交互,但好的特征仍然很重要。比如把用户历史行为统计特征(如最近7天点击次数)加入模型,效果提升明显。
-
超参数调优:嵌入维度对模型影响很大。通常我会在4-16之间尝试,维度太高容易过拟合,太低则表达能力不足。
-
线上部署:模型上线时要注意特征实时性。比如用户最新点击的商品需要实时更新到特征中,这对提升推荐效果很关键。
-
冷启动问题:对新用户或新商品,可以用内容特征(如商品类别、价格段)来缓解冷启动问题。
-
模型解释性:虽然DeepFM预测效果好,但解释性不如逻辑回归。我们可以通过分析特征重要性来理解模型决策。
5. 常见问题与解决方案
在实现过程中遇到过几个典型问题:
问题1:内存不足 当特征维度很高时,嵌入层会占用大量内存。解决方案:
- 使用稀疏张量存储
- 对低频特征做分桶处理
- 减小嵌入维度
问题2:训练不稳定 有时模型会出现梯度爆炸。解决方案:
- 使用梯度裁剪
- 调整初始化方式
- 添加BatchNorm层
问题3:过拟合 在数据量较小时容易发生。解决方案:
- 增加Dropout比例
- 使用L2正则化
- 早停法
6. 进阶优化方向
如果想进一步提升模型性能,可以考虑:
-
注意力机制:在DNN部分加入注意力层,让模型更关注重要特征
-
多任务学习:同时预测点击率和转化率等多个目标
-
动态权重:让FM和DNN部分的组合权重可学习,而不是简单相加
-
特征交互可视化:通过可视化工具分析学到的特征交互模式
-
增量学习:定期用新数据更新模型,适应数据分布变化

1989

被折叠的 条评论
为什么被折叠?



