【图神经网络】 AM-GCN代码实战(2)【pytorch】代码可运行

请添加图片描述

代码实践部分

本专栏致力于深入探讨图神经网络模型相关的学术论文,并通过具体的编程实验来深化理解。读者可以根据个人兴趣选择相关内容进行学习。上一节中详细解读了 “AM-GCN” 这篇论文其主体代码是如何运行的。对于那些对传统图神经网络感兴趣的读者,可以通过点击此处查阅更多相关内容。在本章节中,我们将对该论文的主体代码进行逐个文件的讲解,以帮助读者逐步理解代码的具体含义并掌握其实际应用。

这个原文的代码地址感兴趣的读者 自行下载即可 https://github.com/2578562306/AM-GCN

在这里插入图片描述

😃当然要是觉得还不错的话,烦请点赞,收藏➕关注👍

1.代码文件详解

下图为文件的划分情况:
请添加图片描述
文件的内容还是比较多的,我们先在此对每个文件的内容其展开介绍,然后再一点点的看其代码的主体内容:

  • case_study:此文件夹包含两个文件,它们对应于论文中提到的使用生成数据来识别 GCN 模型的潜在问题的实验。其中,Case1 展示了数据中存在的相关性结构与分类结果无关的情况,而 Case2 则展示了与分类结果相关的数据结构。
  • config:该文件夹存放模型在不同数据集及不同标签规模下的配置参数,这些配置文件在运行代码时可以直接调用,确保实验结果的一致性。
  • config.py:该文件主要负责加载config文件夹下的配置内容,供模型使用。
  • dataprocess.py:此文件提供了从原始数据到图结构的完整处理流程,包括数据的读取、预处理、图的构建和存储。这对于图神经网络或其他图分析任务来说至关重要,文件中还包括了参数化处理和生成不同K值的KNN图,允许用户灵活地设置实验,以探索不同图结构对模型性能的影响。
  • layer.py:该文件定义了图卷积网络(Graph Convolutional Network, GCN)的基础层。可以理解为定义了基础的卷积层,方便后续像搭积木一样构建网络结构。
  • model.py:在这个文件中定义了完整的网络模型,使用之前定义的层以及Torch的函数库来堆叠出论文中提到的网络架构。
  • utils.py:这里包含了各种实验过程中需要的工具函数,比如计算准确率的函数等。
  • main.py:该文件中包含了模型的训练与验证代码,整合了模型和各种参数,实施训练和评估过程。

以上概述了项目的文件结构和每个文件的主要用途,为深入理解项目框架和代码实施提供了基础。

2. case_study

本章节主要是对case_study,文件夹下的两组数据代码进行讲解。 这里实际上也是论文工作量的一部分。具体的为下图这部分的内容,论文中第二节展示的实验部分:

请添加图片描述
首先看代码CASE1的内容:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
import numpy as np
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
# 前面的这几个包都没用上,看起来比较像作者为了看分布情况做的实验

 # 这里构建的数据是节点特征和标签高度相关但是图结构是随机生成的

edge_file = open("/Users/wangyang/Desktop/图神经网络/AM-GCN-master/data/case1.edge",'w') 
# 创建一个文件对象,,使用相关的方法可以对其进行读写操作

adj = np.zeros((900, 900)) 
# 创建一个都是0的邻接矩阵,用于存储节点间的邻接矩阵信息。

for i in range(300): # i,j一个控制行坐标,一个控制列坐标.前300个节点
    for j in range(i+1, 300):  # 这个就是为什么从1-300n呢?因为[0,0]这个位置是自连接,先不考虑自连接的问题。
        z = np.random.randint(0, 100, dtype=int) # 简单粗暴,z是0-100中随机生成的整数。底下判断其是否大雨96 为真的概率只有百分之0.03。
        if z > 96:  #0.03 ,随机生成边,每对节点之间有 3% 的概率相连。
            adj[i, j] = 1 # 矩阵对角化,就是无向边的构造
            adj[j, i] = 1
            
