跳转至

深度学习推荐

⚠️ 时效性说明:本章涉及前沿模型/价格/榜单等信息,可能随版本快速变化;请以论文原文、官方发布页和 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):学习特征的高阶组合 - 使用深度神经网络

融合:

Text Only
y = sigmoid(W_wide^T x + b_wide + W_deep^T a + b_deep)

6.2.2 模型结构

Text Only
输入特征
    ├── Wide部分 ─────┐
    │   线性模型      │
    │   特征交叉       ├──→ 输出
    │                │
    └── Deep部分 ────┘
        Embedding层
        隐藏层

6.2.3 PyTorch实现

Python
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 训练代码

Python
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 模型结构

Text Only
输入特征
Embedding层
    ├── FM部分 ─────┐
    │   一阶特征     │
    │   二阶特征     ├──→ 输出
    │               │
    └── Deep部分 ───┘
    隐藏层

6.3.3 PyTorch实现

Python
# 注意:此简化实现仅处理类别特征的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:

Python
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适合推荐?

Text Only
传统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预测

Python
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}")

📝 本章小结

本章介绍了深度学习推荐的核心内容:

  1. ✅ 深度学习在推荐中的优势
  2. ✅ Wide&Deep模型
  3. ✅ DeepFM模型
  4. ✅ 其他深度推荐模型
  5. ✅ 实战案例

通过本章学习,你应该能够: - 理解深度学习推荐的优势 - 实现Wide&Deep和DeepFM模型 - 了解其他深度推荐模型 - 应用深度学习解决推荐问题

🔗 下一步

下一章我们将学习序列推荐算法,了解如何建模用户的行为序列。

继续学习: 07-序列推荐算法.md

💡 思考题

  1. Wide&Deep模型为什么能同时兼顾记忆和泛化?

    Wide部分(线性模型+交叉特征):记住历史共现模式("买了手机壳的常买贴膜"),提供强记忆性。Deep部分(多层MLP):通过Embedding捕捉隐含变量间关系,实现泛化("喜欢科幻的可能喜欢奇幻")。两部分联合训练、共享梯度,由Google提出并应用于Google Play推荐。

  2. DeepFM相比Wide&Deep有什么改进?

    ①用FM替代Wide部分,自动学习二阶特征交叉,无需手动设计交叉特征 ②FM和Deep共享Embedding,减少参数量 ③端到端训练,无需特征工程。效果:在多个基准上优于Wide&Deep,特别是稀疏特征丰富的场景。后续演进:DCN(自动高阶交叉)、AutoInt(Attention交叉)。

  3. 如何选择合适的深度学习推荐模型?

    按场景选:①CTR预估→DeepFM/DCNv2(强特征交叉) ②序列推荐→DIN/DIEN/SIM(Attention捕捉兴趣演变) ③多任务→MMoE/PLE(多目标优化) ④召回→双塔模型(DSSM)。工程建议:先用DeepFM作基线,再尝试DIN(加行为序列)和MMoE(加多目标)。

  4. 深度学习推荐如何处理稀疏特征?

    ①Embedding层(将高维稀疏转为低维稠密,如用户ID→128维向量) ②特征哈希(将罕见值映射到固定桶数) ③预训练Embedding(Word2Vec/Item2Vec) ④多值特征池化(mean/sum pooling) ⑤正则化(L2/Dropout防过拟合)。Embedding是深度推荐的基石,通常选择32/64/128维。

  5. 如何优化深度学习推荐模型的训练效率?

    ①混合精度训练(FP16加速2x) ②大batch训练+学习率warmup ③特征缓存(热门Embedding缓存到GPU) ④数据并行(多GPU分布式训练) ⑤增量训练(只用新数据更新) ⑥梯度累积(当GPU显存不足时)。工具:DeepCTR/RecBole(快速实验) + PyTorch/TF生产训练。

📚 参考资料

  1. "Wide & Deep Learning for Recommender Systems" - Cheng et al.
  2. "DeepFM: A Factorization-Machine based Neural Network for CTR Prediction" - Guo et al.
  3. "Neural Factorization Machines for Sparse Predictive Analytics" - He & Chua
  4. "Deep Interest Network for Click-Through Rate Prediction" - Zhou et al.
  5. PyTorch Documentation