资讯动态

AGNN推荐算法解析:属性感知的图神经网络如何提升推荐效果

发布时间:2026/10/26 15:19:12 来源:尧图企业网站定制
简介基于属性和图神经网络AGNN的推荐算法本科毕业设计项目包面向推荐系统方向学生与研究者完整实现了融合用户/商品属性信息与图神经网络嵌入学习的推荐模型可作为毕业设计或课题研究的直接参考范例。项目基于公开的MovieLens等数据集涵盖了数据处理、模型构建、训练优化与评估验证等完整流程并针对图结构数据的卷积与池化操作给出了具体实现。压缩包共19个文件包含5个Python源码模型、工具、数据处理与测试脚本、7个说明文档、3个npy数据文件、2个csv数据集及1个pyc编译文件整体约4.19MB目录结构清晰方便对照学习。已有62人学习下载。通过该项目可掌握AGNN模型的嵌入表示学习、图卷积与图池化操作的实际应用思路并能直接复用代码进行实验或二次开发为深入推荐系统研究提供有力支持。1. 基于属性和图神经网络的推荐算法AGNN 到底改了什么如果你刷到过“B站首页web推荐算法”和“抖音推荐算法”的热搜会发现一个共同点如今的推荐系统早就不只靠“你和物品像不像”了而是靠“你和物品在关系网里离得近不近”。图神经网络GNN干的就是这件事——把用户、物品、属性当成一张大网里的节点让信息沿着边传播。而这份标着“AGNN”的本科毕业设计资源核心是把“属性”这个被很多模型当辅助信息的角色提到了和结构信息并列的位置上。换句话说它不只是拿 GNN 做推荐而是专门回答了“物品属性到底该怎么进图、怎么参与聚合才能让推荐更准”这个问题。适合正在做推荐系统课题、需要完整代码骨架和实验流程的本科生或刚入门的研究生也适合想快速看一份“属性 GNN”怎么落地成可跑工程的人。它能帮你省掉从零搭环境、写数据管道、调训练循环的大把时间。2. 推荐系统为什么要用图神经网络从协同过滤到 AGNN 的演进2.1 传统推荐的结构瓶颈传统的协同过滤CF把用户和物品表示成隐向量靠内积算相似度。它能捕捉“张三和李四都买了某本书”但捕捉不了“张三买了某本书是因为李四所在的读书会里大部分人都在读这本”——这种二跳以上的关系CF 的向量内积很难表达清楚。属性信息比如物品的类目、价格区间、用户的地理位置在传统模型里要么拼进特征向量要么单独做一个浅层模型和交互结构是割裂的。到了 GNN 时代推荐系统把用户–物品交互看成二部图用消息传递把邻居信息聚合到当前节点上。但大部分 GNN 推荐模型比如 NGCF、LightGCN只聚合“交互邻居”的表示属性只是作为初始特征拼一拼。问题在于如果两个物品从未被同一个用户点击过它们在图上的路径就很长属性上的相似性很难通过有限层数的聚合传过来。AGNN 的思路就是让属性成为显式的图节点而不是被塞进特征向量里。2.2 AGNN 的图结构设计这份资源里的 AGNN 模型构建的是“用户—物品—属性”三类节点构成的多关系图。用户和物品之间是交互边物品和属性之间是“拥有边”用户和属性之间是“偏好边”。这三类边分别用不同的邻接矩阵存聚合时按关系类型分开做消息传递再在注意力机制里融合。# 邻接矩阵构建的核心逻辑伪代码风格资源内为完整实现 user_item_edge build_edge(user_ids, item_ids, rating_mask) # 交互边 item_attr_edge build_edge(item_ids, attr_ids, item_attr_mask) # 拥有边 user_attr_edge build_edge(user_ids, attr_ids, user_attr_mask) # 偏好边 adj_list [user_item_edge, item_attr_edge, user_attr_edge]这里rating_mask是把评分矩阵二值化后的结果只保留有交互的条目item_attr_mask是物品–属性的共现矩阵比如一部电影属于“科幻”和“冒险”两个属性对应位置就置 1。user_attr_edge不完全等于用户–物品–属性的间接关系而是根据用户历史交互物品的属性分布统计出来的显式偏好。这样设计的原因是如果把用户偏好属性当成隐式信息要靠 GNN 传好几层才能传到而把它建成显式边第一层消息传递时用户就能直接收到属性信号。实验里你会发现加了这层边之后冷启动物品的表示质量提升明显因为新物品只要挂了属性就能通过属性边把信号传给潜在感兴趣的用户。2.3 属性感知的消息传递机制传统 GNN 推荐模型的消息传递通常写成一个统一聚合函数# LightGCN 风格聚合示意 h_u sum( h_i for i in neighbors_of_user(u) )AGNN 把这个过程拆成了“分关系聚合再融合”。具体来说用户节点的邻居分成三类交互过的物品、偏好过的属性、以及通过属性桥接到的“相似用户”第二层才需要考虑。每一类邻居先独立聚合得到三个候选表示再用注意力权重把三者加起来。# AGNN 分层聚合主体逻辑节选 for layer in range(n_layers): h_u_item aggregate(user_emb, item_emb, user_item_edge) # 从交互物品收消息 h_u_attr aggregate(user_emb, attr_emb, user_attr_edge) # 从偏好属性收消息 h_u attention_fuse(h_u_item, h_u_attr, user_emb) # 注意力融合 h_i_user aggregate(item_emb, user_emb, user_item_edge.T) # 物品从用户收消息 h_i_attr aggregate(item_emb, attr_emb, item_attr_edge) # 物品从属性收消息 h_i attention_fuse(h_i_user, h_i_attr, item_emb)注意力融合不是简单拼接而是给每一类消息算一个标量权重权重由当前节点表示和消息向量的相似度决定。这个设计的直觉是不同用户对不同信息源的依赖程度不一样。重度追剧用户可能更依赖“看过的剧”这条消息而新用户没什么行为只能靠“偏好属性”这条消息。注意力机制让模型自己学会调节。参数层面你需要注意三个东西n_layers控制信息传播深度一般取 2 到 3再深容易过平滑emb_dim嵌入维度决定表示容量资源默认在 32 到 64 之间小数据集上用 64 效果不错attention_fuse里的温度参数如果有控制权重分布的尖锐程度调大让模型更倾向选单一信息源调小则更平均。3. 从零复现 AGNN 推荐系统数据处理、模型训练与评估全流程3.1 数据集准备与格式转换这份资源用的是标准的推荐数据集格式用户–物品–评分–时间戳的四列 CSV以及物品–属性标签的映射文件。如果你手里是 MovieLens 1M 这种常见数据需要先做一次格式对齐。# 把 MovieLens ratings.dat 转成 AGNN 需要的 CSV import pandas as pd ratings pd.read_csv(ratings.dat, sep::, headerNone, names[user_id, item_id, rating, timestamp]) ratings ratings[ratings[rating] 4] # 保留正向反馈 ratings[user_id] ratings[user_id].astype(int) ratings[item_id] ratings[item_id].astype(int) ratings.to_csv(ratings.csv, indexFalse)这里把评分阈值设为 4 是常见做法因为推荐系统一般只关心“用户喜欢什么”3 分以下的不确定性太大当成负样本又不够准确。如果你做的是 Top-N 推荐而不是评分预测建议同样只保留 4 分以上数据把隐式反馈问题简化。物品属性文件长什么样MovieLens 的 movies.dat 里包含类型字段管道分隔。需要拆成“物品–属性”的长表# 物品属性长表转换 movies pd.read_csv(movies.dat, sep::, headerNone, names[item_id, title, genres], enginepython) movies[genres] movies[genres].fillna() movie_attr movies[genres].str.split(|, expandTrue).stack() movie_attr movie_attr.reset_index().rename(columns{level_0: item_id, 0: attr}) movie_attr[attr] movie_attr[attr].astype(category).cat.codes movie_attr.to_csv(item_attr.csv, indexFalse)属性必须编码成整数 ID图神经网络里的节点索引不能是字符串。常见做法是用astype(category)把文本标签自动映射成整数码保存后下次加载还要维护一份attr_code映射否则训练和推理时属性 ID 对不上。3.2 训练主循环与负采样AGNN 的训练目标是让正样本用户–物品对的表示相似度高于负样本。资源里的损失函数用的是 BPRBayesian Personalized Ranking损失配合随机负采样——每个正样本配一个用户没交互过的物品作为负样本。# BPR 损失核心计算 def bpr_loss(pos_scores, neg_scores): pos_scores: 正样本 user-item 匹配分 neg_scores: 负样本 user-item 匹配分 return -torch.mean(torch.log(torch.sigmoid(pos_scores - neg_scores)))BPR 的直觉是模型不需要精确预测评分只需要把正样本的排序分数压过负样本。所以你在训练时会发现 loss 下降很快但 AUC 不一定同步上升——AUC 看的是全量排序质量BPR 只看采样到的负样本。资源里负采样是每轮随机抽的如果你想让结果更稳定可以把负样本数量从默认的 1 提到 3 或者 5效果会好一些但训练时间线性增加。训练轮数epoch一般设 100 到 200数据集小的话 50 轮就够。关键监控指标是每 5 轮在验证集上算一次 RecallK 和 NDCGK不要光看训练 loss。AGNN 这类模型过拟合比较慢但一旦过了最佳 epochRecall 会开始波动甚至下降所以务必保存验证集表现最好的模型权重别用最后一轮的权重做测试。3.3 评估指标与测试协议推荐系统评估讲究“排序命中率”不是准确率。资源里实现了 RecallK、PrecisionK、NDCGK 三个指标。# RecallK 计算示例 def recall_at_k(pred_ranks, ground_truth, k20): pred_ranks: 用户对所有物品的排序分数降序排列后取前 k 个 ground_truth: 测试集中该用户真实交互过的物品集合 pred_items pred_ranks[:k] hits len(set(pred_items) set(ground_truth)) return hits / len(ground_truth)评估时有个容易出错的地方测试集的负样本集合怎么定。正确的做法是把训练集里用户交互过的物品屏蔽掉只对“用户没交互过 测试集里交互过”的物品做排序否则推荐结果里全是训练集里的热门物品指标虚高。资源里已经写了 masking 逻辑你复现时务必确认train_mask有没有传对。关于数据划分参考实现里用的是 leave-one-out每个用户随机保留一个交互作为测试一个作为验证其余训练。对 MovieLens 1M 这种规模直接按时间戳切分也可以但 leave-one-out 更容易复现论文里的指标数字。4. AGNN 与基线模型对比效果提升的来源与实验设计4.1 基线选择与公平比较资源里给了三个基线最经典的 MF-BPR矩阵分解 BPR 损失、NGCFGNN 推荐先驱模型、LightGCN去掉特征变换的轻量 GNN。为什么选这三个而不是别的因为它们构成了一条清晰的对比链MF 验证“图结构到底有没有用”NGCF 验证“属性显式建模和隐式特征拼接的区别”LightGCN 验证“AGNN 比最简 GNN 多出的复杂度值不值”。# 基线模型配置示例MF-BPR model MF_BPR(num_users, num_items, emb_dim64) optimizer torch.optim.Adam(model.parameters(), lr0.001)对比实验里最容易犯的错是超参数不统一。AGNN 用了 64 维嵌入MF 也用 64 维AGNN 训练 150 轮MF 也训练 150 轮。资源里把基线的emb_dim、lr、batch_size都对齐了但如果你要自己加新基线比如 SVD务必保持相同的训练预算否则“提升”可能是训练更久带来的不是模型结构带来的。4.2 属性数据占比的影响AGNN 的一个隐藏优势是当属性信息变稀疏时表现下降得比基线慢。你可以在实验里做“属性删减”测试——随机去掉 20% 和 50% 的物品–属性边重新训练看 Recall20 的下降幅度。资源里没直接给这个实验但数据管道支持我建议你加上这一组写论文时这是个很加分的分析点。现实场景里新上架的商品往往只有类目属性没有交互记录。AGNN 因为有一条“用户–属性”偏好边能让新物品通过属性匹配到潜在用户。对比实验中你会看到如果只统计冷启动物品交互数小于 5的 RecallAGNN 比 LightGCN 高出不止一个点。这也是属性显式建边最大的价值。4.3 消融实验怎么切资源模型文件里有attention_fuse和三条边做消融时把某条边去掉重新训练即可。最值得做的三组消融是去掉用户–属性偏好边、去掉注意力融合改成平均融合、把图层数减到 1。结果通常会发现去掉用户–属性边影响最大说明显式属性偏好比结构信息本身更关键注意力融合在数据量足够时能贡献 3% 左右的 Recall 提升数据少的时候反而不如平均融合稳定。5. AGNN 复现避坑指南图构建、训练稳定性与内存优化5.1 稀疏矩阵与全图计算的坑现象数据量稍微一大显存直接爆炸或者训练慢到无法忍受。原因AGNN 的邻接矩阵如果有 N 个节点用稠密张量存就是 N×N 个浮点数。MovieLens 1M 的用户加物品加属性大约 2 万多个节点稠密矩阵要占 3 个多 GB 显存还没算嵌入和梯度。很多人在这一步翻车。解决把邻接矩阵转成稀疏 COO 格式用 PyTorch 的torch.sparse.FloatTensor存储或者干脆用 DGL/ PyG 这类图库的SparseGraph封装。资源代码里已经用了稀疏矩阵但如果你是从别的项目改过来的务必检查adj_list的类型。5.2 负采样导致的训练震荡现象训练 loss 在下降但测试指标忽高忽低不同次运行结果差异大。原因随机负采样每次抽到的负样本不同如果数据稀疏很容易抽到“假阴性”——用户其实喜欢这个物品但没交互过。模型被反复教导“这个用户不喜欢该物品”表示空间就会出现震荡。解决把负采样改成“全域负采样”之后可以缓解一点但我更推荐的是把负样本数调大并且每轮固定随机种子。资源里没有固定种子你复现时在train.py开头加一行np.random.seed(0); torch.manual_seed(0)结果就稳了。5.3 属性 ID 编码不一致现象训练正常但推理时代码报“index out of range”或者有些物品永远得不到推荐。原因训练和推理用了不同的属性编码表。训练时attr_encode把属性映射成 0 到 N-1推理时加载了新数据属性 ID 对不上。解决把编码表保存成一个 JSON 文件训练和推理都从同一个文件加载。资源里item_attr.csv存的是编码后的 ID但没强制校验数量你最好在加载数据后加一个断言确认max_attr_id 1 num_attrs。5.4 注意力权重的过平滑现象层数加到 4 以上指标反而显著下降节点表示几乎都聚成一团。原因GNN 每多一层节点就多聚合一次邻居信息。重复聚合会让所有节点表示趋向于全局平均这就是“过平滑”。AGNN 的注意力机制能推迟但无法完全阻止这个问题。解决n_layers设成 2 或 3别贪多。如果你想试更深层可以给每层加残差连接h h layer_out或者用 DropEdge训练时随机丢弃部分边缓解。资源里默认没有残差连接你可以自己加一个if self.use_residual: h h h_prev实测多一层不容易崩。5.5 显存占用与批次大小权衡现象小数据集上一切正常换大数据集就 OOM。原因全图训练时所有节点的嵌入和中间表示都得存在显存里batch size 越大存储的消息向量越多。GNN 推荐模型不像 CNN 那样能靠 padding 控制内存。解决用小批次训练替代全图训练。资源里给的是全图训练适合 1M 这种规模如果数据集是 10M 以上你需要把邻居采样逻辑加上——每个 batch 只采样一部分邻居而不是全部邻居。这是 AGNN 工程化的必经之路。6. 模型训练完怎么验证与进一步调优从指标排查到嵌入可视化训练完成不代表模型能用。在交付或写论文前我会强制自己过一遍下面几个验证步骤每一步都能暴露不同层面的问题。第一步检查损失曲线是否收敛且没有锯齿。保存训练时的 loss 序列画出来看尾部是否平稳。如果 100 轮后还在明显波动多半是学习率太高或负采样不稳。AGNN 的 BPR loss 收敛后一般停留在 0.1 到 0.3 之间如果高于 0.5说明模型没有学到排序能力。第二步做一次“推荐结果人工审计”。从测试集里挑 10 个用户打印出每个用户的推荐 Top-10 和真实交互用肉眼判断推荐列表里有没有明显不合理的物品。这一步能发现指标发现不了的问题——比如模型把所有用户都推成热门物品、或者属性建边出错导致推荐的全是同一类目下的冷门垃圾。我见过有人 Recall 很高但推荐结果完全不可用就是因为测试集泄露。第三步嵌入向量可视化。把训练好的用户嵌入和物品嵌入降维到二维用 PCA 或 t-SNE按属性着色看同类物品是否聚在一起用户是否按兴趣聚类。这一步不是必须但能直观验证 AGNN 的“属性感知”是否真的起效。正常情况是同一属性簇的物品在二维空间里距离较近而普通 GNN 模型的嵌入则更偏向按交互热度聚类。第四步参数敏感性测试。固定其他参数把n_layers从 1 扫到 4、把emb_dim从 16 扫到 128画一条指标曲线。这能帮你确认当前参数不是在过拟合某个特殊配置也能写进论文的“参数分析”小节。# t-SNE 可视化嵌入示例 from sklearn.manifold import TSNE import matplotlib.pyplot as plt item_emb model.item_emb.detach().cpu().numpy() tsne TSNE(n_components2, perplexity30, random_state42) item_2d tsne.fit_transform(item_emb[:500]) # 采样 500 个物品避免过慢 plt.scatter(item_2d[:, 0], item_2d[:, 1], citem_attr[:500], cmaptab20, s5) plt.savefig(item_embedding_tsne.png, dpi150)perplexity一般取 30样本量小时可以降到 10颜色编号用的是物品属性的编码如果相近属性颜色接近说明嵌入学到了属性结构。我个人踩过最大的坑是跳过第三步指标好看就直接拿去跑线上 AB结果线上 CTR 反而下降。从那以后我每次训练完都强制走一遍“人工审计 嵌入可视化”哪怕花半小时也要确认模型学的是业务信号而不是数据噪声。做图神经网络推荐的项目结构、属性、训练、验证四个环节环环相扣任何一个环节偷懒最后都会反映在说不清的指标波动上。希望这份 AGNN 资源的复现过程能帮你绕过我走过的弯路。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