当前位置: 首页 > news >正文

从社交网络到推荐系统:手把手用PyTorch+GCN构建你的第一个图神经网络模型

从社交网络到推荐系统:手把手用PyTorch+GCN构建你的第一个图神经网络模型

当你在电商平台浏览商品时,那些"猜你喜欢"的推荐从何而来?当社交网络为你推荐可能认识的人,背后又是什么算法在运作?这些场景的核心技术之一就是图卷积网络(GCN)。与传统的卷积神经网络不同,GCN专门用于处理图结构数据——这种数据在我们的数字生活中无处不在,从社交关系到商品购买,从知识图谱到交通网络。

本文将带你从零开始,构建一个基于PyTorch和切比雪夫多项式的GCN推荐系统。不同于大多数教程只关注理论推导,我们将聚焦于实际应用,教你如何将抽象的图卷积概念转化为可运行的代码,最终打造一个能处理用户-商品交互数据的推荐模型。无论你是想提升现有推荐系统的效果,还是希望掌握图神经网络这一前沿技术,本文都能提供实用的指导。

1. 图神经网络基础与推荐系统场景

图神经网络之所以在推荐系统中表现出色,是因为它能够自然地建模用户和商品之间的复杂交互。想象一下,在电商平台上:

  • 每个用户和商品都是图中的一个节点
  • 用户购买商品、浏览商品、将商品加入购物车等行为构成了图中的边
  • 用户之间的社交关系也可以作为边加入图中

传统推荐系统通常将用户和商品视为独立的个体,而GCN则能够捕捉它们之间的高阶连接关系。例如,通过分析"用户A→商品1←用户B→商品2"这样的路径,模型可以推断出用户A可能也对商品2感兴趣。

为什么选择切比雪夫多项式?

切比雪夫多项式在图卷积中的应用有三大优势:

  1. 计算高效:避免了直接计算拉普拉斯矩阵的特征分解
  2. 局部性:K阶多项式只考虑K跳邻居,适合大规模图数据
  3. 灵活性:可以通过调整K值控制感受野大小

下面是一个简单的用户-商品交互矩阵示例:

用户\商品商品1商品2商品3
用户A101
用户B110
用户C011

这个矩阵可以转化为图的邻接矩阵,其中用户和商品都是节点,交互行为是边。

2. 环境搭建与数据准备

2.1 PyTorch环境配置

推荐使用Python 3.8+和PyTorch 1.10+环境。可以通过以下命令安装所需库:

pip install torch torch-geometric numpy pandas scikit-learn

注意:torch-geometric是PyTorch的图神经网络扩展库,安装时需选择与PyTorch和CUDA版本兼容的版本。

2.2 构建推荐系统图数据集

我们将使用一个模拟的用户-商品交互数据集来演示。实际应用中,你可以替换为自己的业务数据。

import numpy as np import torch from torch_geometric.data import Data # 模拟数据:3个用户,4个商品 num_users = 3 num_items = 4 # 用户-商品交互边(用户0购买商品0和1,用户1购买商品1和2,等等) edge_index = torch.tensor([ [0, 0, 1, 1, 2, 2, 2], # 用户节点 [3, 4, 4, 5, 3, 5, 6] # 商品节点(编号从num_users开始) ], dtype=torch.long) # 节点特征:用户年龄和性别(0/1),商品类别和价格 x = torch.tensor([ [25, 0], # 用户0 [30, 1], # 用户1 [22, 1], # 用户2 [1, 29], # 商品3 [2, 39], # 商品4 [1, 19], # 商品5 [3, 49] # 商品6 ], dtype=torch.float) # 创建PyTorch Geometric的Data对象 data = Data(x=x, edge_index=edge_index) print(data)

这个数据集包含:

  • 7个节点(3用户+4商品)
  • 7条边(交互记录)
  • 每个节点有2个特征

3. 切比雪夫GCN模型实现

3.1 切比雪夫多项式基础

切比雪夫多项式是一组正交多项式,在图卷积中用于近似图傅里叶变换。其递归定义为:

T₀(x) = 1 T₁(x) = x Tₖ(x) = 2xTₖ₋₁(x) - Tₖ₋₂(x) (k ≥ 2)

在GCN中,我们用切比雪夫多项式来近似图拉普拉斯矩阵的函数:

gθ = ∑ θₖTₖ(L̃)

其中L̃是缩放后的拉普拉斯矩阵。

3.2 实现切比雪夫卷积层

import torch.nn as nn import torch.nn.functional as F class ChebConv(nn.Module): def __init__(self, in_channels, out_channels, K): super(ChebConv, self).__init__() self.K = K self.weights = nn.Parameter(torch.Tensor(K+1, in_channels, out_channels)) self.reset_parameters() def reset_parameters(self): nn.init.xavier_uniform_(self.weights) def forward(self, x, L): """ x: 节点特征矩阵 [num_nodes, in_channels] L: 缩放后的拉普拉斯矩阵 [num_nodes, num_nodes] 返回: 卷积后的特征 [num_nodes, out_channels] """ # 计算切比雪夫多项式 Tx = [x] # T₀(L̃)x = x if self.K > 0: Tx.append(torch.sparse.mm(L, x)) # T₁(L̃)x = L̃x for k in range(2, self.K+1): Tx.append(2 * torch.sparse.mm(L, Tx[-1]) - Tx[-2]) # Tₖ(L̃)x = 2L̃Tₖ₋₁(L̃)x - Tₖ₋₂(L̃)x # 加权求和 out = torch.zeros_like(Tx[0]) for k in range(self.K+1): out += torch.mm(Tx[k], self.weights[k]) return out

