当前位置: 首页 > 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…...

Tomcat启动后的日志输出为乱码

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

CSP-J第二轮试题-2021年-4题

文章目录 参考&#xff1a;总结 [CSP-J 2021] 小熊的果篮题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 样例 #3样例输入 #3样例输出 #3 提示答案答案1答案2答案3 现场真题注意事项 参考&#xff1a; https://www.luogu.com.cn/probl…...

10.1 今日任务:select实现服务器并发

#include <myhead.h>#define ERR_MSG(msg) do{\fprintf(stderr, "__%d__:", __LINE__); \perror(msg);\ }while(0)#define PORT 8888 //端口号&#xff0c;范围1024~49151 #define IP "192.168.112.115" //本机IP&#xff0c;ifco…...

P1540 [NOIP2010 提高组] 机器翻译(模拟)

[NOIP2010 提高组] 机器翻译 题目背景 小晨的电脑上安装了一个机器翻译软件&#xff0c;他经常用这个软件来翻译英语文章。 题目描述 这个翻译软件的原理很简单&#xff0c;它只是从头到尾&#xff0c;依次将每个英文单词用对应的中文含义来替换。对于每个英文单词&#xf…...

生信教程:ABBA-BABA分析之滑动窗口

简介 ABBA BABA 统计&#xff08;也称为 D 统计&#xff09;为偏离严格的分叉进化历史提供了简单而有力的检验。因此&#xff0c;它们经常用于使用基因组规模的 SNP 数据测试基因渗入。 虽然最初开发用于基因渗入的全基因组测试&#xff0c;但它们也可以应用于较小的窗口&#…...

二分答案(求最大值的最小值||求最小值的最大值)

引入 二分答案要建立在二分查找的基础上&#xff0c;在此之前&#xff0c;要知道二分查找的三个模板 模板一 while(l<r) {int mid(lr)>>1;if(check(mid)) rmid;else lmid1; }模板二 while(l<r) {int midlr1>>1;if(check(mid)) lmid;else rmid-1; }模板三…...

思维模型 周期

本系列文章 主要是 分享 思维模型&#xff0c;涉及各个领域&#xff0c;重在提升认知。周期是一个看似极为简单&#xff0c;但背后却蕴藏着大智慧的模型&#xff0c;了解周期&#xff0c;对于了解王朝更替&#xff0c;数学之美&#xff0c;经济运转等都有帮助。 1 周期的应用 …...

从 0 到 1 ,手把手教你编写《消息队列》项目(Java实现) —— 介绍项目/ 需求分析

文章目录 一、消息队列是什么&#xff1f;二、需求分析结构解析功能解析规则解析绑定关系交换机类型消息应答 三、持久化存储四、网络通信提供的API复用TCP连接 五、消息队列概念图 一、消息队列是什么&#xff1f; 消息队列 (Message Queue, MQ)就是将阻塞队列这一数据结构提取…...

Python学习之索引与切片

Python学习之索引与切片 s “0abcdefghijklmnopqrstuvwxyz”&#xff0c;第一个元素‘0’&#xff0c;索引号为0&#xff0c;最后一个元素‘z’&#xff0c;索引号为26 1. s[0]获取索引号为0的元素 2. s[1:3]获取索引号为1的元素&#xff0c;直到但不包括索引号为3的元素。即…...

编程每日一练(多语言实现)基础篇:满足abcd=(ab+cd)^2的数 (增加Go语言实现)

文章目录 一、实例描述二、技术要点三、代码实现3.1 C 语言实现3.2 Python 语言实现3.3 Java 语言实现3.4 JavaScript 语言实现3.5 Go 语言实现 一、实例描述 假设 abcd 是一个四位整数&#xff0c;将它分成两段&#xff0c;即 ab 和 cd&#xff0c;使之相加求和后再平方。求满…...

网站建设实训个人总结3000字/上海专业seo

为什么80%的码农都做不了架构师&#xff1f;>>> 最近公司业务上使用webservice 频繁。由于之前都是自己搭建webservice 自己定义提供给别人服务&#xff0c;现在则相反需求都是根据人家提供的wsdl 文件来生成 我们平台需要提供的接口。刚开始不知道如何生成&#x…...

网站引导页下载/营销咨询公司排名前十

题目&#xff1a; 本题要求计算 A/B&#xff0c;其中 A 是不超过 1000 位的正整数&#xff0c;B 是 1 位正整数。你需要输出商数 Q 和余数 R&#xff0c;使得 ABQR 成立。 输入格式&#xff1a; 输入在一行中依次给出 A 和 B&#xff0c;中间以 1 空格分隔。 输出格式&#xff…...

真正免费的网站建站平台一/宁德市委书记

为什么80%的码农都做不了架构师&#xff1f;>>> 日期&#xff1a;2012-8-4 来源&#xff1a;GBin1.com 昨天我们分享过一篇关于免费深色UI工具包下载的素材文章。今天给大家介绍的是一款免费的纯黑色用户界面素材下载&#xff0c;里面包括了单选按钮、复选框、开关…...

帝国建站系统/焊工培训内容

关于使用处理流的优势&#xff0c;归纳起来就是两点&#xff1a;&#xff08;1&#xff09;对于开发人员来说&#xff0c;使用处理流进行输入/输出操作更简单&#xff1b;&#xff08;2&#xff09;使用处理流执行效率更高。 1、BufferedInputStream/BufferedOutputStream和Buf…...

做电影网站赚钱的方法/目前常用的搜索引擎有哪些

在OpenGL中&#xff0c;我们通过把场景中的所有物体往反方向移动的方式来模拟相机的移动。 1.摄像机/观察空间 讨论摄像机/观察空间&#xff08;Camera/view space&#xff09;的时候&#xff0c;是在讨论以摄像机的视角作为场景原点时场景中所有的顶点坐标&#xff1a;观察矩…...

项目计划书包含哪些内容/站长工具查询seo

不说太多虚的&#xff0c;这次要聊的&#xff0c;是JavaScript的三种事件绑定方式。方法1&#xff1a;直接在HTML中指定&#xff0c;称为“内嵌”会不会更合适一点&#xff1f;(1)直接在HTML的属性里写代码示例代码&#xff1a;<button onclick"alert(我我我)">…...