Task01 简单图论与环境配置与PyG库
简单图论
图论是数学的一个分支。它以图为研究对象。图论中的图是由若干给定的点及连接两点的线所构成的图形,这种图形通常用来描述某些事物之间的某种特定关系,用点代表事物,用连接两点的线表示相应两个事物间具有这种关系。
图论常见的定义
定义一:图
一些元素及它们之间的某种关系称为图。一个图被记作G={
ν
\nu
ν,
ε
\varepsilon
ε}。其中
ν
\nu
ν={
ν
i
\nu_i
νi},i
∈
\in
∈N,N为节点个数。
ε
\varepsilon
ε={
e
i
e_i
ei},i
∈
\in
∈M,M为边个数。
如给定G={
ν
\nu
ν,
ε
\varepsilon
ε}。
ν
\nu
ν={
ν
1
\nu_1
ν1,
ν
2
\nu_2
ν2,
ν
3
\nu_3
ν3},
ε
\varepsilon
ε={
e
1
e_1
e1,
e
2
e_2
e2,
e
3
e_3
e3}={(
ν
1
\nu_1
ν1,
ν
2
\nu_2
ν2),(
ν
2
\nu_2
ν2,
ν
3
\nu_3
ν3),(
ν
3
\nu_3
ν3,
ν
1
\nu_1
ν1)},这便定义了一个图。
定义二:无向图与有向图
有向与无向直接去区别是,节点与节点直接连接的边是不是有方向的。无方向称为无向图。反之亦然。
定义三:邻接矩阵
邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵。其对应的邻接矩阵被记为A。A的大小为 N × N\times N× N N N。 a i j a_{ij} aij的值为基于 ν i \nu_i νi到 ν j \nu_j νj的关系自己定义的值。如常见的定义连接为1,不连接为0。即A ∈ { 0 , 1 } N × N \in\{0,1\}^{N\times N} ∈{0,1}N×N。
定义四:节点的度
节点度是指和该节点相关联的边的条数,又称关联度。对于有向图,节点的入度是指进入该节点的边的条数。节点的出度是指从该节点出发的边的条数。节点 ν i \nu_i νi的度记 d ( ν i ) d(\nu_i) d(νi)。
定义五:拉普拉斯矩阵
图的拉普拉斯矩阵定义为: L = D − A L=D-A L=D−A。其中D为对角矩阵, D = d i a g ( d ( ν 1 ) , . . . , d ( ν n ) ) D=diag(d(\nu_1) ,...,d(\nu_n) ) D=diag(d(ν1),...,d(νn))。A为邻接矩阵。归一化的拉普拉斯矩阵为 L = D − 1 2 ( D − A ) D − 1 2 L=D^{-\frac{1}{2}}(D-A)D^{-\frac{1}{2}} L=D−21(D−A)D−21。
图的基本分类
同质图:只有一种类型的节点和一种类型的边的图。
异质图:存在多种类型的节点和多种类型的边的图。
二部图:节点分为两类,只有不同类的节点之间存在边。
环境的配置
安装pytorch
进入pytorch官网下载选择合适的版本安装即可。
安装PyG
进入PyG的文档介绍,选择合适版本,安装PyG文档指导安装即可。
PyG-Data类
在PyG-Data类官方文档,Data类需要传递参数为:x=None, edge_index=None, edge_attr=None, y=None, pos=None, normal=None, face=None, **kwargs。通常,一个图至少包含x, edge_index, edge_attr, y, num_nodes 5个属性。简易版的Data构造类如下:
class Data(object):
r"""A plain old python object modeling a single graph with various
(optional) attributes:
Args:
x (Tensor, optional): Node feature matrix with shape :obj:`[num_nodes,
num_node_features]`. (default: :obj:`None`)
edge_index (LongTensor, optional): Graph connectivity in COO format
with shape :obj:`[2, num_edges]`. (default: :obj:`None`)
edge_attr (Tensor, optional): Edge feature matrix with shape
:obj:`[num_edges, num_edge_features]`. (default: :obj:`None`)
y (Tensor, optional): Graph or node targets with arbitrary shape.
(default: :obj:`None`)
The data object is not restricted to these attributes and can be extented
by any other additional data.
Example::
data = Data(x=x, edge_index=edge_index)
"""
def __init__(self, x=None, edge_index=None, edge_attr=None, y=None, **kwargs):
self.x = x
self.edge_index = edge_index
self.edge_attr = edge_attr
self.y = y
for key, item in kwargs.items():
if key == 'num_nodes':
self.__num_nodes__ = item
else:
self[key] = item
if edge_index is not None and edge_index.dtype != torch.long:
raise ValueError(
(f'Argument `edge_index` needs to be of type `torch.long` but '
f'found type `{edge_index.dtype}`.'))
其中edge_index需要注意是LongTensor,是coo格式。
PyG-Dataset类
PyG内置了大量常用的基准数据集,接下来我们以PyG内置的Planetoid 数
据集为例,来学习PyG中图数据集的表示及使用。
from torch_geometric.datasets import Planetoid
dataset = Planetoid(root='/dataset/Cora', name='Cora')
data = dataset[0]
data
结果显示为:Data(edge_index=[2, 10556], test_mask=[2708], train_mask=[2708], val_mask=[2708], x=[2708, 1433], y=[2708])。
通过以下命令可以查看节点、边等的个数。
print(len(dataset))
print(dataset.num_classes)
print(dataset.num_node_features)
print(data.train_mask.sum().item())
print(data.val_mask.sum().item())
print(data.test_mask.sum().item())
看到该数据集包含的唯一的图,有2708个节点,节点特征为1433维,有10556条边,有140个用作训练集的节点,有500个用作验证集的节点,有1000个用作测试集的节点。
作业
请通过继承Data类实现一个类,专门用于表示“机构-作者-论文”的网
络。该网络包含“机构“、”机构“和”论文”三类节点,以及“作者-机构“和 “作者-论文“两类边。对要实现的类的要求:1)用不同的属性存储不同节点的属性;2)用不同的属性存储不同的边(边没有属性);3)逐一实现获取不同节点数量的方法。
假设:机构、机构、论文节点的值分别为[1,0,0]、[0,1,0]、[0,0,1]。
导入相关库和包:
import torch
from torch_geometric.data import Data
自定义一个图,有5个节点、2个机构、2个作者、1篇论文。
x = torch.tensor([[1,0,0],[0,1,0],[0,0,1],[0,1,0],[1,0,0]],dtype=torch.float)
edge_index = torch.tensor([[0,1,0,2,3],
[1,4,3,1,4]],dtype=torch.long)
edge_attr = torch.tensor([[1,0],[1,0],[1,0],[0,1],[1,0]])
data = Data(x=x,edge_index=edge_index,edge_attr=edge_attr)
data
#Data(edge_attr=[5, 2], edge_index=[2, 5], x=[5, 3])
通过继承Data类构建一个类
class Mydata(Data):
def __init__(self, x=None, edge_index=None, edge_attr=None,**kwargs):
super(Mydata,self).__init__()
self.x = x
self.edge_index = edge_index
self.edge_attr = edge_attr
for key,item in kwargs.items():
self[key] = item
#统计不同的节点个数
def get_note_num(self,str):
num = 0
for i in range(self.num_nodes):
if torch.sum(torch.sqrt(self[str] - self.x[i]))==0:
num += 1
print('Number of '+str+' : %d'%(num))
return num
测试如下:
note_in = {'agency':torch.tensor([1,0,0],dtype=torch.float),
'author':torch.tensor([0,1,0],dtype=torch.float),
'paper':torch.tensor([0,0,1],dtype=torch.float)}
data1 = Mydata(x=x,edge_index=edge_index,edge_attr=edge_attr,**note_in)
data1.get_note_num('agency')
#Number of agency : 2
data1.get_note_num('paper')
#Number of paper : 1
完整代码如下:
import torch
from torch_geometric.data import Data
x = torch.tensor([[1,0,0],[0,1,0],[0,0,1],[0,1,0],[1,0,0]],dtype=torch.float)
edge_index = torch.tensor([[0,1,0,2,3],
[1,4,3,1,4]],dtype=torch.long)
edge_attr = torch.tensor([[1,0],[1,0],[1,0],[0,1],[1,0]])
class Mydata(Data):
def __init__(self, x=None, edge_index=None, edge_attr=None,**kwargs):
super(Mydata,self).__init__()
self.x = x
self.edge_index = edge_index
self.edge_attr = edge_attr
for key,item in kwargs.items():
self[key] = item
#统计不同的节点个数
def get_note_num(self,str):
num = 0
for i in range(self.num_nodes):
if torch.sum(torch.sqrt(self[str] - self.x[i]))==0:
num += 1
print('Number of '+str+' : %d'%(num))
return num
note_in = {'agency':torch.tensor([1,0,0],dtype=torch.float),
'author':torch.tensor([0,1,0],dtype=torch.float),
'paper':torch.tensor([0,0,1],dtype=torch.float)}
data1 = Mydata(x=x,edge_index=edge_index,edge_attr=edge_attr,**note_in)
data1.get_note_num('agency')
参考文献
[1] https://pytorch-geometric.readthedocs.io/en/latest/index.html
[2] https://blog.csdn.net/stark_summer/article/details/49050079
[3] https://github.com/datawhalechina/team-learning-nlp/tree/master/GNN