3.3 构建完整推荐模型

现在我们将切比雪夫卷积层整合到一个完整的推荐模型中:

class GCNRecommender(nn.Module): def __init__(self, num_users, num_items, user_feats, item_feats, hidden_size, K): super(GCNRecommender, self).__init__() self.user_embedding = nn.Embedding(num_users, user_feats) self.item_embedding = nn.Embedding(num_items, item_feats) self.conv1 = ChebConv(user_feats + item_feats, hidden_size, K) self.conv2 = ChebConv(hidden_size, hidden_size, K) self.predict = nn.Linear(hidden_size, 1) def forward(self, user_idx, item_idx, L): # 获取用户和商品的嵌入 user_emb = self.user_embedding(user_idx) item_emb = self.item_embedding(item_idx) # 拼接所有节点特征 x = torch.cat([user_emb, item_emb], dim=0) # 图卷积 x = F.relu(self.conv1(x, L)) x = F.relu(self.conv2(x, L)) # 预测评分 user_out = x[user_idx] item_out = x[num_users + item_idx] return torch.sigmoid(self.predict(user_out * item_out))

4. 模型训练与评估

4.1 数据预处理与拉普拉斯矩阵计算

def prepare_data(data, num_users, num_items): # 构建邻接矩阵 num_nodes = num_users + num_items adj = torch.zeros((num_nodes, num_nodes)) adj[data.edge_index[0], data.edge_index[1]] = 1 adj = adj + adj.t() # 使矩阵对称 adj = adj.clamp(max=1) # 确保没有大于1的值 # 计算度矩阵 degree = torch.diag(adj.sum(dim=1)) # 计算归一化拉普拉斯矩阵 degree_inv_sqrt = torch.diag(1.0 / torch.sqrt(adj.sum(dim=1))) L = torch.eye(num_nodes) - degree_inv_sqrt @ adj @ degree_inv_sqrt # 缩放拉普拉斯矩阵到[-1,1]区间 lambda_max = 2.0 # 正则图的最大特征值理论为2 L_scaled = (2 * L) / lambda_max - torch.eye(num_nodes) return adj, L_scaled # 准备数据 adj, L_scaled = prepare_data(data, num_users=3, num_items=4)

4.2 训练循环与评估

from sklearn.model_selection import train_test_split # 创建训练和测试集 all_pairs = [(u, i) for u in range(3) for i in range(4)] labels = [adj[u, 3+i].item() for u, i in all_pairs] # 使用邻接矩阵中的交互作为标签 train_pairs, test_pairs, y_train, y_test = train_test_split(all_pairs, labels, test_size=0.2) # 初始化模型 model = GCNRecommender(num_users=3, num_items=4, user_feats=2, item_feats=2, hidden_size=16, K=2) optimizer = torch.optim.Adam(model.parameters(), lr=0.01) criterion = nn.BCELoss() # 训练 for epoch in range(100): model.train() optimizer.zero_grad() # 准备batch数据 users = torch.tensor([u for u, i in train_pairs]) items = torch.tensor([i for u, i in train_pairs]) preds = model(users, items, L_scaled).squeeze() loss = criterion(preds, torch.tensor(y_train, dtype=torch.float)) loss.backward() optimizer.step() # 评估 model.eval() with torch.no_grad(): test_users = torch.tensor([u for u, i in test_pairs]) test_items = torch.tensor([i for u, i in test_pairs]) test_preds = model(test_users, test_items, L_scaled).squeeze() test_loss = criterion(test_preds, torch.tensor(y_test, dtype=torch.float)) print(f'Epoch {epoch+1}, Train Loss: {loss.item():.4f}, Test Loss: {test_loss.item():.4f}')

4.3 推荐生成

训练完成后,我们可以为特定用户生成推荐:

def recommend_for_user(user_idx, model, num_items, L_scaled, top_k=2): model.eval() with torch.no_grad(): # 为指定用户对所有商品评分 user_tensor = torch.tensor([user_idx] * num_items) item_tensor = torch.tensor(range(num_items)) scores = model(user_tensor, item_tensor, L_scaled).squeeze() # 排除已交互的商品 interacted = adj[user_idx, 3:].nonzero().squeeze() scores[interacted] = -1 # 获取top-k推荐 _, top_items = torch.topk(scores, top_k) return top_items.tolist() # 为用户0生成推荐 print("为用户0推荐的商品:", recommend_for_user(0, model, num_items=4, L_scaled=L_scaled))

5. 进阶优化与实际应用技巧

5.1 处理大规模图的技巧

