存储图的类:dgl.DGLGraph
创建图的函数:dgl.graph()
首先创建边:0->1, 0->2, 0->3, 1->3
import torch u, v = torch.tensor([0,0,0,1]), torch.tensor([1,2,3,3])在dgl的图中,所有边都是有向的,如果要创建无向图,需要创建双向边
import torch src, dst = torch.tensor([0,0,0,1]), torch.tensor([1,2,3,3]) u = torch.cat((src,dst)) v = torch.cat((dst,src))创建图
import dgl g = dgl.graph((u,v))除了通过双向边外,还可通过dgl.to_bidirected直接由单向图创建双向图
bg = dgl.to_bidirected(g)如果在图中有没有边链接的点,需要通过graph函数的num_nodes属性指定有多少单点
# 有4个edge,总共有8个点,则有4个单点 g = dgl.graph((u, v), num_nodes=8)通过ndata与edata可以指定节点与边的特征
"建图" g = dgl.graph(([0, 0, 1, 5], [1, 2, 2, 0])) # 6 nodes, 4 edges "指定特征" g.ndata['x']=torch.ones(g.num_nodes(), 3) g.ndata['y']=torch.randn(g.num_nodes(),5) # 不同名字可以有不同的特征 g.edata['x']=torch.ones(g.num_edges(),dtype=torch.int32) "查看特征" print(g.ndata) # 输出dict {'x':tensor, 'y':tensor} print(g.edata) # {'x': tensor([1, 1, 1, 1], dtype=torch.int32)} print(g.ndata['x'][1]) # tensor([1., 1., 1.]) print(g.edata['x'][torch.tensor([0, 3])]) # 查看第0和3号的特征 # tensor([1, 1], dtype=torch.int32)注意事项:
只有数字类型可以做特征(e.g., float, double, and int),特征可以是标量,向量,矩阵或多维张量点特征之间,边特征之间名字要不同,但点特征与边特征之间名字可以相同无法给点/边的子集设置特征,特征tensor的最高维必须等于点/边数特征张量是row-major的,即每一行是一个点/边的特征对于有权图,可将权值作为图的边特征存储
# edges 0->1, 0->2, 0->3, 1->3 edges = th.tensor([0, 0, 0, 1]), th.tensor([1, 2, 3, 3]) weights = th.tensor([0.1, 0.6, 0.9, 0.7]) # weight of each edge g = dgl.graph(edges) g.edata['w'] = weights print(g) # Graph(num_nodes=4, num_edges=4, # ndata_schemes={} # edata_schemes={'w' : Scheme(shape=(,), dtype=torch.float32)})指点/边有不同的类型,每种类型可以有独立的ID及特征,如下图所示,该图有两种类型的节点:User与Game,两种类型有各自的特征,且ID均从0开始
dgl中,每个关系指定一个图,异质图将由多个关系的图组成
首先,每个关系写成一个三元组(原节点类型,关系类型,目标节点类型),如('drug', 'treats', 'disease') 该关系称为规范边类型(canonical edge types)
接着写出图数据,该数据中每个关系都对应一个图
{relation1 : (u, v), relation2 : (u, v), ...}最后,使用dgl.heterograph()创建异质图
import torch as th import dgl # Create a heterograph with 3 node types and 3 edges types. graph_data = { ('drug', 'interacts', 'drug'): (th.tensor([0, 1]), th.tensor([1, 2])), ('drug', 'interacts', 'gene'): (th.tensor([0, 1]), th.tensor([2, 3])), ('drug', 'treats', 'disease'): (th.tensor([1]), th.tensor([2])) } hg = dgl.heterograph(graph_data) print(hg) # Graph(num_nodes={'disease': 3, 'drug': 3, 'gene': 4}, # num_edges={('drug', 'interacts', 'drug'): 2, ('drug', 'interacts', 'gene'): 2, ('drug', 'treats', 'disease'): 1}, # metagraph=[('drug', 'drug', 'interacts'), ('drug', 'gene', 'interacts'), ('drug', 'disease', 'treats')])方法1:构建GPU上的tensor,再传给DGLGraph
>>> u, v = u.to('cuda:0'), v.to('cuda:0') >>> g = dgl.graph((u, v)) >>> g.device device(type='cuda', index=0)方法2:将DGLGraph传到GPU上
>>> u, v = th.tensor([0, 1, 2]), th.tensor([2, 3, 4]) >>> g = dgl.graph((u, v)) >>> g.ndata['x'] = th.randn(5, 3) # original feature is on CPU >>> g.device device(type='cpu') >>> cuda_g = g.to('cuda:0') # accepts any device objects from backend framework >>> cuda_g.device device(type='cuda', index=0) >>> cuda_g.ndata['x'].device # feature data is copied to GPU too device(type='cuda', index=0)Scipy sparse matrix 作为图的邻接矩阵 转换成dgl的图 : g = dgl.from_scipy(sp.g) Networkx graph : g = dgl.from_networkx(nx.g)
import dgl import scipy.sparse as sp sp_g = sp.rand(100, 100, density=0.5) # 5% nonzero entries g = dgl.from_scipy(sp_g) print(g) # Graph(num_nodes=100, num_edges=5000, # ndata_schemes={} # edata_schemes={}) import networkx as nx nxg = nx.path_graph(5) # a chain 0-1-2-3-4 # nx.path_graph constructs an undirected NetworkX graph g = dgl.from_networkx(nxg) print(g) # Graph(num_nodes=5, num_edges=8, # ndata_schemes={} # edata_schemes={}) nxg = nx.DiGraph([(2, 1), (1, 2), (2, 3), (0, 0)]) # constructs an directed NetworkX graph g = dgl.from_networkx(nxg) print(g) # Graph(num_nodes=4, num_edges=4, # ndata_schemes={} # edata_schemes={})从内存导入图 列举几种常见的存储格式:
csv文件 使用csv文件存储图:从csv文件中加载图: ->pandas -> dgl
JSON/GML 格式->Networkx->dgl
DGL Binary Format APIs : dgl.save_graphs() dgl.load_graphs()创建一个图
u, v = torch.tensor([0,0,0,1,2]), torch.tensor([1,2,3,3,1]) g = dgl.graph((u,v)) g.ndata['n_fe'] = torch.ones((g.num_nodes(), 3)) g.ndata['n_fe_matrix'] = torch.rand((g.num_nodes(), 3, 2)) g.edata['e_fe'] = torch.zeros(g.num_edges(), 5)查看图信息
print(g) """ Graph(num_nodes=4, num_edges=5, ndata_schemes={'n_fe': Scheme(shape=(3,), dtype=torch.float32), 'n_fe_matrix': Scheme(shape=(3, 2), dtype=torch.float32)} edata_schemes={'e_fe': Scheme(shape=(5,), dtype=torch.float32)}) """二分图 unibipartite 图中节点属性可以分为两类SRC与DST,使得所有边均为SRC中节点指向DST中节点
多关系图 multigraph 多关系图指同一对节点间有多个边,称为并行边parallel edges,对于同质图,只意味着边的两端节点相同,对于异质图,还意味着边的类型相同,即规范边相同
图特征的切片操作:
g.ndata[‘x’]=th.randn(10,3)对所有节点赋特征值g.ndata[‘x’][0]=th.zeros(1,3)对单个节点赋特征值g.ndata[‘x’][[0,5,6]]=th.zeros(3,3)对多个节点赋特征值g.ndata[‘x’][th.tensor([0, 5, 6])]=th.randn(3,3)对多个节点赋特征值g.edata[‘w’]=th.randn(9, 2)对所有边赋特征值g.data[‘w’][1]=th.randn(1,2)对单个边赋特征值g.edata[‘w’][[0,5,6]]=th.randn(3,2)对多个边赋特征值g.edata[‘w’][th.tensor([0,5,6])]=th.randn(3,2)对多个边赋特征值DGL可使用int32或着int64类型存储节点和边的ID。节点和边ID的数据类型应当一致。
ID数据类型node和edge的个数上限int32 2 31 − 1 2^{31}-1 231−1int64 2 63 − 1 2^{63}-1 263−1节点数较小时,应使用int32类型,因其可以有更快的速度和更小的存储空间
指定,转换与查看ID的数据类型
查看数据类型g.idtypetorch.int64(默认)指定g = dgl.graph(edges, idtype=torch.int32)变换为int64g64 = g.long()变换为int32g32 = g.int()