
PyG 浅层节点嵌入实战基于 PyTorch Geometric 的 Node2Vec 与 MetaPath2Vec 无监督表示学习【免费下载链接】pytorch_geometricGraph Neural Network Library for PyTorch项目地址: https://gitcode.com/GitHub_Trending/py/pytorch_geometric本文是一份基于 PyTorch GeometricPyG的浅层节点嵌入Shallow Node Embeddings技术指南。文章以官方教程 docs/source/tutorial/shallow_node_embeddings.rst 为主线结合 torch_geometric/nn/models/node2vec.py、torch_geometric/nn/models/metapath2vec.py 的源码实现与配套示例讲解如何通过随机游走与负采样在同构图Node2Vec与异构图MetaPath2Vec上无监督地学习节点嵌入。读完本文你将掌握两种模型的完整训练流程、核心参数语义、底层实现原理以及如何将学到的嵌入用于节点分类等下游任务。引言浅层嵌入与深度嵌入的本质区别图上的节点表示学习核心在于选择编码器 ENC(v, G) z_v ∈ R^d它将节点 v 映射为 d 维向量。浅层shallow节点嵌入与深度deep节点嵌入如 GNN的关键区别就在编码器的选择上浅层嵌入通过一张嵌入查找表embedding lookup table将每个节点直接映射为低维向量最大化“保留邻域结构”的可能性——即相邻节点获得相近嵌入、相距较远的节点获得不同的嵌入深度嵌入GNN则通过多层消息传递机制聚合节点特征与图结构得到可以泛化到新图的编码器。浅层嵌入技术是经典 SkipGram 词嵌入模型在图上的推广把“词序列”换成“节点序列”由随机游走生成训练目标与优化方式一脉相承。随机游走与对比学习目标给定从节点 v ∈ V 出发、长度为 k 的随机游走 W (v_π(1), ..., v_π(k))浅层嵌入的目标是最大化在给定节点 v 的条件下观察到节点 v_π(i) 的似然。该目标可以通过随机梯度下降在对比学习contrastive learning框架下高效训练L Σ_{w ∈ W} -log(σ(z_v^T z_w)) Σ_{w ~ V\W} -log(1 - σ(z_v^T z_w))其中第一项鼓励游走序列中共同出现的节点对正样本的嵌入内积更大第二项从图中采样不存在的“游走”负样本联合训练σ 为 sigmoid 函数。值得注意的是点积 z_v^T z_w 通常用于衡量节点相似度但源码中同样可以替换为其他相似度度量。源码视角损失函数如何实现上述目标在 torch_geometric/nn/models/node2vec.py 的loss()方法中原样落地# Positive loss. start, rest pos_rw[:, 0], pos_rw[:, 1:].contiguous() h_start self.embedding(start).view(pos_rw.size(0), 1, self.embedding_dim) h_rest self.embedding(rest.view(-1)).view(pos_rw.size(0), -1, self.embedding_dim) out (h_start * h_rest).sum(dim-1).view(-1) pos_loss -torch.log(torch.sigmoid(out) self.EPS).mean() # Negative loss. start, rest neg_rw[:, 0], neg_rw[:, 1:].contiguous() h_start self.embedding(start).view(neg_rw.size(0), 1, self.embedding_dim) h_rest self.embedding(rest.view(-1)).view(neg_rw.size(0), -1, self.embedding_dim) out (h_start * h_rest).sum(dim-1).view(-1) neg_loss -torch.log(1 - torch.sigmoid(out) self.EPS).mean() return pos_loss neg_loss实现细节值得注意正/负样本各取矩阵第一列作为“起点”嵌入h_start其余列为“上下文”嵌入h_rest通过逐元素相乘求和得到相似度再套用二元交叉熵式的 sigmoid 对数损失。self.EPS 1e-15用于数值稳定性。训练结果的使用方式浅层嵌入以无监督方式训练学到的 z_v 可直接用于下游任务节点级任务z_v 直接作为最终分类器的输入特征边级任务边表示可通过平均 ½(z_v z_w) 或 Hadamard 积 z_v ⊙ z_w 得到。浅层嵌入的局限性与适用场景尽管实现简单浅层嵌入也有明确短板无法利用丰富的节点/边特征信息——模型输入只有图结构edge_index不含任何特征难以泛化到未见图——可学习参数与特定图的节点一一绑定本质上是直推式transductive的参数复杂度高——O(|V| · d) 的嵌入表在大图上开销显著不易扩展。即便如此它仍是把结构信息压入固定维度向量的常用手段也常被用作特征不丰富时的 GNN 输入生成器例如作为后续 GNN 层的初始节点特征。Node2Vec同构图上的浅层嵌入Node2Vec 是学习浅层节点嵌入的经典方法其核心创新在于通过p与q两个参数灵活控制随机游走的广度优先BFS与深度优先DFS倾向p控制游走中立即回访上一节点的似然q在广度优先与深度优先策略之间插值。对应实现类为 torch_geometric.nn.models.Node2Vec本小节以官方示例 examples/node2vec.py 为蓝本展开。数据准备与模型初始化import torch from torch_geometric.nn import Node2Vec from torch_geometric.datasets import Planetoid data Planetoid(./data/Planetoid, nameCora)[0] device cuda if torch.cuda.is_available() else cpu model Node2Vec( data.edge_index, embedding_dim128, walks_per_node10, walk_length20, context_size10, p1.0, q1.0, num_negative_samples1, ).to(device) optimizer torch.optim.Adam(model.parameters(), lr0.01)模型只接收图结构edge_index不接收任何特征信息其余参数控制随机游走与负采样过程参数含义默认值edge_index图的边索引Tensor必填embedding_dim每个嵌入向量的维度必填walk_length随机游走长度源码中实际使用walk_length - 1见下必填context_size正样本的实际上下文窗口大小该参数通过在不同源节点间复用样本提高有效采样率必填walks_per_node每个节点采样的游走数量1p游走中立即回访节点的似然1.0q广度优先/深度优先插值控制参数1.0num_negative_samples每个正样本对应的负样本数1num_nodes节点数可选默认从 edge_index 推断Nonesparse若为 True权重矩阵梯度为稀疏梯度配合 SparseAdamFalse参数语义补充源码确认在init中self.walk_length walk_length - 1即实际采样步数比传入值少 1起点已占一步内部将 edge_index 排序后转换为 CSR 格式rowptr/col并调用torch.ops.pyg.random_walk来自pyg-lib完成带 p/q 偏置的随机游走采样——因此Node2Vec 依赖pyg-lib0.6.0源码在 node2vec.py 中会显式校验并抛出 ImportErrorwalk_length context_size是构造时的硬性断言。数据加载器与正负样本生成模型自带loader()方法内部是torch.utils.data.DataLoadercollate 函数即采样函数用于批量生成正负随机游走loader model.loader(batch_size128, shuffleTrue, num_workers4) pos_rw, neg_rw next(iter(loader))返回的张量形状pos_rw形状为[batch_size * walks_per_node * (2 walk_length - context_size), context_size]的二维矩阵存放正样本随机游走的节点索引neg_rw形状为[num_negative_samples * pos_rw.size(0), context_size]的二维矩阵存放负样本游走的节点索引。正样本生成原理pos_samplebatch 中每个节点重复walks_per_node次后调用pyg.random_walk采样随后按num_walks_per_rw 1 walk_length 1 - context_size个滑窗切片每个窗口长度为context_size拼接后返回——这正是“滑动窗口 上下文复用”提升采样效率的体现。负样本生成neg_sample则直接在节点编号空间均匀随机采样torch.randint起点为当前节点、其余位置随机。训练循环与嵌入提取def train(): model.train() total_loss 0 for pos_rw, neg_rw in loader: optimizer.zero_grad() loss model.loss(pos_rw.to(device), neg_rw.to(device)) loss.backward() optimizer.step() total_loss loss.item() return total_loss / len(loader)训练结束后通过forward获取嵌入node2vec.pyz model() # 全部节点的嵌入等价于 embedding.weight z model(torch.tensor([0, 1, 2])) # 前三个节点的嵌入完整示例训练、评估与可视化官方示例 examples/node2vec.py 额外包含三个关键环节值得参考稀疏优化示例设置sparseTrue并使用torch.optim.SparseAdam配合num_workers 4 if sys.platform linux else 0适合大规模嵌入表的训练下游评估model.test(train_z, train_y, test_z, test_y)方法node2vec.py内部用sklearn.linear_model.LogisticRegression默认 lbfgs 求解器在训练集嵌入上拟合、在测试集嵌入上打分用于检验嵌入空间质量示例中每轮训练后都计算一次 Cora 上的分类准确率可视化将全部嵌入用 TSNE 降维到 2 维后按类别着色散点绘制。测试用例 test/nn/models/test_node2vec.py 验证了模型核心行为输出维度正确Node2Vec(3, 16)、sample()与loss()可用且损失非负、可选torch.jit.script编译后仍可执行。MetaPath2Vec异构图上基于元路径的扩展Node2Vec 向异构图heterogeneous graphs的自然推广是 MetaPath2Vec实现在 torch_geometric/nn/models/metapath2vec.py。它与 Node2Vec 的训练流程一致区别在于输入从单个edge_index变为按边类型组织的字典edge_index_dict键为(src_node_type, rel_type, dst_node_type)三元组随机游走不再基于单一图结构而是依据给定的metapath定义按边类型逐步采样。定义元路径例如examples/hetero/metapath2vec.py 中的 AMiner 学术网络metapath [ (author, writes, paper), (paper, published_in, venue), (venue, publishes, paper), (paper, written_by, author), ]它表示随机游走从 author 节点出发 → paper → venue → paper → author 的循环模式在异构网络上引入语义约束。模型初始化与训练from torch_geometric.datasets import AMiner from torch_geometric.nn import MetaPath2Vec dataset AMiner(path) data dataset[0] model MetaPath2Vec( data.edge_index_dict, embedding_dim128, metapathmetapath, walk_length50, context_size7, walks_per_node5, num_negative_samples5, sparseTrue, ).to(device) loader model.loader(batch_size128, shuffleTrue, num_workers6) optimizer torch.optim.SparseAdam(list(model.parameters()), lr0.01)与 Node2Vec 相比MetaPath2Vec 的构造参数见 metapath2vec.py去掉了p/q元路径本身已定义游走策略新增metapath与可选的num_nodes_dictsparseTrue同样配合 SparseAdam 使用。示例脚本注释标注约 5 个 epoch 后可达到约 91.8% 的 Micro-F1。源码级实现要点元路径合法性校验构造时要求相邻边类型的终点与起点节点类型一致metapath2vec.py否则抛出 ValueError若walk_length大于元路径长度则要求元路径构成环首尾节点类型相同L92-L96否则抛出 AttributeError类型偏移offset技巧异构图各节点类型共享一张嵌入表按类型划分[start, end)区间L109-L114采样时通过offset把各类型的节点索引平移到全局编号嵌入表末尾额外预留一个 dummy 节点用于承接孤立节点的游走L123-L125逐边类型采样_pos_sample按metapath[i % len(metapath)]循环取边类型对每个类型基于 CSR 结构随机取 1 个邻居推进游走L153-L177负样本则按目标节点类型均匀随机采样类型化嵌入提取forward(node_type, batch)只返回指定节点类型的嵌入区间L133-L138例如z model(author, batchdata[author].y_index.to(device))损失与评估loss()与 Node2Vec 完全一致test()同样通过逻辑回归评估嵌入质量L229-L240。测试用例 test/nn/models/test_metapath2vec.py 覆盖了常规训练MetaPath2Vec(5, 16)的字符串表示、各类型嵌入维度、loss 非负以及空边集的极端场景test_metapath2vec_empty_edges说明模型对孤立节点与空图结构的容错处理。总结维度Node2VecMetaPath2Vec适用图类型同构图异构图输入edge_indexedge_index_dict按边类型游走控制p/q参数元路径metapath额外参数无num_nodes_dict可选共享特性无监督 随机游走 负采样 嵌入查找表 逻辑回归评估同左两者都继承“无监督、直推式、O(|V|·d) 参数复杂度”的浅层嵌入范式也都依赖pyg-lib提供的高效游走采样内核。若你的任务包含丰富节点特征、需要泛化到新图应转向 GNN 等深度编码器而当你需要快速、轻量地把图结构压缩为向量或为 GNN 生成初始特征时PyG 的这两个模块就是开箱即用的标准选择。更多示例可参阅 examples/node2vec.py 与 examples/hetero/metapath2vec.py。【免费下载链接】pytorch_geometricGraph Neural Network Library for PyTorch项目地址: https://gitcode.com/GitHub_Trending/py/pytorch_geometric创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考