当前位置: 首页 > news >正文

GNN PyG~torch_geometric 学习理解

目录

1. PyG Introduction

2. PyG Installation

2.1 PyG 安装常见错误及原因

2.2 PyG 具体安装步骤

3. torch_geometric packages

torch_geometric.data.Data

Dataset 与 DataLoader

Dropout、BatchNorm

3. torch_geometric: 理解edge_index

3.1 理解 mini-batch edge index for GNN models

torch_geometric.loader.NeighborSampler

GraphSAGE model base on mini-batch edge_index

3.2 理解 full node embedding + full edge index

3.2.1 GCN

full edge index train方式:

full edge index test

 3.2.2 GraphSAGE

3.2.3 GAT

4. PyG 实现的 GNN models

4.1  基于MessagePassing + propagate 构建的GCN模型

4.2 Graph Transformer with mini-batch edge_index

10. Torch-geometric errors

torch_geometric报错(一): "找不到指定的模块"

Reference​​​​​​​​​​​​​


1. PyG Introduction

GNN, Graph Neural Network,也称为Graph Machine Learning

PyG 就是PyTorch Geometric package, 它集成了经典的和最新的GNN algorithms, such as GCN、GraphSAGE、GAT、Graph Transformer, etc. 

它可以让GNN研究人员安心做一个“调包侠”,而不用自己费心费力去实现和debug,而且自己写的GNN model还可能是错的,你哭不哭?

2. PyG Installation

这里涉及的PyG安装包括: torch_cluster、torch_scatter、torch_sparse、torch_spline_conv和torch_geometric。

2.1 PyG 安装常见错误及原因

不兼容问题、版本冲突问题

OSError: /home/zh1995/anaconda3/lib/python3.6/site-packages/torch_sparse/_version_cuda.so: undefined symbol: _ZN3c106detail23torchInternalAssertFailEPKcS2_jS2_S2_

这是因为安装了多个pytorch或多个CUDA版本的原因。通过anaconda-navigator安装pytorch 时它将自动安装cpu和gpu两个版本,因此产生错误。

不要通过来安装Torch,而是通过pip从以下网址下载特定版本的pytorch: Installation — pytorch_geometric documentation。

2.2 PyG 具体安装步骤

参考:     python安装torch-geometric包出现的错误:OSError: torch_sparse/_version_cuda.so: undefined symbol:_oserror: /home/ubuntu/anaconda3/lib/python3.10/sit-CSDN博客

安装完torch geometric,import torch_geometric然后报错:OSError: [WinError 127] 找不到指定的模块-CSDN博客

PyG 2.3 requires that at least PyTorch 1.12 is installed. 

所以,torch版本最好≥1.12.0

1. 卸载原有的包: pip uninstall 相应的依赖包,如torch、torch-scatter、torch-sparse。

2. 查询系统兼容的torch和CUDA版本。

torch指的是cpu版本;torch-cuda是GPU版本。如果需要在服务器上跑代码,就需要安装torch-cuda版本。 torch对应的cuda版本查询地址:Previous PyTorch Versions | PyTorch

3. 确定好torch-cuda版本后,就需要确定兼容的PyG版本了。

torch_cluster、torch_sparse、torch_scatter等版本查询地址:https://data.pyg.org/whl/index.html

 4. 一定要用pip安装!!!安装指令和顺序如下:

需要指定package version和torch-cuda version!

比如:基于torch-1.12.0+cuda102版本安装PyG packages

pip install torch-scatter==2.0.9 -f https://pytorch-geometric.com/whl/torch-1.12.0+cu102.html

安装其他的包时,需要替换对应的package name and version。

5. 最后安装torch-geometric package

它不用指定版本

pip install torch-geometric -f https://pytorch-geometric.com/whl/torch-1.12.0+cu102.html

3. torch_geometric packages

参考:

图神经网络 PyTorch Geometric 入门教程 - 知乎

torch_geometric.data.Data

节点和节点之间的边构成了图。所以在 PyG 中,如果你要构建图,那么需要两个要素:节点和边。PyG 提供了torch_geometric.data.Data (下面简称Data) 用于构建图,包括 5 个属性,每一个属性都不是必须的,可以为空。

  • x: 用于存储每个节点的特征,形状是[num_nodes, num_node_features]
  • edge_index: 用于存储节点之间的边,形状是 [2, num_edges]
  • pos: 存储节点的坐标,形状是[num_nodes, num_dimensions]
  • y: 存储样本标签。如果是每个节点都有标签,那么形状是[num_nodes, *];如果是整张图只有一个标签,那么形状是[1, *]
  • edge_attr: 存储边的特征。形状是[num_edges, num_edge_features]

