MPNN 模型:GNN 传递规则的实现

2023-10-16 07:30

本文主要是介绍MPNN 模型:GNN 传递规则的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先,假如我们定义一个极简的传递规则

f(X,A) = AX

A是邻接矩阵,X是特征矩阵, 其物理意义就是 通过矩阵乘法操作,批量把图中的相邻节点汇聚到当前节点。

但是由于A的对角线都是 0.因此自身的节点特征会被过滤掉。

图神经网络的核心是 吸周围之精华,再叠加自身,因而需要改进来保留自身特征。如何做?

方法是给每个节点添加一个自环,即将邻接矩阵对角线值各加1,此时用\widetilde{A}表示,\widetilde{A}X做到了聚合邻居节点并保留自身信息。

但是当图过于复杂时,聚合邻居信息会不断执行矩阵乘法或加法,可能导致特征值太大而溢出。如何做?

方法是邻接矩阵归一化。那么如何归一化呢?我们由A可以得到图的度D,由于A变成了\widetilde{A},我们认为\widetilde{A}的度为\widetilde{D}。常用的归一化方式就是用度数矩阵的倒数\widetilde{D}^{-1}

f(X,A) = \widetilde{D}^{-1}\widetilde{A}X

但是\widetilde{D}^{-1}\widetilde{A}仅仅对矩阵A进行了列上的缩放,操作后的元素值是不对称的,某种程度破坏了图结构的对称性。(这是为什么?)那么如何修复这种对称性呢?

方法是在行的方向上也进行对等缩放,具体 做法是,让邻接矩阵\widetilde{A}右乘一个缩放因子\widetilde{D}^{-1},这样就使得缩放版本的邻接矩阵重新恢复对称性。于是信息聚合的方式为

f(X,A) = \widetilde{D}^{-1}\widetilde{A}\widetilde{D}^{-1}X

\widetilde{D}^{-1}\widetilde{A}\widetilde{D}^{-1}能够很好地缩放邻接矩阵,既然-1次幂可以完成,为什么不尝试一下(-1/2)次幂呢?

事实上,对每个矩阵元素都实施\widetilde{D}^{-\frac{1}{2}}\widetilde{D}^{-\frac{1}{2}}=\frac{1}{\sqrt{deg(v_i)\sqrt{deg(v_j)}}}

这种操作可以对邻接矩阵地每一行每一列”无偏差“地进行一次归一化,以防相邻节点间度数不匹配对归一化地影响。(why)?

于是就出现了被众多学术论文广泛采纳地邻接矩阵地缩放形式

f(X,A) = \widetilde{D}^{-\frac{1}{2}}\widetilde{A}\widetilde{D}^{-\frac{1}{2}}X

考虑权值影响的信息聚合

上述仅仅考虑到邻接矩阵对获取邻居节点信息的影响,即只考虑拓扑结构施加的影响。事实上,对于特定节点而言,不同维度的特征值对给定任务的影响程度是不同的,如果第对各个特征值进行时 打分就,就要涉及到权值矩阵W了,也就是要构造更为完整的图神经网络模型 AWX。权值矩阵W通常是通过学习得到的。

f(X,A) = \widetilde{D}^{-\frac{1}{2}}\widetilde{A}\widetilde{D}^{-\frac{1}{2}}XW

如果我们想压缩节点输出的维度,也可以缩减权值矩阵的输出维度。

在以上的分析中,没有考虑激活函数的影响,无法给予神经网络的非线性变换能力,因此通常我们需要使用sigmoid、tanh、Relu等作为激活函数,最后再用argmax函数模拟一个分类的输出。

reference:

《从深度学习到图神经网络:模型与实践》  张玉宏 等

code:

