基于Pytorch Gemotric在昇腾上实现GAT图神经网络

简介: 本实验基于昇腾平台,使用PyTorch实现图神经网络GAT(Graph Attention Networks)在Pubmed数据集上的分类任务。内容涵盖GAT网络的创新点分析、图注意力机制原理、多头注意力机制详解以及模型代码实战。实验通过两层GAT网络对Pubmed数据集进行训练,验证模型性能,并展示NPU上的内存使用情况。最终,模型在测试集上达到约36.60%的准确率。

本实验主要介绍了如何在昇腾上,使用pytorch对经典的图神经网络GAT在论文引用数据集Pubmed上进行分类训练的实战讲解。内容包括GAT网络创新点分析、图注意力机制原理与架构剖析、多头注意力机制分析与GAT网络模型代码实战分析等等。

本实验的目录结构安排如下所示:

  • GAT网络创新点分析
  • 图注意力机制原理与架构分析
  • 多头注意力机制分析
  • GAT网络用于Pubmed数据集分类实战

GAT网络创新点分析

注意机制已成功用于许多基于序列的任务,例如机器翻译,机器阅读等等。与GCN平等对待节点的所有邻居相比,注意力机制可以为每个邻居分配不同的注意力得分,从而识别出更重要的邻居。将注意力机制纳入图谱神经网络的传播步骤是很直观的。图注意力网络也可以看作是图卷积网络家族中的一种方法。其创新点如下:

  • GAT是一种图结构化数据上操作的新型神经网络架构,利用掩码自注意力层来解决基于图卷积或其近似值的现有方法的缺点。
  • GAT网络对不同的相邻节点分配相应的权重,既不需要矩阵运算,也不需要事先知道图结构。
  • GAT网络克服了基于谱神经网络的几个关键挑战,使得模型更加适用于归纳问题以及转导问题。
  • 在Cora、Citeseer和Pubmed引文网络数据集上取得了非常好的效果。

图注意力机制原理与架构分析

