本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:该项目是人工智能领域的毕业设计或课程设计,聚焦深度学习推荐系统的构建,使用经典电影推荐数据集ml-100k,并基于PyTorch框架实现《深度学习推荐系统》一书中的多种模型。通过数据预处理、模型构建、训练与评估等流程,帮助学生掌握协同过滤、矩阵分解、神经网络等推荐系统核心技术,并提升深度学习在实际推荐场景中的应用能力。
该项目使用经典的电影推荐数据集ml-100k并基于PyTorch实现《深度学习推荐系统(王喆著)》的部分经典模型.zip

1. 推荐系统基础概述

推荐系统是一种通过分析用户行为和偏好,自动预测并推荐用户可能感兴趣的物品(如商品、电影、新闻等)的技术系统。其核心目标是解决信息过载问题,提升用户体验与平台转化率。推荐系统常见方法包括协同过滤(Collaborative Filtering)、基于内容的推荐(Content-Based Recommendation)以及融合多种策略的混合推荐(Hybrid Recommendation)。协同过滤依赖用户-物品交互数据,基于内容推荐则关注物品本身的特征信息。随着深度学习的发展,推荐系统逐步向高维特征建模和端到端优化演进,显著提升了推荐精度与个性化能力。本章将为读者构建推荐系统的整体认知框架,为后续深入学习打下基础。

2. 深度学习推荐系统原理

深度学习在推荐系统领域的应用,标志着推荐技术从传统统计模型向高维非线性建模的飞跃。随着用户行为数据的爆炸式增长以及特征维度的复杂化,传统的协同过滤和基于内容的方法逐渐暴露出冷启动、稀疏性和语义建模能力不足等问题。深度学习通过其强大的特征提取能力和端到端的建模方式,为推荐系统提供了新的建模视角与解决方案。本章将深入探讨深度学习在推荐系统中的关键原理,包括模型结构、特征嵌入、训练策略及经典模型实现,为后续PyTorch实战打下理论基础。

2.1 推荐系统与深度学习的结合

2.1.1 深度学习在推荐系统中的优势

深度学习之所以在推荐系统中展现出巨大潜力,主要得益于其以下几个核心优势:

  1. 特征自动提取 :传统的推荐系统往往依赖人工设计特征(如用户行为、物品属性等),而深度学习可以通过神经网络自动挖掘高阶特征组合。
  2. 处理高维稀疏数据 :推荐系统中常见的用户-物品交互矩阵通常极度稀疏,深度学习通过嵌入层(Embedding Layer)将离散特征映射到低维稠密向量空间,缓解稀疏性问题。
  3. 端到端建模 :深度学习模型可以直接以原始输入数据(如ID、文本、图像)作为输入,输出推荐结果,无需繁琐的特征工程流程。
  4. 多模态融合能力 :深度学习天然支持融合多源异构数据,如文本、图像、视频等,使得推荐系统能更好地理解用户兴趣和物品内容。

以下是一个典型的用户嵌入表示的代码示例:

import torch
import torch.nn as nn

# 用户嵌入层
class UserEmbedding(nn.Module):
    def __init__(self, num_users, embedding_dim):
        super(UserEmbedding, self).__init__()
        self.embedding = nn.Embedding(num_users, embedding_dim)

    def forward(self, user_ids):
        return self.embedding(user_ids)

# 示例使用
num_users = 10000
embedding_dim = 64
user_ids = torch.tensor([1, 45, 123])
user_emb = UserEmbedding(num_users, embedding_dim)
print(user_emb(user_ids))

代码解析:

  • nn.Embedding 是PyTorch中用于构建嵌入层的模块,其输入为用户ID(离散整数),输出为对应的稠密向量。
  • num_users 表示总的用户数量, embedding_dim 是嵌入向量的维度。
  • 在前向传播中, user_ids 被映射为一个 batch_size × embedding_dim 的张量。

2.1.2 典型的深度学习推荐模型分类

根据模型结构和应用场景,深度学习推荐系统可以分为以下几类:

模型类型 代表模型 主要特点
协同深度学习 CDL(Collaborative Deep Learning) 将协同过滤与深度生成模型结合
矩阵分解神经网络 NeuMF(Neural Matrix Factorization) 利用神经网络替代传统矩阵分解方法
多层感知机 Wide & Deep、DeepFM 捕捉低阶与高阶特征交互
序列模型 DIN(Deep Interest Network)、GRU4Rec 捕捉用户行为的时序依赖
图神经网络 GraphSAGE、PinSage 利用图结构建模用户与物品关系

深度学习模型的多样性为不同业务场景提供了灵活的建模选择。例如,电商推荐中更注重用户行为序列的建模,而社交推荐则可能更关注用户关系图的结构特征。

2.2 神经网络在推荐系统中的应用

2.2.1 用户和物品特征的嵌入表示

在推荐系统中,用户和物品通常以ID形式存在。深度学习通过嵌入层将这些ID映射为向量,从而实现语义建模。

graph TD
    A[用户ID] --> B[Embedding Layer]
    C[物品ID] --> B
    B --> D[向量表示]

示例代码:用户与物品嵌入拼接

class UserItemEmbedding(nn.Module):
    def __init__(self, num_users, num_items, embed_dim):
        super(UserItemEmbedding, self).__init__()
        self.user_emb = nn.Embedding(num_users, embed_dim)
        self.item_emb = nn.Embedding(num_items, embed_dim)

    def forward(self, user_id, item_id):
        u_emb = self.user_emb(user_id)
        i_emb = self.item_emb(item_id)
        return torch.cat((u_emb, i_emb), dim=1)

# 实例化
model = UserItemEmbedding(10000, 5000, 64)
user = torch.tensor([123])
item = torch.tensor([456])
print(model(user, item))

参数说明:
- dim=1 表示在第1维度(即特征维度)进行拼接;
- 输出为 1 × 128 的向量,可用于后续的评分预测或分类任务。

2.2.2 非线性关系建模与高阶特征提取

推荐系统中的用户行为和物品特征之间往往存在复杂的非线性关系。多层感知机(MLP)通过引入多个隐藏层,能够建模高阶特征交互。

class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dims, output_dim):
        super(MLP, self).__init__()
        layers = []
        prev_dim = input_dim
        for h_dim in hidden_dims:
            layers.append(nn.Linear(prev_dim, h_dim))
            layers.append(nn.ReLU())
            prev_dim = h_dim
        layers.append(nn.Linear(prev_dim, output_dim))
        self.net = nn.Sequential(*layers)

    def forward(self, x):
        return self.net(x)