当面对百万级节点的图数据时,直接计算切比雪夫多项式可能不可行。以下是几种优化策略:

  1. 邻居采样:每次训练只采样每个节点的K-hop邻居
  2. 图分区:将大图分割为多个子图分别处理
  3. 稀疏矩阵运算:利用PyTorch的稀疏矩阵操作减少内存使用
# 稀疏矩阵版本的切比雪夫卷积 class SparseChebConv(nn.Module): def forward(self, x, L_sparse): Tx = [x] if self.K > 0: Tx.append(torch.sparse.mm(L_sparse, x)) for k in range(2, self.K+1): Tx.append(2 * torch.sparse.mm(L_sparse, Tx[-1]) - Tx[-2]) out = torch.zeros_like(Tx[0]) for k in range(self.K+1): out += torch.mm(Tx[k], self.weights[k]) return out

5.2 融合多种图结构

实际推荐系统中,可以融合多种图结构信息:

  • 用户-商品交互图
  • 用户-用户社交图
  • 商品-商品相似图
class MultiGraphGCN(nn.Module): def __init__(self, in_channels, hidden_size, K): super().__init__() self.conv_interact = ChebConv(in_channels, hidden_size, K) self.conv_social = ChebConv(in_channels, hidden_size, K) self.fusion = nn.Linear(2*hidden_size, hidden_size) def forward(self, x, L_interact, L_social): h1 = F.relu(self.conv_interact(x, L_interact)) h2 = F.relu(self.conv_social(x, L_social)) h = torch.cat([h1, h2], dim=1) return self.fusion(h)

5.3 冷启动问题解决方案

对于新用户或新商品,可以采用以下策略:

  1. 元学习:训练模型快速适应新节点
  2. 内容特征增强:利用商品描述、用户画像等辅助信息
  3. 图扩充:通过相似度连接新节点到现有图
# 处理新用户的示例 def process_new_user(user_features, existing_model, L_scaled): # 将新用户特征与现有图连接 new_x = torch.cat([existing_model.x, user_features], dim=0) # 更新拉普拉斯矩阵(需要重新计算) new_adj = update_adjacency_matrix() # 实现略 new_L = compute_laplacian(new_adj) # 实现略 # 生成推荐 return recommend_for_user(new_user_idx, existing_model, num_items, new_L)
http://www.jsqmd.com/news/994737/

相关文章:

  • 2026黔西电能质量评估权威机构排行 TOP 谐波检测 + 电压波动 + 能效测评 附电话地址 - 中检检测集团
  • 三小时变三分钟:BibiGPT如何让音视频学习效率提升600%
  • 2026黔东企业业主高频选择的 5 家危房检测房屋结构安全鉴定机构实地测评整理 - 科信检测
  • 显卡驱动清理终极指南:3步解决90%显卡问题
  • 告别闭集限制:手把手教你用OVSeg和Mask-adapted CLIP实现开放词汇图像分割
  • P87LPC761单片机UART自动地址识别与看门狗定时器深度应用指南
  • FModel终极指南:5个步骤轻松提取虚幻引擎游戏资源
  • 5个超实用场景,让BilibiliDown成为你的B站视频收藏神器
  • 2026庆阳本地土壤检测农田土壤检测哪家强?TOP 正规机构榜单 + 联系方式 - 鉴安检测
  • 从Halcon的.om3文件到C#窗体:一步步教你用ActiViz.NET显示三维点云(避坑VS版本与位数问题)
  • 使用YOLOv12模型在生产线上验证网络电缆(跳线)中导线的正确颜色序列
  • 目前整体自动评价系统整体输出95%以上是积极内容
  • 南通母婴除甲醛检测治理公司2026避雷手册:Top5品牌横向对比与科学选择 - AZJ888
  • 一个制造部门的组织重构:从30人到8人加20个数字员工
  • 京东物流200公斤跨省多少钱?教你省下一半运费 - 快递物流资讯
  • 计算机毕业设计之基于协同过滤算法的短视频推荐系统
  • MPC8240时序配置实战:PCI与I2C接口稳定性设计精要
  • 南通母婴除甲醛检测治理公司2026挑选指南:Top5品牌横向对比与科学选择 - AZJ888
  • 2026年爱我东雄高周波设备深度选型:如何为塑胶熔接生产匹配最佳方案 - 信息热点
  • P89LPC93x1系列MCU的ADC与比较器电气特性深度解析与设计实践
  • 抖音发短视频是绝对红海--------抖音现在就是一个视频博客平台
  • WM主数据配置实战:从零构建高效仓位结构(Bin Structures)
  • 数据建模技巧:用 RedisJSON 管理复杂文档结构
  • 如何精准识别高校院所与地方政府之间的潜在创新合作机会?
  • MPC7455硬件规格增补:1.85V核心电压与65°C结温下的电源与散热设计实战
  • 宁波CMA甲醛检测治理公司2026避雷手册:Top5品牌横向对比与科学选择 - AZJ888
  • 工业园区如何高效识别产业链技术断点与卡脖子环节?
  • Notepad4:轻量级文本编辑器解决你的编程烦恼
  • 计算机毕业设计之基于协同过滤算法的汽车推荐系统
  • FanControl V269终极指南:如何彻底解决Windows风扇噪音与散热难题