前言
下载这个库要去官方网站:https://www.dgl.ai/,网站上会给你下载命令,这有点像下载pytorch的时候。
然后,官方网站提供了一些入门的例子。如果自己有能力,可以自行学习,就不用跟着我们这篇文章学习啦,网址见:https://docs.dgl.ai/tutorials/blitz/index.html。
这个库基本是由中国人开发和维护的,我用了之后的感觉就是:还行。API定义得很人性,所以很容易学习。跟一个普通的库没有什么差别。
import dgl
import torch
import torch.nn as nn
import torch.nn.functional as F
但是,要求你有一些pytorch的基础哦。
简单?
内置数据集
内置了一些数据集,例如 cora数据集,读取很快,不但如此,读取之后的对象dataset非常清晰易懂。
import dgl.data
dataset = dgl.data.CoraGraphDataset()
print('Number of categories:', dataset.num_classes)
其定义为dataset可能由多个图组成,所以熟悉python的你应该知道,像列表一样获取第一个图对吧,这个库也是这么定义的,所以很人性。
g = dataset[0]#获取第一个图,不过其实cora数据集就一个图,[1]将越界。
print('Node features')
print(g.ndata)#所有关于节点的附加信息你都可以放在这里,以字典形式保存,所以说很人性,显然你可以自己加自己的信息。
print('Edge features')
print(g.edata)#所有关于边附加信息你都可以放在这里。以字典形式保存,所以说很人性,显然你可以自己加自己的信息。
定义模型
一些经典的GNN模型被这个dgl库肢解了,或者你可以认为是内置了,但是又以一种比较灵活的方式内置。我们以GCN模型为例,其定义方式和pytorch特别相似。
from dgl.nn import GraphConv
class GCN(nn.Module):
def __init__(self, in_feats, h_feats, num_classes):
super(GCN, self).__init__()
self.conv1 = GraphConv(in_feats, h_feats)#gcn中的一层卷积已经写好了
self.conv2 = GraphConv(h_feats, num_classes)
def forward(self, g, in_feat):
h = self.conv1(g, in_feat)#g就是这个图,其实用的是邻接矩阵,in_feat就是g.ndata["feat"]即节点的初始特征。
h = F.relu(h)
h = self.conv2(g, h)
return h
# Create the model with given dimensions
model = GCN(g.ndata['feat'].shape[1], 16, dataset.num_classes)#这样就定义完了。
至此,已经复现了GCN模型,注意到,model就是pytorch中的model,所以,下面就是pytorch干的事了,dgl可以退场了。比如设置优化器,训练,测试等,这都不关dgl的事。dgl只是在定义模型的时候提供一些经典的算法供直接调用,更快更准构造好一个GNN。
定义dgl中的一个图
GNN是基于图操作的,显然我们要构造它,上面是用内置数据集,这显然不够,所以我们还得学习dgl的一个地方就在于这,还得学怎么创建一个dgl格式的图,有点像你需要学怎么创建一个networkx格式的图一样。
所以,其实我们可以猜到,由于涉及构造图,这里会有很多api,所以会是容易使用,但是很难记住,印象中,好像和networkx的构造图的api不一样,所以,头大。出于私心,由于学过一点networkx,所以当然希望可以用nextworkx创建图,然后dgl支持转换。然而,应该是不可以。
所以,从这个角度看,这两个库存在竞争关系。我看了一下两者的欢迎程度,截止2021/12/09,nextworkx的github收藏数:10k,dgl的github收藏数:8.6k。我感觉前者偏向于创建图,而后者偏向于对图进行深度学习的处理。
不管怎么样吧,如果忘记了dgl怎么创建图,或者创建好了之后怎么查看多少条边啊,出入度啊之类的,可以翻看官方api就行了。https://docs.dgl.ai/tutorials/blitz/2_dglgraph.html。话说回来,networkx其实我也记不住,也是要翻看官方api的。
这里展示一小部分dgl创建图的大概用法(我没有看错的话,dgl创建的图的基类是DGLGraph):
g = dgl.graph(([0, 0, 0, 0, 0], [1, 2, 3, 4, 5]))
#表示[0,1],[0,2]是有向边。似乎等价于g=dgl.DGLGraph(),官方不推荐使用前者,而不是这个,但是之前看到有人这么用,所以说一下。
print(g.num_nodes())
print(g.num_edges())
# Out degrees of the center node
print(g.out_degrees(0))
# In degrees of the center node - note that the graph is directed so the in degree should be 0.
print(g.in_degrees(0))
其实,创建图还涉及如何创建无向图,同构图,异构图对吧,这个自己查吧,不管哪个库都是需要这样的。你要的全都在这里了:https://docs.dgl.ai/api/python/dgl.DGLGraph.html?highlight=dglgraph#dgl.DGLGraph。
比如,上面我们是初始化就创建好了一个图,但是如果我们需要临时添加一个节点呢?在基类DGLGraph的方法大全里面有:
这个库做得还不错,大家可以多多支持国人的东西。
附录
g.number_of_nodes()#节点数量
g.number_of_edges()#边数量
g.nodes()#查看节点
g.edges()#查看边
g.add_nodes()#添加节点
g.add_edges()#添加边
g.in_degrees([0,1])#查看节点0和节点1的入度。
g.out_degrees([0,1])#查看节点0和节点1的出度。
g.ndata.update({'id': torch.arange(5), 'in_degree':torch.tensor([0,1,1,1,1]) })#添加节点附件信息。
#上面相当于下面两句。所以上面这句有点鸡肋。
g.ndata["in_degree"]=torch.tensor([0,1,1,1,1])
g.ndata['id']=torch.arange(5)
g.ndata.pop('id')#返回g.ndata['id']并且将"id"这一属性完全删除。
g.apply_edges(lambda edges: {'in_degree': edges.dst['in_degree'] * edges.src['in_degree']})#对每一条边都添加一个特征,计算方式为源节点和目标节点的入度相乘。