GCN——DGL教程

官方教程
中文版
GCN——DGL教程_第1张图片

安装DGL

内置函数和消息传递API

dgl.function

查阅需要的函数,官方教程没有注释

消息传递框架(Message Passing Paradigm):
可以对“边” 或者 “节点” 计算,(小白,还不知道怎么运用“边”的特征)

message function消息函数:它通过将边上特征与其两端节点的特征相结合来生成消息。

update function更新函数:结合聚合后的消息和节点本身的特征来更新节点的特征。

reduce function聚合函数:聚合节点接受到的消息

图一
GCN——DGL教程_第2张图片
图二
定义一个reduce 函数,需要指定一个输入消息名称和一个输出节点特征名称。
GCN——DGL教程_第3张图片
图三
GCN——DGL教程_第4张图片
图四

import dgl
import dgl.function as fn
import torch as th
g = ... # create a DGLGraph
g.ndata['h'] = th.randn((g.num_nodes(), 10)) # each node has feature size 10
g.edata['w'] = th.randn((g.num_edges(), 1))  # each edge has feature size 1
# collect features from source nodes and aggregate them in destination nodes
g.update_all(fn.copy_u('h', 'm'), fn.sum('m', 'h_sum'))
# multiply source node features with edge weights and aggregate them in destination nodes
g.update_all(fn.u_mul_e('h', 'w', 'm'), fn.max('m', 'h_max'))
# compute edge embedding by multiplying source and destination node embeddings
g.apply_edges(fn.u_mul_v('h', 'h', 'w_new'))

在这里插入图片描述

解释都放出来了,理解看个人了


下面是灰信网的DGL介绍,带注释+我的理解。

import dgl
import dgl.function as fn
import torch as th
import torch.nn as nn
import torch.nn.functional as F
from dgl import DGLGraph
 
gcn_msg=fn.copy_src(src="h",out="m") #使用源节点数据复制为消息
gcn_reduce=fn.sum(msg="m",out="h")#按总和聚合消息,聚合邻居节点的特征
 
#定义节点的UDF(update function ) apply_nodes  他是一个完全连接层
class NodeApplyModule(nn.Module):
    #初始化
    def __init__(self,in_feats,out_feats,activation):
        super(NodeApplyModule,self).__init__()
        self.linear=nn.Linear(in_feats,out_feats)
        self.activation=activation
    #前向传播
    def forward(self,node):
        h=self.linear(node.data["h"])
        if self.activation is not None:
            h=self.activation(h)
        return {"h":h}
 
#定义GCN模块  GCN模块的本质是在所有节点上执行消息传递  然后再调用NodeApplyModule全连接层
class GCN(nn.Module):
    #初始化
    def __init__(self,in_feats,out_feats,activation):
        super(GCN,self).__init__()
        #调用全连接层模块
        self.apply_mod=NodeApplyModule(in_feats,out_feats,activation)
    #前向传播
    def forward(self,g,feature):
        g.ndata["h"]=feature#feature应该对应的整个图的特征矩阵
        g.update_all(gcn_msg,gcn_reduce)
        g.apply_nodes(func=self.apply_mod)#将更新操作应用到节点上
        
        return g.ndata.pop("h")
		##pop() 函数用于移除列表中的一个元素(默认最后一个元素),并且返回该元素的值。

#利用cora数据集搭建网络然后训练
class Net(nn.Module):
    #初始化网络参数
    def __init__(self):
        super(Net,self).__init__()
        self.gcn1=GCN(1433,16,F.relu)#第一层GCN
        self.gcn2=GCN(16,7,None)
    #前向传播
    def forward(self,g,features):
        x=self.gcn1(g,features)
        x=self.gcn2(g,x)
        return x
net=Net()
net
 
#使用DGL内置模块加载cora数据集
from dgl.data import citation_graph as citegrh
import networkx as nx
def load_cora_data():
    data = citegrh.load_cora()#加载数据集
    features=th.FloatTensor(data.features)#特征向量  张量的形式
    labels=th.LongTensor(data.labels)#所属类别
    train_mask=th.BoolTensor(data.train_mask)#那些参与训练
    test_mask=th.BoolTensor(data.test_mask)#哪些是测试集
    g=data.graph
    g.remove_edges_from(nx.selfloop_edges(g))#删除自循环的边
    g = DGLGraph(g)
    g.add_edges(g.nodes(), g.nodes()) #自连接
    return g, features, labels, train_mask, test_mask
 
g, features, labels, train_mask, test_mask=load_cora_data()
 
 
import matplotlib.pyplot as plt
nx.draw(g.to_networkx(),node_size=50,with_labels=True)
plt.show()
 