Dataset 与 DataLoader

PyG 的 Dataset继承自torch.utils.data.Dataset,自带了很多图数据集,我们以TUDataset为例,通过以下代码就可以加载数据集,root参数设置数据下载的位置。通过索引可以访问每一个数据。

from torch_geometric.datasets import TUDataset
dataset = TUDataset(root='/tmp/ENZYMES', name='ENZYMES')
data = dataset[0]

 在一个图中,由edge_indexedge_attr可以决定所有节点的邻接矩阵。PyG 通过创建稀疏的对角邻接矩阵,并在节点维度中连接特征矩阵和 label 矩阵,实现了在 mini-batch 的并行化。PyG 允许在一个 mini-batch 中的每个Data (图) 使用不同数量的节点和边。​​​​​​​​​​​​​​

Dropout、BatchNorm

 PyG实现GAT,使用封装好的GATConv函数。

  • model.train()和model.eval()分别定义模型的训练模型和测试模式,主要对Dropout层和BatchNorm产生影响。
  • Dropout: 训练过程中,为防止模型过拟合,增加其泛化性,会随机屏蔽掉一些神经元,相当于每次经过不同的神经元,最终得到不同的模型。测试模式时,所有神经元共同作用,类似于boosting。
  • BatchNorm: 训练过程中,模型每处理一次minibatch数据,BN层根据一个minibatch来计算mean和std后做归一化处理。测试时,BN层会利用训练时得到的参数来处理测试数据。如果不设置model.eval(),输入单个数据,模型会报错。

3. torch_geometric: 理解edge_index

参考: 

pytorch geometric教程四 利用NeighorSampler实现节点维度的mini-batch + GraphSAGE样例-CSDN博客

3.1 理解 mini-batch edge index for GNN models

PyG的官方文档中有mini-batchAdvanced mini-batching两部分内容,但实现的都是图维度的mini-batch。如何像GraphSAGE paper中对minibatch的节点进行邻居采样并训练模型,使得大规模全连接图的GNNs模型训练成为可能,PyG是通过torch_geometric.loader.NeighborSampler实现的(早一点版本是torch_geometric.data.NeighborSampler)。
需要注明的一点是,这篇文章中虽然举了SAGEConv的代码样例,但只要卷积层支持bipartite图,大家举一反三,就可以与NeighborSampler结合使用,实现节点维度的mini-batch模型训练与推断

torch_geometric.loader.NeighborSampler
from torch_geometric.loader import NeighborSampler, RandomNodeSampler

A data loader that performs neighbor sampling as introduced in the "Inductive Representation Learning on Large Graphs" paper. 它允许对GNNs mini-batch training进行neighbor采样,并训练模型,使得大规模全连接的GNNs模型训练成为可能。

核心想法

NeighborSampler的核心想法是,给定mini-batch的节点和图卷积的层数L,以及每一层需要采样的邻居数目sizes,依次从第一层到第L层,对每一层进行邻居采样并返回一个bipartite子图。sizes是一个L长度的list,包含每一层需要采样的邻居个数。以下是主要逻辑的归纳:
For i in L:

  • 1层使用初始minibatch的节点进行邻居采样,返回采样结果。
  • i (i>0)层,使用上层采样中涉及到的所有节点进行邻居采样,返回采样结果。   

i层采样完成后,返回结果(batch_size, n_id, adjs),其中batch_size就是mini-batch的节点数目,n_id是包含所有在L层卷积中遇到的节点的list,且target节点在n_id前几位。adjs是一个list,包含了第L层到第1层采样的结果,所以adjs中的子图是从大到小的。每一层采样返回的结果具体形式为(edge_index, e_id, size)。其中edge_index是采样得到的bipartite子图中source节点到target节点的边。e_id是edge_index的边在原始大图中的IDs, the index of node index,就是bipartite子图的shape。

以下是一个2层采样的示意图,注意在第2层采样的时候,使用了第1层中涉及到的所有节点,包括出发点
在这里插入图片描述

