基于Pytorch的图卷积网络GCN实例应用及详解

基于Pytorch的图卷积网络GCN实例应用及详解

一、图卷积网络GCN定义

图卷积网络GCN实际上就是特征提取器,只不过GCN的数据对象是图。图的结构一般来说是十分不规则,可以看作是多维的一种数据。GCN精妙地设计了一种从图数据中提取特征的方法,从而让我们可以使用这些特征去对图数据进行节点分类(node classification)、图分类(graph classification)、边预测(link prediction)和获得图的嵌入表示(graph embedding),用途十分广泛。

二、图卷积网络GCN的原理

  • 博主学习图卷积网络主要参考下面两篇深入浅出的好文章:
  • 第一篇参考文章: 点击打开《一文读懂图卷积GCN》文章
  • 第二篇参考文章点击打开《最通俗易懂的图神经网络(GCN)原理详解》文章
  • 阅读上面两篇文章需要理解图的定义、图相关矩阵的定义(邻接矩阵、度矩阵、拉普拉斯矩阵、稀疏矩阵COO)、图卷积的通式或者公式的推导发展及意义。
  • 若阅读完两篇文章公式推导大家还对 邻接矩阵的归一化操作通过对邻接矩阵两边乘以节点的度开方然后取逆得到 这个知识点”一知半解”,那么请看下面博主就图卷积网络GCN公式进行举例计算, 以此帮助有需要的小伙伴理解理解的可以选择跳过
    基于Pytorch的图卷积网络GCN实例应用及详解
    基于Pytorch的图卷积网络GCN实例应用及详解
    基于Pytorch的图卷积网络GCN实例应用及详解

; 三、图卷积网络GCN实现前期准备

PyTorch Geometric (简称PYG)中设计了一种新的表示图数据的存储结构,也是 PyTorch Geometric中实现的各种方法的基本数据形式。GCN在PyTorch Geometric中有已经封装好的模型(当然大家也可以自己用python代码根据GCN的实现原理自己搭建模型,那么可以不使用PYG自带模型),因此可以直接导包再根据自己的数据集或者PyTorch Geometric自带的数据集(如Cora、ENZYMES等)去实现节点分类(node classification)、图分类(graph classification)、边预测(link prediction)和获得图的嵌入表示(graph embedding)等这些案例。

四、图卷积网络GCN实现案例分析

首先PYG自带的数据集网上的资料和代码很多,大家第一次练手博主认为可以选择PYG自带的数据集,如Cora等,并且训练预测的结果也是非常不错的,大家理解代码也是极好的,给用户体验感受非常不错,因此博主强烈的推荐一篇文章大家可以去试试:点击打开《[PyG] 1.如何使用GCN完成一个最基本的训练过程(含GCN实现)》文章 。但是另一种情况是用户需要用自己的数据集(比如mat文件)通过图卷积网络GCN去实现一些图预测等目的,所以博主通过大量阅读理解和总结,提供一个已经实现的用自己的数据集去跑GCN模型以实现图预测的案例给大家做个参考。

  • 案例目的是 构造图卷积网络模型训练后进行图片二分类(0和1)预测
  • mat文件数据集( MATLAB的专属文件)的导入和构造,博主已有的数据集存放在J盘以aidb.mat文件形式保存下来。

基于Pytorch的图卷积网络GCN实例应用及详解
  • aidb.mat文件 数据结构如下图。 *aidb 是一个数据结构体(struct),包含10364个子结构体(struct),每个子结构体(struct)表示一张图,每张图又包含 nl、am 和 no;nl 表示节点及特征,维度是[20,1];am 表示节点之间的邻接矩阵,维度是[20,20];no 表示图片序号,维度是[1] 。laidb 表示所有图片的分类,结果是0或1,总共有10364张图,维度是[10364] ,注意:每张图的维度是[1] 。

基于Pytorch的图卷积网络GCN实例应用及详解
基于Pytorch的图卷积网络GCN实例应用及详解
基于Pytorch的图卷积网络GCN实例应用及详解

基于Pytorch的图卷积网络GCN实例应用及详解
基于Pytorch的图卷积网络GCN实例应用及详解
基于Pytorch的图卷积网络GCN实例应用及详解
基于Pytorch的图卷积网络GCN实例应用及详解
import numpy as np
import torch
import torch.nn.functional as F
from torch_geometric.nn import GCNConv
import mat4py
import scipy.sparse as sp
from torch_geometric.data import Data
import torch_geometric.nn as pyg_nn
from torch_geometric.data import DataLoader
import warnings
warnings.filterwarnings("ignore", category=Warning)

data = mat4py.loadmat('J:/aidb.mat')
laidb = data['laidb']
aidb = data['aidb']
nl = aidb['nl']
am = aidb['am']

dataset = []
for i in range(len(laidb)):

    edge_index_temp = sp.coo_matrix(am[i])
    indices = np.vstack((edge_index_temp.row, edge_index_temp.col))
    edge_index = torch.LongTensor(indices)

    x = np.array(list(nl[i].values()))
    x = x.squeeze(0)
    x = torch.FloatTensor(x)

    y = torch.LongTensor(laidb[i])

    data = Data(x=x, edge_index=edge_index, y=y)
    dataset.append(data)
  • 构造GCN的模型网络,下面代码中的 池化降维 这个重要的步骤可能有些小伙伴不明白此举意义,所以博主举例说明一下,比如: 输入的每批次data是20张图片(设定batch_size=20),这20张图片的每张图片是由3个节点构成,每个节点的特征只有1个,那么20张图片总共有60个节点,此时data.x的维度是[60,1],data.batch这个结果返回的是20张图片的节点下标,60个节点的下标结果是[0,0,0,1,1,1,2,2,2…,18,18,18,19,19,19],也就是表示属于同一个图片的节点下标相同。经过第二层GCN卷积之后那么输出结果x的维度就变成[60,2],然后将每张图片的3个节点取1个全局最大的节点作为代表该张图片的一个输出,那么20张图片每张图片选自己3个节点范围中最大的那一个,那么输入到输出结果的维度由[60,2]就变成[20,2]。 注意:刚刚只是举例,实际上 博主的此篇文章的数据集因为每张图有20个节点,当设定batch_size=20时,总共有400个节点,因此data.batch的维度是[1],长度是400
