图神经网络学习01:图卷积神经网络GCN实战解决论文分类问题(tensorflow实现)

2023-11-03

图神经网络学习01:图卷积神经网络GCN实战解决论文分类问题(tensorflow实现)

前言

​ 关于最近兴起的图神级网络,博主是在一次旁听长达多个小时的论文汇报中听到的,当然由于那时博主处于对深度学习只知道概念,而不知道具体是怎么实现,所以我天马行空了整场。。。跳过,最近经过一段时间对于深度学习的学习,博主膨胀了,出于好奇心,我开始了对于图神经网络的学习,今天介绍的是图卷积神经网络GCN。

​ 图卷积神经网络,顾名思义就是对于图(数学意义上的),进行我们类似在图片上的卷积操作,聚合各个节点(图中)之间的特征,从而得出我们想要的输出。他处理的问题一般是每个输入的节点之间存在某个关系,可以让他们之间被连接起来(比如本篇博客中的采用的数据集cora,我们输入的每个节点都有其对应的文本向量,然后每个节点都是一篇论文,论文之间存在引用关系,一个论文可以被其他多个论文引用,也就是相当于每个节点的度可能超过一),那么GCN在这里执行的任务就是将每个节点的特征用图节点之间连接的关系聚合起来(有很多种聚合方式,这里我们之后介绍),然后最终输出的数据的channel,由我们决定(类似我们使用的CNN)

1.数据集的介绍

​ 本次数据集使用的是cora数据集他含有2708篇论文的特征,和这些论文之间的互相引用关系,这里我们可以读写来展示一下:

​ cora.content文件

data=pd.read_csv('cora/cora.content',sep = '\t',header=None)
data.head()

在这里插入图片描述

其中每一行代表的是一个论文,第一列是论文的编号,每个论文拥有一个1433维的向量,这个向量中每一个索引对应的是一个关键单词,如果是0代表该单词没有出现,1则代表该关键词出现在论文中,在最后一列则是我们论文的标签每个论文被分类为七类,这里我们可以展示一下

label=data.iloc[:,-1]
label.value_counts()#切片整个数据的最后一列,然后我们查看最后一列每个数据类数

在这里插入图片描述

可以看到有七类其中关于神经网络的最多有818个(可见火热),这就是我们的真值,我们的输入可不止每一个论文的文本向量,还有他们论文之间的关系,这里我们查看另一个文件,cora.cite

cite=pd.read_csv('cora/cora.cites',sep = '\t',header=None)
cite

在这里插入图片描述

可以看到这是一个拥有5429行的数据,其中每一行代表的意义是,被引用论文-引用论文,比如 35 103482表示的是编号为103482的论文中引用了我们编号为35的论文,我们要根据每个论文之间的引用关系去构造一个图。

2.网络的搭建

​ 整个图神经网络传导公式区别于一般的神经网络W*x+b,即权重乘以我们的输入再加上偏置,那么我们换算到这里x就是我们会为每个论文编码的文本向量。

​ 但是我们这里的X还要经过处理,我们将所有文本看成节点,每个节点的值是对应的文本向量,当两个论文之间存在引用关系,我们连接这两个节点,那么在数学上我们表示图一般会使用邻接矩阵(用A来表示),来表达图之间是否连接(这里我使用无向图),那么聚合每个节点的特征我们就可以用邻接矩阵来聚合:

​ x_new=A*x,这里我们假设x为(n,1433),那么A作为邻接矩阵他的维度就是(n,n),所以这样的矩阵形状仍然是(n,1433)。可以看到经过这样我们提取到了一个全新的矩阵,该矩阵聚合了每个节点与之相邻节点的特征,但是这样提取过于粗糙:

​ 1.我们根据引用关系创造的图的邻接矩阵对角线上都为0(毕竟数据上不会写自己引用自己),所以我们这样提取特征会每个节点自己自带的特征

  1. 聚合出来的数据并未使用归一化,这样会严重影响模型训练,可能会出现梯度消失与梯度爆炸的效果。