返回结果 of NeighborSampler:

  • batch_size
  • n_id: L层采样中遇到的所有的节点的list,其中target节点在list最前端。
  • adjs: 第L层到第1层采样结果的list
    • edge_index: 采样得到的bipartite子图中source节点到target节点的边。
    • e_id: edge_index的边在原始大图中的IDs
    • size: bipartite子图中的shape。

参数

class NeighborSampler(torch.utils.data.DataLoader):def __init__(self, edge_index: Union[Tensor, SparseTensor],sizes: List[int], node_idx: Optional[Tensor] = None,num_nodes: Optional[int] = None, return_e_id: bool = True,transform: Callable = None, **kwargs):
  • edge_index (Tensor or SparseTensor):图的边信息,可以是Tensor,也可以是SparseTensor。
  • sizes ([int]):note that 这是个list!!每一层需要采样的邻居数目,如果是-1的话,选取所有的邻居
  • node_idx (LongTensor, optional):提供需要被采样节点的信息,比如模型训练的时候,只给出数据集train中的节点。在预测的时候,使用None,考虑所有的节点。
  • num_nodes: Optional[int] = None:图中节点的数目,可选参数。
  • return_e_id: bool = True:当设为False的时候,不会返回partite子图的边在原图中的IDs。
  • transform
  • **kwargs:NeighborSampler是torch.utils.data.DataLoader的子类,所以父类DataLoader的参数NeighborSampler都可以使用,比如:batch_size, shuffle, num_workers。
GraphSAGE model base on mini-batch edge_index

模型训练
train_loader
首先代码里定义了模型训练时的数据加载器train_loader。 node_idx=data.train_mask指定只对训练集的节点进行邻居采样,sizes=[25, 10]指明了这是一个两层的卷积,第一层卷积采样邻居数目25,第二层卷积采样邻居数目10。batch_size=1024指定了mini-batch的节点数目,每次只对1024个节点进行采样。

train_loader = NeighborSampler(data.edge_index, node_idx=data.train_mask,sizes=[25, 10], batch_size=1024, shuffle=True,num_workers=12)

 train
train_loader每次返回一个batch_size节点邻居采样的结果,其形式是(batch_size, n_id, adjs),其中n_id是采样过程中涉及的所有节点的id,也是adjs中涉及的所有节点,因此x[n_id]是所有相关节点的特征。而且x[n_id]相当于做了一次映射,x[n_id]中第i行就是adjs中i节点的特征(关于这一点,会在后面NeighborSampler工作原理部分详述)。adjs是包含了所有bipartite子图边信息的list。所以model(x[n_id], adjs)传入了所有bipartite子图的节点特征和边信息。
另外NeighborSampler是在CPU中完成的,所以返回的结果都在CPU上。如果用GPU训练模型,要记得将loader的结果放到GPU上。

def train(epoch):model.train()total_loss = total_correct = 0for batch_size, n_id, adjs in train_loader:# `adjs` holds a list of `(edge_index, e_id, size)` tuples.adjs = [adj.to(device) for adj in adjs]optimizer.zero_grad()out = model(x[n_id], adjs)loss = F.nll_loss(out, y[n_id[:batch_size]])loss.backward()optimizer.step()total_loss += float(loss)total_correct += int(out.argmax(dim=-1).eq(y[n_id[:batch_size]]).sum())loss = total_loss / len(train_loader)approx_acc = total_correct / int(data.train_mask.sum())return loss, approx_acc

model中的forward()函数
forward函数依次实现了从第L层到第1层采样得到的bipartite子图的卷积。
adjs包含L层邻居采样的bipartite子图:(edge_index, e_id, size)。在上一个教程中讲过了,SAGEConv是支持bipartite图的。对bipartite图进行卷积时,输入的x是一个tuple: (x_source, x_target)。上面提到过,n_id是包含所有在L层卷积中遇到的节点的list,且target节点在n_id前几位。而bipartite图的size是(num_of_source_nodes, num_of_target_nodes),因此对每一层的bipartite图都有x_target = x[:size[1]] 。所以 self.convs[i]((x, x_target), edge_index)实现了对一层bipartite图的卷积。