for i in range(300, 600): # 对 300-599 和 600-899 范围内的节点执行类似操作,形成另外两个集群。
    for j in range(i+1, 600):
        z = np.random.randint(0, 100, dtype=int)
        if z > 96: #0.03
            adj[i, j] = 1
            adj[j, i] = 1
            
for i in range(600, 900): 
    for j in range(i+1, 900):
        z = np.random.randint(0, 100, dtype=int)
        if z > 96: #0.03
            adj[i, j] = 1
            adj[j, i] = 1
# ——————————————————————————————————————————————————————————————————————————————
# 上面集群内部的连接操作,可以看到900个节点分成三个群组。比如第一个群组中0-300个节点的边只会连接在0-300个节点之间,不连接300-900其他节点
# 下面的代码则是集群对外部的连接了。前300个节点开始和外部的节点进行连接,比如下面代码的前两个循环就是前300个节点和其他的300-900节点的边生
# 成代码。然后就是一个300-600节点开始和600-900边的构建
# 简而言之一个簇内的边一个是簇外边的构建
# ——————————————————————————————————————————————————————————————————————————————
for i in range(300):
    for j in range(300, 600):
        z = np.random.randint(0, 100, dtype=int)
        if z > 96: #0.03
            adj[i, j] = 1
            adj[j, i] = 1
            
for i in range(300):
    for j in range(600, 900):
        z = np.random.randint(0, 100, dtype=int)
        if z > 96: #0.03
            adj[i, j] = 1
            adj[j, i] = 1

for i in range(300, 600):
    for j in range(600, 900):
        z = np.random.randint(0, 100, dtype=int)
        if z > 96: #0.03
            adj[i, j] = 1
            adj[j, i] = 1
# 将邻接矩阵信息写入文件:
x, y = np.where(adj > 0) # 开始找存在边的节点的坐标,就是adj那里是非0的数值坐标位置,将他们的坐标给x,y
for i in range(len(x)): # 判断一下边的个数,就是遍历的形式将, 边信息写入到文件中
    if x[i] != y[i]: # 并且自连接边进行忽视,就是不考虑自连接的形式
       edge_file.write('{} {}\n'.format(x[i], y[i]))
edge_file.close() # 关闭文件,打开后一定要关闭
# ——————————————————————————————————————————————————————————————————————————————
# 上面完成了没有图结构的构造方式,下面生成节点特征数据
# ——————————————————————————————————————————————————————————————————————————————

dim = 50 # 节点的特征维度
mask_convariance_maxtix = np.diag([1 for i in range(dim)]) 
# 创建了一个 50x50 对角矩阵矩阵,对角线上的值为 1,其余为 0。这表示特征间没有相关性,每个特征的方差为 1。
# 就是假设特征之间是高度不相关的,最理想的特征工程了。特征之间高度不相关没冗余。每个特征都很有用
# ——————————————————————————————————————————————————————————————————————————————
# 在这列解释下实际上就是一个dim = 4.目的就是限定比如第一个维度0,0就是第一个特征和自己的相关性为100其他都是0,就是是高度不相关
# [[1. 0. 0. 0.]
#  [0. 1. 0. 0.]
#  [0. 0. 1. 0.]
#  [0. 0. 0. 1.]]
# ——————————————————————————————————————————————————————————————————————————————

center1 = 2.5 * np.random.random(size=dim) - 1 
center2 = 2.5 * np.random.random(size=dim) - 1
center3 = 2.5 * np.random.random(size=dim) - 1
# np.random.random(size=dim)生成的是 0 到 1 之间的随机数,乘以 2.5 后范围变为 0 到 2.5,再减去 1,
# 范围调整为 - 1 到 1.5。这三个中心向量决定了生成的数据点在高维空间中的大致位置。
# 就是三个簇心,

center = np.vstack((center1, center2, center3))

data1 = multivariate_normal.rvs(mean=center1, cov=mask_convariance_maxtix, size=300)

