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

发布时间:2026/6/11 21:50:30

从社交网络到推荐系统:手把手用PyTorch+GCN构建你的第一个图神经网络模型 从社交网络到推荐系统手把手用PyTorchGCN构建你的第一个图神经网络模型当你在电商平台浏览商品时那些猜你喜欢的推荐从何而来当社交网络为你推荐可能认识的人背后又是什么算法在运作这些场景的核心技术之一就是图卷积网络GCN。与传统的卷积神经网络不同GCN专门用于处理图结构数据——这种数据在我们的数字生活中无处不在从社交关系到商品购买从知识图谱到交通网络。本文将带你从零开始构建一个基于PyTorch和切比雪夫多项式的GCN推荐系统。不同于大多数教程只关注理论推导我们将聚焦于实际应用教你如何将抽象的图卷积概念转化为可运行的代码最终打造一个能处理用户-商品交互数据的推荐模型。无论你是想提升现有推荐系统的效果还是希望掌握图神经网络这一前沿技术本文都能提供实用的指导。1. 图神经网络基础与推荐系统场景图神经网络之所以在推荐系统中表现出色是因为它能够自然地建模用户和商品之间的复杂交互。想象一下在电商平台上每个用户和商品都是图中的一个节点用户购买商品、浏览商品、将商品加入购物车等行为构成了图中的边用户之间的社交关系也可以作为边加入图中传统推荐系统通常将用户和商品视为独立的个体而GCN则能够捕捉它们之间的高阶连接关系。例如通过分析用户A→商品1←用户B→商品2这样的路径模型可以推断出用户A可能也对商品2感兴趣。为什么选择切比雪夫多项式切比雪夫多项式在图卷积中的应用有三大优势计算高效避免了直接计算拉普拉斯矩阵的特征分解局部性K阶多项式只考虑K跳邻居适合大规模图数据灵活性可以通过调整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开始) ], dtypetorch.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 ], dtypetorch.float) # 创建PyTorch Geometric的Data对象 data Data(xx, edge_indexedge_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(K1, 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.K1): 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.K1): out torch.mm(Tx[k], self.weights[k]) return out3.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], dim0) # 图卷积 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(max1) # 确保没有大于1的值 # 计算度矩阵 degree torch.diag(adj.sum(dim1)) # 计算归一化拉普拉斯矩阵 degree_inv_sqrt torch.diag(1.0 / torch.sqrt(adj.sum(dim1))) 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_users3, num_items4)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, 3i].item() for u, i in all_pairs] # 使用邻接矩阵中的交互作为标签 train_pairs, test_pairs, y_train, y_test train_test_split(all_pairs, labels, test_size0.2) # 初始化模型 model GCNRecommender(num_users3, num_items4, user_feats2, item_feats2, hidden_size16, K2) optimizer torch.optim.Adam(model.parameters(), lr0.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, dtypetorch.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, dtypetorch.float)) print(fEpoch {epoch1}, 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_k2): 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_items4, L_scaledL_scaled))5. 进阶优化与实际应用技巧5.1 处理大规模图的技巧当面对百万级节点的图数据时直接计算切比雪夫多项式可能不可行。以下是几种优化策略邻居采样每次训练只采样每个节点的K-hop邻居图分区将大图分割为多个子图分别处理稀疏矩阵运算利用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.K1): Tx.append(2 * torch.sparse.mm(L_sparse, Tx[-1]) - Tx[-2]) out torch.zeros_like(Tx[0]) for k in range(self.K1): out torch.mm(Tx[k], self.weights[k]) return out5.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], dim1) return self.fusion(h)5.3 冷启动问题解决方案对于新用户或新商品可以采用以下策略元学习训练模型快速适应新节点内容特征增强利用商品描述、用户画像等辅助信息图扩充通过相似度连接新节点到现有图# 处理新用户的示例 def process_new_user(user_features, existing_model, L_scaled): # 将新用户特征与现有图连接 new_x torch.cat([existing_model.x, user_features], dim0) # 更新拉普拉斯矩阵需要重新计算 new_adj update_adjacency_matrix() # 实现略 new_L compute_laplacian(new_adj) # 实现略 # 生成推荐 return recommend_for_user(new_user_idx, existing_model, num_items, new_L)

相关新闻