class SAGE(torch.nn.Module):def __init__(self, in_channels, hidden_channels, out_channels, num_layers):super(SAGE, self).__init__()self.num_layers = num_layers...def forward(self, x, adjs):for i, (edge_index, _, size) in enumerate(adjs):x_target = x[:size[1]]  # Target nodes are always placed first.x = self.convs[i]((x, x_target), edge_index)if i != self.num_layers - 1:x = F.relu(x)x = F.dropout(x, p=0.5, training=self.training)return x.log_softmax(dim=-1)

 NeighborSampler工作原理&具体实例

上文只是简略讲了NeighborSampler的工作原理,这里用几个实例,让大家更清楚地理解其中的细节。
首先用networkx建以下一张图:

import networkx as nx
graph = nx.Graph()
graph.add_edges_from([(0,1), (1,2), (1,3), (2,3), (3,4), (4,2)])
nx.draw_kamada_kawai(graph, with_labels=True)

 

 将其转换成PyG中的Data格式。

from torch_geometric.data.data import Data
from torch_geometric.utils import from_networkxdata = from_networkx(graph)
data.edge_index
>>> tensor([[0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4],[1, 0, 2, 3, 1, 3, 4, 1, 2, 4, 2, 3]])

 batch_size =1 ,采样邻居数小于邻居数

from torch_geometric.data import NeighborSampler
loader = NeighborSampler(edge_index=data.edge_index, sizes=[2], node_idx=torch.tensor([2]), batch_size=1)
next(iter(loader))
>>> (1,tensor([2, 3, 1]),EdgeIndex(edge_index=tensor([[1, 2],[0, 0]]), e_id=tensor([8, 2]), size=(3, 1)))

以上代码对2号节点取两个邻居。n_id: tensor([2, 3, 1])是遇到的所有节点,target节点在最前面,是2号节点,3, 1是采样到的邻居。edge_index=tensor([[1,2], [0,0]])是采样得到的bipartite子图。n_id中的index对应edge_index中的数值。edge_index[1]中是target节点,bipartite子图是从target节点开始计数的,所以n_id里面永远是target节点在前几位。另外size[0]是source节点的数目,size[1]是target节点的数目,所以n_id[size[1]]可以获取target节点在原图中的id。看以下示意图:

知道了bipartite子图中的节点对应原图哪个节点后,还可以将bipartite子图中的边对应到原图中的边。看以下示意图: 

[3, 2]和边[1, 2]分别是原图中的第8,第2条边,和返回的e_id相同。

batch_size =1 ,采样邻居数大于邻居数

以下结果可以看出,当采样邻居数大于邻居数的时候,NeighborSampler不会对邻居进行随机填充,如果打算sample 4个,但neighbor nodes只有3个,那就取这三个,不会用0填充。这是因为在源码中,作者将采样的replace设置成了False

from torch_geometric.data import NeighborSampler
loader = NeighborSampler(edge_index=data.edge_index, sizes=[4], node_idx=torch.tensor([2]), batch_size=1)
next(iter(loader))
>>>(1,tensor([2, 4, 1, 3]),EdgeIndex(edge_index=tensor([[1, 2, 3],[0, 0, 0]]), e_id=tensor([10,  2,  8]), size=(4, 1)))

 batch_size = [2, 2]

from torch_geometric.data import NeighborSampler
loader = NeighborSampler(edge_index=data.edge_index, sizes=[2, 2], node_idx=torch.tensor([2]), batch_size=1)
next(iter(loader))
>>> (1,tensor([2, 4, 1, 3, 0]),[EdgeIndex(edge_index=tensor([[2, 3, 0, 3, 0, 4],[0, 0, 1, 1, 2, 2]]), e_id=tensor([2, 8, 6, 9, 4, 0]), size=(5, 3)),EdgeIndex(edge_index=tensor([[1, 2],[0, 0]]), e_id=tensor([10,  2]), size=(3, 1))])

其中EdgeIndex(edge_index=tensor([[1, 2], [0, 0]]), e_id=tensor([10, 2]), size=(3, 1))是第一层采样得到的bipartite图, EdgeIndex(edge_index=tensor([[2, 3, 0, 3, 0, 4], [0, 0, 1, 1, 2, 2]]), e_id=tensor([2, 8, 6, 9, 4, 0]), size=(5, 3))是第二层采样得到的bipartite图。
可以看出来,第二层采样是建立在第一层采样的基础上的,第一层采样bipartite中所有的节点[0, 1, 2] (在原图中对应[2, 4, 1])作为第二层采样的出发点。所以edge_index[1]有[0, 0, 1, 1, 2, 2],这是将0, 1, 2作为target节点采样两个邻居的结果。