data2 = multivariate_normal.rvs(mean=center2, cov=mask_convariance_maxtix, size=300)
data3 = multivariate_normal.rvs(mean=center3, cov=mask_convariance_maxtix, size=300)
data = np.vstack((data1, data2, data3))
# 简单的介绍一下multivariate_normal.rvs 函数 。mean的意思就是生成特征的簇中心的位置。cov则是每个维度
# 之间的相关性,已经在之前定义行了极度不想逛。size就是每个数据点的维度
# 使用 multivariate_normal.rvs 函数分别为每个群集生成 300 个数据点。这些数据点遵循多元正态分布,均
# 值由 center1, center2, center3决定,协方差矩阵为对角矩阵(各特征独立,方差为 1)。最后,将这三组数
# 据垂直堆叠起来,形成一个 900x50 的数组,即图中 900 个节点各自的 50 维特征向量。

# 上面多行代码是为三个不同的集群生成具有随机中心的多元正态分布的数据。就是0-300这样的节点的特征比较一致

label = np.array([0 for i in range(300)] + [1 for i in range(300)] + [2 for i in range(300)])
# 0-300,300-600,600-900三种类别打标签

permutation = np.random.permutation(label.shape[0]) # 对其索引进行打乱,实际上就死活打乱其数据的顺序
# 举个例子
# np.random.permutation(10)
# array([1, 7, 4, 3, 0, 9, 2, 5, 8, 6]) # random
data = data[permutation, :] # 
label = label[permutation]
# 存文件称txt格式
np.savetxt('/Users/wangyang/Desktop/图神经网络/AM-GCN-master/data/case1.feature', data, fmt='%f')
np.savetxt('/Users/wangyang/Desktop/图神经网络/AM-GCN-master/data/case1.label', label, fmt='%d')


代码的具体细节全部都用注释进行了解释,接下来对整体进行总结下。下面对整个流程进行总结:

第一部分:构建图结构

  • 邻接矩阵的初始化:创建一个900x900的零矩阵,用作邻接矩阵,存储图中节点间的连接信息。
  • 内部集群连接:生成三个各含300个节点的集群。集群内部的节点用3%的概率随机连接。
  • 集群间连接:不同集群间的节点也以3%的概率随机连接,增加图的复杂性。

第二部分:生成节点特征

  • 特征维度与协方差矩阵:定义每个节点的特征向量维度为50,并创建一个对角协方差矩阵,表明特征间无相关性。
  • 集群中心:为每个集群随机生成一个50维的均值向量,代表该集群的中心。
  • 数据生成:使用多元正态分布生成每个集群的数据,每个集群300个样本,使得每个集群的数据点在特征空间中聚集在其集群中心周围。

第三部分:标签与文件存储

  • 标签生成:为每个集群的节点生成唯一的标签,0 对应第一个集群,1 对应第二个,2 对应第三个。
  • 随机打乱:打乱数据和标签的顺序,以模拟现实世界数据的随机性。
  • 数据保存:将特征数据和标签数据保存到指定位置的文件中。

这种数据生成方法常用于测试图神经网络模型的性能,尤其是在没有足够实验数据的初期研究阶段。通过控制节点特征与标签的相关性以及图结构的随机性,研究者可以深入了解模型对于特定类型的图数据的处理能力和限制。此外,通过修改生成数据的参数(如连接概率、集群中心、特征维度等),可以进一步探索模型在不同情境下的表现,帮助优化模型设计。

首先看代码CASE2的内容:
有了上文中代码的理解,现在再看这些代码其实难度就是比较低了:

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import multivariate_normal
import numpy as np
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt

# 这里则是图结构和标签高度相关,但是其特征是随机生成的

edge_file = open("/Users/wangyang/Desktop/图神经网络/AM-GCN-master/data/case2.edge",'w')

adj = np.zeros((900, 900))
for i in range(300):
    for j in range(i+1, 300):
        z = np.random.randint(0, 100, dtype=int)
        if z > 96:  #0.03
            adj[i, j] = 1
            adj[j, i] = 1
            
