详解使用Pytorch Geometric实现GraphSAGE模型

作者:实力 时间:2021-09-30 21:30:18 

GraphSAGE是一种用于图神经网络中的节点嵌入学习方法。它通过聚合节点邻居的信息来生成节点的低维表示,使节点表示能够更好地应用于各种下游任务,如节点分类、链路预测等。

图构建

在使用GraphSAGE对节点进行嵌入学习之前,我们需要先将原始数据转换为图结构,并将其存储为Pytorch Tensor格式。例如,我们可以使用networkx库来构建一个简单的图:

import networkx as nx

G = nx.karate_club_graph()

然后,我们可以使用Pytorch Geometric库将NetworkX图转换为Pytorch Tensor格式。首先,我们需要安装Pytorch Geometric并导入所需的类:

!pip install torch-geometric

from torch_geometric.datasets import Planetoid
from torch_geometric.transforms import NormalizeFeatures
from torch_geometric.utils.convert import from_networkx

接着,我们可以使用from_networkx函数将NetworkX图转换为Pytorch Tensor格式:

data = from_networkx(G)

此时,data对象包含了关于节点、边及其属性的信息,例如:

data.edge_index: 2x(#edges)的长整型张量,表示边的起点和终点

  • data.x: n×dn \times dn×d 的浮点型张量,表示每个节点的特征向量(其中nnn是节点数量,ddd是特征维度)

注意,此时的data对象并未包含邻居信息。接下来,我们将介绍如何使用Sampler方法采样节点邻居。

Sampler方法

GraphSAGE使用Sampler方法来聚合邻居信息。在Pytorch Geometric中,可以使用Various Sampling方法来实现Sampler。例如,使用ClusterData方法将图分成多个子图,然后对每个子图进行采样操作。

以下是ClusterData的使用示例:

from torch_geometric.utils import degree, to_undirected
from torch_geometric.transforms import ClusterData

# Convert the graph to an undirected graph, so we can aggregate neighbors in both directions.
G = to_undirected(G)

# Compute the degree of each node.
deg = degree(data.edge_index[0], num_nodes=data.num_nodes)

# Use METIS algorithm to partition the graph into multiple subgraphs.
cluster_data = ClusterData(data, num_parts=2, recursive=False, transform=NormalizeFeatures(),
                          degree=deg)

这里我们将原始图分成两个子图,并对每个子图进行规范化特征转换。注意,在使用ClusterData方法之前,需要将原始图转换为无向图。

另一个常用的Sampler方法是在随机游动时对邻居进行采样,这种方法被称为随机游走采样(Random Walk Sampling)。以下是随机游走采样的示例代码:

from torch_geometric.utils import random_walk

# Perform random walk sampling to obtain node neighbor samples.
walk_length = 20  # The length of random walk trail.
num_steps = 4     # The number of nodes to sample from each step.
data.batch = None
data.edge_index = to_undirected(data.edge_index)  # Use undirected edge for random walk.

rw_data = random_walk(data.edge_index, walk_length=walk_length, num_steps=num_steps)

这里我们将使用一个长度为20、每个步骤采样4个邻居的随机游走方法。注意,在使用随机游走方法进行采样之前,需要使用无向边。

GraphSAGE模型定义

GraphSAGE模型包含3个部分:1)图卷积层;2)聚合器(Aggregator);3)输出层。我们将在本节中介绍如何使用Pytorch实现这些组件。

首先,让我们定义一个图卷积层。图卷积层的输入是节点特征矩阵、邻接矩阵和聚合器,输出是新的节点特征矩阵。以下是图卷积层的代码实现:

import torch.nn.functional as F
from torch_geometric.nn.conv import MessagePassing
from torch_geometric.nn import global_mean_pool

class GraphSageConv(MessagePassing):
   def __init__(self, in_channels, out_channels, aggr='mean'):
       super(GraphSageConv, self).__init__(aggr=aggr)
       self.lin = nn.Linear(in_channels, out_channels)

def forward(self, x, edge_index):
       return self.propagate(edge_index, x=x)

def message(self, x_j):
       return x_j

def update(self, aggr_out, x):
       return F.relu(self.lin(torch.cat([x, aggr_out], dim=1)))

这里我们继承了MessagePassing类,并在__init__函数中定义了一个全连接层,用于将输入特征矩阵x从 dind_{in}din 维映射到 doutd_{out}dout 维。在forward函数中,我们使用propagate方法来实现消息传递操作;在message函数中,我们仅向下游节点发送原始特征数据;在update函数中,我们首先对聚合结果进行ReLU非线性变换,然后再通过全连接层进行节点特征的更新。

接下来,让我们定义一个聚合器。聚合器的输入是采样得到的邻居特征矩阵,输出是新的节点嵌入向量。以下是聚合器的代码实现:

class MeanAggregator(nn.Module):
   def __init__(self, input_dim, output_dim):
       super(MeanAggregator, self).__init__()
       self.input_dim = input_dim
       self.output_dim = output_dim
       self.lin = nn.Linear(input_dim, output_dim)

def forward(self, neigh_mean):
       out = F.relu(self.lin(neigh_mean))
       return out

这里我们定义了一个简单的均值聚合器,其将邻居特征矩阵中每列的均值作为节点嵌入向量,并使用全连接层进行维度变换。

最后,让我们定义整个GraphSage模型。GraphSage模型包含2个图卷积层和1个输出层。以下是模型的代码实现:

class GraphSAGE(nn.Module):
   def __init__(self, in_channels, hidden_channels, out_channels, num_layers=2):
       super(GraphSAGE, self).__init__()
       self.conv1 = GraphSageConv(in_channels, hidden_channels)
       self.aggreg1 = MeanAggregator(hidden_channels, hidden_channels)
       self.conv2 = GraphSageConv(hidden_channels, out_channels)

def forward(self, x, edge_index):
       x = self.conv1(x, edge_index)
       x = global_mean_pool(x, edge_index)  # Compute global mean over nodes.
       x = self.aggreg1(x)
       x = self.conv2(x, edge_index)
       return x

这里我们定义了一个包含2层GraphSAGE Conv层的神经网络。在最后一层GraphSAGE Conv层之后,我们使用global_mean_pool函数来计算节点嵌入的全局平均值。注意,在本示例中,我们仅保留了一个输出节点,因此输出矩阵的大小为1。如果需要输出多个节点,则需要设置global_mean_pool函数中的参数。

模型训练与测试

在定义好模型后,我们可以使用Pytorch进行模型训练和测试。首先,让我们定义一个损失函数和优化器:

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

这里我们使用交叉熵作为损失函数,并使用Adam优化器来更新模型参数。

接着,我们可以开始训练模型。以下是训练过程的代码实现:

num_epochs = 100

for epoch in range(num_epochs):
   model.train()

optimizer.zero_grad()
   out = model(data.x, data.edge_index)
   loss = criterion(out[data.train_mask], data.y[data.train_mask])
   loss.backward()
   optimizer.step()

print('Epoch {:03d}, Loss: {:.4f}'.format(epoch, loss.item()))

这里我们遍历所有数据样本,计算预测结果和真实标签之间的交叉熵损失,并使用反向传播来更新权重。我们在每个epoch结束后打印出当前损失值。

最后,我们可以对模型进行测试。以下是测试过程的代码实现:

model.eval()

with torch.no_grad():
   pred = model(data.x, data.edge_index)
   pred = pred.argmax(dim=1)

acc = (pred[data.test_mask] == data.y[data.test_mask]).sum().item() / data.test_mask.sum().item()
print('Test accuracy: {:.4f}'.format(acc))

这里我们使用测试集来计算模型的准确率。注意,在执行model.eval()后,我们需要使用torch.no_grad()包装代码块,以禁止梯度计算。

来源:https://juejin.cn/post/7225053568152518714

标签:Pytorch,Geometric,GraphSAGE,模型
0
投稿

猜你喜欢

  • 详解Python 爬取13个旅游城市,告诉你五一大家最爱去哪玩?

    2022-05-22 08:39:32
  • 禁用JavaScript控制台调试的方法

    2024-06-22 03:09:08
  • Python爬虫Scrapy框架CrawlSpider原理及使用案例

    2023-12-23 07:41:55
  • Python 实现自动化Excel报表的步骤

    2022-12-01 10:49:29
  • Python图像处理库PIL的ImageEnhance模块使用介绍

    2023-05-14 17:29:51
  • python 删除excel表格重复行,数据预处理操作

    2023-04-19 06:10:33
  • python变量赋值方法(可变与不可变)

    2021-02-14 08:51:55
  • Pandas实现在线文件和剪贴板数据读取详解

    2021-06-02 16:49:55
  • python子类在多继承中使用MRO机制原理

    2021-03-09 00:52:35
  • Asp中Server.ScriptTimeOut脚本超时属性需要注意的一点

    2008-10-18 14:53:00
  • asp多关键词查询方案

    2008-05-09 12:24:00
  • Python之str操作方法(详解)

    2021-07-21 09:14:16
  • Mysql锁机制之行锁、表锁、死锁的实现

    2024-01-26 08:29:43
  • python多进程实现进程间通信实例

    2023-01-30 10:39:35
  • python实现数通设备tftp备份配置文件示例

    2022-12-02 13:59:21
  • python监控nginx端口和进程状态

    2023-08-25 16:15:13
  • python生成图片验证码的方法

    2022-07-27 13:39:11
  • Python 列表去重去除空字符的例子

    2021-07-11 02:49:14
  • 详解Python发送email的三种方式

    2023-07-01 07:19:28
  • 将 html 转成 ubb代码的小脚本

    2013-06-25 07:07:00
  • asp之家 网络编程 m.aspxhome.com