import networkx as nx
import matplotlib.pyplot as plt
import numpy as np#定义节点
N = [(f"v{i}", 0) for i in range (1,3)] + [(f"v{i}",1) for i in range (3,5)] + [(f"v{i}",2) for i in range (5,6)] #定义节点#定义边
E = [("v1","v2"),("v1","v3"),("v2","v1"),("v2","v3"),("v2","v4"),("v3","v1"),("v3","v2"),("v3","v4"),("v4","v2"),("v4","v3"),("v4","v5"),("v5","v4")] #定义边G = nx.Graph() #构造图G.add_nodes_from(list(map(lambda x: x[0],N))) #给图添加节点
G.add_edges_from(E) #给图添加边ncolor =['r']*2 + ['b']*2 +['g']*1 #设置节点颜色
nsize = [700]*2 + [700]*2 + [700]*1 #设置节点的大小#显示图
nx.draw(G, with_labels= True, font_weight ='bold', font_color = 'w', node_color =ncolor, node_size =nsize)
plt.show()#借用nx构造邻接矩阵
A = np.array(nx.adjacency_matrix(G).todense())
print(A)#构造特征矩阵X
X = np.array([[i,-i, i+2] for i in  range (A.shape[0])])
print(X)#为了不丢失自己的属性,需要修改本身的邻接矩阵,因为最初邻接矩阵的斜对角线为0
I = np.eye(A.shape[0])
A_hat = A + I
print('A_hat')
print(A_hat)#计算自环邻接矩阵的度
D_hat = np.diag(np.sum(A_hat,axis= 0 ))
print(D_hat)#获取D——hat的逆矩阵,即一个缩放因子
D_1 = np.diag(D_hat) ** (-1) *np.eye(A_hat.shape[0])
print('D_1')
print(D_1)#缩放版的邻接矩阵
A_scale = D_1 @ A_hat  #对矩阵A仅仅进行了列方向上的缩放
print('A_scale')
print(A_scale)#用A_scale来聚合邻居节点的信息
X_new = A_scale @ X
print('X_new')
print(X_new)#修复原本的缩放的不对称性
scale_factor = D_1 @ A_hat @ D_1    #scale_factor 是对称的,而 A_scale是不对称 的
print('scale_factor')
print(scale_factor)#用scale_factor来聚合邻居节点的信息
X_new1 = scale_factor  @ X
print('X_new1')
print(X_new1)D_sq_half = np.diag(D_hat) ** (-0.5) *np.eye(A_hat.shape[0])
print('D_sq_half')
print(D_sq_half)#修复原本的缩放的不对称性
scale_factor2 = D_sq_half @ A_hat @ D_sq_half    #scale_factor 是对称的,而 A_scale是不对称 的
print('scale_factor2')
print(scale_factor2)#用scale_factor2来聚合邻居节点的信息
X_new2 = scale_factor2  @ X
print('X_new2')
print(X_new2)#给出的权值矩阵
W = np.array([[0.13,0.24],[0.37,-0.32],[0.14,-0.15]])X_new3 = X_new2 @ W
print(X_new3)#也可以缩减W的尺寸压缩节点的输出维度
W1 = np.array([[0.13],[0.37],[0.14]])
#计算logits
logits = X_new2 @ W1
print(logits)#以上都没有考虑到激活函数,无法模拟神经网络的非线性变换能力,可以使用激活函数
y = logits * (logits >0)  #使用Relu函数
print(y)#为了实现分类等功能,还需要添加一层Softmax
def softmax(x):return np.exp(x) /np.sum(np.exp(x), axis = 0)prob = softmax(y)
print('y')
print(y)#模拟一个分类输出
pred = np.argmax(prob)
print(pred)

这篇关于MPNN 模型:GNN 传递规则的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/219974

相关文章

Python使用python-can实现合并BLF文件

《Python使用python-can实现合并BLF文件》python-can库是Python生态中专注于CAN总线通信与数据处理的强大工具,本文将使用python-can为BLF文件合并提供高效灵活... 目录一、python-can 库:CAN 数据处理的利器二、BLF 文件合并核心代码解析1. 基础合

Python使用OpenCV实现获取视频时长的小工具

《Python使用OpenCV实现获取视频时长的小工具》在处理视频数据时,获取视频的时长是一项常见且基础的需求,本文将详细介绍如何使用Python和OpenCV获取视频时长,并对每一行代码进行深入解析... 目录一、代码实现二、代码解析1. 导入 OpenCV 库2. 定义获取视频时长的函数3. 打开视频文

golang版本升级如何实现

《golang版本升级如何实现》:本文主要介绍golang版本升级如何实现问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录golanwww.chinasem.cng版本升级linux上golang版本升级删除golang旧版本安装golang最新版本总结gola

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

Mysql实现范围分区表(新增、删除、重组、查看)

《Mysql实现范围分区表(新增、删除、重组、查看)》MySQL分区表的四种类型(范围、哈希、列表、键值),主要介绍了范围分区的创建、查询、添加、删除及重组织操作,具有一定的参考价值,感兴趣的可以了解... 目录一、mysql分区表分类二、范围分区(Range Partitioning1、新建分区表:2、分

MySQL 定时新增分区的实现示例

《MySQL定时新增分区的实现示例》本文主要介绍了通过存储过程和定时任务实现MySQL分区的自动创建,解决大数据量下手动维护的繁琐问题,具有一定的参考价值,感兴趣的可以了解一下... mysql创建好分区之后,有时候会需要自动创建分区。比如,一些表数据量非常大,有些数据是热点数据,按照日期分区MululbU

MySQL中查找重复值的实现

《MySQL中查找重复值的实现》查找重复值是一项常见需求,比如在数据清理、数据分析、数据质量检查等场景下,我们常常需要找出表中某列或多列的重复值,具有一定的参考价值,感兴趣的可以了解一下... 目录技术背景实现步骤方法一:使用GROUP BY和HAVING子句方法二:仅返回重复值方法三:返回完整记录方法四:

IDEA中新建/切换Git分支的实现步骤

《IDEA中新建/切换Git分支的实现步骤》本文主要介绍了IDEA中新建/切换Git分支的实现步骤,通过菜单创建新分支并选择是否切换,创建后在Git详情或右键Checkout中切换分支,感兴趣的可以了... 前提:项目已被Git托管1、点击上方栏Git->NewBrancjsh...2、输入新的分支的

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方