PyTorch图神经网络实践(二)自定义图数据

数据类型

PyTorch Geometric定义了自己的数据类型。

节点和节点之间的边构成了图。在PyTorch Geometric中,如果要构建图,那么需要两个要素:节点和边。PyTorch Geometric 提供了torch_geometric.data.Data 用于构建图,包括 5 个属性,每一个属性都不是必须的,可以为空。

  • data.x: 用于存储每个节点的特征,形状是[num_nodes, num_node_features]
  • data.edge_index: 用于存储节点之间的边,形状是 [2, num_edges]
  • data.pos: 存储节点的坐标,形状是[num_nodes, num_dimensions]
  • data.y: 存储样本标签。如果是每个节点都有标签,那么形状是[num_nodes, *];如果是整张图只有一个标签,那么形状是[1, *]
  • data.edge_attr: 存储边的特征。形状是[num_edges, num_edge_features]

实际上,Data对象不仅仅限制于这些属性,我们可以通过data.face来扩展Data,以张量保存三维网格中三角形的连接关系。

还可以添加其他的属性,如下所示

data = Data(x=x, edge_index=edge_index)
data.train_idx = torch.tensor([...], dtype=torch.long)
data.train_mask = torch.tensor([...], dtype=torch.bool)
data.test_mask = torch.tensor([...], dtype=torch.bool)

简单案例

创建一个图

用networkx包创建一个图,然后用torch转换为Data对象。注意节点编号要从0开始,索引须为整形。

import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import community as community_louvain

# build a graph
G = nx.Graph()
edgelist = [(0, 1), (0, 2), (1, 3)]  # note that the order of edges
G.add_edges_from(edgelist)

# plot the graph
fig, ax = plt.subplots(figsize=(4,4))
option = {'font_family':'serif', 'font_size':'15', 'font_weight':'semibold'}
nx.draw_networkx(G, node_size=400, **option)  #pos=nx.spring_layout(G)
plt.axis('off')
plt.show()

图如下

在这里插入图片描述

创建Data示例

利用networkx图数据创建Data对象。

import torch
from torch_geometric.data import InMemoryDataset, Data

x = torch.eye(G.number_of_nodes(), dtype=torch.float)

adj = nx.to_scipy_sparse_matrix(G).tocoo()
row = torch.from_numpy(adj.row.astype(np.int64)).to(torch.long)
col = torch.from_numpy(adj.col.astype(np.int64)).to(torch.long)
edge_index = torch.stack([row, col], dim=0)

# Compute communities.
partition = community_louvain.best_partition(G)
y = torch.tensor([partition[i] for i in range(G.number_of_nodes())])

# Select a single training node for each community
# (we just use the first one).
train_mask = torch.zeros(y.size(0), dtype=torch.bool)
for i in range(int(y.max()) + 1):
    train_mask[(y == i).nonzero(as_tuple=False)[0]] = True

data = Data(x=x, edge_index=edge_index, y=y, train_mask=train_mask)

依次查看每个变量的值

在这里插入图片描述

上面

  • x是节点特征矩阵,这里设为单位矩阵。
  • adj是图G的邻接矩阵的稀疏表示,左边节点对代表一条边,右边是边的值,adj是对称矩阵。
  • row和col分别是adj中非零元素所在的行索引以及列索引。
  • edge_index就是PyTorch Geometric中边列表的表示形式,里面包含两个列表,第一个是row,第二个是col,row和col对应位置的元素就构成一条边。注意edge_index是可以表示边方向的,如果是无向图,则一条边会出现两次,比如(0, 1)(1, 0)是指一条边,如果是在有向图中,它们就表示两条不同的边。
  • partition是用louvain算法对图G进行社区划分后的结果,可以看到0和2属于一个社区,1和3属于另一个社区。
  • y就是节点的社区标签。
  • train_mask是训练集的标签,用于半监督节点分类任务,每类节点中只有一个节点的标签设置为已知True,其他为未知False