3.2 理解 full node embedding + full edge index

参考:

使用Pytorch Geometric实现GCN、GraphSAGE和GAT - 知乎

https://github.com/DGraphXinye/2022_finvcup_baseline/tree/master/models

3.2.1 GCN
import torch
import torch.nn.functional as F
# 导入GCN层、GraphSAGE层和GAT层
from torch_geometric.nn import GCNConv, SAGEConv, GATConv
from torch_geometric.datasets import Planetoidclass GCN_NET(torch.nn.Module):def __init__(self, features, hidden, classes):super(GCN_NET, self).__init__()self.conv1 = GCNConv(features, hidden)  # shape(输入的节点特征维度 * 中间隐藏层的维度)self.conv2 = GCNConv(hidden, classes)  # shaape(中间隐藏层的维度 * 节点类别)def forward(self, data):# 加载节点特征和邻接关系x, edge_index = data.x, data.edge_index# 传入卷积层x = self.conv1(x, edge_index)x = F.relu(x)  # 激活函数x = F.dropout(x, training=self.training)  # dropout层,防止过拟合x = self.conv2(x, edge_index)  # 第二层卷积层# 将经过两层卷积得到的特征输入log_softmax函数得到概率分布return F.log_softmax(x, dim=1)
full edge index train方式:

参考:

         GCN Pytorch实现(GCN、GraphSAGE、GAT) - 知乎

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = GCN().to(device)
data = dataset[0].to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=5e-4)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()
full edge index test
model.eval()
pred = model(data).argmax(dim=1)
correct = (pred[data.test_mask] == data.y[data.test_mask]).sum()
acc = int(correct) / int(data.test_mask.sum())
print(f'Accuracy: {acc:.4f}')
>>> Accuracy: 0.8150
 3.2.2 GraphSAGE
import torch
import torch.nn.functional as F
# 导入GCN层、GraphSAGE层和GAT层
from torch_geometric.nn import GCNConv, SAGEConv, GATConv
from torch_geometric.datasets import Planetoidclass GraphSAGE_NET(torch.nn.Module):def __init__(self, feature, hidden, classes):super(GraphSAGE_NET, self).__init__()self.sage1 = SAGEConv(feature, hidden)  # 定义两层GraphSAGE层self.sage2 = SAGEConv(hidden, classes)def forward(self, data):x, edge_index = data.x, data.edge_indexx = self.sage1(x, edge_index)x = F.relu(x)x = F.dropout(x, training=self.training)x = self.sage2(x, edge_index)return F.log_softmax(x, dim=1)
3.2.3 GAT
import torch
import torch.nn.functional as F
# 导入GCN层、GraphSAGE层和GAT层
from torch_geometric.nn import GCNConv, SAGEConv, GATConv
from torch_geometric.datasets import Planetoidclass GAT_NET(torch.nn.Module):def __init__(self, features, hidden, classes, heads=4):super(GAT_NET, self).__init__()self.gat1 = GATConv(features, hidden, heads=4)  # 定义GAT层,使用多头注意力机制self.gat2 = GATConv(hidden*heads, classes)  # 因为多头注意力是将向量拼接,所以维度乘以头数。def forward(self, data):x, edge_index = data.x, data.edge_indexx = self.gat1(x, edge_index)x = F.relu(x)x = F.dropout(x, training=self.training)x = self.gat2(x, edge_index)return F.log_softmax(x, dim=1)

4. PyG 实现的 GNN models

4.1  基于MessagePassing + propagate 构建的GCN模型

参考:

        图神经网络之神器——PyTorch Geometric 上手 & 实战 - 知乎

MessagePassing本质上是自己写模型,而不是调用现成的包!

self.propagete机制是自动调用message函数!