class Net(torch.nn.Module):
    """构造GCN模型网络"""
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = GCNConv(1, 16)
        self.conv2 = GCNConv(16, 2)

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

        x = self.conv1(x, edge_index)

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

        x = pyg_nn.global_max_pool(x, batch)

        return F.log_softmax(x, dim=1)

model = Net()
optimizer = torch.optim.Adam(model.parameters(), lr=0.005)
train_loader = DataLoader(train_dataset, batch_size=20, shuffle=False)
  • 训练数据集导入模型,进行模型训练优化参数。下面代码中的 损失函数计算 这个重要的步骤可能有些小伙伴不明白此举意义,所以博主举例说明一下,比如: *下面代码中的output的维度是[20,2],标签lable的维度是[20],根据标签Label的数值[1,0,1…1]将output对应的那个值拿出来,也就是把output中的第一、三到二十行的每行第二个元素,第二行的第一个元素取出,然后先去掉这取出来的20个元素的负号,再对20个元素进行求和,最后除以20取平均值。

model.train()
for epoch in range(100):
    loss_all = 0

    for data in train_loader:

        optimizer.zero_grad()
        output = model(data)
        label = data.y

        loss = F.nll_loss(output,label)
        loss.backward()
        loss_all += loss.item()
        optimizer.step()
    tmp = (loss_all / len(train_dataset))
    if epoch % 20 == 0:
        print(tmp)
  • 测试数据集导入模型, 进行图片二分类(0,1)结果预测

from  sklearn.metrics import accuracy_score
def evaluate(loader):
    model.eval()
    with torch.no_grad():

        for data in loader:

            pred = model(data).numpy()
            label = data.y.numpy()

    return pred,label

loaders = DataLoader(test_dataset, batch_size=20, shuffle=False)

pred,label = evaluate(loaders)

preds = []

for i in range(pred.shape[0]):
    tmp = pred[i].tolist()

    preds.append(tmp.index(max(tmp)))

print(accuracy_score(label, preds))

五、图卷积网络GCN实现完整代码和结果

import numpy as np
import torch
import torch.nn.functional as F
from torch_geometric.nn import GCNConv
import mat4py
import scipy.sparse as sp
from torch_geometric.data import Data
import torch_geometric.nn as pyg_nn
from torch_geometric.data import DataLoader
import warnings
warnings.filterwarnings("ignore", category=Warning)

data = mat4py.loadmat('J:/aidb.mat')
laidb = data['laidb']
aidb = data['aidb']
nl = aidb['nl']
am = aidb['am']

dataset = []
for i in range(len(laidb)):

    edge_index_temp = sp.coo_matrix(am[i])
    indices = np.vstack((edge_index_temp.row, edge_index_temp.col))
    edge_index = torch.LongTensor(indices)

    x = np.array(list(nl[i].values()))
    x = x.squeeze(0)
    x = torch.FloatTensor(x)

    y = torch.LongTensor(laidb[i])

    data = Data(x=x, edge_index=edge_index, y=y)
    dataset.append(data)

train_dataset = dataset[:5000]
test_dataset = dataset[5030:5050]

class Net(torch.nn.Module):
    """构造GCN模型网络"""
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = GCNConv(1, 16)
        self.conv2 = GCNConv(16, 2)

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

        x = self.conv1(x, edge_index)

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

        x = pyg_nn.global_max_pool(x, batch)

        return F.log_softmax(x, dim=1)

model = Net()
optimizer = torch.optim.Adam(model.parameters(), lr=0.005)
train_loader = DataLoader(train_dataset, batch_size=20, shuffle=False)

model.train()
for epoch in range(100):
    loss_all = 0

    for data in train_loader:

        optimizer.zero_grad()
        output = model(data)
        label = data.y

        loss = F.nll_loss(output,label)
        loss.backward()
        loss_all += loss.item()
        optimizer.step()
    tmp = (loss_all / len(train_dataset))
    if epoch % 20 == 0:
        print(tmp)

from  sklearn.metrics import accuracy_score
def evaluate(loader):
    model.eval()
    with torch.no_grad():

        for data in loader:

            pred = model(data).numpy()
            label = data.y.numpy()

    return pred,label

loaders = DataLoader(test_dataset, batch_size=20, shuffle=False)

pred,label = evaluate(loaders)

preds = []

for i in range(pred.shape[0]):
    tmp = pred[i].tolist()

    preds.append(tmp.index(max(tmp)))

print(accuracy_score(label, preds))

基于Pytorch的图卷积网络GCN实例应用及详解

六、基于Pytorch的图卷积网络GCN实例应用及详解3.0

文章链接:点击打开《基于Pytorch的图卷积网络GCN实例应用及详解3.0》文章

Original: https://blog.csdn.net/rothschild666/article/details/123772602
Author: rothschildlhl
Title: 基于Pytorch的图卷积网络GCN实例应用及详解

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/711309/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球