从Deep Crossing到DIEN:手把手拆解主流深度学习推荐模型的核心结构与代码实现
从Deep Crossing到DIEN:深度学习推荐模型实战指南
推荐系统作为互联网产品的核心组件,其技术演进始终与业务需求紧密相连。过去十年间,深度学习技术彻底重塑了推荐系统的技术栈,从早期的协同过滤到如今的复杂神经网络架构,每一次突破都带来了显著的性能提升。本文将带您深入剖析主流深度学习推荐模型的技术细节,并附上可落地的PyTorch实现代码。
1. 深度学习推荐模型演进图谱
深度学习在推荐系统中的应用大致经历了三个关键发展阶段:
- 特征工程自动化阶段 (2016-2017):以Deep Crossing、PNN为代表的模型,主要解决特征自动交叉问题
- 用户兴趣建模阶段 (2018-2019):DIN、DIEN等模型引入注意力机制和序列建模
- 多模态融合阶段 (2020至今):图神经网络、跨模态学习等新技术融入推荐系统
下表对比了各阶段代表性模型的核心创新点:
| 模型类型 | 代表模型 | 关键技术 | 适用场景 |
|---|---|---|---|
| 特征交叉 | Deep Crossing | 残差网络+特征拼接 | 结构化特征丰富的场景 |
| PNN | 内积/外积特征交叉 | 需要精细特征交互的场景 | |
| 兴趣建模 | DIN | 注意力机制 | 用户行为序列分析 |
| DIEN | GRU+注意力进化 | 长周期用户兴趣追踪 | |
| 多模态 | MIND | 多兴趣提取网络 | 多元化兴趣场景 |
2. Deep Crossing模型深度解析
作为微软2016年提出的开创性工作,Deep Crossing奠定了深度学习推荐模型的基础架构。其核心在于构建了一个端到端的特征学习框架:
import torch
import torch.nn as nn
class ResidualBlock(nn.Module):
def __init__(self, input_dim, hidden_dim):
super().__init__()
self.linear1 = nn.Linear(input_dim, hidden_dim)
self.linear2 = nn.Linear(hidden_dim, input_dim)
self.relu = nn.ReLU()
def forward(self, x):
residual = x
out = self.relu(self.linear1(x))
out = self.linear2(out)
out += residual
return self.relu(out)
class DeepCrossing(nn.Module):
def __init__(self, num_features, embedding_dim, hidden_dims):
super().__init__()
self.embedding = nn.Embedding(num_features, embedding_dim)
self.res_blocks = nn.Sequential(
*[ResidualBlock(embedding_dim, dim) for dim in hidden_dims]
)
self.output = nn.Linear(embedding_dim, 1)
def forward(self, x):
# x: [batch_size, num_features]
embedded = self.embedding(x).mean(dim=1) # 特征平均池化
features = self.res_blocks(embedded)
return torch.sigmoid(self.output(features))
模型包含几个关键设计:
- Embedding层 :将高维稀疏特征映射为低维稠密向量
- Stacking层 :实现多种特征的无差别拼接
- 残差单元 :解决深层网络梯度消失问题
- Scoring层 :完成最终的预测任务
实际应用中需要注意:数值型特征应该直接进入Stacking层,而类别型特征需要先经过Embedding处理。这种混合特征处理方式是工业级推荐系统的标配。
3. 从PNN到DIN:特征交叉的进化之路
PNN(Product-based Neural Network)在Deep Crossing基础上做出了重要改进 - 引入乘积层替代简单的特征拼接:
class PNN(nn.Module):
def __init__(self, num_features, embedding_dim):
super().__init__()
self.embedding = nn.Embedding(num_features, embedding_dim)
self.z_linear = nn.Linear(embedding_dim, embedding_dim)
self.p_linear = nn.Linear(embedding_dim, embedding_dim)
self.output = nn.Linear(2*embedding_dim, 1)
def forward(self, x):
embedded = self.embedding(x) # [batch, num_features, embed_dim]
# 线性部分
z = self.z_linear(embedded).sum(dim=1)
# 乘积部分
p = (embedded.unsqueeze(2) @ embedded.unsqueeze(3)).squeeze()
p = self.p_linear(p)
combined = torch.cat([z, p], dim=1)
return torch.sigmoid(self.output(combined))
PNN的乘积操作可以分为两种形式:
- 内积(IPNN) :计算特征向量间的点积相似度
- 外积(OPNN) :生成特征交叉矩阵
阿里巴巴提出的DIN(Deep Interest Network)则更进一步,引入注意力机制实现动态特征加权:
class DIN(nn.Module):
def __init__(self, num_features, embedding_dim):
super().__init__()
self.embedding = nn.Embedding(num_features, embedding_dim)
self.attention = nn.Sequential(
nn.Linear(4*embedding_dim, 80),
nn.ReLU(),
nn.Linear(80, 1)
)
self.output = nn.Linear(embedding_dim, 1)
def forward(self, user_hist, target_item):
# user_hist: [batch, seq_len]
# target_item: [batch, 1]
hist_embed = self.embedding(user_hist) # [batch, seq_len, embed_dim]
target_embed = self.embedding(target_item) # [batch, 1, embed_dim]
# 注意力得分计算
expanded_target = target_embed.expand_as(hist_embed)
attention_input = torch.cat([
hist_embed,
expanded_target,
hist_embed * expanded_target,
hist_embed - expanded_target
], dim=-1)
scores = self.attention(attention_input).squeeze() # [batch, seq_len]
weights = torch.softmax(scores, dim=-1)
# 加权求和
weighted = (hist_embed * weights.unsqueeze(-1)).sum(dim=1)
return torch.sigmoid(self.output(weighted))
DIN的创新点在于:
- 使用目标item作为query,计算与历史行为的注意力权重
- 通过加权求和得到用户兴趣表示
- 实现了"局部激活" - 只有相关历史行为会被重点关注
4. DIEN:动态兴趣演化网络
DIEN(Deep Interest Evolution Network)在DIN基础上引入时间序列建模,主要解决两个问题:
- 兴趣抽取:从用户行为序列中提取潜在兴趣
- 兴趣演化:建模兴趣随时间的变迁过程
class DIEN(nn.Module):
def __init__(self, num_features, embedding_dim):
super().__init__()
self.embedding = nn.Embedding(num_features, embedding_dim)
# 兴趣抽取层
self.gru = nn.GRU(embedding_dim, embedding_dim, batch_first=True)
# 兴趣进化层
self.attention = nn.Sequential(
nn.Linear(4*embedding_dim, 80),
nn.ReLU(),
nn.Linear(80, 1)
)
self.output = nn.Linear(embedding_dim, 1)
def forward(self, user_hist, target_item):
# 兴趣抽取
hist_embed = self.embedding(user_hist)
_, hidden = self.gru(hist_embed) # hidden: [1, batch, embed_dim]
# 兴趣进化
target_embed = self.embedding(target_item)
expanded_target = target_embed.expand_as(hist_embed)
attention_input = torch.cat([
hist_embed,
expanded_target,
hist_embed * expanded_target,
hist_embed - expanded_target
], dim=-1)
scores = self.attention(attention_input).squeeze()
weights = torch.softmax(scores, dim=-1)
# 最终预测
weighted = (hist_embed * weights.unsqueeze(-1)).sum(dim=1)
return torch.sigmoid(self.output(weighted))
DIEN的关键改进:
- 使用GRU捕捉行为序列的时序依赖
- 分层注意力机制分别处理兴趣提取和进化
- 引入辅助loss监督兴趣抽取过程
5. 实战:PyTorch模型训练技巧
在实际工程落地时,有几个关键点需要注意:
数据准备
# 示例数据预处理流程
def prepare_data():
# 1. 加载原始日志数据
df = pd.read_csv('user_behavior.csv')
# 2. 构建特征字典
user_features = {v:k for k,v in enumerate(df['user_id'].unique())}
item_features = {v:k for k,v in enumerate(df['item_id'].unique())}
# 3. 序列填充
user_hist = df.groupby('user_id')['item_id'].apply(list)
max_len = 20
padded_hist = pad_sequences(user_hist, maxlen=max_len)
# 4. 构建训练集
dataset = TensorDataset(
torch.LongTensor(padded_hist), # 历史行为
torch.LongTensor(df['item_id'].map(item_features)), # 目标item
torch.FloatTensor(df['label']) # 点击标签
)
return dataset
模型训练
def train_model():
# 初始化
model = DIN(num_features=10000, embedding_dim=64)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.BCELoss()
# 数据加载
dataset = prepare_data()
loader = DataLoader(dataset, batch_size=1024, shuffle=True)
# 训练循环
for epoch in range(10):
for hist, target, label in loader:
pred = model(hist, target.unsqueeze(1))
loss = criterion(pred.squeeze(), label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f'Epoch {epoch} Loss: {loss.item():.4f}')
性能优化技巧
- 使用混合精度训练加速计算
- 采用负采样策略处理海量物品
- 实现异步数据加载避免IO瓶颈
- 使用梯度裁剪稳定训练过程
6. 模型选型与业务适配
不同业务场景下,模型选型需要考虑多个维度:
推荐场景适配指南
| 场景特征 | 推荐模型 | 原因 |
|---|---|---|
| 新用户冷启动 | Wide&Deep | 宽部分处理稀疏特征能力强 |
| 短视频推荐 | DIN/DIEN | 强时序依赖,需要捕捉兴趣变化 |
| 电商推荐 | PNN/DCN | 需要精细特征交叉 |
| 新闻推荐 | NARM | 考虑阅读顺序和时效性 |
模型部署考量因素
- 线上推理延迟要求
- 特征实时性需求
- 模型更新频率
- 硬件资源限制
在实际业务中,我们通常会采用模型融合策略。例如将DIEN的用户兴趣表征作为额外特征输入到排序模型中,既利用了深度序列建模的优势,又保持了排序阶段的灵活性。
更多推荐




所有评论(0)