#测试模型
def evaluate(model, g, features, labels, mask):
    model.eval()#会通知所有图层您处于评估模式
    with th.no_grad():
        logits = model(g, features)
        logits = logits[mask]
        labels = labels[mask]
        _, indices = th.max(logits, dim=1)
        correct = th.sum(indices == labels)
        return correct.item() * 1.0 / len(labels)
 
#训练网络
import time
import numpy as np
g, features, labels, train_mask, test_mask = load_cora_data()
 
#定义优化器
optimizer=th.optim.Adam(net.parameters(),lr=1e-3)
dur=[]#时间
for epoch in range(200):
    print(epoch)
    if epoch>=10:
        t0=time.time()
    net.train()
    logits = net(g, features)
    logp = F.log_softmax(logits, 1)
    loss = F.nll_loss(logp[train_mask], labels[train_mask])
 
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
 
    if epoch >=10:
        dur.append(time.time() - t0)
 
    acc = evaluate(net, g, features, labels, test_mask)
    print("Epoch {:05d} | Loss {:.4f} | Test Acc {:.4f} | Time(s) {:.4f}".format(
            epoch, loss.item(), acc, np.mean(dur)))
 

第一次会下载数据集,官方加载数据与上面不同。两个都可以跑。

from dgl.data import CoraGraphDataset
def load_cora_data():
    dataset = CoraGraphDataset()
    g = dataset[0]
    features = g.ndata['feat']
    labels = g.ndata['label']
    train_mask = g.ndata['train_mask']
    test_mask = g.ndata['test_mask']
    return g, features, labels, train_mask, test_mask
g, features, labels, train_mask, test_mask=load_cora_data()
print(features.shape)
print(labels.shape)
print(train_mask.shape)
print(test_mask.shape)
Downloading C:\Users\Administrator\.dgl\cora_v2.zip from https://data.dgl.ai/dataset/cora_v2.zip...
Extracting file to C:\Users\Administrator\.dgl\cora_v2
Finished data loading and preprocessing.
  NumNodes: 2708
  NumEdges: 10556
  NumFeats: 1433
  NumClasses: 7
  NumTrainingSamples: 140
  NumValidationSamples: 500
  NumTestSamples: 1000
Done saving data into cached files.

torch.Size([2708, 1433])
torch.Size([2708])
torch.Size([2708])
torch.Size([2708])

第二个不同就是GCN网络,区别:h = g.ndata[‘h’] 和 g.ndata.pop(“h”)

class GCNLayer(nn.Module):
    def __init__(self, in_feats, out_feats):
        super(GCNLayer, self).__init__()
        self.linear = nn.Linear(in_feats, out_feats)

    def forward(self, g, feature):
        # Creating a local scope so that all the stored ndata and edata
        # (such as the `'h'` ndata below) are automatically popped out
        # when the scope exits.
        with g.local_scope():
            g.ndata['h'] = feature
            g.update_all(gcn_msg, gcn_reduce)
            h = g.ndata['h']
            return self.linear(h)

其他解说

GNN教程:DGL框架实现GCN算法!—— Datawhale 讲的内容跟上面差不多

GCN 实现3 :代码解析 介绍数据集还行,后面模型都是截图,谁会看

空手道俱乐部(Zachary’s karate club)数据集

以下3篇都是针对这个数据集,可以扎实一下。
【1】 https://www.jianshu.com/p/c0da16b75aa3
【2】https://blog.csdn.net/qq_38234785/article/details/107984924 讲到GCN的缺点
【3】 https://zhuanlan.zhihu.com/p/93828551 苘郁蓁

这个我也不了解

为了易于理解,整个教程忽略了归一化的步骤

由于版本问题:或者看博客的评论

DGLError: DGLGraph.send is deprecated. As a replacement, use DGLGraph.apply_edges
API to compute messages as edge data. Then use DGLGraph.send_and_recv
and set the message function as dgl.function.copy_e to conduct message
aggregation.

GCNLayer需要改写下,按新的来,否则 不能运行:
import dgl.function as fn
gcn_msg=fn.copy_src(src='h',out='m')
gcn_reduce=fn.sum(msg='m',out='h')

class GCNLayer(nn.Module):
    def __init__(self, in_feats, out_feats):
        super(GCNLayer, self).__init__()
        self.linear = nn.Linear(in_feats,out_feats)

    def forward(self,g,feature):
        with g.local_scope():
            g.ndata['h'] =feature
            g.update_all(gcn_msg,gcn_reduce)
            h=g.ndata['h']
        return self.linear(h)

你可能感兴趣的:(GNN,pytorch)