图中输入由N个节点组成,每个节点feature数为F(也就是feature vector长度),下述两个公式分别表示输入的节点向量通过GAT网络进行注意力计算后得到的输出。

    Input: $h = { \vec{h_1}, \vec{h_2}, . . . , \vec{h_N} },\vec h_i \in R\^{F} $

    Output: $h = { \vec{h_1\^{'}}, \vec{h_2\^{'}}, . . . , \vec{h_N\^{'}} },\vec h_i\^{'} \in R\^{F\^{'}} $

为了将输入的特征转换为高维的特征,这里至少需要一个科学系的线性转换。在 (Velickovic et al.,2017)中,作者对于每一个点使用了一个共享的线性转换方式,同时介绍了一个权重矩阵$W$来参数化线性转换。对于节点中的每两个node间都有了相互关注机制(用来做加权平均,卷积时每个node的更新是其他的加权平均)。

计算节点$i$与节点$j$的相关性系数(注意力值):

先初步计算节点i与节点j的相关性:$e_{ij} = a(W * h_i ,W * h_j)$其中a是一个共享的权重系数,执行的是$R\^{F\^{'}} X R\^{F\^{'}} -> R\^{F} 转换,这里可以定义成一个前馈全连接神经网络$

计算节点i与节点j的相关性(归一化)$\alpha_{i, j} = softmaxj(e{ij}) = \frac {exp(e{ij})} {\sum{k \in Ni}exp(e{ik})}$

论文中采取取的计算attention coefficient的函数a是一个单层的前馈网络,经LeakyReLU处理得最终的$\alpha_{i, j}值$:

$\alpha_{i, j} = \frac {exp(LeakyReLU({\vec a\^T}[W\vec{h_i} || W \vec{hj}]))} {\sum{k \in N_i}exp(LeakyReLU(\vec a\^T[W \vec{h_i} ,W \vec{h_k}])} $

式中 || 表示串联/连接,一旦获得,归一化的相互注意系数用来计算对应特征的线性组合,以用作每个节点的最终输出特征。

左图表示在模型中应用注意机制a(W * h_i ,W * h_j) 通过权重向量$a$参数化,应用LeakyReLU 激活输出。

右图表示$h_1\^′$在邻域中具有多端连接,不同的箭头样式表示独立的注意力计算,通过直连concat或平均avg获取$h_1\^′$。

多头注意力机制分析

对于图中多头注意力情况,对应上图中右图情景,不只用一个函数进行attention coefficient的计算,而是设置K个函数,每一个函数都能计算出一组attention coefficient,并能计算出一组加权求和用的系数,每一个卷积层中,K个attention机制独立的工作,分别计算出自己的结果后连接在一起,得到卷积的结果。

我们知道对于单个注意力层输出$\vec h_i\^′$计算如下:

$\vec hi\^′ = \delta (\sum{k \in Ni}(a{ij}W\vec h_j))$

对于有k个独立的相互注意机制同时计算,则集中其特征,可得到特征表示如下:

分别遍历1~k个头,每一个上按照下述公式计算:

$\vec hi\^′ = \delta (\sum{k \in Ni}(a{ij}\^k W\^k \vec h_j))$

对于网络的最后一层卷积层,如果还是使用multi-head attention机制,那么就不采取连接的方式合并不同的attention机制的结果了,而是采用求平均的方式进行处理。

$\vec hi\^′ = \delta({\frac {1}{K}}(\sum{k=1}\^K)(\sum_{k \in Ni}(a{ij}\^k W\^k \vec h_j)))$

GAT网络用于Pubmed数据集分类实战

#导入torch相关库
import torch
import torch.nn.functional as F

该实验需要跑在npu上,因此需要导入Npu相关库使得模型快速迁移到npu上运行

import torch_npu
from torch_npu.contrib import transfer_to_npu
/home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/dynamo/__init__.py:18: UserWarning: Register eager implementation for the 'npu' backend of dynamo, as torch_npu was not compiled with torchair.
  warnings.warn(
/home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py:164: ImportWarning: 
    *************************************************************************************************************
    The torch.Tensor.cuda and torch.nn.Module.cuda are replaced with torch.Tensor.npu and torch.nn.Module.npu now..
    The torch.cuda.DoubleTensor is replaced with torch.npu.FloatTensor cause the double type is not supported now..
    The backend in torch.distributed.init_process_group set to hccl now..
    The torch.cuda.* and torch.cuda.amp.* are replaced with torch.npu.* and torch.npu.amp.* now..
    The device parameters have been replaced with npu in the function below:
    torch.logspace, torch.randint, torch.hann_window, torch.rand, torch.full_like, torch.ones_like, torch.rand_like, torch.randperm, torch.arange, torch.frombuffer, torch.normal, torch._empty_per_channel_affine_quantized, torch.empty_strided, torch.empty_like, torch.scalar_tensor, torch.tril_indices, torch.bartlett_window, torch.ones, torch.sparse_coo_tensor, torch.randn, torch.kaiser_window, torch.tensor, torch.triu_indices, torch.as_tensor, torch.zeros, torch.randint_like, torch.full, torch.eye, torch._sparse_csr_tensor_unsafe, torch.empty, torch._sparse_coo_tensor_unsafe, torch.blackman_window, torch.zeros_like, torch.range, torch.sparse_csr_tensor, torch.randn_like, torch.from_file, torch._cudnn_init_dropout_state, torch._empty_affine_quantized, torch.linspace, torch.hamming_window, torch.empty_quantized, torch._pin_memory, torch.Tensor.new_empty, torch.Tensor.new_empty_strided, torch.Tensor.new_full, torch.Tensor.new_ones, torch.Tensor.new_tensor, torch.Tensor.new_zeros, torch.Tensor.to, torch.nn.Module.to, torch.nn.Module.to_empty
    *************************************************************************************************************

  warnings.warn(msg, ImportWarning)

由于torch_geometric中集成了单层的GATConv模块,这里直接进行导入,若有兴趣可以自行实现该类,注意输入与输出对齐即可。此外,数据集用的是Pubmed,该数据集也直接集成在Planetoid模块中,这里也需要将其import进来。

from torch_geometric.nn import GATConv
from torch_geometric.datasets import Planetoid
/home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_npu/contrib/transfer_to_npu.py:124: RuntimeWarning: torch.jit.script will be disabled by transfer_to_npu, which currently does not support it.
  warnings.warn(msg, RuntimeWarning)

Pubmed数据集介绍

PubMed数据集是一个广泛用于图神经网络(GNN)研究的基准数据集,主要用于节点分类任务。其由生物医学文献组成,每篇文献被视为一个节点,引用关系被视为边。该数据集包含三类糖尿病相关的论文,每个节点都带有特征向量和标签。

数据集一共有19717个节点 ,每一个节点代表一篇生物医学文献,每个节点有一个500 维的特征向量,用来表示该医学文献的内容。总共含44338条边 ,每条边表示一篇文献对另一篇文献的引用关系,边与边之间是无向的,因此可以看做是对称的。总类别数包含Diabetes Mellitus Experiment、Diabetes Mellitus Type 1与Diabetes Mellitus Type2三类

# 加载数据
print("===== begin Download Dadasat=====\n")
dataset = Planetoid(root='/home/pengyongrong/workspace/data', name='PubMed')
print("===== Download Dadasat finished=====\n")
print("dataset num_features  is:  ", dataset.num_features)
print("dataset.num_classes is:  ", dataset.num_classes)

print("dataset.edge_index is:  ", dataset.edge_index)

print("train data is:   ", dataset.data)
print("dataset0 is:  ", dataset[0])

print("train data mask is:   ", dataset.train_mask, "num train is: ", (dataset.train_mask ==True).sum().item())
print("val data mask is:   ",dataset.val_mask, "num val is: ", (dataset.val_mask ==True).sum().item())
print("test data mask is:   ",dataset.test_mask,  "num test is: ", (dataset.test_mask ==True).sum().item())
===== begin Download Dadasat=====

===== Download Dadasat finished=====

dataset num_features  is:   500
dataset.num_classes is:   3
dataset.edge_index is:   tensor([[ 1378,  1544,  6092,  ..., 12278,  4284, 16030],
        [    0,     0,     0,  ..., 19714, 19715, 19716]])
train data is:    Data(x=[19717, 500], edge_index=[2, 88648], y=[19717], train_mask=[19717], val_mask=[19717], test_mask=[19717])
dataset0 is:   Data(x=[19717, 500], edge_index=[2, 88648], y=[19717], train_mask=[19717], val_mask=[19717], test_mask=[19717])
train data mask is:    tensor([ True,  True,  True,  ..., False, False, False]) num train is:  60
val data mask is:    tensor([False, False, False,  ..., False, False, False]) num val is:  500
test data mask is:    tensor([False, False, False,  ...,  True,  True,  True]) num test is:  1000


/home/pengyongrong/miniconda3/envs/AscendCExperiments/lib/python3.9/site-packages/torch_geometric/data/in_memory_dataset.py:300: UserWarning: It is not recommended to directly access the internal storage format `data` of an 'InMemoryDataset'. If you are absolutely certain what you are doing, access the internal storage via `InMemoryDataset._data` instead to suppress this warning. Alternatively, you can access stacked individual attributes of every graph via `dataset.{attr_name}`.
  warnings.warn(msg)

下载后的pubmed数据集总共包含8个文件,分别是ind.pubmed.x、ind.pubmed.tx、ind.pubmed.all、ind.pubmed.y、ind.pubmed.ty、ind.pubmed.ally、ind.pubmed.graph与ind.pubmed.test.index。每个文件的作用说明如下:

ind.pubmed.x:训练集节点特征向量,大小(140,1433)

ind.pubmed.tx:测试集节点特征向量,实际展开后大小为(1000,1433)

ind.pubmed.allx:包含标签核无标签的训练节点特征向量(1708,1433)

ind.pubmed.y:one-hot表示的训练节点的标签

ind.pubmed.ty:one-hot表示的测试节点的标签

ind.pubmed.ally:one-hot表示的ind.cora.allx对应的标签

ind.pubmed.graph:保存节点之间边的信息

ind.pubmed.test.index:保存测试集节点的索引,用于后面的归纳学习设置

从打印结果可以看出,数据集的特点与上述描述的相对应,GAT_NET网络定义了一个两层的GAT网络,heads的数量设置成4。

开启Pubmed数据训练过程

class GAT_NET(torch.nn.Module):
    def __init__(self, features, hidden, classes, heads=4):
        super(GAT_NET, self).__init__()
        # 定义GAT层,使用多头注意力机制
        self.gat1 = GATConv(features, hidden, heads=4) 
        # 因为多头注意力是将向量拼接,所以维度乘以头数。
        self.gat2 = GATConv(hidden*heads, classes) 

    def forward(self, data):
        # 从输入数据集中获取x与边集相关信息
        x, edge_index = data.x, data.edge_index
        # 将输入传入GAT层中,获得第一层Gat层的输出
        x = self.gat1(x, edge_index)
        # 经过非线性激活与dropout,减少过拟合现象,增加模型的泛化能力
        x = F.relu(x)
        x = F.dropout(x, training=self.training)
        # 第二层GAT层,得到整个网络的输出送给分类器进行分类
        x = self.gat2(x, edge_index)
        return F.log_softmax(x, dim=1)

定义设备跑在Npu上,这里如果需要替换成Gpu或Cpu,则替换成'cuda'或'cpu'即可。

device = 'npu'

定义GAT_NET网络,中间隐藏层节点个数定义为16,'dataset.num_classes'为先前数据集中总的类别数,这里是7类。'to()'的作用是将该加载到指定模型设备上。优化器用的是'optim'中的'Adam'。

model = GAT_NET(dataset.num_node_features, 16, dataset.num_classes).to(device)  # 定义GraphSAGE
data = dataset[0].to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)

开始训练模型,指定训练次数200次,训练后采用极大似然用作损失函数计算损失,然后进行反向传播更新模型的参数,训练完成后,用验证集中的数据对模型效果进行验证,最后打印模型的准确率。

model.train()
for epoch in range(200):
    optimizer.zero_grad()
    out = model(data)
    loss = F.nll_loss(out[data.train_mask], data.y[data.train_mask])
    loss.backward()
    optimizer.step()

# 模型验证过程,对训练得到的模型效果进行评估,并打印准确率。
model.eval()
_, pred = model(data).max(dim=1)
correct = int(pred[data.test_mask].eq(data.y[data.test_mask]).sum().item())
acc = correct / int(data.test_mask.sum())
print('GAT Accuracy: {:.4f}'.format(acc))
[W VariableFallbackKernel.cpp:51] Warning: CAUTION: The operator 'aten::scatter_reduce.two_out' is not currently supported on the NPU backend and will fall back to run on the CPU. This may have performance implications. (function npu_cpu_fallback)


GAT Accuracy: 0.3660

内存使用情况: 整个训练过程的内存使用情况可以通过"npu-smi info"命令在终端查看,因此本文实验只用到了单个npu卡(也就是chip 0),内存占用约573M,对内存、精度或性能优化有兴趣的可以自行尝试进行优化。

Reference

[1] Velikovi, Petar , et al. "Graph Attention Networks." (2017).

相关文章
|
4月前
|
机器学习/深度学习 PyTorch 算法框架/工具
基于Pytorch 在昇腾上实现GCN图神经网络
本文详细讲解了如何在昇腾平台上使用PyTorch实现图神经网络(GCN)对Cora数据集进行分类训练。内容涵盖GCN背景、模型特点、网络架构剖析及实战分析。GCN通过聚合邻居节点信息实现“卷积”操作,适用于非欧氏结构数据。文章以两层GCN模型为例,结合Cora数据集(2708篇科学出版物,1433个特征,7种类别),展示了从数据加载到模型训练的完整流程。实验在NPU上运行,设置200个epoch,最终测试准确率达0.8040,内存占用约167M。
基于Pytorch 在昇腾上实现GCN图神经网络
|
4月前
|
机器学习/深度学习 搜索推荐 PyTorch
基于昇腾用PyTorch实现CTR模型DIN(Deep interest Netwok)网络
本文详细讲解了如何在昇腾平台上使用PyTorch训练推荐系统中的经典模型DIN(Deep Interest Network)。主要内容包括:DIN网络的创新点与架构剖析、Activation Unit和Attention模块的实现、Amazon-book数据集的介绍与预处理、模型训练过程定义及性能评估。通过实战演示,利用Amazon-book数据集训练DIN模型,最终评估其点击率预测性能。文中还提供了代码示例,帮助读者更好地理解每个步骤的实现细节。
|
4月前
|
算法 PyTorch 算法框架/工具
PyTorch 实现FCN网络用于图像语义分割
本文详细讲解了在昇腾平台上使用PyTorch实现FCN(Fully Convolutional Networks)网络在VOC2012数据集上的训练过程。内容涵盖FCN的创新点分析、网络架构解析、代码实现以及端到端训练流程。重点包括全卷积结构替换全连接层、多尺度特征融合、跳跃连接和反卷积操作等技术细节。通过定义VOCSegDataset类处理数据集,构建FCN8s模型并完成训练与测试。实验结果展示了模型在图像分割任务中的应用效果,同时提供了内存使用优化的参考。
|
4月前
|
机器学习/深度学习 算法 PyTorch
基于Pytorch Gemotric在昇腾上实现GraphSage图神经网络
本实验基于PyTorch Geometric,在昇腾平台上实现GraphSAGE图神经网络,使用CiteSeer数据集进行分类训练。内容涵盖GraphSAGE的创新点、算法原理、网络架构及实战分析。GraphSAGE通过采样和聚合节点邻居特征,支持归纳式学习,适用于未见节点的表征生成。实验包括模型搭建、训练与验证,并在NPU上运行,最终测试准确率达0.665。
|
4月前
|
机器学习/深度学习 PyTorch API
PyTorch量化感知训练技术:模型压缩与高精度边缘部署实践
本文深入探讨神经网络模型量化技术,重点讲解训练后量化(PTQ)与量化感知训练(QAT)两种主流方法。PTQ通过校准数据集确定量化参数,快速实现模型压缩,但精度损失较大;QAT在训练中引入伪量化操作,使模型适应低精度环境,显著提升量化后性能。文章结合PyTorch实现细节,介绍Eager模式、FX图模式及PyTorch 2导出量化等工具,并分享大语言模型Int4/Int8混合精度实践。最后总结量化最佳策略,包括逐通道量化、混合精度设置及目标硬件适配,助力高效部署深度学习模型。
509 21
PyTorch量化感知训练技术:模型压缩与高精度边缘部署实践
|
9天前
|
PyTorch 算法框架/工具 异构计算
PyTorch 2.0性能优化实战:4种常见代码错误严重拖慢模型
我们将深入探讨图中断(graph breaks)和多图问题对性能的负面影响,并分析PyTorch模型开发中应当避免的常见错误模式。
72 9
|
6月前
|
机器学习/深度学习 JavaScript PyTorch
9个主流GAN损失函数的数学原理和Pytorch代码实现:从经典模型到现代变体
生成对抗网络(GAN)的训练效果高度依赖于损失函数的选择。本文介绍了经典GAN损失函数理论,并用PyTorch实现多种变体,包括原始GAN、LS-GAN、WGAN及WGAN-GP等。通过分析其原理与优劣,如LS-GAN提升训练稳定性、WGAN-GP改善图像质量,展示了不同场景下损失函数的设计思路。代码实现覆盖生成器与判别器的核心逻辑,为实际应用提供了重要参考。未来可探索组合优化与自适应设计以提升性能。
368 7
9个主流GAN损失函数的数学原理和Pytorch代码实现:从经典模型到现代变体
|
3月前
|
机器学习/深度学习 存储 PyTorch
PyTorch + MLFlow 实战:从零构建可追踪的深度学习模型训练系统
本文通过使用 Kaggle 数据集训练情感分析模型的实例,详细演示了如何将 PyTorch 与 MLFlow 进行深度集成,实现完整的实验跟踪、模型记录和结果可复现性管理。文章将系统性地介绍训练代码的核心组件,展示指标和工件的记录方法,并提供 MLFlow UI 的详细界面截图。
96 2
PyTorch + MLFlow 实战:从零构建可追踪的深度学习模型训练系统
|
2月前
|
机器学习/深度学习 数据可视化 PyTorch
Flow Matching生成模型:从理论基础到Pytorch代码实现
本文将系统阐述Flow Matching的完整实现过程,包括数学理论推导、模型架构设计、训练流程构建以及速度场学习等关键组件。通过本文的学习,读者将掌握Flow Matching的核心原理,获得一个完整的PyTorch实现,并对生成模型在噪声调度和分数函数之外的发展方向有更深入的理解。
776 0
Flow Matching生成模型:从理论基础到Pytorch代码实现
|
3月前
|
机器学习/深度学习 PyTorch 算法框架/工具
提升模型泛化能力:PyTorch的L1、L2、ElasticNet正则化技术深度解析与代码实现
本文将深入探讨L1、L2和ElasticNet正则化技术,重点关注其在PyTorch框架中的具体实现。关于这些技术的理论基础,建议读者参考相关理论文献以获得更深入的理解。
90 4
提升模型泛化能力:PyTorch的L1、L2、ElasticNet正则化技术深度解析与代码实现

热门文章

最新文章

推荐镜像

更多