# 示例使用
mlp = MLP(128, [256, 128], 1)
input_vec = model(user, item)
print(mlp(input_vec))

逻辑分析:
- 该MLP由两个隐藏层组成,使用ReLU激活函数;
- 最终输出一个评分值,用于预测用户对物品的偏好;
- 可用于评分预测任务(如MovieLens评分)或点击率预估任务。

2.2.3 多任务学习与个性化排序

在实际推荐场景中,系统通常需要同时优化多个目标,例如点击率(CTR)、转化率(CVR)和停留时长等。多任务学习(Multi-Task Learning)允许模型共享底层表示,同时学习多个任务的专有特征。

graph TD
    Input[输入特征] --> Shared[共享层]
    Shared --> Task1[任务1头]
    Shared --> Task2[任务2头]
    Shared --> TaskN[任务n头]

示例代码:多任务推荐模型

class MultiTaskModel(nn.Module):
    def __init__(self, input_dim, shared_dim, task_dims):
        super(MultiTaskModel, self).__init__()
        self.shared = nn.Linear(input_dim, shared_dim)
        self.task_heads = nn.ModuleList([
            nn.Linear(shared_dim, task_dim) for task_dim in task_dims
        ])

    def forward(self, x):
        shared_rep = torch.relu(self.shared(x))
        outputs = [head(shared_rep) for head in self.task_heads]
        return outputs

参数说明:
- shared_dim 控制共享层的大小;
- task_dims 是一个列表,表示每个任务输出的维度;
- 适用于多目标优化场景,如CTR + CVR预测。

2.3 经典模型原理详解

2.3.1 协同深度学习(CDL)

CDL模型将协同过滤与深度学习结合,其核心思想是通过贝叶斯深度网络建模用户-物品评分与物品内容之间的联合分布。

graph LR
    Ratings[用户评分] --> CDL[协同深度学习模型]
    Content[物品内容] --> CDL
    CDL --> Predictions[预测评分]

模型特点:
- 使用深度生成模型(如Stacked Denoising Autoencoder)建模物品内容;
- 同时学习评分矩阵与内容表示;
- 适用于内容丰富的推荐场景(如新闻、电影)。

2.3.2 矩阵分解与神经网络结合

传统矩阵分解方法(如SVD)仅能建模低阶线性交互,而神经网络可进一步建模高阶非线性关系。

