GCN代码实战

书中5.6节的GCN代码实战做的是最经典Cora数据集上的分类,恰当又不恰当的类比Cora之于GNN就相当于MNIST之于机器学习。

有关Cora的介绍网上一搜一大把我就不赘述了,这里说一下Cora这个数据集对应的是怎么样的。

Cora有2708篇论文,之间有引用关系共5429个,每篇论文作为一个节点,引用关系就是节点之间的边。每篇论文有一个1433维的特征来表示某个词是否在文中出现过,也就是每个节点有1433维的特征。最后这些论文被分为7类。

所以在Cora上训练的目的就是学习节点的特征及其与邻居的关系,根据已知的节点分类对未知分类的节点的类别进行预测。

知道这些应该就OK了,下面来看代码。

数据处理

注释里自己都写了代码引用自PyG我觉得就扫几眼就行了,因为现在常用的数据集两个GNN轮子(DGL和PyG)里都有,现在基本都是直接用,很少自己下原始数据再处理了,所以略过。

GCN层定义

回顾第5章中GCN层的定义:

\[X'=\sigma(\tilde L_{sym}XW)
\]

所以对于一层GCN,就是对输入\(X\),乘一个参数矩阵\(W\),再乘一个算好归一化后的“拉普拉斯矩阵”即可。

来看代码:

class GraphConvolution(nn.Module):
def __init__(self, input_dim, output_dim, use_bias=True):
super(GraphConvolution, self).__init__()
self.input_dim = input_dim
self.output_dim = output_dim
self.use_bias = use_bias
self.weight = nn.Parameter(torch.Tensor(input_dim, output_dim))
if self.use_bias:
self.bias = nn.Parameter(torch.Tensor(output_dim))
else:
self.register_parameter('bias', None)
self.reset_parameters() def reset_parameters(self):
init.kaiming_uniform_(self.weight)
if self.use_bias:
init.zeros_(self.bias) def forward(self, adjacency, input_feature):
support = torch.mm(input_feature, self.weight)
output = torch.sparse.mm(adjacency, support)
if self.use_bias:
output += self.bias
return output def __repr__(self):
return self.__class__.__name__ + ' (' \
+ str(self.input_dim) + ' -> ' \
+ str(self.output_dim) + ')'

定义了一层GCN的输入输出维度和偏置,对于GCN层来说,每一层有自己的\(W\),\(X\)是输入给的,\(\tilde L_{sym}\)是数据集算的,所以只需要定义一个weight矩阵,注意一下维度就行。

