PyTorch 神经协同过滤 (NCF) 推荐系统教程

目录

      • 教程概述
      • [1. 神经协同过滤模型概述](#1. 神经协同过滤模型概述)
        • [NCF 模型的主要组成部分:](#NCF 模型的主要组成部分:)
      • [2. 数据加载与预处理](#2. 数据加载与预处理)
      • [3. 定义神经协同过滤模型](#3. 定义神经协同过滤模型)
      • [4. 训练模型](#4. 训练模型)
      • [5. 模型评估](#5. 模型评估)
      • [6. 推荐物品](#6. 推荐物品)
      • [7. 完整示例](#7. 完整示例)
      • [8. 总结](#8. 总结)

在本教程中,我们将使用 PyTorch 实现一个神经协同过滤(Neural Collaborative Filtering,简称 NCF)推荐系统。神经协同过滤是一种基于深度学习的推荐系统模型,通过学习用户和物品的嵌入表示来预测用户对物品的评分,进而提供个性化的推荐。

教程概述

推荐系统通过分析用户历史行为数据,为用户推荐相关的物品或内容。在协同过滤方法中,我们关注于从用户-物品评分矩阵中挖掘出潜在的规律,从而预测用户对未见物品的评分。

在本教程中,我们将:

  1. 介绍神经协同过滤模型的基本原理。
  2. 使用 PyTorch 实现 NCF 模型。
  3. 训练并评估该模型。
  4. 使用训练好的模型为用户推荐物品。
  5. 绘制训练过程中的损失曲线图表,帮助我们更直观地理解模型训练效果。

1. 神经协同过滤模型概述

神经协同过滤 (NCF) 是一种深度学习方法,用于解决传统协同过滤方法在处理用户-物品关系时的限制。其基本思想是通过将用户和物品的特征嵌入到低维向量空间中,然后通过神经网络对这些嵌入向量进行组合和映射,最终预测用户对物品的评分。

NCF 模型的主要组成部分:
  • 嵌入层 (Embedding Layer):通过学习低维的用户和物品嵌入向量,将高维的用户 ID 和物品 ID 映射到低维空间。
  • 多层感知机 (MLP):通过一个多层感知机(全连接层)将用户和物品的嵌入向量拼接起来,进行进一步的特征学习和映射,最后输出预测的评分。

2. 数据加载与预处理

首先,我们需要准备一个评分数据集。该数据集通常包含用户对物品的评分,格式如下:

复制代码
userId, movieId, rating
1, 102, 4.32
2, 47, 3.85
3, 356, 4.72
...

我们使用 pandas 加载数据并进行预处理,将用户 ID 和物品 ID 昻射到连续的整数索引,并划分训练集和测试集。

python 复制代码
import torch
import torch.nn as nn
import torch.optim as optim
import pandas as pd
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt

# 1. 加载并准备数据
def load_data(file_path):
    df = pd.read_csv(file_path)
    train_data, test_data = train_test_split(df, test_size=0.2, random_state=42)
    
    # 创建用户和物品的映射字典
    user_map = {user: idx for idx, user in enumerate(df['userId'].unique())}
    movie_map = {movie: idx for idx, movie in enumerate(df['movieId'].unique())}
    
    # 映射用户和物品 ID
    train_data['user'] = train_data['userId'].map(user_map)
    train_data['movie'] = train_data['movieId'].map(movie_map)
    test_data['user'] = test_data['userId'].map(user_map)
    test_data['movie'] = test_data['movieId'].map(movie_map)

    return train_data, test_data, len(user_map), len(movie_map)

3. 定义神经协同过滤模型

接下来,我们将使用 PyTorch 定义神经协同过滤模型。该模型包含两个嵌入层(一个用于用户,另一个用于物品)和一个多层感知机(MLP)来组合用户和物品的嵌入向量,最后输出一个预测评分。

python 复制代码
import torch
import torch.nn as nn

class NCF(nn.Module):
    def __init__(self, num_users, num_movies, embedding_dim=50, hidden_dim=64):
        super(NCF, self).__init__()
        
        # 嵌入层
        self.user_embedding = nn.Embedding(num_users, embedding_dim)
        self.movie_embedding = nn.Embedding(num_movies, embedding_dim)
        
        # MLP 层
        self.mlp = nn.Sequential(
            nn.Linear(embedding_dim * 2, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, 1)
        )
    
    def forward(self, user, movie):
        # 获取用户和物品的嵌入向量
        user_emb = self.user_embedding(user)
        movie_emb = self.movie_embedding(movie)
        
        # 拼接用户和物品的嵌入向量
        x = torch.cat([user_emb, movie_emb], dim=-1)
        
        # 通过 MLP 计算预测评分
        output = self.mlp(x)
        return output.squeeze()  # 返回标量预测值

4. 训练模型

模型训练包括使用均方误差 (MSE) 损失函数,采用 Adam 优化器进行优化。我们在每个 epoch 后记录损失值,并使用 matplotlib 绘制损失曲线图。

python 复制代码
def train_model(model, train_data, num_epochs=10, batch_size=64, learning_rate=0.001):
    criterion = nn.MSELoss()
    optimizer = optim.Adam(model.parameters(), lr=learning_rate)
    
    train_users = torch.tensor(train_data['user'].values, dtype=torch.long)
    train_movies = torch.tensor(train_data['movie'].values, dtype=torch.long)
    train_ratings = torch.tensor(train_data['rating'].values, dtype=torch.float32)

    model.train()

    # 用于记录每个epoch的损失
    epoch_losses = []

    for epoch in range(num_epochs):
        total_loss = 0
        for i in range(0, len(train_users), batch_size):
            user_batch = train_users[i:i+batch_size]
            movie_batch = train_movies[i:i+batch_size]
            rating_batch = train_ratings[i:i+batch_size]
            
            # 前向传播
            optimizer.zero_grad()
            predictions = model(user_batch, movie_batch)
            
            # 计算损失
            loss = criterion(predictions, rating_batch)
            
            # 反向传播
            loss.backward()
            optimizer.step()
            
            total_loss += loss.item()
        
        avg_loss = total_loss / len(train_users)
        epoch_losses.append(avg_loss)  # 记录损失值

        print(f"Epoch {epoch+1}/{num_epochs}, Loss: {avg_loss}")

    return epoch_losses

5. 模型评估

训练完成后,我们可以使用测试集来评估模型的表现,计算其均方误差(MSE)来衡量预测的准确性。

python 复制代码
def evaluate_model(model, test_data):
    test_users = torch.tensor(test_data['user'].values, dtype=torch.long)
    test_movies = torch.tensor(test_data['movie'].values, dtype=torch.long)
    test_ratings = torch.tensor(test_data['rating'].values, dtype=torch.float32)

    model.eval()
    with torch.no_grad():
        predictions = model(test_users, test_movies)
        mse = nn.MSELoss()(predictions, test_ratings)
        print(f'Mean Squared Error on Test Set: {mse.item()}')

6. 推荐物品

一旦模型训练完成,我们可以使用它为用户推荐物品。模型将根据用户的历史评分为其推荐最相关的电影。

python 复制代码
def recommend_for_user(model, user_id, num_movies, movie_map, top_n=10):
    user_tensor = torch.tensor([user_id], dtype=torch.long)
    all_movies = torch.tensor(range(num_movies), dtype=torch.long)
    
    model.eval()
    with torch.no_grad():
        scores = model(user_tensor.repeat(num_movies), all_movies)
    
    # 获取前 N 个物品
    recommended_movie_ids = scores.argsort(descending=True)[:top_n]
    recommended_movies = [list(movie_map.keys())[i.item()] for i in recommended_movie_ids]
    return recommended_movies

7. 完整示例

最后,将所有组件组合在一起,完成模型的训练和推荐过程:

python 复制代码
if __name__ == "__main__":
    # 1. 加载数据
    train_data, test_data, num_users, num_movies = load_data('ratings.csv')
    
    # 2. 创建和训练模型
    model = NCF(num_users, num_movies)
    num_epochs = 10  # 训练的 epoch 数
    epoch_losses = train_model(model, train_data, num_epochs=num_epochs, batch_size=64, learning_rate=0.001)
    
    # 3. 测试模型
    evaluate_model(model, test_data)
    
    # 4. 推荐:为用户 1 推荐物品
    recommended_movies = recommend_for_user(model, 1, num_movies, dict(enumerate(range(num_movies))))
    print("Recommended movies for user 1:", recommended_movies)
    
    # 5. 绘制损失图表
    plt.plot(range(1, num_epochs + 1), epoch_losses, marker='o', color='b')
    plt.title('Training Loss Over Epochs')
    plt.xlabel('Epoch')
    plt.ylabel('Loss')
    plt.grid(True)
    plt.show()

8. 总结

在本教程中,我们使用 PyTorch 实现了一个基于神经网络的协同过滤推荐系统(NCF)。通过训练用户和物品的嵌入向量,模型能够学习到用户和物品之间的复杂关系,从而进行准确的评分预测和个性化推荐。我们还通过绘制损失曲线图,直观地展示了模型训练过程中的损失变化。

相关推荐
程序员阿超的博客16 分钟前
Python 数据分析与机器学习入门 (五):Matplotlib 数据可视化基础
python·信息可视化·数据分析·matplotlib·数据可视化·python教程·pyplot
站大爷IP31 分钟前
Python 办公实战:用 python-docx 自动生成 Word 文档
python
MO2T1 小时前
使用 Flask 构建基于 Dify 的企业资金投向与客户分类评估系统
后端·python·语言模型·flask
慢热型网友.1 小时前
用 Docker 构建你的第一个 Python Flask 程序
python·docker·flask
Naiva1 小时前
【小技巧】Python + PyCharm 小智AI配置MCP接入点使用说明(内测)( PyInstaller打包成 .exe 可执行文件)
开发语言·python·pycharm
云动雨颤1 小时前
Python 自动化办公神器|一键转换所有文档为 PDF
运维·python
梅孔立1 小时前
yum update 报错 Cannot find a valid baseurl for repo: centos-sclo-rh/x86_64 等解决办法
linux·python·centos
喝过期的拉菲1 小时前
使用 Pytorch Lightning 时追踪指标和可视化指标
pytorch·可视化·lightning·指标追踪
前端付豪2 小时前
13、你还在 print 调试🧾?教你写出自己的日志系统
后端·python
这里有鱼汤2 小时前
hvPlot:用你熟悉的 Pandas,画出你没见过的炫图
后端·python