import torch
from torch_geometric.nn import MessagePassing
from torch_geometric.utils import add_self_loops, degreeclass GCNConv(MessagePassing):def __init__(self, in_channels, out_channels):super(GCNConv, self).__init__(aggr='add')  # "Add" aggregation.self.lin = torch.nn.Linear(in_channels, out_channels)def forward(self, x, edge_index):# x has shape [N, in_channels]# edge_index has shape [2, E]# Step 1: Add self-loops to the adjacency matrix.edge_index, _ = add_self_loops(edge_index, num_nodes=x.size(0))# Step 2: Linearly transform node feature matrix.x = self.lin(x)# Step 3-5: Start propagating messages.return self.propagate(edge_index, size=(x.size(0), x.size(0)), x=x)def message(self, x_j, edge_index, size):# x_j has shape [E, out_channels]# Step 3: Normalize node features.row, col = edge_indexdeg = degree(row, size[0], dtype=x_j.dtype)deg_inv_sqrt = deg.pow(-0.5)norm = deg_inv_sqrt[row] * deg_inv_sqrt[col]return norm.view(-1, 1) * x_jdef update(self, aggr_out):# aggr_out has shape [N, out_channels]# Step 5: Return new node embeddings.return aggr_out

4.2 Graph Transformer with mini-batch edge_index

mport torch
import torch.nn as nn
import torch.nn.functional as F
from torch_geometric.nn import GATConv, GCNConv, TransformerConv  # PyG封装好的GATConv函数
from torch_geometric.nn.inits import glorot, ones, zerosfrom torch.nn import Linear, BatchNorm1d, Sequential, ModuleList, ReLU, Dropout, ELUclass GraphFormer(nn.Module):'''adopt this module when using mini-batch'''def __init__(self, in_dim, hid_dim, out_dim, heads) -> None:  # in_dim, 302; hid_dim, 128; out_dim, 64, heads, 4super(GraphFormer, self).__init__()self.GraphFormer1 = TransformerConv(in_channels=in_dim, out_channels=hid_dim, heads=heads, dropout=0.5)  # 这只是__init__函数声明变量self.GraphFormer2 = TransformerConv(in_channels=hid_dim * heads, out_channels=hid_dim, dropout=0.5)  # 隐藏层维度,输出维度64self.GraphFormer3 = TransformerConv(in_channels=hid_dim, out_channels=out_dim, dropout=0.5)  # 隐藏层维度,输出维度64self.layers = ModuleList([self.GraphFormer1, self.GraphFormer2, self.GraphFormer3])self.norm = BatchNorm1d(heads * hid_dim)  # 将num_features那一维进行归一化,防止梯度扩散def forward(self, x, adjs, device):  # 这里的x是指batch node feature embedding, adjs是指RL_samplers 采样的batch node 子图 edgefor i, (edge_index, _, size) in enumerate(adjs):  # adjs list包含了从第L层到第1层采样的结果,adjs中子图是从大到小的。adjs(edge_index,e_id,size), edge_index是子图中的边# x: Tensor, edge_index: Tensorx, edge_index = x.to(device), edge_index.to(device)  # x: (2703, 302); (2, 53005); -> x: (1418, 512); (2, 2329)x_target = x[:size[1]]  # (1418, 302); (100, 512) Target nodes are always placed first; size是子图shape, shape[1]即子图 node number; x[:size[1], : ]即取出前n个nodex = self.layers[i]((x, x_target), edge_index)  # 这里调用的是forward函数, layers[1] output (1418, 512) out_dim * heads; layers[2] output (100, 64)if i == 0:x = self.norm(x)  # 归一化操作,防止梯度散射x = F.elu(x)  # 非线性激活函数elux = F.dropout(x, training=self.training)del edge_indexreturn x

10. Torch-geometric errors

torch_geometric报错(一): "找不到指定的模块"

problem: 兼容性错误

solution: 重装package

pip install torch-scatter==2.0.9 -f https://pytorch-geometric.com/whl/torch-1.10.0+cpu.html

Reference

  • torch_geometric.nn — pytorch_geometric documentation
  • 图神经网络 PyTorch Geometric 入门教程 - 知乎
  • pytorch geometric教程四 利用NeighorSampler实现节点维度的mini-batch + GraphSAGE样例-CSDN博客最好的一篇PyG blog
  • 使用Pytorch Geometric实现GCN、GraphSAGE和GAT - 知乎
  • 图神经网络之神器——PyTorch Geometric 上手 & 实战 - 知乎
  • GCN Pytorch实现(GCN、GraphSAGE、GAT) - 知乎

相关文章:

GNN PyG~torch_geometric 学习理解

目录 1. PyG Introduction 2. PyG Installation 2.1 PyG 安装常见错误及原因 2.2 PyG 具体安装步骤 3. torch_geometric packages torch_geometric.data.Data Dataset 与 DataLoader Dropout、BatchNorm 3. torch_geometric: 理解edge_index 3.1 理解 mini-batch edg…...