传播的时候只要按照公式\(X'=\sigma(\tilde L_{sym}XW)\)进行一下矩阵乘法就好,注意一个trick:\(\tilde L_{sym}\)是稀疏矩阵,所以先矩阵乘法得到\(XW\),再用稀疏矩阵乘法计算\(\tilde L_{sym}XW\)运算效率上更好。

GCN模型定义

知道了GCN层的定义之后堆叠GCN层就可以得到GCN模型了,两层的GCN就可以取得很好的效果(过深的GCN因为过度平滑的问题会导致准确率下降):

class GcnNet(nn.Module):
def __init__(self, input_dim=1433):
super(GcnNet, self).__init__()
self.gcn1 = GraphConvolution(input_dim, 16)
self.gcn2 = GraphConvolution(16, 7) def forward(self, adjacency, feature):
h = F.relu(self.gcn1(adjacency, feature))
logits = self.gcn2(adjacency, h)
return logits

这里设置隐藏层维度为16,调到32,64,...都是可以的,我自己试的结果来说没有太大的区别。从隐藏层到输出层直接将输出维度设置为分类的维度就可以得到预测分类。

传播的时候相比于每一层的传播只需要加上激活函数,这里选用ReLU

训练

定义模型、损失函数(交叉熵)、优化器:

model = GcnNet(input_dim).to(DEVICE)
criterion = nn.CrossEntropyLoss().to(DEVICE)
optimizer = optim.Adam(model.parameters(),
lr=LEARNING_RATE,
weight_decay=WEIGHT_DACAY)

具体的训练函数注释已经解释的很清楚:

def train():
loss_history = []
val_acc_history = []
model.train()
train_y = tensor_y[tensor_train_mask]
for epoch in range(EPOCHS):
logits = model(tensor_adjacency, tensor_x) # 前向传播
train_mask_logits = logits[tensor_train_mask] # 只选择训练节点进行监督
loss = criterion(train_mask_logits, train_y) # 计算损失值
optimizer.zero_grad()
loss.backward() # 反向传播计算参数的梯度
optimizer.step() # 使用优化方法进行梯度更新
train_acc, _, _ = test(tensor_train_mask) # 计算当前模型训练集上的准确率
val_acc, _, _ = test(tensor_val_mask) # 计算当前模型在验证集上的准确率
# 记录训练过程中损失值和准确率的变化,用于画图
loss_history.append(loss.item())
val_acc_history.append(val_acc.item())
print("Epoch {:03d}: Loss {:.4f}, TrainAcc {:.4}, ValAcc {:.4f}".format(
epoch, loss.item(), train_acc.item(), val_acc.item())) return loss_history, val_acc_history

对应的测试函数:

def test(mask):
model.eval()
with torch.no_grad():
logits = model(tensor_adjacency, tensor_x)
test_mask_logits = logits[mask]
predict_y = test_mask_logits.max(1)[1]
accuarcy = torch.eq(predict_y, tensor_y[mask]).float().mean()
return accuarcy, test_mask_logits.cpu().numpy(), tensor_y[mask].cpu().numpy()

注意模型得到的分类不是one-hot的,而是对应不同种类的预测概率,所以要test_mask_logits.max(1)[1]取概率最高的一个作为模型预测的类别。

这些都写好之后直接运行训练函数即可。有需要还可以对train_lossvalidation_accuracy进行画图,书上也给出了相应的代码,比较简单不再赘述。

深入浅出图神经网络 GCN代码实战的更多相关文章

  1. 深入浅出图神经网络 第6章 GCN的性质 读书笔记

    第6章 GCN的性质 第5章最后讲到GCN结束的有些匆忙,作为GNN最经典的模型,其有很多性质需要我们去理解. 6.1 GCN与CNN的区别与联系 CNN卷积卷的是矩阵某个区域内的值,图卷积在空域视角 ...

  2. 图机器学习(GML)&图神经网络(GNN)原理和代码实现(前置学习系列二)

    项目链接:https://aistudio.baidu.com/aistudio/projectdetail/4990947?contributionType=1 欢迎fork欢迎三连!文章篇幅有限, ...

  3. Scala 深入浅出实战经典 第64讲:Scala中隐式对象代码实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  4. Scala 深入浅出实战经典 第63讲:Scala中隐式类代码实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-87讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  5. Scala 深入浅出实战经典 第52讲:Scala中路径依赖代码实战详解

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  6. Scala 深入浅出实战经典 第51讲:Scala中链式调用风格的实现代码实战及其在Spark中应用

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  7. Scala 深入浅出实战经典 第49课 Scala中Variance代码实战(协变)

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  8. Scala 深入浅出实战经典 第48讲:Scala类型约束代码实战及其在Spark中的应用源码解析

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

  9. Scala 深入浅出实战经典 第47讲:Scala多重界定代码实战及其在Spark中的应用

    王家林亲授<DT大数据梦工厂>大数据实战视频 Scala 深入浅出实战经典(1-64讲)完整视频.PPT.代码下载:百度云盘:http://pan.baidu.com/s/1c0noOt6 ...

随机推荐

  1. TcaplusDB君 · 行业新闻汇编(5月25日)

    TcaplusDB君一直密切关注着游戏行业和数据库行业的动态.以下是TcaplusDB君收集的近期的游戏行业和数据库行业的新闻,汇编整理,献给大家观看. (本篇文章部分内容来自网络) 第十一届中国数据 ...

  2. GO汇编-函数

    GO汇编-函数 终于到函数了!因为Go汇编语言中,可以也建议通过Go语言来定义全局变量,那么剩下的也就是函数了.只有掌握了汇编函数的基本用法,才能真正算是Go汇编语言入门.本章将简单讨论Go汇编中函数 ...

  3. Go语言web开发---Beego基础

    一.框架 框架:可复用的设计组件,它规定了应用的体系结构,明确了整个设计,协作各个组件之间的依赖关系,责任分配,和流程控制.通俗解释框架就是一堆代码的集合,为了提高软件的开发效率和质量,一般都会使用框 ...

  4. CodeGen结构循环回路

    CodeGen结构循环回路 structure循环是一个模板文件构造,它允许您迭代CodeGen拥有的有关结构的集合.为了使用结构循环,必须同时基于多个存储库结构生成代码. CodeGen可以通过以下 ...

  5. 阿里面试挂了,就因为面试官说我Spring 事务管理(器)不熟练?

    前言 事务管理,一个被说烂的也被看烂的话题,还是八股文中的基础股之一.但除了八股文中需要熟读并背诵的那些个传播行为之外,背后的"为什么"和核心原理更为重要. ​ 写这篇文章之前,我 ...

  6. MIT6.828-LAB1 : PC启动

    Lab1 1. 先熟悉PC的物理地址空间 这里其实有很多可以说的,不过先简单描述一下吧.从0x00000000到0x00100000这1mb的地址空间时机器处于16位的实模式.也就是说这个时候机器的汇 ...

  7. 散列数据结构以及在HashMap中的应用

    1. 为什么需要散列表? 对于线性表和链表而言,访问表中的元素,时间复杂度均为O(n).即便是通过树结构存储数据,时间复杂度也为O(logn).那么有没有一种方式可以将这个时间复杂度降为O(1)呢?当 ...

  8. Python分析44130条用户观影数据,挖掘用户与电影之间的隐藏信息!

    01.前言 很多电影也上映,看电影前很多人都喜欢去 『豆瓣』 看影评,所以我爬取44130条 『豆瓣』 的用户观影数据,分析用户之间的关系,电影之间的联系,以及用户和电影之间的隐藏关系. 02.爬取观 ...

  9. Simpleperf分析之Android系统篇

    [译]Simpleperf分析之Android系统篇 译者按: Simpleperf是用于Native的CPU性能分析工具,主要用来分析代码执行耗时.本文是主文档的一部分,系统篇. 原文见aosp仓库 ...

  10. Java并发之Semaphore源码解析(二)

    在上一章,我们学习了信号量(Semaphore)是如何请求许可证的,下面我们来看看要如何归还许可证. 可以看到当我们要归还许可证时,不论是调用release()或是release(int permit ...