深度学习推荐¶
⚠️ 时效性说明:本章涉及前沿模型/价格/榜单等信息,可能随版本快速变化;请以论文原文、官方发布页和 API 文档为准。
📖 章节导读¶
深度学习在推荐系统中的应用越来越广泛,它能够自动学习复杂的非线性特征,提升推荐效果。本章将介绍深度学习推荐的基本原理、主流模型和实际应用。
🎯 学习目标¶
- 理解深度学习在推荐中的优势
- 掌握Wide&Deep模型
- 掌握DeepFM模型
- 了解其他深度推荐模型
- 能够实现深度学习推荐系统
6.1 深度学习推荐概述¶
6.1.1 为什么使用深度学习?¶
优势: 1. 自动特征学习:无需人工特征工程 2. 非线性建模:能够捕捉复杂的非线性关系 3. 多模态融合:可以融合文本、图像、音频等多模态数据 4. 端到端学习:从原始数据直接学习到推荐结果 5. 泛化能力强:在大数据上表现更好
6.1.2 深度学习推荐的特点¶
与传统方法的区别: - 传统方法:依赖人工特征工程 - 深度学习:自动学习特征表示
挑战: - 需要大量数据 - 训练成本高 - 模型可解释性差
6.2 Wide&Deep模型¶
6.2.1 模型原理¶
Wide&Deep模型由Google提出,结合了线性模型(Wide部分)和深度神经网络(Deep部分)的优势。
Wide部分: - 记忆(Memorization):学习历史共现特征 - 使用线性模型 + 特征交叉
Deep部分: - 泛化(Generalization):学习特征的高阶组合 - 使用深度神经网络
融合:
6.2.2 模型结构¶
6.2.3 PyTorch实现¶
import torch
import torch.nn as nn
import torch.nn.functional as F
class WideAndDeep(nn.Module): # 继承nn.Module定义网络层
def __init__(self, wide_dim, deep_dim, hidden_dims):
"""
wide_dim: Wide部分的特征维度
deep_dim: Deep部分的输入维度
hidden_dims: Deep部分的隐藏层维度列表
"""
super(WideAndDeep, self).__init__()
# Wide部分
self.wide_linear = nn.Linear(wide_dim, 1)
# Deep部分
deep_layers = []
input_dim = deep_dim
for hidden_dim in hidden_dims:
deep_layers.append(nn.Linear(input_dim, hidden_dim))
deep_layers.append(nn.ReLU())
deep_layers.append(nn.BatchNorm1d(hidden_dim))
deep_layers.append(nn.Dropout(0.3))
input_dim = hidden_dim
deep_layers.append(nn.Linear(input_dim, 1))
self.deep = nn.Sequential(*deep_layers)
def forward(self, wide_features, deep_features):
"""
wide_features: Wide部分的特征 [batch_size, wide_dim]
deep_features: Deep部分的特征 [batch_size, deep_dim]
"""
# Wide部分
wide_output = self.wide_linear(wide_features)
# Deep部分
deep_output = self.deep(deep_features)
# 融合
output = wide_output + deep_output
return torch.sigmoid(output)
6.2.4 训练代码¶
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset
# 准备数据
wide_features = torch.randn(1000, 100)
deep_features = torch.randn(1000, 50)
labels = torch.randint(0, 2, (1000, 1)).float()
dataset = TensorDataset(wide_features, deep_features, labels)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True) # DataLoader批量加载数据
# 初始化模型
model = WideAndDeep(wide_dim=100, deep_dim=50, hidden_dims=[128, 64, 32])
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 训练
for epoch in range(10):
model.train() # train()训练模式
total_loss = 0
for wide_feat, deep_feat, label in dataloader:
optimizer.zero_grad() # 清零梯度
# 前向传播
output = model(wide_feat, deep_feat)
# 计算损失
loss = criterion(output, label)
# 反向传播
loss.backward() # 反向传播计算梯度
optimizer.step() # 更新参数
total_loss += loss.item() # 将单元素张量转为Python数值
avg_loss = total_loss / len(dataloader)
print(f"Epoch {epoch + 1}, Loss: {avg_loss:.4f}")
6.3 DeepFM模型¶
6.3.1 模型原理¶
DeepFM结合了FM(Factorization Machines)和DNN的优势,能够同时学习低阶和高阶特征交互。
组成部分: 1. FM部分:学习二阶特征交互 2. Deep部分:学习高阶特征交互 3. 共享Embedding:FM和Deep共享Embedding层
6.3.2 模型结构¶
6.3.3 PyTorch实现¶
# 注意:此简化实现仅处理类别特征的Embedding。生产环境中需要额外处理数值特征(直接拼接或BN后拼接到DNN输入中)。
class DeepFM(nn.Module):
def __init__(self, field_dims, embed_dim, hidden_dims):
"""
field_dims: 每个字段的取值个数列表
embed_dim: Embedding维度
hidden_dims: 隐藏层维度列表
"""
super(DeepFM, self).__init__()
# Embedding层
self.embedding = nn.ModuleList([
nn.Embedding(dim, embed_dim) for dim in field_dims
])
# FM部分
self.fm_linear = nn.ModuleList([
nn.Embedding(dim, 1) for dim in field_dims
])
# Deep部分
input_dim = len(field_dims) * embed_dim
deep_layers = []
for hidden_dim in hidden_dims:
deep_layers.append(nn.Linear(input_dim, hidden_dim))
deep_layers.append(nn.ReLU())
deep_layers.append(nn.BatchNorm1d(hidden_dim))
deep_layers.append(nn.Dropout(0.3))
input_dim = hidden_dim
self.deep = nn.Sequential(*deep_layers)
# 输出层
self.output_layer = nn.Linear(hidden_dims[-1] + 1, 1) # [-1]负索引取最后元素
def forward(self, X):
"""
X: [batch_size, num_fields]
"""
# Embedding
embeddings = []
for i in range(X.shape[1]):
embed = self.embedding[i](X[:, i])
embeddings.append(embed)
embeddings = torch.stack(embeddings, dim=1) # [batch_size, num_fields, embed_dim] # torch.stack沿新维度拼接张量
# FM一阶部分
fm_first_order = 0
for i in range(X.shape[1]):
fm_first_order += self.fm_linear[i](X[:, i])
# FM二阶部分
square_of_sum = torch.sum(embeddings, dim=1) ** 2
sum_of_square = torch.sum(embeddings ** 2, dim=1)
fm_second_order = 0.5 * torch.sum(square_of_sum - sum_of_square, dim=1, keepdim=True)
# Deep部分
deep_input = embeddings.view(embeddings.size(0), -1) # 重塑张量形状
deep_output = self.deep(deep_input)
# FM完整输出(一阶 + 二阶)
fm_output = fm_first_order + fm_second_order
# 融合FM和Deep
concat = torch.cat([fm_output, deep_output], dim=1) # torch.cat沿已有维度拼接张量
output = self.output_layer(concat)
return torch.sigmoid(output)
6.4 其他深度推荐模型¶
6.4.1 NFM(Neural Factorization Machines)¶
- 将FM的二阶交互替换为神经网络
- 能够学习更复杂的特征交互
6.4.2 AFM(Attentional Factorization Machines)¶
- 在FM的基础上引入注意力机制
- 自动学习不同特征交互的重要性
6.4.3 DIN(Deep Interest Network)¶
- 使用注意力机制建模用户兴趣
- 根据候选物品动态调整用户兴趣
6.4.4 DIEN(Deep Interest Evolution Network)¶
- 建模用户兴趣的演化过程
- 使用GRU捕捉兴趣序列
6.4.5 图神经网络推荐(GNN-based)¶
图神经网络是2023-2025推荐系统最重要的技术方向之一
核心思想:将用户-物品交互建模为二部图,通过消息传播捕捉高阶协同信号。
LightGCN(最经典)¶
简化GCN,只保留邻域聚合+Layer Combination:
import torch
import torch.nn as nn
class LightGCN(nn.Module):
"""LightGCN: Simplifying and Powering GCN for Recommendation (SIGIR 2020)"""
def __init__(self, n_users, n_items, embed_dim, n_layers, adj_matrix):
super().__init__() # super()调用父类方法
self.n_layers = n_layers
self.user_embed = nn.Embedding(n_users, embed_dim)
self.item_embed = nn.Embedding(n_items, embed_dim)
self.adj = adj_matrix # 归一化邻接矩阵
nn.init.xavier_uniform_(self.user_embed.weight)
nn.init.xavier_uniform_(self.item_embed.weight)
def forward(self):
# 初始嵌入
all_embed = torch.cat([self.user_embed.weight, self.item_embed.weight], dim=0)
embeds_list = [all_embed]
# L层图卷积(无参数!只做聚合)
for _ in range(self.n_layers):
all_embed = torch.sparse.mm(self.adj, all_embed)
embeds_list.append(all_embed)
# Layer Combination: 各层取均值
final_embed = torch.stack(embeds_list, dim=0).mean(dim=0)
user_embeds = final_embed[:self.user_embed.num_embeddings]
item_embeds = final_embed[self.user_embed.num_embeddings:]
return user_embeds, item_embeds
def predict(self, user_ids, item_ids):
user_embeds, item_embeds = self.forward()
u = user_embeds[user_ids]
i = item_embeds[item_ids]
return (u * i).sum(dim=-1) # 内积预测
核心GNN推荐模型对比¶
| 模型 | 年份 | 核心创新 | 适用场景 |
|---|---|---|---|
| LightGCN | 2020 | 去掉变换矩阵和非线性 | 协同过滤通用 |
| KGAT | 2019 | 知识图谱+注意力聚合 | KG增强推荐 |
| PinSage | 2018 | 随机游走+采样(Pinterest) | 十亿级规模 |
| SR-GNN | 2019 | 会话图+GRU | 会话推荐 |
| GraphRec | 2019 | 社交关系图 | 社交推荐 |
为什么GNN适合推荐?¶
传统CF: 只用1阶邻居信息 (u→i)
GCN L=2: u→i1→u2→i2 捕捉2阶协同信号
GCN L=3: 更高阶传播,但可能过平滑
关键公式:
e_u^{(l+1)} = Σ (1/√|N_u| · 1/√|N_i|) · e_i^{(l)}
e_u^{final} = 1/(L+1) · Σ e_u^{(l)} # Layer Combination
6.5 实战案例¶
案例:CTR预测¶
import pandas as pd
import numpy as np
import torch
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import LabelEncoder
# 1. 加载数据
data = pd.read_csv('ctr_data.csv')
# 2. 特征处理
categorical_features = ['user_id', 'item_id', 'category', 'brand']
numerical_features = ['price', 'rating', 'sales']
# 类别特征编码
label_encoders = {}
for feat in categorical_features:
le = LabelEncoder()
data[feat] = le.fit_transform(data[feat])
label_encoders[feat] = le
# 3. 构建训练数据
field_dims = [data[feat].nunique() for feat in categorical_features]
X_cat = data[categorical_features].values
X_num = data[numerical_features].values
y = data['click'].values
# 4. 划分数据集
X_cat_train, X_cat_test, X_num_train, X_num_test, y_train, y_test = \
train_test_split(X_cat, X_num, y, test_size=0.2, random_state=42)
# 5. 转换为Tensor
X_cat_train = torch.LongTensor(X_cat_train)
X_cat_test = torch.LongTensor(X_cat_test)
X_num_train = torch.FloatTensor(X_num_train)
X_num_test = torch.FloatTensor(X_num_test)
y_train = torch.FloatTensor(y_train).unsqueeze(1) # unsqueeze增加一个维度
y_test = torch.FloatTensor(y_test).unsqueeze(1)
# 6. 训练模型
model = DeepFM(field_dims=field_dims, embed_dim=16, hidden_dims=[128, 64, 32])
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
def calculate_auc(y_true, y_pred):
"""
计算AUC
"""
from sklearn.metrics import roc_auc_score
return roc_auc_score(y_true, y_pred)
# 训练
for epoch in range(10):
model.train()
optimizer.zero_grad()
output = model(X_cat_train)
loss = criterion(output, y_train)
loss.backward()
optimizer.step()
# 评估
model.eval()
with torch.no_grad(): # 禁用梯度计算,节省内存
test_output = model(X_cat_test)
test_loss = criterion(test_output, y_test)
auc = calculate_auc(y_test.numpy(), test_output.numpy())
print(f"Epoch {epoch + 1}, Train Loss: {loss.item():.4f}, "
f"Test Loss: {test_loss.item():.4f}, AUC: {auc:.4f}")
📝 本章小结¶
本章介绍了深度学习推荐的核心内容:
- ✅ 深度学习在推荐中的优势
- ✅ Wide&Deep模型
- ✅ DeepFM模型
- ✅ 其他深度推荐模型
- ✅ 实战案例
通过本章学习,你应该能够: - 理解深度学习推荐的优势 - 实现Wide&Deep和DeepFM模型 - 了解其他深度推荐模型 - 应用深度学习解决推荐问题
🔗 下一步¶
下一章我们将学习序列推荐算法,了解如何建模用户的行为序列。
继续学习: 07-序列推荐算法.md
💡 思考题¶
-
Wide&Deep模型为什么能同时兼顾记忆和泛化?
Wide部分(线性模型+交叉特征):记住历史共现模式("买了手机壳的常买贴膜"),提供强记忆性。Deep部分(多层MLP):通过Embedding捕捉隐含变量间关系,实现泛化("喜欢科幻的可能喜欢奇幻")。两部分联合训练、共享梯度,由Google提出并应用于Google Play推荐。
-
DeepFM相比Wide&Deep有什么改进?
①用FM替代Wide部分,自动学习二阶特征交叉,无需手动设计交叉特征 ②FM和Deep共享Embedding,减少参数量 ③端到端训练,无需特征工程。效果:在多个基准上优于Wide&Deep,特别是稀疏特征丰富的场景。后续演进:DCN(自动高阶交叉)、AutoInt(Attention交叉)。
-
如何选择合适的深度学习推荐模型?
按场景选:①CTR预估→DeepFM/DCNv2(强特征交叉) ②序列推荐→DIN/DIEN/SIM(Attention捕捉兴趣演变) ③多任务→MMoE/PLE(多目标优化) ④召回→双塔模型(DSSM)。工程建议:先用DeepFM作基线,再尝试DIN(加行为序列)和MMoE(加多目标)。
-
深度学习推荐如何处理稀疏特征?
①Embedding层(将高维稀疏转为低维稠密,如用户ID→128维向量) ②特征哈希(将罕见值映射到固定桶数) ③预训练Embedding(Word2Vec/Item2Vec) ④多值特征池化(mean/sum pooling) ⑤正则化(L2/Dropout防过拟合)。Embedding是深度推荐的基石,通常选择32/64/128维。
-
如何优化深度学习推荐模型的训练效率?
①混合精度训练(FP16加速2x) ②大batch训练+学习率warmup ③特征缓存(热门Embedding缓存到GPU) ④数据并行(多GPU分布式训练) ⑤增量训练(只用新数据更新) ⑥梯度累积(当GPU显存不足时)。工具:DeepCTR/RecBole(快速实验) + PyTorch/TF生产训练。
📚 参考资料¶
- "Wide & Deep Learning for Recommender Systems" - Cheng et al.
- "DeepFM: A Factorization-Machine based Neural Network for CTR Prediction" - Guo et al.
- "Neural Factorization Machines for Sparse Predictive Analytics" - He & Chua
- "Deep Interest Network for Click-Through Rate Prediction" - Zhou et al.
- PyTorch Documentation
