Deep Graph Library (DGL)是一个用于构建图神经网络模型的框架
    
    网址:
    
     https://www.dgl.ai/
    
    
    官方文档:
    
     https://docs.dgl.ai/
    
    
    论坛:
    
     https://discuss.dgl.ai/
    
   
安装
- CPU版本:pip install dgl -f https://data.dgl.ai/wheels/repo.html
- CUDA 11.0:pip install dgl-cu110 -f https://data.dgl.ai/wheels/repo.html
DGL支持PyTorch, MXNet和TensorFlow三种后端,默认为PyTorch,可在~/.dgl/config.json中配置
    本章官方文档:
    
     https://docs.dgl.ai/guide/graph.html
    
   
    
    
    1.基本概念
   
    图由顶点集合和边集合构成,表示为G=(V, E)
    
    DGL表示图的核心数据结构是
    
     dgl.DGLGraph
    
    
    DGL用整数表示一个顶点,叫做
    
     顶点ID
    
    ;用一对整数(u, v)表示一条边,分别对应边的起点和终点的顶点ID,同时每条边也有一个
    
     边ID
    
    ;在DGL中边都是有向的
    
    DGL使用长度为n的一维张量来表示n个顶点,叫做
    
     顶点张量
    
    ;使用两个顶点张量的元组(U, V)来表示n条边,其中(U[i], V[i])表示第i条边
   
    
    
    创建图
   
>>> import dgl
>>> import torch
>>> u, v = torch.tensor([0, 0, 0, 1]), torch.tensor([1, 2, 3, 3])
>>> g = dgl.graph((u, v))
>>> g
Graph(num_nodes=4, num_edges=4,
      ndata_schemes={}
      edata_schemes={})
>>> g.num_nodes()
4
>>> g.num_edges()
4
>>> g.nodes()
tensor([0, 1, 2, 3])
>>> g.edges()
(tensor([0, 0, 0, 1]), tensor([1, 2, 3, 3]))
    
    
    其中
    
     u
    
    和
    
     v
    
    可以是PyTorch张量,也可以是Python的整数可迭代对象(例如列表)
    
    (
    
     g
    
    的实际类型是
    
     dgl.DGLHeteroGraph
    
    ,在最新版本中与
    
     dgl.DGLGraph
    
    等价)
   
上面的例子中顶点ID的范围是从边中推断出来的,如果具有最大ID的顶点是孤立的(没有关联的边),则需要指定顶点个数:
>>> g = dgl.graph((u, v), num_nodes=8)
    
     dgl.to_bidirected()
    
    将有向图转换为无向图
   
>>> bg = dgl.to_bidirected(g)
>>> bg.edges()
(tensor([0, 0, 0, 1, 1, 2, 3, 3]), tensor([1, 2, 3, 0, 3, 0, 0, 1]))
    
    
    图的可视化
   
import networkx as nx
import matplotlib.pyplot as plt
# Since the actual graph is undirected, we convert it for visualization purpose.
nx_g = g.to_networkx().to_undirected()
# Kamada-Kawaii layout usually looks pretty for arbitrary graphs
pos = nx.kamada_kawai_layout(nx_g)
nx.draw(nx_g, pos, with_labels=True, node_color=[[.7, .7, .7]])
plt.show()
    完整操作列表:
    
     https://docs.dgl.ai/api/python/dgl.DGLGraph.html
    
   
    
    
    2.顶点和边的特征
   
    顶点和边都可以具有若干自定义名字的
    
     特征
    
    ,分别通过
    
     ndata
    
    和
    
     edata
    
    属性访问
    
    下面的代码创建了两个顶点特征x(长度为3的1维向量)和y(标量),以及一个边特征x(标量)
   
>>> import dgl
>>> import torch
>>> g = dgl.graph(([0, 0, 1, 5], [1, 2, 2, 0]))  # 6 nodes, 4 edges
>>> g
Graph(num_nodes=6, num_edges=4,
      ndata_schemes={}
      edata_schemes={})
>>> g.ndata['x'] = torch.ones(g.num_nodes(), 3)  # node feature of length 3
>>> g.edata['x'] = torch.ones(g.num_edges(), dtype=torch.int32)  # scalar integer feature
>>> g
Graph(num_nodes=6, num_edges=4,
      ndata_schemes={'x': Scheme(shape=(3,), dtype=torch.float32)}
      edata_schemes={'x': Scheme(shape=(), dtype=torch.int32)})