​ 所以最终学者们提出可以用一种经过特殊处理的矩阵来聚合我们输入x的特征
在这里插入图片描述

​ 其中我们的A是邻接矩阵,D是图的度矩阵,是一个对角矩阵,每个值,记录了对应节点的度数,I是单位矩阵,加上他是为了聚合每个节点对应的自己的特征,所以我们最终打算用来聚合输入特征的矩阵是Lsym,那么我们的想法也就很简单了,网络前向传播公式如下,y=Lsym* x * w+b。

​ 说了这么多了接下来就开始写代码定义图卷积神经网络,如下

class GraphConv(layers.Layer):
    def __init__(self, num_outputs, A,activation="softmax"):
        super(GraphConv, self).__init__()
        self.num_outputs = num_outputs
        self.activation_function = activation
        self.A = tf.Variable(A, trainable=False)
    #A是我们最终用来聚合输入特征的矩阵
    def build(self, input_shape):
        # Weights
        self.W = self.add_weight("W", shape=[int(input_shape[-1]), self.num_outputs])
        self.W=tf.cast(self.W,tf.float32)
        # bias
        self.bias = self.add_weight("bias", shape=[self.num_outputs])
        self.bias=tf.cast(self.bias,tf.float32)

    def call(self, input):
        if self.activation_function == 'relu':
            return tf.nn.relu(tf.matmul(tf.matmul(self.A, input), self.W) + self.bias)
        else:
            return tf.nn.softmax(tf.matmul(tf.matmul(self.A, input), self.W) + self.bias)

这里我只用一层图卷积神经网络,所以最后就直接softmax激活,输出多分类值

3.数据的处理

网络定义好了,接下来我们开始对于数据的处理,首先提取出我们的标签并转化为数字

1.将标签提取出来并处理为one-hot编码

label=data.iloc[:,-1]
x=np.unique(label)
label_to_index=dict((k,v) for v,k in enumerate(x))#创造单词转换字典
def appply_label(label):
    return label_to_index.get(label)
label_index=label.apply(appply_label)
label_index=keras.utils.to_categorical(label_index)
#这里将标签转换为one-hot编码
label_index=np.array(label_index)
label_index
#可以看到最终所有标签都被用one-hot编码表示
array([[0., 0., 1., ..., 0., 0., 0.],
       [0., 0., 0., ..., 0., 1., 0.],
       [0., 0., 0., ..., 1., 0., 0.],
       ...,
       [0., 1., 0., ..., 0., 0., 0.],
       [1., 0., 0., ..., 0., 0., 0.],
       [0., 0., 1., ..., 0., 0., 0.]], dtype=float32)

标签提取好了,那就要转换到我们对于输入特征的处理,以及上文提到的提取特征的矩阵的制作

2.输入特征的处理

feature=data.iloc[:,1:-1]
feature.shape
(2708, 1433)

​ 我们这里利用切片获取特征,获取从第2列到最后一列前的所有数据,可以看到从输出形状,我们截取的是对的,然后转换成ndarray格式与数据格式

feature_np=np.array(feature)
feature_np=tf.cast(feature_np,tf.float32)

3.聚合特征矩阵Lsym的制作

我们读取cora.cite文件,然后开始接下来的操作

cite=pd.read_csv('cora/cora.cites',sep = '\t',header=None)
#cite文件含有每个论文之间的引用关系,我们要创造一个图这个就相当于一个告诉我们边的信息
new_id=list(data.index)
id = list(data[0])
m1=zip(id,new_id)
m1=dict(m1)
#因为论文的编号都不是按照2708的顺序排序,所以我将论文编号与数据编号从1到2708之间进行映射
nodes_num=data.shape[0]
adjestive_matrix=np.zeros((nodes_num,nodes_num),dtype=np.float)
for i,j in zip(cite[0],cite[1]):
    i=m1.get(i)
    j=m1.get(j)
    adjestive_matrix[i][j] = 1
    adjestive_matrix[j][i] = 1
	#制作邻接矩阵,根据提供的论文引用关系我们对邻接矩阵赋值

