备案信息修改网站名称,怎么注册建设银行网站,响应式设计网站怎么做,做搜索引擎的网站1. 图同构网络#xff1a;Weisfeiler-Lehman 测试与图神经网络的表达力 本节介绍一个关于图神经网络表达力的经典工作#xff0c;以及随之产生的另一个重要的模型——图同构网络。图同构问题指的是验证两个图在拓扑结构上是否相同。Weisfeiler-Lehman 测试是一种有效的检验两…1. 图同构网络Weisfeiler-Lehman 测试与图神经网络的表达力 本节介绍一个关于图神经网络表达力的经典工作以及随之产生的另一个重要的模型——图同构网络。图同构问题指的是验证两个图在拓扑结构上是否相同。Weisfeiler-Lehman 测试是一种有效的检验两个图是否同构的近似方法。当我们要判断两个图是否同构时先通过聚合节点和它们邻居的标签再通过散列函数得到节点新的标签不断重复直到每个节点的标签稳定不变。如果在某些迭代中两个图的节点标签不同则可以判定这两个图是不同的。在Weisfeiler-Lehman测试的过程中K次迭代之后我们会得到关于一个节点的高度为K 的子树。Weisfeiler-Lehman子树常被用于核方法中来计算两个图的相似度。 类似于消息传递网络中所归纳的框架大部分基于空域的图神经网络都可以归结为两个步骤聚合邻接点信息和更新节点信息。 与Weisfeiler-Lehman测试一样在表达网络结构的时候一个节点的表征会由该节点的父节点的子树信息聚合而成。在图同构网络的论文中作者证明了Weisfeiler-Lehman测试是图神经网络表征能力的上限。 定理 设G₁和G₂ 为任意非同构图。如果一个图神经网络遵循领域聚合方案 将G₁和G₂ 映射到不同的嵌入则Weisfeiler-Lehman测试也判定G₁和G₂不是同构的。这说明图神经网络的表达能力不会超过Weisfeiler-Lehman测试的区分能力。那么,我们有没有办法得到和Weisfeiler-Lehman测试一样强大的图神经网络呢?Weisfeiler-Lehman 测试最大的特点是其对每个节点的子树的聚合函数采用的是单射的散列函数。那么,是否将图神经网络的聚合函数也改成单射函数就能达到和Weisfeiler-Lehman测试一样的效果呢? 定理4设A:G→Rd上标是一个遵循邻域聚合方案的图神经网络。通过足够的迭代次数(在图神经网络层数多的情况下),如果满足以下条件则 A可以通过 Weisfeiler-Lehman测试把非同构的两个图G₁ 和G₂ 映射到不同的嵌入 (1)A 在每次迭代时所采用的节点状态更新公式 其中φ是单射函数f 是一个作用在多重集上的函数也是单射函数。 (2)从节点嵌入整合到最终的图嵌入时A 所采用的读取函数运行在节点嵌入的多重集{hvk}上也是一个单射函数。单射指的是不同的输入值一定会对应到不同的函数值。这个结论说明要设计与Weisfeiler-Lehman一样强大的图卷积网络最重要的条件是设计一个单射的聚合函数。 其实求和函数在多重集上就是一个单射函数。由此我们得到了一个新模型——图同构网络只需要把聚合函数改为求和函数就可以提升图神经网络的表达力 2.图卷积网络实战
init部分
#导入确保代码在Python 2中也能使用Python 3的特性
from __future__ import print_function
#从layers模块导入所有内容
from __future__ import division
from .layers import *
#从models模块导入所有内容
from .models import *
#utils模块导入所有内容
from .utils import *
layers部分
import math
import torch
#从 PyTorch 的 nn 模块中导入 Parameter 类它用于定义可学习的参数
from torch.nn.parameter import Parameter
#从 PyTorch 的 nn 模块中导入 Module 类它是所有神经网络模块的基类
from torch.nn.modules.module import Module
#定义一个名为 GraphConvolution 的类它继承自 Module 类
class GraphConvolution(Module):
#biasTrue 是一个常见的参数设置它用于决定是否在模型的某些层中添加偏置项。偏置项是神经网络中的一个参数它允许模型在特征空间中进行平移从而提高模型的灵活性和学习能力
#接收输入特征数 in_features、输出特征数 out_featuresdef __init__(self,in_features,out_features,biasTrue):super(GraphConvolution,self).__init__()self.in_featuresin_featuresself.out_featuresout_features#创建一个权重矩阵 weight它是一个 Parameter 对象用于存储可学习的权重参数self.weightParameter(torch.FloatTensor(in_features,out_features))if bias:self.biasParameter(torch.FloatTensor(out_features))else:#如果 bias 参数为 False则不创建偏置向量而是将 bias 注册为一个不存在的参数self.register_parameter(bias,None)#调用 reset_parameters 方法来初始化权重和偏置参数self.reset_parameters()def reset_parameters(self):#计算权重的初始化标准差使用输出特征数的平方根的倒数stdv1./math.sqrt(self.weight.size(1))#使用均匀分布初始化权重范围在 [-stdv, stdv] 之间self.weight.data.uniform_(-stdv,stdv)#定义 forward 方法它是模型的前向传播方法接收输入数据 input 和邻接矩阵 adjdef forward(self,input,adj):#定义 forward 方法它是模型的前向传播方法接收输入数据 input 和邻接矩阵 adjsupporttorch.mm(input,self.weight)#使用矩阵乘法计算输入数据和权重的乘积得到变换后的特征outputtorch.spmm(adj,support)if self.bias is not None:return outputself.biaselse:return output#定义 __repr__ 方法用于返回类的字符串表示def __repr__(self):return self.__class__.__name (\str(self.in_features)-\str(self.out_features))
models部分
#导入 PyTorch 的神经网络模块
import torch.nn as nn
#导入 PyTorch 的函数模块它包含了一些常用的函数比如激活函数。
import torch.nn.functional as F
#从 pygcn 库中导入 GraphConvolution 类这是一个图卷积层的实现
from pygcn.layers import GraphConvolution
#定义了一个名为 GCN 的类它继承自 nn.Module
class GCN(nn.Module):#nfeat输入特征的数量,nhid隐藏层的特征数量#nclass输出类别的数量,dropoutDropout 层的丢弃概率def __init__(self,nfeat,nhid,nclass,dropout):super(GCN,self).__init__()
#self.gc1GraphConvolution(nfeat,nhid)创建第一个图卷积层将输入特征从 nfeat 转换到 nhid。self.gc1GraphConvolution(nfeat,nhid)
#self.gc2GraphConvolution(nhid,nclass)创建第二个图卷积层将隐藏层特征从 nhid 转换到输出类别 nclassself.gc2GraphConvolution(nhid,nclass)
#将Dropout 层的丢弃概率设置为传入的 dropout 参数self.dropoutdropout#定义了模型的前向传播函数它接收两个参数#x输入的特征矩阵,adj邻接矩阵表示图结构def forward(self,x,adj):#通过第一个图卷积层 gc1 传递 x 和 adj然后应用 ReLU 激活函数xF.relu(self.gc1(x,adj))#在激活后的特征上应用 Dropout 层xF.dropout(x,self.dropout,trainingself.training)#通过第二个图卷积层 gc2 传递 x 和 adjxself.gc2(x,adj)
#在最后一层上应用 log-softmax 函数得到每个类别的对数概率并返回结果
#Softmax 目的是将一个向量或一个批量的向量中的元素值转换成概率分布return F.log_softmax(x,dim1)
utils部分函数或代码模块
import numpy as np
#导入 SciPy 库中的稀疏矩阵模块用于处理稀疏矩阵sparse稀疏矩阵
import scipy.sparse as sp
import torch
#定义一个函数将标签编码为 one-hot 格式
def encode_onehot(labels):classesset(labels)#从标签中提取所有唯一的类别classes_dict{c:np.identity(len(classes))[i,:] for i,c in enumerate(classes)}labels_onehotnp.array(list(map(classes_dict.get,labels)),dtypenp.int32)#将所有标签转换为 one-hot 编码格式return labels_onehot
#返回 one-hot 编码的标签数组
def load_data(path../data/cora/,datasetcora):print(Loading {} dataset ....format(dataset))idx_features_labelsnp.genfromtxt({}{}.content.format(path,dataset),dtypenp.dtype(str))#从文件中加载节点的特征和标签 sp.csr_matriX稀疏矩阵featuressp.csr_matrix(idx_features_labels[:,1,-1],dtypenp.int32)#创建一个稀疏矩阵包含节点的特征idx_map{j:i for i,j in enumerate(idx)}#创建一个映射将索引映射到一个新值edges_unordednp.genformtxt({}{}.cites.format(path,dataset),dtypenp.int32)#从文件中加载引用边信息edgesnp.array(list(map(idx_map.get,edges_unorded.flatten())),dtypenp.int32).reshape(edges_unorded.shape)shape(labels.shape[0],labels.shape[0]), dtypenp.float32)#创建一个 COO 格式的稀疏邻接矩阵adjsp.coo_matrix((np.ones(edges.shape[0]),(edges[:,0],edges[:,1])),shape(labels.shape[0],labels.shape[0]),dtypenp.float32)#构建对称邻接矩阵是图数据处理中的一个常见步骤adjadjadj.T.multiply(adj.Tadj)-adj.multiply(adj.Tadj)#确保邻接矩阵是对称的featuresnormalize(features)#对特征矩阵进行归一化处理归一化数据按照一定的比例缩放使其落在特定的区间内adjnormalize(adjsp.eye(adj.shape[0]))
#对邻接矩阵进行归一化并添加自环添加自环是指在图中添加一条边使得这条边连接一个顶点和它自身。idx_trainrange(140)
#定义训练集的索引idx_valrange(200,500)
#定义验证集的索引idx_testrange(500,1500)
#定义测试集的索引featurestorch.FloatTensor(np.array(features.todense()))
#将特征矩阵转换为 PyTorch 的 FloatTensorlabelstorch.LongTensor(np.where(labels)[1])
#将标签转换为 PyTorch 的 LongTensoradjsparse_mx_to_torch_sparse_tensor(adj)
#将稀疏邻接矩阵转换为 PyTorch 的稀疏张量idx_traintorch.LongTensor(idx_train)
#将训练集索引转换为 PyTorch 的 LongTensoridx_valtorch.LongTensor(idx_val)
#将验证集索引转换为 PyTorch 的 LongTensoridx_testtorch.LongTensor(idx_test)
#将测试集索引转换为 PyTorch 的 LongTensor。return adj,features,labels,idx_train,idx_val,idx_test
def normalize(mx):#定义一个函数用于归一化矩阵rowsumnp.array(mx.sum(1))#计算每一行的和r_invnp.power(rowsum,-1).flatten()#计算每一行的倒数r_mat_invsp.diags(r_inv)#创建一个对角矩阵对角线上是行的倒数mxr_mat_inv.dot(mx)#用对角矩阵乘以原矩阵进行归一化,#mxr_mat_inv.dot(mx)是矩阵乘法操作return mx
def accuracy(output,labels):#定义一个函数用于计算准确率predsoutput.max(1)[1].type_as(labels)#获取预测的类别correctpreds.eq(labels).double()#计算预测正确的数量correctcorrect.sum()#将正确的数量相加return correct/len(labels)
#返回准确率
def sparse_mx_to_torch_sparse_tensor(sparse_mx):#定义一个函数将 SciPy 的稀疏矩阵转换为 PyTorch 的稀疏张量sparse_mxsparse_mx.tocoo().astype(np.float32)#将稀疏矩阵转换为 COO 格式indicestorch.from_numpy(np.vstack((sparse_mx.row,sparse_mx.col)).astype(np.int64))#创建一个包含行和列索引的张量valuestorch.from_numpy(sparse_mx.data)#创建一个包含数据值的张量shapetorch.Size(sparse_mx.shape)return torch.sparse.FloatTensor(indices,values,shape)
#返回一个 PyTorch 的稀疏 FloatTensor
train部分
from __future__ import division
#从 __future__ 模块导入 division使得除法 / 总是产生浮点数结果
from __future__ import print_function
#从 __future__ 模块导入 print_function确保在 Python 2 中使用 Python 3 的打印语法
import time
import argparse
#导入argparse模块用于解析命令行参数
import numpy as np
import torch
import torch.nn.functional as F
import torch.optim as optim
#从 torch 导入 optim 模块提供优化算法
from pygcn.utils import load_data, accuracy
#从 pygcn 包的 utils 模块导入 load_data 和 accuracy 函数
from pygcn.models import GCN
#从 pygcn 包的 models 模块导入 GCN 类
parser argparse.ArgumentParser()
#创建一个 ArgumentParser 对象用于解析命令行参数
parser.add_argument(--no-cuda, actionstore_true, defaultFalse,helpDisables CUDA training.)
#添加一个命令行参数用于禁用 CUDA 训练
parser.add_argument(--fastmode, actionstore_true, defaultFalse,helpValidate during training pass.)
#添加一个命令行参数用于在训练过程中进行验证
parser.add_argument(--seed, typeint, default42, helpRandom seed.)
#添加一个命令行参数用于设置随机种子
parser.add_argument(--epochs,typeint,default42,helpRandom seed.)
#添加一个命令行参数用于设置训练的轮数
parser.add_argument(--lr,typefloat,default0.01,helpInital learning rate.)
#添加一个命令行参数用于设置初始学习率
parser.add_argument(--weight_deacy,typefloat,default5e-4,helpWeight deacy(L2 loss on parameters).)
#添加一个命令行参数用于设置权重衰减
parser.add_argument(--hidden,typeint,default16,helpNumber of hidden units.)
#添加一个命令行参数用于设置隐藏层单元的数量
parser.add_argument(--dropout,typefloat,default0.5,helpDropout rate (1-keep probability).)
#添加一个命令行参数用于设置 dropout 率
argsparser.parse_args()
#解析命令行参数
args.cudanot args.no_cuda and torch.cuda.is_available()
#设置 cuda 标志如果命令行参数 --no-cuda 没有被设置且 CUDA 可用则启用 CUDA
np.random.seed(args.seed)
#设置 NumPy 的随机种子
torch.manual_seed(args.seed)
#设置 PyTorch 的随机种子
if args.cuda:torch.cuda.manual_seed(args.seed)#如果使用 CUDA则设置 CUDA 的随机种子
#load data
adj,features,labels,idx_train,idx_val,idx_testload_data()
#调用 load_data 函数加载数据
#model and optimizer
model GCN(nfeatfeatures.shape[1],#nfeat特征的数量nhidargs.hidden,#nhid隐藏层的单元数nclasslabels.max().item1,#nclass类别的数量dropoutargs.dropout)#dropout 比率用于正则化以防止过拟合
#创建一个 GCN 模型实例并设置相应的参数
optimizeroptim.Adam(model.parameters(),lrargs.lr,weight_deacyargs.weight_deacy)
#创建一个 Adam 优化器实例并设置学习率和权重衰减
if args.cuda:model.cuda()featuresfeatures.cuda()adjadj.cuda()labelslabels.cuda()idx_trainidx_train.cuda()idx_validx_val.cuda()idx_testidx_test.cuda()#如果使用 CUDA则将模型和数据迁移到 GPU
def train(epoch):#定义 train 函数用于执行一个训练周期ttime.time()#记录训练开始的时间model.train()#设置模型为训练模式optimizer.zero_grad()#清空优化器的梯度outputmodel(features,adj)#前向传播计算模型输出loss_trainF.nll_loss(output[idx_train],labels[idx_train])#计算训练集上的损失acc_trainaccuracy(output[idx_train],labels[idx_train])#计算训练集上的准确率loss_train.backward()#反向传播计算梯度optimizer.step()#更新模型参数if not args.fastmode:#fast mode通常是指一种优化的执行模式旨在提高程序的运行速度通常是以牺牲一些功能或降低准确性为代价model.eval()outputmodel(features,adj)loss_valF.nll_loss(output[idx_val],labels[idx_val])acc_valaccuracy(output[idx_val],labels[idx_val])print(Epoch:{:04d}.format(loss_train.item()),loss_train:{:.4f}.format(loss_train.item()),acc_train:{:.4f}.format(acc_train.item()),loss_val:{:.4f}.format(acc_val.item()),time:{:.4f}s.format(time.time()-t))#如果不使用快速模式则在每个训练周期后进行验证并计算验证集上的损失和准确率
def test():#定义 test 函数用于测试模型model.eval()#设置模型为评估模式outputmodel(features,adj)#前向传播计算模型输出loss_testF.nll_loss(output[idx_test],labels[idx_test])#计算测试集上的损失print(Test set results:,loss{:.4f}.format(acc_test.item()))#打印测试集的结果
t_totaltime.time()
#记录总的开始时间
for epoch in range(args.epochs):train(epoch)#进行指定次数的训练周期
print(Optimization Finished!)
#训练完成后打印信息
print(Total time elapsed:{:.4f}s.format(time.time()-t_total))
#打印总的执行时间
test()
#调用 test 函数进行测试
#前向传播是模型评估和预测的基础它使得模型能够根据训练过程中学到的权重和偏差来对新的输入数据做出响应
#1.在训练过程中前向传播用于计算预测值然后通过反向传播算法计算损失函数的梯度并更新模型的权重
# 2.在模型部署或推理阶段前向传播用于生成最终的预测结果 先在第一层图卷积网络后面加上非线性激活函数ReLU, 再加一层dropout防止过拟合第二层图卷积网络则直接加上softmax, 输出多分类的结果。对于大部分标准数据两层图卷 积网络即可达到很好的效果叠加更多的层并不一定能提升模型的表现反而 可能导致过平滑的问题。 Softmax 函数是一种在机器学习和深度学习中常用的激活函数特别是在处理多分类问题时。它的主要作用是将一个向量或一组实数转换为概率分布使得每个元素的值都在0到1之间并且所有元素的和为1。这使得softmax函数非常适合用于分类任务中作为输出层的激活函数。 在这个简单的图卷积网络实现中没有使用批处理的方式进行训练因为 这样实现更容易。对于大部分数据集来说这种实现方式是没有问题的 但对于一些大规模的数据集(如Reddit), 因为节点数过多如果不采用 批处理或采样的方式进行训练就会出现内存爆炸等问题。 内存爆炸通常用来描述计算机系统中内存使用量急剧增加以至于系统无法正常工作或性能严重下降的情况。 早停是一种在机器学习模型训练过程中用来防止过拟合的技术。过拟合是指模型在训练数据上表现得很好但是在新的、未见过的数据上表现不佳即模型的泛化能力差。早停的目的是提前结束训练过程以避免模型在训练数据上过度拟合。 沿着图神经网络的发展脉络介绍了主要的两类图神经网络模型谱域图神经网络和空域图神经网络。谱域图神经网络的方法以图论傅里叶变换为基础通过在谱域定义卷积来实现图信号的处理而空域图神经网络则可以视为图上节点的消息传递和聚合。之后发展出的各种各样的图神经网络大都可以归于这两种框架(即基于“谱域卷积”的方式或基于“消息传递”的方式)