>>> # different names can have different shapes
>>> g.ndata['y'] = torch.randn(g.num_nodes(), 5)
>>> g.ndata['x'][1]   # get node 1's feature
tensor([1., 1., 1.])
>>> g.edata['x'][torch.tensor([0, 3])]  # get features of edge 0 and 3
tensor([1, 1], dtype=torch.int32)
关于顶点和边特征:
- 特征只能是数值(整数/浮点数),可以是标量、向量或多维张量,名字可以任意指定
- 给顶点特征赋值时,第一维大小必须等于顶点数;给边特征赋值时,第一维大小必须等于边数
- 要实现加权图,将边的权重作为边特征即可
    
    
    3.异构图
   
    异构图是具有不同类型的顶点和边的图
    
    在DGL中,不同类型的顶点/边有独立的ID范围和特征存储,如下图所示
    
     
   
    在DGL中,异构图是由一系列二分子图指定的,每个二分子图的起点类型、边类型、终点类型分别相同,由一个
    
     关系
    
    指定,关系是一个字符串三元组:(起点类型, 边类型, 终点类型),例如(‘user’, ‘plays’, ‘game’)
   
构造异构图的方法是指定一系列关系及其顶点张量对:
{
    relation1 : (src_node_tensor1, dst_node_tensor1),
    relation2 : (src_node_tensor2, dst_node_tensor2),
    ...
}
例如,下面的代码构造了一个包含“药物”、“基因”、“疾病”三种顶点和“反应”、“作用”、“治疗”三种边的异构图
>>> import dgl
>>> import torch
>>> # Create a heterograph with 3 node types and 3 edges types.
>>> g = dgl.heterograph({
    ('drug', 'interacts', 'drug'): (torch.tensor([0, 1]), torch.tensor([1, 2])),
    ('drug', 'interacts', 'gene'): (torch.tensor([0, 1]), torch.tensor([2, 3])),
    ('drug', 'treats', 'disease'): (torch.tensor([1]), torch.tensor([2]))
})
>>> g
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')])
    访问异构图中的顶点和边需要指定类型
    
    注意:如果边类型的名字唯一,则可仅使用边类型的名字,否则必须使用关系三元组
   
>>> g.ntypes
['disease', 'drug', 'gene']
>>> g.etypes
['interacts', 'interacts', 'treats']
>>> g.canonical_etypes
[('drug', 'interacts', 'drug'), ('drug', 'interacts', 'gene'), ('drug', 'treats', 'disease')]
>>> g.num_nodes()
10
>>> g.num_nodes('drug')
3
>>> g.nodes()
DGLError('Node type name must be specified if there are more than one '
>>> g.nodes('drug')
tensor([0, 1, 2])
>>> g.num_edges()
5
>>> g.num_edges(('drug', 'interacts', 'drug'))
2
>>> g.edges['interacts']
dgl._ffi.base.DGLError: Edge type "interacts" is ambiguous. Please use canonical edge type in the form of (srctype, etype, dsttype)
>>> g.num_edges(('drug', 'treats', 'disease'))
1
>>> g.num_edges('treats')
1
同构图和二分图就是只有一个关系的特殊异构图,同构图的起点类型和终点类型也相同,而二分图的起点类型和终点类型不同
>>> # A homogeneous graph
>>> dgl.heterograph({('node_type', 'edge_type', 'node_type'): (u, v)})
>>> # A bipartite graph
>>> dgl.heterograph({('source_type', 'edge_type', 'destination_type'): (u, v)})
    访问异构图中顶点和边的特征要使用新的语法:
    
     g.nodes['node_type'].data['name']
    
    和
    
     g.edges['edge_type'].data['name']
    
>>> # Set/get feature 'hv' for nodes of type 'drug'
>>> g.nodes['drug'].data['hv'] = torch.ones(g.num_nodes('drug'))
g.nodes['drug'].data['hv']
tensor([1., 1., 1.])
>>> # Set/get feature 'he' for edge of type 'treats'
>>> g.edges['treats'].data['he'] = torch.zeros(g.num_edges(('drug', 'treats', 'disease')))
>>> g.edges['treats'].data['he']
tensor([0.])
    将异构图转换为同构图:
    
     dgl.to_homogeneous()
    
 