邻接矩阵制作好了,那么我们接下来开始制作下面这个矩阵

在这里插入图片描述

#制作度矩阵
D = np.array(np.sum(adjestive_matrix, axis=0))
D=np.array(np.diag(D))
#这里直接求D**(-1/2)会出现inf等无法计算的字符影响,所以我这里换了种方法参考https://blog.csdn.net/qq_23947237/article/details/88813353
i=np.eye(adjestive_matrix.shape[0])
A_=adjestive_matrix+i
D_=D+i#这里让两个矩阵都先加上单位矩阵
from numpy import linalg as la

# v 为特征值    Q 为特征向量
v, Q = la.eig(D)
# print(v)
V = np.diag(v**(-0.5))
# print(V)
T = Q * V * la.inv(Q)
#最终求出来的T就是D**(-0.5)这样求出来的矩阵类数值不会出现inf
lapician=T*A_*T
lapician

在这里插入图片描述

可以看到这是一个被归一化后的对角矩阵,他的最大值也的确是1

np.max(lapician)
1.0

4.模型的初始化以及训练结果的分析

关于数据集,我们都已经预处理好了那么我们接下来直接开始模型的搭建

net=GraphConv(7,lapician)
#初始化定义图卷积神经网络,给出最终输出的类别数和聚合特征的矩阵
net.build(input_shape=(2708,1433))
#告诉我们的网络输入数据的形状让他可以根据这个初始化权重与偏置
model=keras.Sequential()
model.add(net)
#图卷积神经网络我定义的只是一层,不是模型,所以我这里将该层包装进一个模型里去

然后开始我们自定义训练步骤,对于每次的准确率以及损失函数定义如下

label_index=tf.cast(label_index,tf.float32)
loss_object = tf.keras.losses.CategoricalCrossentropy()
#one-hot编码计算损失采用CategoricalCrossentropy
label_index=keras.utils.to_categorical(label_index)
train_acc=keras.metrics.CategoricalAccuracy(name='train_accuracy')
train_loss=keras.metrics.Mean(name='train_loss')
optimizer=keras.optimizers.Adam(0.1)
#这里的学习率达到0.1是经过调试的结果

定义训练步骤如下

@tf.function
def train_step(feature_np,labels):
    with tf.GradientTape() as t:
        pred=net(feature_np)
        loss_step=loss_object(labels,pred)
    gradies=t.gradient(loss_step,net.trainable_variables)#求解梯度
    optimizer.apply_gradients(zip(gradies,net.trainable_variables))#将梯度应用于优化器从而让模型的可训练参数改变
    train_loss(loss_step)
    train_acc(labels,pred)

然后开始训练

Epoch=10
for epoch in range(Epoch):
    train_loss.reset_states()
    train_acc.reset_states()
    train_step(feature_np,label_index)
    print('-',end='')#标志训练完一个batch
    print('>')
    template = 'Epoch {:.3f}, Loss: {:.3f}, Accuracy: {:.3f}'
    print (template.format(epoch+1,
                           train_loss.result(),
                           train_acc.result()*100
                           ))
        
    

训练结果如下

在这里插入图片描述

​ 可以看到正确率上升的非常快,十次正确率就达到了84.74,最终训练了四十次达到了

在这里插入图片描述

当然最后肯定是学习率过大了,但是99.52我感觉正确率已经够高了,就没有在继续训练下去(这里我只用了单层图卷积神经网络),那么接下来我们可以随机查看结果是否相同(由于预测的只是种类,最终需要的预测值只是一个编号,所以我们查看模型的预测值,是否和原标签一样就可以了),用下列代码随机抽取并查看分类是否相同