for i in range(300, 600):
    for j in range(i+1, 600):
        z = np.random.randint(0, 100, dtype=int)
        if z > 96: #0.03
            adj[i, j] = 1
            adj[j, i] = 1
            
for i in range(600, 900):
    for j in range(i+1, 900):
        z = np.random.randint(0, 100, dtype=int)
        if z > 96: #0.03
            adj[i, j] = 1
            adj[j, i] = 1
            

# ——————————————————————————————————————————————————————————————————————————————
# 两组生成实验数据代码只是在这里出现了差异,就是概率问题,不同簇之间连接的概率变得很低
# ——————————————————————————————————————————————————————————————————————————————
for i in range(300):
    for j in range(300, 600):
        z = np.random.randint(0, 10000, dtype=int)
        if z > 9984: #0.0015
            adj[i, j] = 1
            adj[j, i] = 1
            
for i in range(300):
    for j in range(600, 900):
        z = np.random.randint(0, 10000, dtype=int)
        if z > 9984: #0.0015
            adj[i, j] = 1
            adj[j, i] = 1

for i in range(300, 600):
    for j in range(600, 900):
        z = np.random.randint(0, 10000, dtype=int)
        if z > 9984: #0.0015
            adj[i, j] = 1
            adj[j, i] = 1

x, y = np.where(adj > 0)
for i in range(len(x)):
    if x[i] != y[i]:
       edge_file.write('{} {}\n'.format(x[i], y[i]))
edge_file.close()


dim = 50
mask_convariance_maxtix = np.diag([1 for i in range(dim)])
# 同样生层数据特征还是高度不相关,但是可以看到只有一个簇心,就是特征都是一样的了,不利用分类,只能通过结构信息来分类
center = 2.5 * np.random.random(size=dim) - 1
data = multivariate_normal.rvs(mean=center, cov=mask_convariance_maxtix, size=900)

label = np.array([0 for i in range(300)] + [1 for i in range(300)] + [2 for i in range(300)])

np.savetxt('/Users/wangyang/Desktop/图神经网络/AM-GCN-master/data/case2.feature', data, fmt='%f')
np.savetxt('/Users/wangyang/Desktop/图神经网络/AM-GCN-master/data/case2.label', label, fmt='%d')


只需要将我的文件地址修改两组代码就能正常的进行执行。主要是用于去分析GCN中的实际能力。代码创建了第二种类型的人工数据,用于在图神经网络中测试图结构与标签的相关性,而特征则是随机生成的。这种数据设置有助于探究模型是否能够主要从图的结构而不是特征来学习节点的分类。
与case1不同,集群间连接的概率极低,仅为 0.0015,显示节点间的连接更加稀疏。随机生成一个公共的中心向量center,所有节点的特征数据均来自以此中心为均值的多元正态分布。这意味着尽管所有节点特征数据来源相同, 但通过这种方式生成的特征信息是不利于分类的,因为所有节点的特征分布完全一致。

可以测试图神经网络模型是否能够在节点特征帮助不大的情况下,仅凭图结构信息进行有效的分类。这对于理解模型对于图结构的敏感性以及如何处理非结构化或弱结构化特征数据具有研究价值。此外,极低的集群间连接概率也使得模型更依赖于每个簇内的结构信息,从而检验模型在处理稀疏图数据时的性能表现。
这样的实验设计有助于评估和改进图神经网络模型,在面对现实世界复杂和多样的图数据时,提高其适应性和鲁棒性。

3. 总结

这只是对AMGCN模型性能展开的一项初步实验。在接下来的章节中,我们将逐步揭开图神经网络全面架构的细节,并深入解析相关论文。如果您觉得这些内容对您有帮助,请考虑订阅支持。就是对我工作的最大支持,我会持续更新有关图神经网络的最新动态和深入分析,我们一同努力、共同进步。还是老样子感兴趣的各位点赞收藏关注就是对我的最大动力,感谢感谢感谢。有问题欢迎私信哦。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这个男人是小帅

请小弟喝杯咖啡☕️鼓励下吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值