自带函数

接下来,我们可以看看data示例本身自带哪些函数。

在这里插入图片描述

上面可以看到data示例本身可以调用很多函数,比如查看数据键名、数据键值、节点数量、边数量、节点特征数量、是否有孤立节点、是否有自环、有向或者无向等等。

添加属性

试试添加其他属性。

在这里插入图片描述

从上面例子看到可以继续添加test_mask属性,设置某些节点为测试集。

节点分类

利用上面这个简单的图实现节点分类任务,类别就是上面louvain算法给出的社区类别。训练数据为节点0和1,测试数据为节点2和3。

构建一个图卷积神经网络,包含两个卷积层,第一层输入维度为4,输出维度为16;第二层输入维度为16,输出维度为2;第一层后面接上一个激活函数,并进行dropout操作。

import torch.nn.functional as F
from torch_geometric.nn import GCNConv

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = GCNConv(data.num_node_features, 16)
        self.conv2 = GCNConv(16, 2)

    def forward(self):
        x, edge_index = data.x, data.edge_index

        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)
        x = self.conv2(x, edge_index)

        return F.log_softmax(x, dim=1)

指定优化器,训练函数和测试函数的代码如下:

device = torch.device('cuda:1' if torch.cuda.is_available() else 'cpu')
model, data = Net().to(device), data.to(device)
optimizer = torch.optim.Adam([
    dict(params=model.conv1.parameters(), weight_decay=5e-4),
    dict(params=model.conv2.parameters(), weight_decay=0)
], lr=0.01)  # Only perform weight-decay on first convolution.

def train():
    optimizer.zero_grad()  
    out = model()
    loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask])
    loss.backward()
    optimizer.step()
    
def test():
    model.eval()
    logits, accs = model(), []
    for _, mask in data('train_mask', 'test_mask'):
        pred = logits[mask].max(1)[1]
        acc = pred.eq(data.y[mask]).sum().item() / mask.sum().item()
        accs.append(acc)
    return accs

训练十次,输出训练集和测试集上的结果:

for epoch in range(1, 11):
    train()
    log = 'Epoch: {:03d}, Train: {:.4f}, Test: {:.4f}'
    print(log.format(epoch, *test()))

输出如下:

Epoch: 001, Train: 0.5000, Test: 0.5000
Epoch: 002, Train: 0.5000, Test: 0.5000
Epoch: 003, Train: 0.5000, Test: 1.0000
Epoch: 004, Train: 1.0000, Test: 1.0000
Epoch: 005, Train: 1.0000, Test: 1.0000
Epoch: 006, Train: 1.0000, Test: 1.0000
Epoch: 007, Train: 1.0000, Test: 1.0000
Epoch: 008, Train: 1.0000, Test: 1.0000
Epoch: 009, Train: 1.0000, Test: 1.0000
Epoch: 010, Train: 1.0000, Test: 1.0000

可以看到在这个简单的网络上,使用图卷积神经网络训练四次以后结果就收敛了,分类很准确。

完整代码

完整代码如下:

import numpy as np
import networkx as nx
import matplotlib.pyplot as plt
import community as community_louvain
import torch
from torch_geometric.data import InMemoryDataset, Data

# build a graph
G = nx.Graph()
edgelist = [(0, 1), (0, 2), (1, 3)]  # note that the order of edges
G.add_edges_from(edgelist)
x = torch.eye(G.number_of_nodes(), dtype=torch.float)
adj = nx.to_scipy_sparse_matrix(G).tocoo()
row = torch.from_numpy(adj.row.astype(np.int64)).to(torch.long)
col = torch.from_numpy(adj.col.astype(np.int64)).to(torch.long)
edge_index = torch.stack([row, col], dim=0)

# Compute communities.
partition = community_louvain.best_partition(G)
y = torch.tensor([partition[i] for i in range(G.number_of_nodes())])