ChatGPT 调教指南:从 PDF 提取标题并保存

一、请使用python编写一段代码,使用pymupdf包从pdf中提取标题,保存标题名称和页数。 我没有加任何的答案提示,看看 GPT 如何反应。它应该是知道 PDF 没有任何语义信息,一切标题或者正文全是文本框。 好的,以下是使用py…...

【day10.01】使用select实现服务器并发

用select实现服务器并发&#xff1a; linuxlinux:~/study/1001$ cat server.c #include <myhead.h>#define ERR_MSG(msg) do{\printf("%d\n",__LINE__);\perror(msg);\ }while(0)#define PORT 8880#define IP "192.168.31.38"int main(int argc, c…...

Android修行手册 - Activity 在 Java 和 Kotlin 中怎么写构造参数

点击跳转>Unity3D特效百例点击跳转>案例项目实战源码点击跳转>游戏脚本-辅助自动化点击跳转>Android控件全解手册点击跳转>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&…...

【IPC 通信】信号处理接口 Signal API(7)

收发信号思想是 Linux 程序设计特性之一&#xff0c;一个信号可以认为是一种软中断&#xff0c;通过用来向进程通知异步事件。 本文讲述的 信号处理内容源自 Linux man。本文主要对各 API 进行详细介绍&#xff0c;从而更好的理解信号编程。 exit(5) 遵循 C11&#xff0c; POSI…...

springboot和vue:十二、VueRouter(动态路由)+导航守卫

VueRouter的简介 VueRouter是官方的路由插件&#xff0c;适合单页面应用/网页的切换。VueRouter目前有3.x版本和4.x版本&#xff0c;3.x版本只能结合vue2使用&#xff0c;4.x版本只能结合vue3使用。安装&#xff1a;npm install vue-router3 目的 初始版本&#xff1a;我们想…...

文心一言 VS 讯飞星火 VS chatgpt (103)-- 算法导论10.1 1题

一、用go语言&#xff0c;仿照图 10-1&#xff0c;画图表示依次执行操作 PUSH(S&#xff0c;4)、PUSH(S&#xff0c;1)、PUSH(S&#xff0c;3)、POP(S)、PUSH(S&#xff0c;8)和 POP(S)每一步的结果&#xff0c;栈 S初始为空&#xff0c;存储于数组 S[1…6]中。 文心一言&…...

【ShaderLab罪恶装备卡通角色_二次元风格_“Sol Badguy“_角色渲染(第二篇)】

罪恶装备背德之炎卡通角色_二次元风格_Unity 角色渲染 角色初始效果&#xff1a;基础渲染SimpleBas 资源分析模型顶点颜色&#xff1a; 贴图资源SOL_base_基础色块效果&#xff1a;其中SOL_base_A通道的效果&#xff1a; SOL_ilm&#xff1a;如下SOL_ilm模型上区域分布- 左到右…...

raw智能照片处理工具DxO PureRAW mac介绍

DxO PureRAW Mac版是一款raw智能照片处理工具&#xff0c;该软件采用了智能技术&#xff0c;以解决影响所有RAW文件的七个问题&#xff1a;去马赛克&#xff0c;降噪&#xff0c;波纹&#xff0c;变形&#xff0c;色差&#xff0c;不想要的渐晕&#xff0c;以及缺乏清晰度。 Dx…...

1.centos7 安装显卡驱动、cuda、cudnn

安装conda 参考 python包 2.安装conda python库-CSDN博客3.Cenots Swin-Transformer-Object-Detection环境配置-CSDN博客 1.安装显卡驱动 步骤1&#xff1a;安装依赖 yum -y install kernel-devel yum -y install epel-release yum -y install gcc 步骤2&#xff1a;查询显…...

WordPress主题开发( 十四)之—— 主题开发示例

要深入了解WordPress主题开发的最佳实践和标准&#xff0c;参考主题示例是一种非常有效的方法。在这里&#xff0c;我们将介绍两个主题示例&#xff1a;默认的Twenty主题和Underscores主题&#xff0c;它们都是出色的学习资源。 默认“Twenty”主题 自WordPress 3.0版本开始&a…...

rust学习-any中的downcast和downcast_ref