choice1=np.random.choice(range(2708))
np.argmax(model(feature_np)[choice1]),np.argmax(label_index[choice1])

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

​ 可以看到通过我们的随机验证,预测值和真实值每次都是一模一样,说明我们到的模型搭建的较为成功。

5.结束语

在本篇博客中,博主完成了对于cora数据的预处理,GCN网络的自定义,并且初始化了模型并训练最终得到了不错的结果。
但这里其实有个问题,博主在这里并没有划分测试与训练集,其实是有划分过但是不知什么原因出现梯度消失爆炸等原因,所以后面就没有展示这方面的代码。

在这里插入图片描述

这里我划分的方法就是在训练的时候只计算训练集的损失,不计算测试集,可能哪里有问题希望有比较会的大佬可以赐教,有任何建议或者疑问欢迎评论区交流,谢谢!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

图神经网络学习01:图卷积神经网络GCN实战解决论文分类问题(tensorflow实现) 的相关文章

随机推荐

  • 无线打印机服务器说明书,无线打印机服务器

    无线打印机服务器 内容精选 换一换 假定某个Flink业务每秒就会收到1个消息记录 基于某些业务要求 开发的Flink应用程序实现功能 实时输出带有前缀的消息内容 Flink样例工程的数据存储在Kafka组件中 Flink向Kafka组件发
  • 生命在于学习——业务逻辑漏洞

    声明 只是用于学习交流 笔记记录 不可用作违规用途 一 业务逻辑漏洞简介 简单理解 就是编程人员的思维逻辑不够严谨导致攻击者有机可乘的漏洞 逻辑漏洞还是一种虽然没有在owasp top10中提及到 但是往往会存在的漏洞 并且在hvv 渗透测
  • 用户和组权限管理笔记

    一 管理用户和组 Linux 是一个多用户 多任务的服务器操作系统 1 Linux用户类型 linux用户和组账户概述 用户和组 系统上的每个进程 运行的程序 都是作为特定用户运行的 每个文件都是由一个特定用户拥有 访问文件和目录受到用户的
  • 疯壳-鸿蒙OS-应用程序监听驱动程序消息

    应用程序监听驱动程序消息 疯壳 出品 在前面课程中 我们通过驱动服务基类成员IDeviceIoService中的Dispatch方法进行用户态应用程序和内核态驱动程序的消息交互 其中涉及到两个HdfSBuf data与reply data
  • python的color函数的参数_Python 函数参数

    参数 我们用函数封装了一个功能 但是希望这个功能可以在不同要求的作用下面得到不同的结果 就需要用到参数 def f color if color green print They re green elif color yellow pri
  • 字符串转换,将前端传过来的json格式的数据转化为以“#”号隔开的格式的数据(replaceAll、substring和数组)

    一 字符串转换 将前端传过来的json格式的数据转化为以 号隔开的格式的数据 需求 在题目新增时 前端传过来的四个选项是json格式的数据 后端存入数据库的格式要求将四个选项以 隔开 例如 将 A 招标人 B 投标人 C 设计单位 D 施工
  • 一篇就够!数据增强方法综述

    作者 太子长琴 整理 NewBeeNLP 数据增强 Data Augmentation DA 缓解了深度学习中数据不足的场景 在图像领域首先得到广泛使用 进而延伸到 NLP 领域 并在许多任务上取得效果 一个主要的方向是增加训练数据的多样性
  • TorchVision Transforms API 大升级,支持目标检测、实例/语义分割及视频类任务

    内容导读 TorchVision Transforms API 扩展升级 现已支持目标检测 实例及语义分割以及视频类任务 新 API 尚处于测试阶段 开发者可以试用体验 本文首发自微信公众号 PyTorch 开发者社区 TorchVisio
  • JDK8的 stream流详解-转载

    本文章 转载自头条网 只是觉得好用很详细 所以自己收集 做下笔记 不做任何商业用途 不收任何费用 不喜勿喷 本文是转载 希望不要涉及到文章版权 只是自己做笔记 这个是最重要的 致敬 头条 程序猿的内心独白 1 Stream初体验 我们先来看
  • 11-1 输入输出流

    1 文件打开方式 打开方式通常有 r w a 三种 分别代表 只读 只写 附加 三种操作加 t 表示以文本文件形式打开 加 b 表示以二进制文件形式打开 什么都不加的情况下 默认打开文本文件 二进制文件和文本文件的区别 1 在 window
  • Mybatis多表模型

    多表模型 多表模型分类 一对一 在任意一方建立外键 关联对方的主键 一对多 在多的一方建立外键 关联一的一方的主键 多对多 借助中间表 中间表至少两个字段 分别关联两张表的主键 多表模型一对一操作 sql语句准备 CREATE TABLE
  • QGIS插件式开发(三)---插件开发

    本篇文章着重讲述插件开发的主要流程 揭开QGIS插件式开发的真面目 正所谓万事开头难 掌握了第一步 后面就可以把主要精力放在功能开发上 而不必再为怎么加载插件 init 函数的功能是什么等问题所困扰 一 自动创建 自动创建很简单 比较适合对
  • useMemo和useCallback的区别 及使用场景

    useMemo 和 useCallback 接收的参数都是一样 第一个参数为回调 第二个参数为要依赖的数据 共同作用 1 仅仅 依赖数据 发生变化 才会重新计算结果 也就是起到缓存的作用 两者区别 1 useMemo 计算结果是 retur
  • Qt里的信号与槽原理

    一 什么是信号与槽机制 信号和槽 Signal Slot 用于两个对象 object 进行交流 通俗地来说 就是一个对象发出什么信号 另一个对象执行相应的动作 比如跑步比赛中 裁判员发出枪响信号 运动员开始起跑 信号 Signal 相当于发
  • Dialog的layout中有fragment,第二次报错

    1 概述 Dialog用的是最简单的AlertDialog Builder建立的 通过setView view 实现自定义布局 布局里嵌套了一个自定义的fragment 第一次弹出对话框的时候没有问题 第二次再弹的话就会出现错误信息 Bin
  • 阿里云——云安全中心安全事件提醒:挖矿程序

    近日收到云安全中心安全事件提醒 出现了紧急安全事件 挖矿程序 建议您立即登录查看事件详情 并根据事件建议的方案进行处理 登录服务器后用top命令查看CPU利用率并不高 感觉不一定真是挖矿程序在作怪 或挖矿还没启动 用ps ef命令列出进程
  • 数据类型、python数字、数据类型转换、字符串

    目录 1 python的数据类型 2 python 数字 2 使用casting完成数据类型转换 3 字符串 4 字符串常用的内置方法 5 字符串的内建方法 6 字符串的内置方法与内建方法的区别有以下几种 1 python的数据类型 可以使
  • Typescript 基本类型 —— 字符串 String

    使用双引号 或单引号 来表示字符串 关键字 string let str string hello world let res string hello world 编译成js var str hello world var res hel
  • python生成t分布随机数_python没有直接生成服从泊松分布随机数的函数吗

    满意答案 bhedba 2017 02 16 采纳率 49 等级 9 已帮助 314人 首先是泊松分布 这是一个离散型的随机变量分布 比较好弄 此外例如考察一些到达事件的概率时 通常服从泊松分布 因此该分布相当实用 在开始编写之前 先感谢知
  • 图神经网络学习01:图卷积神经网络GCN实战解决论文分类问题(tensorflow实现)

    图神经网络学习01 图卷积神经网络GCN实战解决论文分类问题 tensorflow实现 文章目录 图神经网络学习01 图卷积神经网络GCN实战解决论文分类问题 tensorflow实现 前言 1 数据集的介绍 2 网络的搭建 3 数据的处理