# Select a single training node for each community
# (we just use the first one).
train_mask = torch.zeros(y.size(0), dtype=torch.bool)
for i in range(int(y.max()) + 1):
    train_mask[(y == i).nonzero(as_tuple=False)[0]] = True

data = Data(x=x, edge_index=edge_index, y=y, train_mask=train_mask)
remaining = (~data.train_mask).nonzero(as_tuple=False).view(-1)
remaining = remaining[torch.randperm(remaining.size(0))]
data.test_mask = torch.zeros(y.size(0), dtype=torch.bool)
data.test_mask.fill_(False)
data.test_mask[remaining[:]] = True

import torch.nn.functional as F
from torch_geometric.nn import GCNConv

class Net(torch.nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = GCNConv(data.num_node_features, 16)
        self.conv2 = GCNConv(16, 2)

    def forward(self):
        x, edge_index = data.x, data.edge_index

        x = self.conv1(x, edge_index)
        x = F.relu(x)
        x = F.dropout(x, training=self.training)
        x = self.conv2(x, edge_index)

        return F.log_softmax(x, dim=1)

    
device = torch.device('cuda:1' if torch.cuda.is_available() else 'cpu')
model, data = Net().to(device), data.to(device)
optimizer = torch.optim.Adam([
    dict(params=model.conv1.parameters(), weight_decay=5e-4),
    dict(params=model.conv2.parameters(), weight_decay=0)
], lr=0.01)  # Only perform weight-decay on first convolution.

def train():
    optimizer.zero_grad()  
    out = model()
    loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask])
    loss.backward()
    optimizer.step()
    
def test():
    model.eval()
    logits, accs = model(), []
    for _, mask in data('train_mask', 'test_mask'):
        pred = logits[mask].max(1)[1]
        acc = pred.eq(data.y[mask]).sum().item() / mask.sum().item()
        accs.append(acc)
    return accs

for epoch in range(1, 11):
    train()
    log = 'Epoch: {:03d}, Train: {:.4f}, Test: {:.4f}'
    print(log.format(epoch, *test()))

相关文章

