文章说明:
1)参考资料:PYG的文档。文档超链。
2)博主水平不高,如有错误还望批评指正。
导入对应的库
from torch_geometric.data import Data
import torch
创建图数据的第一种方式,简单易懂不过多的赘述
edge_index=torch.tensor([[0,1,1,2],[1,0,2,1]],dtype=torch.long)
x=torch.tensor([[-1],[0],[1]],dtype=torch.float)
data=Data(x=x,edge_index=edge_index)
data
#输出:Data(x=[3, 1], edge_index=[2, 4])
创建图数据的第二种方式,简单易懂不过多的赘述
edge_index=torch.tensor([[0,1],[1,0],[1,2],[2,1]],dtype=torch.long)
x=torch.tensor([[-1],[0],[1]],dtype=torch.float)
data=Data(x=x,edge_index=edge_index.t())
data
#输出:Data(x=[3, 1], edge_index=[2, 4])
打印一些常见关于图的性质
print(data.keys)
#打印图所有键
#输出:['edge_index', 'x']
print(data['x'])
#打印节点特征向量
#输出:
#tensor([[-1.],
# [ 0.],
# [ 1.]])
print(data['edge_index'])
#打印边的稀疏矩阵
#输出:
#tensor([[0, 1, 1, 2],
# [1, 0, 2, 1]])
data.num_nodes
#打印节点个数
#输出:3
data.num_edges
#打印边的条数
#输出:4
data.num_node_features
#打印节点特征维度
#输出:1
data.has_isolated_nodes()
#判断是否有孤立点
#输出:FALSE
data.has_self_loops()
#判断是否有自循环
#输出:FALSE
data.is_undirected()
#判断是否为无向图
#输出:True
device=torch.device('cuda')
data=data.to(device)
#把数据放在GPU
其他说明:
1)孤立点是与其他点没边连接的点。
2)自循环是自己连自己。
3)无向图是边没方向的图。可以通过以下两种方式进行判断:data.is_undirected() or data.is_directed()。实际操作使用一种即可,毕竟,是等效的。
导入对应的库:数据集1
from torch_geometric.datasets import TUDataset
dataset=TUDataset(root='/DATA/ENZYMES',name='ENZYMES')
ENZYMES数据集简单说明:首先它包含600个图,然后每个图代表一个酶,这个酶被人工标记为了6类,具体怎么分类我们并不关心,接着,每个酶有节点(化学原子),有图(原子间化学键)。
其他说明:这段代码会在C盘,生成一个叫做DATA的文件,并将数据集放在DATA之中,有强迫症注意一下。
打印这个数据集的信息:数据集1
len(dataset)
#输出:600
dataset.num_classes
#输出:6
dataset.num_node_features
#输出:3
data=dataset[0]
#具体观察第一个图
data.is_undirected()
#输出:True
train_dataset=dataset[:540]
test_dataset=dataset[540:]
#训测划分
dataset1=dataset.shuffle()
#打乱数据集第一种方法
perm=torch.randperm(len(dataset))
dataset2=dataset[perm]
#打乱数据集第二种方法
导入对应的库:数据集2
from torch_geometric.datasets import Planetoid
dataset=Planetoid(root='/DATA/Cora',name='Cora')
Cora数据集简单说明:图神经网络数据集的御三家之一。首先,这个数据集包含一个图,然后,具体看这个图。
特征矩阵:N x M,N表示论文的数量。M表示特征的维度,具体来说:1433维,每个维度代表一个单词是否在这篇论文中,在就是1,不在是0。邻接矩阵:N x N,N表示论文的数量,如果论文a引用论文b,则Matrix[a,b]=1,否则为0。标签:N,N表示论文的数量。论文被分为了7类,比如:生物论文,化学论文,机器学习等等。这里打个比方,实际不是这样分的,但是实际我们并不关注这些。
其他说明:这段代码会在C盘,生成一个叫做DATA的文件,并将数据集放在DATA之中,有强迫症注意一下。
打印这个数据集的信息:数据集2
len(dataset)
#数据集中图的个数
#输出:1
dataset.num_classes
#数据集节点的类别
#输出:7
data=dataset[0]
#具体查看第一个图,这里有且仅有一个图哦
data.is_undirected()
#不解释了,输出:True
data.train_mask.sum().item()
data.val_mask.sum().item()
data.test_mask.sum().item()
#训练集,验证集,测试集的数量。这里我的感觉是有函数提前划分好了。
导入对应的库
from torch_geometric.loader import DataLoader
导入数据集并且进行小批量划分
dataset=TUDataset(root='/DATA/ENZYMES',name='ENZYMES',use_node_attr=True)
loader=DataLoader(dataset,batch_size=32,shuffle=True)
代码说明:1)第一行的代码使用数据集1,use_node_atte为使用节点信息,默认是False,即不使用节点信息。2)第二行的代码,小批量的划分并且进行顺序打乱,其目的是加快推理。具体来说假如这个数据集中,有68个图,第一个小批量有32个图,第二个小批量有32个图,第三个小批量有4个图。
打印每个小批量的信息
for batch in loader:
print(batch)
print(batch.num_graphs)
#输出每个小批量的信息
#输出每个小批量图个数
#最后三次循环输出
#DataBatch(edge_index=[2, 3880], x=[1032, 21], y=[32], batch=[1032], ptr=[33])
#32
#DataBatch(edge_index=[2, 3476], x=[892, 21], y=[32], batch=[892], ptr=[33])
#32
#DataBatch(edge_index=[2, 2954], x=[734, 21], y=[24], batch=[734], ptr=[25])
#24
edge_index: 2 x M,第一行为起点,第二行为终点,M表示为边的数量,一条边的起点终点在对应的数组索引是相同的,其实就是表示临接矩阵的Coo_Matirx格式。
具体这里:比如这里倒数第三个小批量有32个图,那么这个edge_index就存储32个图边信息,图图之间显然是不连通。
x: N x F,N表示节点的数量,F表示节点特征的维度。
具体这里:比如这里倒数第三个图以及倒数第二个图N不一样。博主认为不同的酶化学原子个数的确是有不同,我们在进行小批量的划分时是随机的,每个小批量的不同种类的酶个数不一,所以导致不同小批量的N不一样。
y: 1 x Batch_Size,Batch_Size表示小批量大小。
具体这里:除了最后一个小批量其他所有小批量均32,最后一个不满32为24
batch: 1 x N,N表示节点数量。
具体这里:batch的N以及x的N是相同的,这个batch反映了x中节点属于哪个种类的图。打个比方:一共3个种类,这个batch_size大小为5,假设batch就为[3,2,3,1,1],表示第一个点属于类别为3的图,第二个点属于类别为2的图,第三个点属于类别为3的图,第四个点属于类别为1的图,第五个点属于类别为1的图。
ptr: 1 x (Batch_Size+1),Batch_Size表示小批量大小。
具体这里:举个例子:ptr就为[0,100,1000,5000]。x[0,100]的节点属于第零个图,x[100,1000]的节点属于第一个图,x[1000,5000]的节点属于第二个图。抽象出来,x[ptr[i],ptr[i+1]]表示x从ptr[i]到ptr[i+1]的点属于第i个图。
导入对应的库:
from torch_geometric.utils import scatter
执行平均操作并且打印信息
for data in loader:
x=scatter(data.x,data.batch,dim=0,reduce='mean')
print(x)
#输出请看:“具体来说”
具体来说:举个例子:Data( x=[[1.0], [2.0], [3.0], [4.0], [5.0], [6.0]], batch=[0, 0, 0, 1, 1, 1]) 注意:这里我的数据信息没有给全,例如没给边的信息。这里只是帮助理解。前三个点属于第0个图;后三个点属于第1个图。执行程序之后输出就应该为tensor([ [2.] , [5.] ])表示第0个图特征向量均值为2,第1个图特征向量均值为5。
导入对应的库:数据集3
from torch_geometric.datasets import ShapeNet
dataset=ShapeNet(root='/DATA/ShapeNet',categories=['Airplane'])
ShapeNet数据集简单说明:就是三维模型点云。什么是点云呢?博主认为就是很多个点密密麻麻构成了这个3D模型,然后称之为点云吧。具体这里我们使用ShapeNet中的Airplane。显然这里是没有图。
其他说明:这段代码会在C盘,生成一个叫做DATA的文件,并将数据集放在DATA之中,有强迫症注意一下。
图的生成
import torch_geometric.transforms as T
dataset=ShapeNet(root='/DATA/ShapeNet',categories=['Airplane'],pre_transform=T.KNNGraph(k=6))
然后我们使用这段代码通过最邻算法构建了图。需要注意的是:一旦执行过了一次这个代码,那么原始数据就被更换为了变换后的数据。下次使用就不用变换了。这是来自官方警告,可能我理解有问题。 原话是这样的”
We use the pre_transform to convert the data before saving it to disk (leading to faster loading times). Note that the next time the dataset is initialized it will already contain graph edges, even if you do not pass any transform. If the pre_transform does not match with the one from the already processed dataset, you will be given a warning.“
目前来说,遇到两个图神经网络可以解决的问题:一个是对图的节点进行分类,一个是直接去对图进行分类。