背景 看rust官方文档,好奇Any和Go的Any是否是一回事,看到下文的一行代码,了解下它的功能 pub trait Any: static {// Required methodfn type_id(&self) -> TypeId; }std::any 用于 dynamic typing 或者 type reflection 模拟动态类型的trait。 大多数类型都实现 …...

js检测数据类型总结

目录 一、typeof 二、instanceof 三、constructor 四、Object.prototype.toString.call() Object.prototype.toString.call(obj)类型检测原理 五、__proto__ 六、 其他 一、typeof typeof在对值类型number、string、boolean 、symbol、 undefined、 function的反应是精准…...

获奖作品展示 | 2023嵌入式大赛AidLux系列作品精彩纷呈

第六届&#xff08;2023&#xff09;全国大学生嵌入式芯片与系统设计竞赛应用赛道全国总决赛已于8月下旬圆满结束。 本届赛事中&#xff0c;AidLux是广和通5G智能物联网赛题的唯一软件支持&#xff0c;阿加犀为该赛题学生们提供了全程线上辅导、技术答疑&#xff0c;以及大赛专…...

Mybatis 二级缓存(使用Redis作为二级缓存)

上一篇我们介绍了mybatis中二级缓存的使用&#xff0c;本篇我们在此基础上介绍Mybatis中如何使用Redis作为二级缓存。 如果您对mybatis中二级缓存的使用不太了解&#xff0c;建议您先进行了解后再阅读本篇&#xff0c;可以参考&#xff1a; Mybatis 二级缓存https://blog.csd…...

VMware vSphere ESXI 6.7 U3封装RTL8125B网卡驱动

之前的教程VMware vSphere ESXI 6.7 U3最新版本封装网卡驱动补丁可参考&#xff0c;本文为此文章的又一次实践 准备工作 1、ESXi-Customizer-PS-v2.6.0.ps1 &#xff08;官网下载&#xff0c;Github下载&#xff09; 2、ESXi670-202210001.zip &#xff08;VMware vSphere Hy…...

黑马JVM总结(二十五)

&#xff08;1&#xff09;字节码指令-cinit 构造方法可以分为两类&#xff0c;一类是cinit 一类init cinit是整个类的构造方法 putstatic&#xff1a;进行static变量的赋值&#xff0c;是到常量池里找到名字一个叫做i的变量 &#xff08;2&#xff09;字节码指令-init in…...

基础数据结构之——【顺序表】(上)

从今天开始更新数据结构的相关内容。&#xff08;我更新博文的顺序一般是按照我当前的学习进度来安排&#xff0c;学到什么就更新什么&#xff08;简单来说就是我的学习笔记&#xff09;&#xff0c;所以不会对一个专栏一下子更新到底&#xff0c;哈哈哈哈哈哈哈&#xff01;&a…...

Apollo自动驾驶系统概述(文末参与活动赠送百度周边)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…...

Java 21 新特性:Unnamed Classes and Instance Main Methods

Java 21引入了两个语言核心功能&#xff1a; 未命名的Java类你说新的启动协议&#xff1a;该协议允许更简单地运行Java类&#xff0c;并且无需太多样板 下面一起来看个例子。通常&#xff0c;我们初学Java的时候&#xff0c;都会写类似下面这样的 Hello World 程序&#xff1…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数

高效线程安全的单例模式:Python 中的懒加载与自定义初始化参数 在软件开发中,单例模式(Singleton Pattern)是一种常见的设计模式,确保一个类仅有一个实例,并提供一个全局访问点。在多线程环境下,实现单例模式时需要注意线程安全问题,以防止多个线程同时创建实例,导致…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

Caliper 配置文件解析:fisco-bcos.json

config.yaml 文件 config.yaml 是 Caliper 的主配置文件,通常包含以下内容: test:name: fisco-bcos-test # 测试名称description: Performance test of FISCO-BCOS # 测试描述workers:type: local # 工作进程类型number: 5 # 工作进程数量monitor:type: - docker- pro…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

软件工程 期末复习

瀑布模型&#xff1a;计划 螺旋模型&#xff1a;风险低 原型模型: 用户反馈 喷泉模型:代码复用 高内聚 低耦合&#xff1a;模块内部功能紧密 模块之间依赖程度小 高内聚&#xff1a;指的是一个模块内部的功能应该紧密相关。换句话说&#xff0c;一个模块应当只实现单一的功能…...