PyTorch图神经网络实践(一)环境安装

  • 21
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
### 回答1: PyTorch是一个基于Python开发的机器学习框架,它拥有丰富的工具和功能,适用于各种任务,包括遥感像地物分类。遥感像地物分类是指通过对遥感像进行分析和识别,将不同地物分类为不同的类别,如建筑、道路、植被等。 在PyTorch中实现遥感像地物分类可以遵循以下步骤: 1. 数据准备:首先,需要准备用于训练和评估的遥感数据集。可以从公开数据集中获取,或者根据实际需要收集和整理数据集。 2. 数据加载:使用PyTorch数据加载器,将数据集加载到内存中,并对数据集进行预处理,如裁剪、缩放和标准化等。 3. 模型设计:选择适合遥感像分类的模型架构,如卷积神经网络(CNN)。可以使用PyTorch提供的模型库,如ResNet、VGG等,也可以自定义模型。 4. 模型训练:将加载的数据集输入到模型中,通过定义损失函数和优化器,使用PyTorch提供的自动求导功能,进行模型训练。可以根据需要设置训练的迭代次数、学习率等超参数,并周期性地评估模型的性能。 5. 模型评估:训练完成后,使用测试集对模型进行评估,计算分类精度、查准率、查全率等指标,评估模型的性能。 6. 模型应用:经过训练和评估后,可以使用该模型对新的遥感像进行分类预测。将新的像输入到模型中,经过前向传播计算,得到像的预测类别。 总而言之,通过PyTorch实现遥感像地物分类可以借助其强大的机器学习功能和便捷的开发环境,快速高效地完成像分类任务。同时,PyTorch还提供了丰富的工具和库,方便用户进行模型设计、训练和评估,并具有良好的可扩展性和灵活性,满足不同用户的需求。 ### 回答2: PyTorch是一个常用的深度学习框架,它提供了丰富的功能和工具,可以用于遥感像地物分类任务的实现。在知乎上,关于PyTorch实现遥感像地物分类的问题,可能会有一些相关的回答。 首先,我们需要准备好用于训练的遥感数据集。可以使用公开的遥感数据集,或者是自己收集的数据集。数据集应包含不同类别的地物像样本,并且要进行适当的标注。 接下来,我们可以使用PyTorch数据处理工具,如`torchvision`来加载和预处理数据。可以使用`torch.utils.data.Dataset`构建一个自定义数据集类,根据需要对像进行预处理操作,如缩放、裁剪、归一化等。 然后,我们可以使用PyTorch搭建一个卷积神经网络(CNN)模型,用于像分类任务。可以根据具体的需求选择不同的网络结构,如ResNet、VGG等。可以使用`torch.nn`模块来构建自定义的网络模型,包括卷积层、池化层、全连接层等。 在模型搭建完成后,我们需要定义损失函数和优化器来进行训练。常用的损失函数有交叉熵损失函数(CrossEntropyLoss),可以通过`torch.nn.CrossEntropyLoss`来定义。优化器可以选择Adam、SGD等,可以使用`torch.optim`模块来构建。 接着,我们可以编写训练循环,使用训练数据来迭代训练模型。可以使用`torch.utils.data.DataLoader`来创建一个数据迭代器,方便获取批量的数据样本。然后,依次将数据输入到模型中,计算损失函数,并通过优化器来更新模型参数。 在训练过程中,可以使用一些技巧来提高模型性能,如数据增强、学习率调整等。可以通过`torchvision.transforms`来实现数据增强操作,如随机裁剪、随机旋转等。可以使用学习率调整器(Learning Rate Scheduler)来动态调整学习率,如StepLR、ReduceLROnPlateau等。 最后,在训练完成后,我们可以使用测试数据对模型进行评估。可以使用测试数据集来验证模型的泛化能力,并计算评估指标,如准确率、召回率等。 总之,使用PyTorch实现遥感像地物分类是一个相对复杂的任务,但通过合理的数据处理、模型搭建和优化方法,可以有效实现。知乎上也有很多关于这一问题的讨论和分享,可以帮助我们更好地理解和实践相关内容。 ### 回答3: pytorch是一个常用的深度学习框架,可以用于遥感像地物分类任务的实现。在pytorch中,可以利用卷积神经网络(CNN)进行像分类任务。 首先,需要准备好遥感像的数据集。数据集应包含标注好的遥感像样本,以及每个样本对应的地物分类标签。接下来,可以利用pytorch数据加载工具,如torchvision库中的datasets模块,将数据集按照一定的比例划分为训练集、验证集和测试集。 然后,可以利用pytorch的模型类来定义一个卷积神经网络模型。模型的结构可以根据具体任务进行设计,一般建议包含多个卷积层、池化层和全连接层。可以根据需要,使用不同的卷积核大小、步幅和激活函数等。 在模型定义好后,可以利用pytorch的优化器类定义一个优化器,如Adam优化器。优化器可以控制模型的权重更新方式,在训练过程中调整学习率和动量等超参数。 接下来,可以利用pytorch的训练循环来训练模型。训练循环包括多个迭代的训练阶段,每个阶段包括前向传播、计算损失、反向传播和模型权重更新等步骤。可以利用pytorch的损失函数类定义一个损失函数,如交叉熵损失函数。在训练过程中,通过最小化损失函数来优化模型的权重。 在训练结束后,可以利用验证集来评估模型的性能,并根据需要进行调参和优化。最后,可以利用测试集对训练好的模型进行评估,并根据评估结果进行后续的地物分类任务。 总之,pytorch可以提供一个灵活、高效的深度学习框架,用于实现遥感像地物分类任务。通过合理设计模型结构、选择合适的优化器和损失函数,以及使用训练循环和数据加载工具等功能,可以实现高准确率的地物分类模型。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值