文章说明:
 1)参考资料:PYG官方文档。超链。
 2)博主水平不高,如有错误还望批评指正。
 3)我在百度网盘上传了这篇文章的jupyter notebook和有关文献。超链。提取码8848。
文章目录
- Pumed数据集
- 文献阅读
- 继续实验
 
Pumed数据集
导库
from torch_geometric.transforms import NormalizeFeatures
from torch_geometric.datasets import Planetoid
下载数据处理数据导入数据
dataset=Planetoid(root='/DATA/Planetoid',name='PubMed',transform=NormalizeFeatures())
其他说明1:这段代码会在C盘生成一个DATA的文件并将数据集放在DATA中,有强迫症注意一下。
 其他说明2:如果下载发生错误直接去官网上下载。下载好了复制C:\DATA\Planetoid\PubMed\raw中。官网链接。不会有人没梯子吧。
 数据描述
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)(N代表序列的长度,F代表特征的数量,L代表网络层数量)。在时间上,梯度下降收敛较慢。2)Mini-batch SGD:在时间空间上引入大量计算开销造成原因邻域扩展。计算某个节点损失需要第L-1层的嵌入然后需要第L-2层的嵌入递归下去。3)VR-GCN:克服上述领域扩展有关问题但是需要第L-1层的嵌入所以空间要求太高NG。然后Cluster-GCN就来啦。1)Cluster-GCN空间小特别是在大型图上2)Cluster-GCN在浅层GCN中速度等同于VR-GCN;深层GCN中Cluster-GCN快得多,Cluster-GCN是线性,VR-GCN是指数。3)尽管有些工作表明深层图神经网络的效果不佳,但是实验表明Cluster-GCN深层的效果不错。下图:各种方法的时空复杂度。
 
理论分析1::将节点划分为n组如 
     
      
       
        
        
          V 
         
        
          1 
         
        
       
         , 
        
        
        
          V 
         
        
          2 
         
        
       
         , 
        
       
         … 
        
        
        
          V 
         
        
          n 
         
        
       
         ] 
        
       
      
        \mathcal{V}_{1},\mathcal{V}_{2},\dots \mathcal{V}_{n}] 
       
      
    V1,V2,…Vn]。同组节点保存邻接不同组间直接断开。所以图被划分为  
     
      
       
        
        
          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}]。这个相当于对图作近似。 
     
      
       
       
         Δ 
        
       
      
        \Delta 
       
      
    Δ保留了删除信息。特征向量以及标签按照节点划分划分。多层图神经网络便变为: 
     
      
       
        
        
          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′XW0)W1)…)WL−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) 。这个便就就是核心思想。大概就是按照下图右边那样进行分割。
 
 理论分析2: 划分引入一种误差,这种误差是与 
     
      
       
       
         Δ 
        
       
      
        \Delta 
       
      
    Δ成正比,所以我们应该减小这种误差。于是引入Metis以及Graclus方法 。重点分析了Metics划分,比起随机划分效果更好如下:这些指标都是Accuracy_Score吧。
 
 理论分析3:
 还有问题。1)毕竟还是删除了一些边,模型效果可能还是受到影响。2)由于集群分配算法导致相似节点被分为了一堆,所以可能会与原始数据不同(PS:原文这样写的,我不能够理解),使用随机梯度算法可能会带来偏差吧。所以为了解决问题或者减小问题影响,提出了一个 stochastic multiple clustering方法。简单来说是这样的:随机梯度算法更新权重需要进行Batch的划分;之前邻接矩阵已经被处理成分块对角矩阵。选择m个对角矩阵进入Batch,前面删除的边重新加上。如下这样。(好吧这个图我也没看懂但是大致想法是清晰的)
 
 结果如下:
 
 算法的伪代码:
 
PS1:后面好像是实验的内容部分,没时间看就这样吧。PS:这是我的理解所以不一定对。
继续实验
导库
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)
#)
开始训练
model=GCN(hidden_channels=16);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 accs
for 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



















