图神经网络:大型图的有关处理
文章说明:
1)参考资料:PYG的文档。文档超链。
2)博主水平不高,如有错误,还望批评指正。
3)我在百度网盘上传这篇文章jupyter notebook以及有关文献。提取码8848。
文章目录
- Pumed数据集
- 文献阅读
- 继续实验
Pumed数据集
导库
from torch_geometric.transforms import NormalizeFeatures
from torch_geometric.datasets import Planetoid
下载数据处理数据导入数据
dataset=Planetoid(root="C:/Users/19216/Desktop/project/project1/Cluster-GCN/Planetoid",name='PubMed',transform=NormalizeFeatures())
PS:如果下载发生错误直接去官网上下载。下载好了复制C:\DATA\Planetoid\PubMed\raw中。官网链接。不会有人没梯子吧。
数据描述1
print(len(dataset),end=" ");print(dataset.num_features,end=" ");print(dataset.num_classes)
#1 500 3
数据描述2
data=dataset[0]
print(data.num_nodes,end=" ");print(data.num_edges)
print(data.train_mask.sum().item(),end=" ");print(data.val_mask.sum().item(),end=" ");print(data.test_mask.sum().item())
print(data.has_isolated_nodes(),end=" ");print(data.has_self_loops(),end=" ");print(data.is_undirected(),end=" ")
#输出如下
#19717 88648
#60 500 1000
#False False True
其他说明:Pumbed数据集开源的生物医学文献数据库。不用细究。
文献阅读
参考文献: Cluster-GCN: An Efficient Algorithm for Training Deep and Large Graph Convolutional Networks。原文链接。
主要贡献: 介绍一种时空复杂度较低的方法。其他方法:1)Full-batch gradient:在空间上:O(NLF)。在时间上,梯度下降收敛较慢。2)Mini-batch SGD:由于邻域拓展问题,时间复杂度呈指数增长。计算某个节点损失,需要第L-1层的嵌入。需要第L-2层的嵌入,递归下去。3)GraphSAGE解决Mini-batch,反向传播用固定大小的邻居样本。但是没有解决完美,深度更深甚至更差。4)Fast-GCN解决Mini-batch,重点采样,深度更深甚至更差。 5)VR-GCN:使用方差减小技术减小采样邻居节点个数,但是空间仍然很大。然后Cluster-GCN就来啦。1)深层网络空间复杂度低2)浅层网络速度等于VR-GCN;深层网络速度大于Cluster-GCN。Cluster-GCN是线性,VR-GCN是指数。3)有些工作表明深层图神经网络的效果不佳,但是实验表明Cluster-GCN深层的效果不错。下图:各种方法的时空复杂度。
PS:N代表序列的长度,F代表特征的数量,L代表网络层数量。

理论分析1: 将节点划分为n组如 [ V 1 , V 2 , … V n ] [\mathcal{V}_{1},\mathcal{V}_{2},\dots \mathcal{V}_{n}] [V1,V2,…Vn]。 V \mathcal V V指节点同组节点保存邻接不同组间直接断开。所以图被划分为 G ‾ = [ G 1 , G 2 , … , G n ] = [ { V 1 , E 1 } , { V 2 , E 2 } , … , { V n , E n } ] \overline{G}=[G_{1},G_{2},\dots,G_{n}]=[\{\mathcal{V}_{1},\mathcal{E}_{1}\},\{\mathcal{V}_{2},\mathcal{E}_{2}\},\dots,\{\mathcal{V}_{n},\mathcal{E}_{n}\}] G=[G1,G2,…,Gn]=[{V1,E1},{V2,E2},…,{Vn,En}]。 A = A ˉ + Δ A=\bar A+\Delta A=Aˉ+Δ, A A A指 G G G的邻接矩阵, A ˉ \bar A Aˉ指 G ˉ \bar G Gˉ的邻接矩阵( n n n维分块对角矩阵), Δ \Delta Δ指 A ˉ \bar A Aˉ补阵(删除的边所构成的邻接矩阵)。多层的图神经网络变为: Z L = A ‾ ′ σ ( A ‾ ′ σ ( … σ ( A ‾ ′ X W ( 0 ) ) W ( 1 ) ) … ) W ( L − 1 ) Z^{L}=\overline{A}^{\prime}\sigma(\overline{A}^{\prime}\sigma(\dots\sigma(\overline{A}^{\prime}XW^{(0)})W^{(1)})\dots)W^{(L-1)} ZL=A′σ(A′σ(…σ(A′XW(0))W(1))…)W(L−1)。 A ‾ ′ \overline{A}^{\prime} A′是分块对角阵 A ‾ \overline{A} A的标准化。那么损失函数变为: L A ‾ ′ = ∑ t ∣ V t ∣ N L A ‾ t t ′ \mathcal{L}_{\overline{A}^{\prime}}=\sum_{t}\frac{|\mathcal{V}_{t}|}{N}\mathcal{L}_{\overline{A}^{\prime}_{tt}} LA′=∑tN∣Vt∣LAtt′ and L A ‾ t t ′ = 1 ∣ V t ∣ ∑ i ∈ V t l o s s ( y i , z i L ) \mathcal{L}_{\overline{A}^{\prime}_{tt}}=\frac{1}{|\mathcal{V}_{t}|}\sum_{i \in \mathcal{V}_{t}}loss(y_{i},z_{i}^{L}) LAtt′=∣Vt∣1∑i∈Vtloss(yi,ziL) 。这个就是核心思想。我说得不是很清楚,可以直接去看原文,不是很难。
理论分析1图示:

理论分析2: 划分引入一种误差,这种误差是与 Δ \Delta Δ成正比,我们应该尽量减小这种误差。于是引入Metis以及Graclus方法 。重点分析了Metics方法,效果如下:这些指标都是Accuracy_Score吧。我们不能随机划分。
理论分析2结果:

理论分析3: 还有问题。1)毕竟删除了一些边,模型效果可能还是受到影响。2)划分算法容易把相似的节点分成一堆,所以聚类分布可能会与原始数据不同,使用随机梯度算法可能会带来偏差吧。所以为了解决问题或者减小问题影响,提出了一个 stochastic multiple clustering方法。简单来说是这样的:通过这个算法加一些边回去。这个图我也没看懂。

理论分析3结果:

算法的伪代码:

继续实验
导库
from torch_geometric.loader import ClusterData,ClusterLoader
图的划分批量构建
cluster_data=ClusterData(data,num_parts=128)
train_loader=ClusterLoader(cluster_data,batch_size=32,shuffle=True)
打印全部批量信息
total_num_nodes=0
for step,sub_data in enumerate(train_loader):print(f'Step {step + 1}:')print('=======')print(f'Number of nodes in the current batch: {sub_data.num_nodes}')print(sub_data)print()total_num_nodes+=sub_data.num_nodes
print(f'Iterated over {total_num_nodes} of {data.num_nodes} nodes!')
#输出如下
#Step 1:
#=======
#Number of nodes in the current batch: 4924
#Data(x=[4924, 500], y=[4924], train_mask=[4924], val_mask=[4924], test_mask=[4924], edge_index=[2, 15404])
#
#Step 2:
#=======
#Number of nodes in the current batch: 4939
#Data(x=[4939, 500], y=[4939], train_mask=[4939], val_mask=[4939], test_mask=[4939], edge_index=[2, 17834])
#
#Step 3:
#=======
#Number of nodes in the current batch: 4928
#Data(x=[4928, 500], y=[4928], train_mask=[4928], val_mask=[4928], test_mask=[4928], edge_index=[2, 17524])
#
#Step 4:
#=======
#Number of nodes in the current batch: 4926
#Data(x=[4926, 500], y=[4926], train_mask=[4926], val_mask=[4926], test_mask=[4926], edge_index=[2, 16042])
#
#Iterated over 19717 of 19717 nodes!
导库
from torch_geometric.nn import GCNConv
import torch.nn.functional as F
import torch
随便搭建
class GCN(torch.nn.Module):def __init__(self,hidden_channels):super(GCN,self).__init__()self.conv1=GCNConv(dataset.num_node_features,hidden_channels)self.conv2=GCNConv(hidden_channels,dataset.num_classes)def forward(self,x,edge_index):x=self.conv1(x,edge_index)x=x.relu()x=F.dropout(x,p=0.5,training=self.training)x=self.conv2(x,edge_index)return x
打印信息
model=GCN(hidden_channels=16)
print(model)
#输出如下
#GCN(
# (conv1): GCNConv(500, 16)
# (conv2): GCNConv(16, 3)
#)
训练
optimizer=torch.optim.Adam(model.parameters(),lr=0.01,weight_decay=5e-4);criterion=torch.nn.CrossEntropyLoss()def train():model.train()for sub_data in train_loader:out=model(sub_data.x,sub_data.edge_index)loss=criterion(out[sub_data.train_mask],sub_data.y[sub_data.train_mask])loss.backward()optimizer.step()optimizer.zero_grad()def test():model.eval()out=model(data.x,data.edge_index)pred=out.argmax(dim=1)accs=[]for mask in [data.train_mask,data.val_mask,data.test_mask]:correct=pred[mask]==data.y[mask]accs.append(int(correct.sum())/int(mask.sum()))return accsfor epoch in range(1,51):loss=train()train_acc,val_acc,test_acc=test()print(f'Epoch: {epoch:03d}, Train: {train_acc:.4f}, Val Acc: {val_acc:.4f}, Test Acc: {test_acc:.4f}')
#最后一次输出如下
#Epoch: 050, Train: 0.9833, Val Acc: 0.8060, Test Acc: 0.7880
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