class NeuMF(nn.Module):
    def __init__(self, num_users, num_items, mf_dim, mlp_dims):
        super(NeuMF, self).__init__()
        self.user_mf = nn.Embedding(num_users, mf_dim)
        self.item_mf = nn.Embedding(num_items, mf_dim)
        self.mlp_user = nn.Embedding(num_users, mlp_dims[0]//2)
        self.mlp_item = nn.Embedding(num_items, mlp_dims[0]//2)
        self.mlp = MLP(mlp_dims[0], mlp_dims[1:], mf_dim)

    def forward(self, user_id, item_id):
        mf_u = self.user_mf(user_id)
        mf_i = self.item_mf(item_id)
        mlp_u = self.mlp_user(user_id)
        mlp_i = self.mlp_item(item_id)
        mlp_input = torch.cat([mlp_u, mlp_i], dim=1)
        mlp_output = self.mlp(mlp_input)
        return torch.cat([mf_u * mf_i, mlp_output], dim=1).sum(1)

模型解析:
- mf_dim 表示矩阵分解维度;
- mlp_dims 表示MLP的各层维度;
- 最终输出为矩阵分解与MLP输出的拼接,并求和得到评分预测;
- 该模型在MovieLens等公开数据集上表现优异。

2.3.3 多层感知机在评分预测中的作用

多层感知机(MLP)是深度推荐模型的基础模块,常用于评分预测、点击率预估等任务。

# 评分预测模型
class RatingModel(nn.Module):
    def __init__(self, input_dim, hidden_dims):
        super(RatingModel, self).__init__()
        self.mlp = MLP(input_dim, hidden_dims, 1)

    def forward(self, x):
        return self.mlp(x)

# 损失函数定义
loss_fn = nn.MSELoss()
optimizer = torch.optim.Adam(RatingModel.parameters(), lr=0.001)

训练流程说明:
1. 输入拼接的用户-物品向量;
2. 通过MLP得到评分预测;
3. 使用均方误差(MSE)计算损失;
4. 反向传播更新参数;
5. 多轮训练后模型收敛。

2.4 推荐系统的训练与优化流程

2.4.1 数据预处理与模型输入构造

在训练推荐模型之前,需要对原始数据进行预处理,包括:

  • 用户与物品ID编码 :使用 LabelEncoder pd.factorize 进行唯一ID编码;
  • 数据标准化 :对连续特征(如年龄、评分)进行归一化;
  • 构建输入张量 :将用户ID、物品ID等转换为PyTorch张量;
  • 构建DataLoader :支持批量训练与随机打乱。
from torch.utils.data import DataLoader, TensorDataset

# 假设已有处理好的用户ID、物品ID和评分
user_ids = torch.tensor([1, 2, 3])
item_ids = torch.tensor([10, 20, 30])
ratings = torch.tensor([4.0, 3.5, 5.0])

# 构建Dataset和DataLoader
dataset = TensorDataset(user_ids, item_ids, ratings)
loader = DataLoader(dataset, batch_size=2, shuffle=True)

# 训练循环
for users, items, labels in loader:
    predictions = model(users, items)
    loss = loss_fn(predictions, labels)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

2.4.2 模型训练策略与优化目标

推荐系统训练中常用的优化策略包括:

策略 描述
批量训练 提高训练效率,减少内存波动
学习率调整 使用 ReduceLROnPlateau 动态调整学习率
负样本采样 对于隐式反馈数据,采样负样本平衡训练数据
正则化 使用L2正则化防止过拟合

2.4.3 模型评估与部署流程

推荐模型的评估指标通常包括:

任务类型 常用指标
回归任务 RMSE、MAE
分类任务 AUC、准确率、F1-score
排序任务 NDCG、MAP

模型训练完成后,需进行以下部署流程:

graph TD
    Training[模型训练] --> Evaluation[模型评估]
    Evaluation --> Deployment[模型部署]
    Deployment --> Serving[在线服务]

部署方式包括:
- 使用 TorchScript ONNX 导出模型;
- 部署至TensorRT、ONNX Runtime等推理引擎;
- 使用Flask/Django构建推荐API服务。

本章系统介绍了深度学习在推荐系统中的核心原理与关键技术,包括模型结构、特征表示、训练策略与经典模型实现。下一章将围绕PyTorch框架展开讲解,介绍如何在实际项目中构建与训练深度推荐模型。

3. PyTorch框架介绍与应用

在深度学习推荐系统的构建过程中,选择合适的开发框架是至关重要的。PyTorch 作为当前主流的深度学习框架之一,凭借其灵活的动态计算图机制和丰富的模块化支持,成为构建推荐模型的理想选择。本章将从 PyTorch 的基础特性出发,深入探讨其在推荐系统中的适配性与应用实践。通过本章的学习,读者将掌握如何使用 PyTorch 构建推荐模型的核心组件,包括张量操作、自动求导机制、嵌入层、多层感知机(MLP)以及损失函数的定义与训练流程实现。同时,还将介绍模型训练与调优的实用技巧,为后续模型训练和部署打下坚实基础。

3.1 PyTorch基础与推荐系统适配性

3.1.1 PyTorch的核心特性与优势

PyTorch 是一个基于 Python 的开源深度学习框架,由 Facebook 的人工智能研究团队开发。它以动态计算图(Dynamic Computation Graph)为核心特性,使得开发者可以在运行时构建和修改计算流程,从而实现更高的灵活性和调试效率。

相较于静态图框架(如 TensorFlow 1.x),PyTorch 的动态图机制允许开发者在代码中直接查看每一步的输出结果,便于调试和模型优化。此外,PyTorch 提供了丰富的库和模块,如 torch.nn torch.optim torch.utils.data ,这些模块为推荐系统的构建提供了极大的便利。

在推荐系统中,模型往往需要处理高维稀疏数据(如用户 ID、物品 ID),而 PyTorch 的 nn.Embedding 层可以高效地将这些离散特征映射为稠密向量表示。同时,PyTorch 的 GPU 加速支持也使得大规模数据训练成为可能。

特性 描述
动态计算图 支持运行时构建计算流程,提升调试效率
易于调试 可在代码中直接打印中间结果
丰富的模块 提供神经网络、优化器、数据加载器等模块
强大的 GPU 支持 支持 CUDA 加速,提升训练效率
社区活跃 拥有庞大的开发者社区和丰富的文档资源

3.1.2 动态计算图在推荐模型中的应用

推荐系统模型通常需要根据用户行为动态调整模型结构,例如在多任务学习中处理不同的输出目标。PyTorch 的动态图机制允许在训练过程中灵活调整网络结构,例如在每轮训练中根据输入数据动态决定是否使用 dropout 或 batch normalization。

例如,以下代码演示了如何在 PyTorch 中动态构建一个简单的神经网络模型:

import torch
import torch.nn as nn

class DynamicModel(nn.Module):
    def __init__(self):
        super(DynamicModel, self).__init__()
        self.layer1 = nn.Linear(10, 20)
        self.layer2 = nn.Linear(20, 1)

    def forward(self, x, use_dropout=False):
        x = torch.relu(self.layer1(x))
        if use_dropout:
            x = nn.Dropout(0.5)(x)
        x = self.layer2(x)
        return x

model = DynamicModel()
input_data = torch.randn(5, 10)
output = model(input_data, use_dropout=True)
print(output)

代码逻辑分析:

  • DynamicModel 类继承自 nn.Module ,定义了两个全连接层。
  • forward 方法中, use_dropout 参数控制是否在中间层添加 dropout 层。
  • nn.Dropout(0.5) 表示以 50% 的概率随机丢弃神经元,防止过拟合。
  • 模型可以根据输入参数动态决定是否启用 dropout,这在训练推荐模型时非常有用。

3.2 PyTorch模型构建基础

3.2.1 张量操作与模型参数管理

张量(Tensor)是 PyTorch 中的基本数据结构,类似于 NumPy 的 ndarray,但支持 GPU 加速。在推荐系统中,张量常用于表示用户 ID、物品 ID、特征向量等。

以下是一个简单的张量操作示例:

import torch

# 创建一个随机张量
x = torch.randn(3, 4)
print("x:", x)

# 获取张量的形状
print("Shape of x:", x.shape)

# 张量加法
y = torch.randn(3, 4)
z = x + y
print("z (x + y):", z)

# 张量乘法
w = torch.matmul(x, y.t())  # 矩阵乘法
print("w (x * y^T):", w)

代码逻辑分析:

  • torch.randn(3, 4) 创建一个 3x4 的正态分布张量。
  • x.shape 返回张量的维度信息。
  • x + y 执行张量逐元素加法。
  • torch.matmul(x, y.t()) 执行矩阵乘法,其中 y.t() 表示转置操作。

在模型训练过程中,PyTorch 自动管理模型参数。通过 model.parameters() 可以获取模型的所有可训练参数,并将其传递给优化器进行更新。

3.2.2 自动求导机制与优化器使用

PyTorch 的自动求导机制(Autograd)是其核心特性之一。它通过记录张量的操作来自动计算梯度,从而实现反向传播。

以下是一个简单的自动求导示例:

import torch

# 创建一个张量并启用梯度计算
x = torch.tensor([2.0], requires_grad=True)

# 定义一个函数
y = x ** 2 + 3 * x + 1

# 计算梯度
y.backward()

# 输出梯度值
print("Gradient of y with respect to x:", x.grad)

代码逻辑分析:

  • requires_grad=True 表示该张量需要计算梯度。
  • y.backward() 自动计算梯度。
  • x.grad 存储了对 x 的梯度值。

在推荐系统中,自动求导机制用于更新嵌入向量和神经网络参数。优化器(如 torch.optim.Adam )负责根据梯度更新模型参数:

import torch
import torch.nn as nn
import torch.optim as optim

# 定义一个简单的线性模型
model = nn.Linear(10, 1)

# 定义损失函数和优化器
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 生成随机输入和目标数据
input_data = torch.randn(5, 10)
target = torch.randn(5, 1)

# 前向传播
output = model(input_data)
loss = criterion(output, target)

# 反向传播与优化
optimizer.zero_grad()
loss.backward()
optimizer.step()

print("Loss:", loss.item())

代码逻辑分析:

  • nn.Linear(10, 1) 定义一个输入维度为 10,输出维度为 1 的线性层。
  • nn.MSELoss() 是均方误差损失函数。
  • Adam 是常用的优化器,支持动态调整学习率。
  • zero_grad() 清除之前的梯度,避免梯度累积。
  • loss.backward() 计算梯度。
  • optimizer.step() 更新参数。

3.3 推荐系统中模型构建实践

3.3.1 构建用户与物品嵌入层

在推荐系统中,用户和物品的 ID 通常是离散的类别型数据。为了将这些数据输入神经网络,通常使用嵌入层(Embedding Layer)将其映射为低维稠密向量。

import torch
import torch.nn as nn

# 用户和物品数量
num_users = 1000
num_items = 500

# 嵌入维度
embedding_dim = 32

# 构建用户和物品嵌入层
user_embedding = nn.Embedding(num_embeddings=num_users, embedding_dim=embedding_dim)
item_embedding = nn.Embedding(num_embeddings=num_items, embedding_dim=embedding_dim)

# 示例用户和物品 ID
user_ids = torch.LongTensor([10, 20, 30])
item_ids = torch.LongTensor([50, 60, 70])

# 获取嵌入向量
user_vecs = user_embedding(user_ids)
item_vecs = item_embedding(item_ids)

print("User Vectors Shape:", user_vecs.shape)
print("Item Vectors Shape:", item_vecs.shape)

代码逻辑分析:

  • nn.Embedding(num_embeddings, embedding_dim) 定义嵌入层。
  • LongTensor 用于表示类别型 ID。
  • user_embedding(user_ids) 将用户 ID 映射为嵌入向量。

3.3.2 实现多层感知机(MLP)模型

多层感知机(MLP)是推荐系统中常用的模型结构,用于建模用户与物品之间的非线性关系。

import torch
import torch.nn as nn

class MLP(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(MLP, self).__init__()
        self.layers = nn.Sequential(
            nn.Linear(input_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, output_dim),
            nn.Sigmoid()
        )

    def forward(self, x):
        return self.layers(x)

# 示例输入维度
input_dim = 64
hidden_dim = 128
output_dim = 1

model = MLP(input_dim, hidden_dim, output_dim)
input_data = torch.randn(5, input_dim)
output = model(input_data)
print("Output:", output)

代码逻辑分析:

  • nn.Sequential 用于按顺序堆叠网络层。
  • nn.ReLU() 是常用的激活函数,用于引入非线性。
  • nn.Sigmoid() 用于二分类输出,如点击预测。

3.3.3 定义损失函数与训练流程

推荐系统常用的损失函数包括交叉熵损失(用于分类)和均方误差损失(用于评分预测)。

import torch
import torch.nn as nn
import torch.optim as optim

# 假设模型输出为点击概率
criterion = nn.BCELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 示例目标数据(点击为1,未点击为0)
targets = torch.FloatTensor([1, 0, 1, 0, 1])

# 前向传播
outputs = model(input_data)

# 计算损失
loss = criterion(outputs.squeeze(), targets)

# 反向传播与优化
optimizer.zero_grad()
loss.backward()
optimizer.step()

print("Loss:", loss.item())

代码逻辑分析:

  • BCELoss() 是二分类交叉熵损失函数。
  • squeeze() 用于去除输出中的多余维度。
  • loss.backward() 计算梯度, optimizer.step() 更新参数。

3.4 模型训练与调优技巧

3.4.1 模型训练过程中的监控与保存

在模型训练过程中,监控损失值和准确率是评估模型性能的重要手段。PyTorch 提供了模型保存功能,可以通过 torch.save() 将模型保存为文件。

# 每训练10个epoch保存一次模型
for epoch in range(100):
    # 训练代码
    ...
    if (epoch + 1) % 10 == 0:
        torch.save(model.state_dict(), f"model_epoch_{epoch+1}.pt")

3.4.2 超参数调优方法与学习率调整

超参数调优是提升模型性能的重要手段。常见的超参数包括学习率、批大小、隐藏层维度等。PyTorch 提供了学习率调度器(如 torch.optim.lr_scheduler )来动态调整学习率。

from torch.optim.lr_scheduler import StepLR

scheduler = StepLR(optimizer, step_size=30, gamma=0.1)

for epoch in range(100):
    # 训练代码
    ...
    scheduler.step()

说明:

  • StepLR(optimizer, step_size=30, gamma=0.1) 表示每 30 个 epoch 将学习率乘以 0.1。

以上内容完整展示了 PyTorch 在推荐系统中的应用基础,包括张量操作、自动求导、嵌入层、MLP 模型构建、损失函数定义与训练流程,以及模型训练与调优技巧。通过本章的学习,读者将具备使用 PyTorch 构建推荐系统模型的完整能力,为后续实战项目奠定坚实基础。

4. ml-100k数据集结构与加载

推荐系统的核心在于对用户行为和物品特征的建模,而这一切的基础是数据。 MovieLens-100k 是一个广泛用于推荐系统研究和教学的经典数据集,它包含 100,000 条用户对电影的评分数据,是入门推荐系统不可或缺的实验数据。本章将深入解析该数据集的结构组成、加载方法、特征构建方式以及数据集划分策略,帮助读者构建完整的数据处理流程,为后续模型训练打下坚实基础。

4.1 ml-100k数据集概述

在深入实践之前,理解数据集的来源、结构和字段含义是进行推荐系统建模的第一步。 ml-100k 是由 GroupLens Research 提供的一个开放数据集,旨在用于研究推荐系统算法的性能和效果。该数据集不仅结构清晰、数据完整,而且已经被广泛应用于学术论文和工程实践中,具有很高的参考价值。

4.1.1 数据集来源与应用场景

ml-100k 数据集最初由明尼苏达大学的 GroupLens Research Group 发布,包含 943 位用户对 1682 部电影的评分数据,共计 100,000 条评分记录。评分范围为 1 到 5 分,时间跨度为 1997 年 4 月到 1998 年 4 月。

该数据集的主要应用场景包括:

  • 推荐算法的基准测试
  • 协同过滤算法实现
  • 用户行为建模研究
  • 推荐系统评估指标验证

此外, ml-100k 数据集还包括用户的基本信息(如年龄、性别、职业)以及电影的元信息(如标题、年份、类别),这些信息可以用于构建更丰富的特征,提升推荐系统的个性化能力。

4.1.2 文件结构与字段说明

下载并解压 ml-100k 数据集后,可以看到以下主要文件:

文件名 内容说明
u.data 用户-电影评分数据
u.user 用户信息(ID、年龄、性别、职业、邮政编码)
u.item 电影信息(ID、标题、年份、类别等)
u.genre 电影分类列表
u.occupation 用户职业列表
u1.base ~ u5.test 预定义的训练集和测试集划分文件

下面详细说明几个关键文件的字段结构:

u.data 文件结构:

每行记录包含四个字段,用 \t 分隔:

user_id movie_id rating timestamp
  • user_id :用户唯一标识
  • movie_id :电影唯一标识
  • rating :用户对电影的评分(1~5)
  • timestamp :评分时间戳(可选)
u.user 文件结构:

每行记录包含五个字段,用 | 分隔:

user_id age gender occupation zipcode
  • age :用户年龄
  • gender :性别(M/F)
  • occupation :职业编号(与 u.occupation 文件对应)
  • zipcode :邮政编码(用于地理位置分析)
u.item 文件结构:

每行记录包含 24 个字段,用 | 分隔:

movie_id movie_title release_date video_release_date IMDb_URL genre_01 ... genre_19
  • movie_title :电影标题
  • release_date :上映日期
  • genre_* :电影类别(共 19 个,如 Action、Romance、Sci-Fi 等)

通过这些字段,我们可以构建丰富的用户与物品特征,从而为推荐模型提供输入。

4.2 数据集的读取与预处理

在实际建模前,必须将原始数据读取为结构化数据,并进行必要的预处理,以确保数据质量与模型输入的一致性。本节将使用 Python 中的 pandas 库对 ml-100k 数据集进行加载与清洗。

4.2.1 使用Pandas进行数据加载

我们以 u.data 为例,演示如何使用 pandas 加载评分数据:

import pandas as pd

# 定义列名
column_names = ['user_id', 'movie_id', 'rating', 'timestamp']

# 读取u.data文件
ratings_df = pd.read_csv('ml-100k/u.data', sep='\t', names=column_names)

# 查看前几行数据
print(ratings_df.head())

执行上述代码后,输出如下:

   user_id  movie_id  rating  timestamp
0        1       119     5.0  978300760
1        1       122     3.0  978300780
2        1       124     1.0  978300800
3        1       126     2.0  978300820
4        1       128     2.0  978300840

逻辑分析:

  • 使用 pd.read_csv 读取数据,通过 sep='\t' 指定以 tab 作为分隔符。
  • names 参数用于自定义列名,避免默认列名带来的混乱。
  • 读取后的数据存储为 DataFrame ,便于后续操作。

同样,可以读取用户信息和电影信息:

# 读取用户信息
user_columns = ['user_id', 'age', 'gender', 'occupation', 'zipcode']
users_df = pd.read_csv('ml-100k/u.user', sep='|', names=user_columns)

# 读取电影信息
item_columns = ['movie_id', 'title'] + ['genre_' + str(i) for i in range(1, 20)]
movies_df = pd.read_csv('ml-100k/u.item', sep='|', names=item_columns, encoding='latin-1')

4.2.2 数据清洗与缺失值处理

加载完成后,我们需要对数据进行清洗和缺失值处理,确保数据质量。

示例:缺失值检测与填充
# 检查缺失值
print(ratings_df.isnull().sum())

输出:

user_id      0
movie_id     0
rating       0
timestamp    0

表明评分数据中无缺失值。

示例:数据类型转换
# 转换为整型
ratings_df['user_id'] = ratings_df['user_id'].astype(int)
ratings_df['movie_id'] = ratings_df['movie_id'].astype(int)
ratings_df['rating'] = ratings_df['rating'].astype(float)
示例:合并用户与电影信息

我们可以将用户与电影信息合并,构建更丰富的特征:

# 合并用户信息
ratings_with_users = pd.merge(ratings_df, users_df, on='user_id')

# 合并电影信息
final_df = pd.merge(ratings_with_users, movies_df, on='movie_id')

# 查看合并后的数据
print(final_df.head())

通过以上操作,我们构建了一个包含用户属性、电影属性和评分信息的完整 DataFrame,为后续建模提供了结构化输入。

4.3 用户与物品特征的构建

为了提升推荐模型的表现,我们需要构建更具代表性的用户与物品特征。在 ml-100k 数据集中,原始数据是离散的 ID 和评分,无法直接输入神经网络模型,因此需要对其进行编码与特征提取。

4.3.1 用户ID与电影ID的编码

在深度学习模型中,通常使用嵌入(Embedding)层将离散的 ID 映射为连续向量。为此,我们需要对用户 ID 和电影 ID 进行编码,使其成为连续整数。

from sklearn.preprocessing import LabelEncoder

# 对用户ID进行编码
user_encoder = LabelEncoder()
final_df['user_id_encoded'] = user_encoder.fit_transform(final_df['user_id'])

# 对电影ID进行编码
movie_encoder = LabelEncoder()
final_df['movie_id_encoded'] = movie_encoder.fit_transform(final_df['movie_id'])

# 查看编码结果
print(final_df[['user_id', 'user_id_encoded', 'movie_id', 'movie_id_encoded']].head())

输出示例:

   user_id  user_id_encoded  movie_id  movie_id_encoded
0        1                0       119               102
1        1                0       122               105
2        1                0       124               107
3        1                0       126               109
4        1                0       128               111

逻辑分析:

  • 使用 LabelEncoder 对 ID 进行编码,将原始 ID 映射为 0 到 N-1 的连续整数。
  • 编码后的 ID 可以直接用于构建 Embedding 层输入。

4.3.2 用户行为数据的统计与特征提取

除了 ID 编码外,我们还可以构建一些统计特征,例如用户的平均评分、评分次数、评分时间分布等。

示例:用户评分行为统计
# 计算每个用户的平均评分和评分数量
user_stats = final_df.groupby('user_id').agg(
    avg_rating=('rating', 'mean'),
    num_ratings=('rating', 'count')
).reset_index()

# 合并统计特征到原始数据
final_df = pd.merge(final_df, user_stats, on='user_id')

# 查看新增特征
print(final_df[['user_id', 'avg_rating', 'num_ratings']].head())

输出示例:

   user_id  avg_rating  num_ratings
0        1    3.529412           89
1        1    3.529412           89
2        1    3.529412           89
3        1    3.529412           89
4        1    3.529412           89

逻辑分析:

  • 使用 groupby 对用户 ID 分组,计算平均评分和评分数量。
  • 这些统计特征可用于建模用户的兴趣强度和活跃程度。

4.4 数据划分与训练验证集准备

为了评估模型的泛化能力,我们需要将数据集划分为训练集、验证集和测试集。常见的划分方式包括随机划分和按时间划分。

4.4.1 数据集划分策略(按时间、随机划分)

随机划分示例:
from sklearn.model_selection import train_test_split

# 随机划分训练集与测试集
train_df, test_df = train_test_split(final_df, test_size=0.2, random_state=42)

print(f"训练集大小: {len(train_df)}")
print(f"测试集大小: {len(test_df)}")

输出示例:

训练集大小: 80000
测试集大小: 20000
按时间划分示例:
# 将时间戳转换为日期格式
final_df['date'] = pd.to_datetime(final_df['timestamp'], unit='s')

# 按时间排序
final_df.sort_values('date', inplace=True)

# 划分训练集和测试集(前80%为训练集)
split_index = int(len(final_df) * 0.8)
train_df = final_df.iloc[:split_index]
test_df = final_df.iloc[split_index:]

print(f"训练集大小: {len(train_df)}")
print(f"测试集大小: {len(test_df)}")

4.4.2 训练集、验证集和测试集的构建方法

通常推荐系统建模流程中,我们会将数据划分为三部分:

  • 训练集(Train) :用于模型训练
  • 验证集(Validation) :用于超参数调优和模型选择
  • 测试集(Test) :用于最终性能评估
示例:三划分代码
# 三划分:训练集、验证集、测试集
train_val_df, test_df = train_test_split(final_df, test_size=0.2, random_state=42)
train_df, val_df = train_test_split(train_val_df, test_size=0.25, random_state=42)

print(f"训练集大小: {len(train_df)}")
print(f"验证集大小: {len(val_df)}")
print(f"测试集大小: {len(test_df)}")

输出示例:

训练集大小: 60000
验证集大小: 20000
测试集大小: 20000

逻辑分析:

  • 使用 train_test_split 先划分测试集,再将剩余数据划分为训练集和验证集。
  • 验证集用于模型调优,防止过拟合。

通过上述划分方法,我们完成了 ml-100k 数据集的加载、预处理、特征构建和数据集划分,为后续推荐模型的训练和评估打下了坚实的数据基础。

5. 协同过滤算法实现

协同过滤(Collaborative Filtering, CF)作为推荐系统中最经典的算法之一,广泛应用于早期推荐系统中。它通过分析用户与物品之间的交互行为,挖掘用户之间的相似性或物品之间的相似性,从而为用户推荐其可能感兴趣的物品。本章将详细介绍基于用户的协同过滤(User-Based CF)和基于物品的协同过滤(Item-Based CF)的实现原理,并探讨其与深度学习模型结合的可能性,为后续构建混合推荐模型提供理论和实践基础。

5.1 基于用户的协同过滤(User-Based CF)

5.1.1 用户相似度计算方法

User-Based CF 的核心思想是: 相似用户喜欢的物品,当前用户也可能喜欢 。为了实现这一点,首先需要计算用户之间的相似度。常见的相似度计算方法包括:

  • 余弦相似度(Cosine Similarity)
  • 皮尔逊相关系数(Pearson Correlation)
  • Jaccard 相似度

以余弦相似度为例,假设我们有一个用户-物品评分矩阵 $ R $,其中 $ R_{ui} $ 表示用户 $ u $ 对物品 $ i $ 的评分。用户 $ u $ 和用户 $ v $ 的余弦相似度定义如下:

\text{sim}(u, v) = \frac{\sum_{i \in I_{uv}} R_{ui} \cdot R_{vi}}{\sqrt{\sum_{i \in I_u} R_{ui}^2} \cdot \sqrt{\sum_{i \in I_v} R_{vi}^2}}}

其中 $ I_{uv} $ 表示用户 $ u $ 和 $ v $ 共同评分的物品集合。

示例代码:用户相似度计算(基于余弦)
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity

# 假设我们有以下用户-物品评分矩阵
# 每一行代表一个用户,每一列代表一个物品
ratings = np.array([
    [5, 3, 0, 1],
    [4, 0, 0, 1],
    [1, 1, 0, 5],
    [1, 0, 0, 4],
    [0, 1, 5, 4]
])

# 计算用户之间的余弦相似度
user_similarity = cosine_similarity(ratings)

print("用户相似度矩阵:")
print(user_similarity)

代码逻辑分析:

  • ratings 是一个 5x4 的矩阵,表示 5 个用户对 4 个物品的评分。
  • cosine_similarity sklearn 提供的函数,用于快速计算矩阵中每两行之间的余弦相似度。
  • 输出结果是一个 5x5 的矩阵,表示每个用户与其他用户之间的相似度。

5.1.2 相似用户推荐生成

在获得用户相似度后,下一步是为当前用户推荐物品。推荐的基本思路是:

  1. 找到与当前用户最相似的 K 个邻居用户(Top-K 相似用户)。
  2. 收集这些邻居用户喜欢的物品,并排除当前用户已评分的物品。
  3. 对这些物品进行加权平均评分,生成推荐列表。
示例代码:生成用户推荐
def recommend_items(user_index, ratings, user_similarity, k=2):
    # 获取当前用户的评分
    user_ratings = ratings[user_index]
    # 获取相似度最高的K个用户索引(排除自己)
    similar_users = np.argsort(user_similarity[user_index])[::-1][1:k+1]
    # 初始化推荐评分字典
    recommendations = {}
    # 遍历每个相似用户
    for neighbor in similar_users:
        # 获取邻居用户的评分
        neighbor_ratings = ratings[neighbor]
        # 获取当前用户未评分但邻居用户评分过的物品
        unrated_items = np.where(user_ratings == 0)[0]
        rated_by_neighbor = np.where(neighbor_ratings > 0)[0]
        candidate_items = np.intersect1d(unrated_items, rated_by_neighbor)
        # 对这些物品进行加权评分
        for item in candidate_items:
            if item not in recommendations:
                recommendations[item] = 0
            recommendations[item] += neighbor_ratings[item] * user_similarity[user_index][neighbor]
    # 返回按评分排序的推荐列表
    return sorted(recommendations.items(), key=lambda x: x[1], reverse=True)

# 为用户0推荐物品
recommended_items = recommend_items(0, ratings, user_similarity, k=2)
print("为用户0推荐的物品索引和加权评分:", recommended_items)

代码逻辑分析:

  • recommend_items 函数接收当前用户索引、评分矩阵、用户相似度矩阵和 K 值。
  • 使用 np.argsort 排序相似度并取前 K 个用户作为邻居。
  • 遍历邻居用户,找出当前用户未评分但邻居用户评分过的物品。
  • 使用邻居用户的评分乘以相似度作为加权分值。
  • 最终返回按加权分值排序的推荐列表。
小结:

用户相似度计算是 User-Based CF 的核心步骤,余弦相似度、皮尔逊相关系数等方法各有优劣,可根据数据分布和场景选择。推荐生成则依赖于相似用户的评分数据,适用于用户行为数据丰富的场景。

5.2 基于物品的协同过滤(Item-Based CF)

5.2.1 物品相似度计算

与 User-Based CF 不同,Item-Based CF 的核心思想是: 喜欢某物品的用户也喜欢与其相似的物品 。因此,该方法更关注物品之间的相似性。

物品相似度的计算方式与用户相似度类似,同样可以使用余弦相似度、皮尔逊相关系数等。以余弦相似度为例,物品 $ i $ 和 $ j $ 的相似度公式如下:

\text{sim}(i, j) = \frac{\sum_{u \in U_{ij}} R_{ui} \cdot R_{uj}}{\sqrt{\sum_{u \in U_i} R_{ui}^2} \cdot \sqrt{\sum_{u \in U_j} R_{uj}^2}}}

其中 $ U_{ij} $ 表示同时评分了物品 $ i $ 和 $ j $ 的用户集合。

示例代码:物品相似度计算(基于余弦)
# 转置评分矩阵,得到物品-用户评分矩阵
item_ratings = ratings.T

# 计算物品之间的余弦相似度
item_similarity = cosine_similarity(item_ratings)

print("物品相似度矩阵:")
print(item_similarity)

代码逻辑分析:

  • 将用户-物品评分矩阵转置,得到物品-用户评分矩阵。
  • 使用 cosine_similarity 计算物品之间的相似度。
  • 输出结果是一个 4x4 的矩阵,表示每个物品与其他物品之间的相似度。

5.2.2 物品推荐策略实现

Item-Based CF 的推荐流程如下:

  1. 对于当前用户已经评分的物品,找出与其最相似的 K 个物品。
  2. 对这些物品进行加权平均,计算当前用户对未评分物品的预测评分。
  3. 按预测评分排序,生成推荐列表。
示例代码:物品推荐生成
def recommend_items_item_based(user_index, ratings, item_similarity, k=2):
    # 获取当前用户的评分
    user_ratings = ratings[user_index]
    # 初始化推荐评分字典
    recommendations = {}
    # 遍历当前用户已评分的物品
    for item in np.where(user_ratings > 0)[0]:
        # 获取与该物品最相似的K个物品
        similar_items = np.argsort(item_similarity[item])[::-1][1:k+1]
        # 对这些相似物品进行加权评分
        for sim_item in similar_items:
            if user_ratings[sim_item] == 0:  # 只推荐未评分的物品
                if sim_item not in recommendations:
                    recommendations[sim_item] = 0
                recommendations[sim_item] += user_ratings[item] * item_similarity[item][sim_item]
    # 返回按评分排序的推荐列表
    return sorted(recommendations.items(), key=lambda x: x[1], reverse=True)

# 为用户0推荐物品(基于物品的CF)
item_based_recommendations = recommend_items_item_based(0, ratings, item_similarity, k=2)
print("为用户0推荐的物品索引和加权评分(基于物品CF):", item_based_recommendations)

代码逻辑分析:

  • recommend_items_item_based 函数接收用户索引、评分矩阵、物品相似度矩阵和 K 值。
  • 遍历当前用户已评分的物品,找到与其相似的 K 个物品。
  • 使用当前物品的评分乘以相似度作为加权分值。
  • 最终返回按加权分值排序的推荐列表。
表格:User-Based CF vs Item-Based CF 对比
指标 User-Based CF Item-Based CF
计算对象 用户之间相似度 物品之间相似度
推荐依据 相似用户的评分 相似物品的评分
适用场景 用户数量 < 物品数量 物品数量 < 用户数量
实时性要求 高(用户变化频繁) 低(物品变化较少)
可解释性 弱(推荐理由为“相似用户”) 强(推荐理由为“相似物品”)

5.3 协同过滤与深度学习的结合

5.3.1 将协同过滤结果作为模型输入

虽然协同过滤本身是传统推荐方法,但其结果可以作为深度学习模型的输入特征之一,增强模型的推荐能力。例如:

  • 将用户相似度或物品相似度作为输入特征向量
  • 将协同过滤的预测评分作为辅助目标函数
  • 将协同过滤的结果作为特征工程的一部分
示例代码:将物品相似度作为特征输入神经网络
import torch
import torch.nn as nn

# 将物品相似度作为特征输入MLP
class ItemBasedMLP(nn.Module):
    def __init__(self, input_dim, hidden_dim, output_dim):
        super(ItemBasedMLP, self).__init__()
        self.embedding = nn.Embedding(4, input_dim)  # 物品嵌入层
        self.fc = nn.Sequential(
            nn.Linear(input_dim + item_similarity.shape[1], hidden_dim),  # 加入物品相似度
            nn.ReLU(),
            nn.Linear(hidden_dim, output_dim)
        )
    def forward(self, item_indices, item_similarities):
        item_emb = self.embedding(item_indices)
        combined = torch.cat((item_emb, item_similarities), dim=1)
        return self.fc(combined)

# 构建模型
model = ItemBasedMLP(input_dim=10, hidden_dim=64, output_dim=1)

# 模拟输入
item_indices = torch.LongTensor([0, 1, 2, 3])
item_similarities = torch.FloatTensor(item_similarity)

# 前向传播
output = model(item_indices, item_similarities)
print("物品评分预测输出:", output)

代码逻辑分析:

  • 定义一个简单的 MLP 模型,包含物品嵌入层和全连接层。
  • 输入包括物品索引和物品相似度特征。
  • forward 中,将物品嵌入与物品相似度拼接后输入全连接层。
  • 最终输出为物品评分预测。

5.3.2 混合推荐模型构建思路

结合协同过滤与深度学习模型的思路,可以构建以下几种混合推荐模型:

  1. 特征融合型 :将协同过滤的相似度矩阵、用户/物品 Embedding 等特征拼接输入神经网络。
  2. 损失函数融合型 :在损失函数中加入协同过滤的预测误差作为辅助损失。
  3. 模型集成型 :使用协同过滤作为基础模型,深度学习模型作为修正模型,进行加权组合。
Mermaid 流程图:混合推荐模型结构
graph TD
    A[用户行为数据] --> B[协同过滤模块]
    C[物品特征数据] --> D[深度学习模型]
    B --> E[融合层]
    D --> E
    E --> F[最终推荐结果]

流程图说明:

  • 用户行为数据输入协同过滤模块,提取用户/物品相似度。
  • 物品特征数据输入深度学习模型,提取高阶特征表示。
  • 融合层将两者结果结合,生成最终推荐结果。
小结:

协同过滤与深度学习的结合,可以有效提升推荐系统的准确性和泛化能力。通过将协同过滤的结果作为特征输入深度学习模型,或作为损失函数的一部分,能够增强模型对用户行为的建模能力。混合推荐模型的构建思路灵活多样,适合不同场景下的推荐任务。

本章从协同过滤的基本原理出发,详细讲解了基于用户和基于物品的协同过滤实现方式,并给出了代码实现和推荐逻辑分析。同时,探讨了协同过滤与深度学习模型结合的可能性,为后续构建混合推荐系统提供了实践基础和理论支持。

6. 推荐模型训练与效果评估

6.1 推荐模型训练流程

推荐模型的训练流程通常包含模型初始化、数据准备、批量训练和模型更新等核心步骤。以下以PyTorch为例,说明一个基于多层感知机(MLP)的推荐模型训练流程。

6.1.1 模型初始化与参数配置

在PyTorch中,推荐模型的构建通常继承 torch.nn.Module 类。例如,构建一个包含嵌入层和MLP层的推荐模型:

import torch
import torch.nn as nn

class MLPRecommender(nn.Module):
    def __init__(self, num_users, num_items, embedding_dim=64, hidden_dim=128):
        super(MLPRecommender, self).__init__()
        self.user_embedding = nn.Embedding(num_users, embedding_dim)
        self.item_embedding = nn.Embedding(num_items, embedding_dim)
        self.mlp = nn.Sequential(
            nn.Linear(embedding_dim * 2, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, 1)
        )
    def forward(self, user_ids, item_ids):
        user_emb = self.user_embedding(user_ids)
        item_emb = self.item_embedding(item_ids)
        vector = torch.cat([user_emb, item_emb], dim=-1)
        return self.mlp(vector)

参数说明:
- num_users :用户数量
- num_items :物品数量
- embedding_dim :用户和物品嵌入向量的维度
- hidden_dim :MLP中间层节点数

6.1.2 批量训练与迭代更新

推荐系统通常采用小批量(mini-batch)训练策略。以下是一个训练循环的示例:

from torch.utils.data import DataLoader, TensorDataset

# 假设我们有训练数据 user_ids, item_ids, ratings
train_dataset = TensorDataset(user_ids_tensor, item_ids_tensor, ratings_tensor)
train_loader = DataLoader(train_dataset, batch_size=256, shuffle=True)

model = MLPRecommender(num_users=943, num_items=1682)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

for epoch in range(10):  # 训练10轮
    for users, items, targets in train_loader:
        outputs = model(users, items)
        loss = criterion(outputs, targets)

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print(f"Epoch {epoch+1}, Loss: {loss.item()}")

说明:
- 使用 DataLoader 进行数据批量加载,提升训练效率。
- 使用 Adam 优化器进行参数更新,学习率设为0.001。
- 损失函数采用均方误差(MSE),适用于评分预测任务。

6.2 模型评估指标设计

推荐系统的评估通常根据任务类型(回归或分类)选择不同的指标。

6.2.1 回归任务常用指标(RMSE、MAE)

评分预测任务属于回归问题,常用指标包括:

指标 公式 说明
RMSE √(1/n ∑(y_true - y_pred)^2) 均方根误差,对大误差更敏感
MAE 1/n ∑ y_true - y_pred

在PyTorch中计算RMSE:

import torch
import math

def compute_rmse(y_true, y_pred):
    return math.sqrt(torch.mean((y_true - y_pred) ** 2))

6.2.2 分类任务常用指标(准确率、AUC)

点击预测任务属于二分类问题,常用指标包括:

指标 说明
Accuracy 准确率,正确预测样本占总样本的比例
AUC 曲线下面积,衡量模型对正负样本的排序能力

使用 sklearn 计算AUC:

from sklearn.metrics import roc_auc_score

y_true = [0, 1, 1, 0]
y_scores = [0.1, 0.9, 0.8, 0.2]
auc = roc_auc_score(y_true, y_scores)
print(f"AUC: {auc}")

6.3 学习曲线与模型调优

学习曲线是分析模型训练过程和调参的重要工具。

6.3.1 学习曲线绘制与分析

学习曲线反映模型在训练集和验证集上的表现变化。以下是一个绘制学习曲线的示例:

import matplotlib.pyplot as plt

train_losses = []
val_losses = []

for epoch in range(10):
    model.train()
    for users, items, targets in train_loader:
        ...
    train_loss = ...
    train_losses.append(train_loss)

    model.eval()
    with torch.no_grad():
        val_loss = ...
        val_losses.append(val_loss)

plt.plot(train_losses, label='Train Loss')
plt.plot(val_losses, label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.title('Learning Curve')
plt.show()

通过观察学习曲线,可以判断是否出现过拟合或欠拟合现象。

6.3.2 学习率与隐藏层节点数的调整策略

调整策略示例:

参数 调整建议
学习率 初始设为0.001,若训练不稳定可尝试0.0001
隐藏层节点数 从64、128、256逐步增加,观察验证集表现

使用学习率调度器动态调整:

scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', patience=2)
for epoch in range(10):
    ...
    val_loss = ...
    scheduler.step(val_loss)

6.4 推荐结果可视化与分析

推荐系统的最终目标是生成高质量的推荐列表,并对结果进行可视化和解释。

6.4.1 推荐列表生成与展示

以下代码展示如何为用户生成Top-N推荐:

def get_top_n_recommendations(model, user_id, all_items, top_n=10):
    model.eval()
    with torch.no_grad():
        user_tensor = torch.tensor([user_id] * len(all_items))
        item_tensor = torch.tensor(all_items)
        scores = model(user_tensor, item_tensor).squeeze()
        top_items = torch.topk(scores, top_n).indices.tolist()
    return top_items

all_items = list(range(1682))  # ml-100k数据集有1682部电影
user_id = 0
top_movies = get_top_n_recommendations(model, user_id, all_items)
print(f"Top 10 recommended movies for user {user_id}: {top_movies}")

6.4.2 推荐结果的可解释性分析

推荐系统的可解释性可以通过以下方式增强:

  • 特征贡献分析 :使用梯度或注意力权重分析用户/物品特征对推荐结果的影响。
  • 可视化工具 :如使用 TensorBoard 记录训练过程与推荐结果分布。

示例:使用 TensorBoard 记录损失变化:

from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter('runs/recommender_experiment')

for epoch in range(10):
    ...
    writer.add_scalar('Loss/train', train_loss, epoch)
    writer.add_scalar('Loss/val', val_loss, epoch)

writer.close()

启动TensorBoard查看:

tensorboard --logdir=runs

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:该项目是人工智能领域的毕业设计或课程设计,聚焦深度学习推荐系统的构建,使用经典电影推荐数据集ml-100k,并基于PyTorch框架实现《深度学习推荐系统》一书中的多种模型。通过数据预处理、模型构建、训练与评估等流程,帮助学生掌握协同过滤、矩阵分解、神经网络等推荐系统核心技术,并提升深度学习在实际推荐场景中的应用能力。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

更多推荐