译者|朱宪忠评论|SunShujuan简介深度学习为预测非结构化数据开辟了一个充满可能性的全新世界。今天,人们经常使用卷积神经网络(CNN)处理图像数据,使用递归神经网络(RNN)处理文本数据,等等。在过去的几年里,出现了一类新的令人兴奋的神经网络:图神经网络(简称“GNNs”)。顾名思义,这种网络类型专注于处理图形数据。在本文中,您将了解图神经网络工作原理的基础知识,以及如何使用Pytorch几何(PyG)库和开放图基准(OGB)库在Python中编写此类图神经网络。请注意,您可以在我的Github和Kaggle网站上找到本文提供的示例项目的源代码。通用GNN的工作原理随着图卷积网络(GCN)的引入,GNN开始流行[请参阅参考资料1],它将CNN的一些概念借用到图世界。这种网络背后的主要思想,也称为消息传递框架,多年来成为该领域的黄金标准。我们将在本文中探讨这个概念。消息传递框架指出,对于图中的每个节点,我们将做两件事:聚合来自其邻居的信息使用来自其上层及其邻居的聚合信息更新当前节点信息消息传递框架图。资料来源:维基百科上图显示了消息传递框架的工作原理。许多在GCN之后开发的架构都专注于定义聚合和更新数据的最佳方式。PyG和OGB简介PyG是Pytorch库的扩展,它使我们能够使用研究中已经建立的层快速实现新的图神经网络架构。OGB[见参考文献。2]的开发是为了提高该领域的研究质量,因为它提供了一个可以使用的精选地图,也是评估给定架构结果的标准方法,从而允许在提案之间进行更公平的比较。这样,我们就可以将这两个库一起使用,一方面更容易想出一个架构,另一方面也不必担心数据的获取和评估机制。实施GNN项目首先,让我们安装示例项目所需的库。请注意,您必须先安装PyTorch:pipinstallogbpipinstalltorch_geometric现在,让我们导入所需的方法和库:nnimportMessagePassing,SAGEConvfromogb.nodepropredimportEvaluator,PygNodePropPredDataset接下来,第一步是从OGB下载数据集。我们将使用ogbn-arxiv网络,其中每个节点都是arxiv网站上的计算机科学论文,每个有向边代表引用另一篇论文的论文。我们的任务是:将每个节点归入一个论文类别。下载过程很简单:target_dataset='ogbn-arxiv'#我们将ogbn-arxiv下载到当前示例项目的'networks'文件夹中dataset=PygNodePropPredDataset(name=target_dataset,root='networks')其中,数据集变量是特定于OGB库的名为PygNodePropPredDataset的类的实例。要将此数据集作为可在PyrotchGeometric上使用的数据类访问,我们只需执行以下操作:data=dataset[0]如果我们通过调试跟踪查看此变量,我们会看到类似这样的内容:Data(num_nodes=169343,edge_index=[2,1166243],x=[169343,128],node_year=[169343,1],y=[169343,1])至此,我们准备了节点数,邻接表,网络,年份的特征向量每个节点的信息,并确定下一个目标标签。此外,ogbn-arxiv网络配备了拆分数据子集,分别用于训练、验证和测试。这是OGB提高该网络研究的可重复性和质量的好方法。我们可以通过以下方式提取:split_idx=dataset.get_idx_split()train_idx=split_idx['train']valid_idx=split_idx['valid']test_idx=split_idx['test']现在,我们将定义两个数据加载器。第一个只会加载训练集中的节点,第二个会加载网络上的所有节点。我们将使用PytorchGeometric库中的邻居加载函数NeighborLoader。该数据加载器为每个节点采样给定数量的邻居。这是一种避免RAM和具有数千个节点的节点计算时间瘫痪的方法。在本教程中,我们将在训练加载器上为每个节点使用30个邻居。train_loader=NeighborLoader(数据,input_nodes=train_idx,shuffle=True,num_workers=os.cpu_count()-2,batch_size=1024,num_neighbors=[30]*2)total_loader=NeighborLoader(data,input_nodes=None,num_neighbors=[-1],batch_size=4096,shuffle=False,num_workers=os.cpu_count()-2)注意我们在训练数据加载器而不是总加载器中随机打乱数据。此外,训练加载器的邻居数量定义为网络每一层的数量。由于我们将在此处使用双层网络,因此我们将其设置为两个值为30的列表。现在是时候创建我们的GNN架构了。对于熟悉Pytorch的人来说,这应该是家常便饭。我们将使用SAGE图层。这些层在一篇出色的论文[参见参考文献3]中进行了定义,该论文非常详细地介绍了邻域采样的思想。幸运的是,PytorchGeometric库已经为我们实现了这一层。因此,与每个PyTorch架构一样,我们必须定义一个包含我们将使用的层的类:self).__init__()self.n_layers=n_layersself.layers=torch.nn.ModuleList()self.layers_bn=torch.nn.ModuleList()如果n_layers==1:self.layers.append(SAGEConv(in_channels,out_channels,normalize=False))elifn_layers==2:self.layers.append(SAGEConv(in_channels,hidden_??channels,normalize=False))self.layers_bn.append(torch.nn.BatchNorm1d(hidden_??channels))self.layers。append(SAGEConv(hidden_??channels,out_channels,normalize=False))else:self.layers.append(SAGEConv(in_channels,hidden_??channels,normalize=False))self.layers_bn.append(torch.nn.BatchNorm1d(hidden_??channels))_in范围(n_layers-2):self.layers.append(SAGEConv(hidden_??channels,hidden_??channels,normalize=False))self.layers_bn.append(torch.nn.BatchNorm1d(hidden_??channels))self.layers.append(SAGEConv(hidden_??channels,out_channels,normalize=False))用于自身层。层:layer.reset_parameters()defforward(self,x,edge_index):iflen(self.layers)>1:looper=self.layers[:-1]else:looper=self.layersfori,layerinenumerate(looper):x=layer(x,edge_index)try:x=self.layers_bn[i](x)exceptexceptase:abs(1)最后:x=F.relu(x)x=F.dropout(x,p=0.5,training=self.training)如果len(self.layers)>1:x=self.layers[-1](x,edge_index)returnF.log_softmax(x,dim=-1),torch.var(x)definference(self,total_loader,device):xs=[]var_=[]forbatchintotal_loader:out,var=self.forward(batch.x.to(device),batch.edge_index.to(device))out=out[:batch.batch_size]xs.append(out.cpu())var_.append(var.item())out_all=torch.cat(xs,dim=0)returnout_all,var_让我们一步步解释上面的代码:我们必须定义网络的in_channels数量,这个值代表数据集中的特征数量out_channels代表我们试图预测的类别总数。隐藏通道参数idden_??channels是我们可以定义的一个值,代表隐藏单元的数量。我们可以设置网络的层数。对于每个隐藏层,我们添加一个批量归一化层,然后重置每个层的参数。forward方法运行forward过程的单个迭代。在此期间,获取特征向量和邻接表并传递给SAGE层,然后将结果传递给batchnormalization层。此外,我们应用ReLU非线性和衰减层进行正则化。最后,推理方法(inference)将为数据集中的每个节点生成预测。我们将使用它来进行验证。现在,让我们定义模型的一些参数:device=torch.device('cuda'iftorch.cuda.is_available()else'cpu')model=SAGE(data.x.shape[1],256,dataset.num_classes,n_layers=2)model.to(device)epochs=100optimizer=torch.optim.Adam(model.parameters(),lr=0.03)scheduler=ReduceLROnPlateau(optimizer,'max',patience=7)现在,我们可以开始测试以验证我们所有的预测:deftest(model,device):evaluator=Evaluator(name=target_dataset)model.eval()out,var=model.inference(total_loader,device)y_true=data.y.cpu()y_pred=out.argmax(dim=-1,keepdim=True)train_acc=evaluator.eval({'y_true':y_true[split_idx['train']],'y_pred':y_pred[split_idx['train']],})['acc']val_acc=evaluator.eval({'y_true':y_true[split_idx['valid']],'y_pred':y_pred[split_idx['valid']],})['acc']test_acc=evaluator.eval({'y_true':y_true[split_idx['test']],'y_pred':y_pred[split_idx['test']],})['acc']返回train_acc,val_acc,test_acc,torch.mean(torch.Tensor(var))在这个函数中,我们从OGB库中实例化一个验证器类Validator。此类将负责为我们之前检索到的每个拆分验证模型。这样,我们就会看到训练集、验证集和测试集在每一代的得分值。最后,让我们创建我们的训练循环:forepochinrange(1,epochs):model.train()pbar=tqdm(total=train_idx.size(0))pbar.set_description(f'Epoch{epoch:02d}')total_loss=total_correct=0forbatchintrain_loader:batch_size=batch.batch_sizeoptimizer.zero_grad()out,_=model(batch.x.to(device),batch.edge_index.to(device))out=out[:batch_size]batch_y=batch.y[:batch_size].to(device)batch_y=torch.reshape(batch_y,(-1,))loss=F.nll_loss(out,batch_y)loss.backward()optimizer.step()total_loss+=float(loss)total_correct+=int(out.argmax(dim=-1).eq(batch_y).sum())pbar.update(batch.batch_size)pbar.close()loss=total_loss/len(train_loader)approx_acc=total_correct/train_idx.size(0)train_acc,val_acc,test_acc,var=test(model,device)print(f'Train:{train_acc:.4f},Val:{val_acc:.4f},测试:{test_acc:.4f},Var:{var:.4f}')这个循环将训练我们的GNN的100个epoch,如果我们的验证分数在7个epoch内没有增加,则提前停止训练。结论总之,GNN是一类有趣的神经网络。今天,人们开发了一些现成的工具来帮助我们开发这样的解决方案。正如您在本文中看到的,在PytorchGeometric和OGB这两个库的帮助下,可以轻松实现针对某些类型图的GNN设计。参考文献[1]Kipf,Thomas&Welling,Max。(2016)。图卷积网络的半监督分类。[2]Hu,W.,Fey,M.,Zitnik,M.,Dong,Y.,Ren,H.,Liu,B.,Catasta,M.,&Leskovec,J.(2020)。OpenGraphBenchmark:图上机器学习的数据集。arXiv预印本arXiv:2005.00687。[3]Hamilton,William&Ying,Rex&Leskovec,Jure。(2017)。大图上的归纳表示学习。译者介绍朱宪忠,社区编辑,专家博主,讲师,潍坊某高校计算机教师,自由编程资深人士。早期专注于各种微软技术(编译成三本与ASP.NETAJX和Cocos2d-X相关的技术书籍)。/ESP32/RaspberryPi等物联网开发技术和Scala+Hadoop+Spark+Flink等大数据开发技术。原标题:HowtoCreateaGraphNeuralNetworkinPython,作者:TiagoToledoJr.
