当前位置 博文首页 > 韦全敏的博客:DGL中图(Graph)的相关操作

    韦全敏的博客:DGL中图(Graph)的相关操作

    作者:[db:作者] 时间:2021-06-22 12:53

    更多图神经网络和深度学习内容请关注:
    在这里插入图片描述

    DGL中图(Graph)的相关操作

    通过文本,你可以学会以下:

    • 使用DGL构造一个图。
    • 为图指定节点特征和边特征。
    • 查询DGL图的相关属性,例如节点度。
    • 将DGL图转换为另一个图。
    • 使用加载并保存图。

    使用DGL创建图

    DGL将有向图(此处假设为同构图)表示为一个DGLGraph对象。我们可以通过指定图中的节点数量(可选)、源节点和目标节点列表来构造图,图中节点id从0开始且为连续的整数。

    例如,以下代码构造了一个有5个叶子结点的有向星型图(类似五角星),其中中心节点的ID为0。

    import dgl
    import torch
    
    # 1、使用python list指定源和目标节点, 同时指定节点数量
    g1 = dgl.graph(([0, 0, 0, 0, 0], [1, 2, 3, 4, 5]), num_nodes=6)
    
    # 2、使用python list指定源和目标节点, 但不指定节点数量,节点数量num_nodes=max(node_id) + 1
    g2 = dgl.graph(([0, 0, 0, 0, 0], [1, 2, 3, 4, 5]))
    
    # 3、使用PyTorch Tensor指定源和目标节点,推荐写法,效率比使用python list要高
    u, v = torch.tensor([0,0,0,0,0]), torch.tensor([1,2,3,4,5])
    g3 = dgl.graph((u, v))
    

    图中的边ID从0开始且连续,与在创建过程中与源节点和目标节点的列表顺序相同。

    print(g3.edges())
    
    (tensor([0, 0, 0, 0, 0]), tensor([1, 2, 3, 4, 5]))
    

    相关API:

    • dgl.graph

    为图添加节点特征和边特征

    许多图数据包含节点和边上的属性,即节点特征边特征。虽然节点特征和边特征的类型在现实世界中可以是任意的,但是DGLGraph只接受存储在张量(Tensor)中的属性,且该属性必须为数值类型。

    我们可以通过ndataedata接口添加和检索节点特征和边特征。

    u, v = torch.tensor([0,0,0,0,0]), torch.tensor([1,2,3,4,5])
    g = dgl.graph((u, v))
    
    # 向图g的每个节点添加名为"x"的3维特征
    g.ndata["x"] = torch.randn(6, 3)
    
    # 向图g的每个边添加名为"x"的5维特征
    g.edata["x"] = torch.randn(5, 5)
    
    # 向图g的每个节点添加名为"x"的5维特征,即覆盖原来3维特征
    g.ndata["x"] = torch.randn(6, 5)
    
    g.ndata["x"] 
    
    tensor([[-0.3983, -0.0457, -0.4452,  0.2354,  0.4232],
            [-2.2643,  0.0501, -1.2971, -0.2198, -1.5397],
            [ 0.0041, -0.0402,  0.3461,  1.3199, -1.5499],
            [ 0.0390, -0.6028, -0.3294, -1.5476,  0.7534],
            [-0.2525,  1.0064, -0.9044, -0.8426,  1.9314],
            [-1.8012, -0.3457,  0.2488,  2.7218,  0.4569]])
    

    注: 由于DGL中的Graph只接受数值类型张量(Tensor)特征,以下提供将不同类型特征转为数值类型特征的方法:

    • 对于分类属性(例如:性别,职业),考虑将它们转换为整数或使用one-hot编码
    • 对于可变长的字符串内容(例如:新闻文章,引用),考虑使用语言模型。
    • 对于图像,请考虑应用视觉模型,例如卷积神经网络CNN。
    • 其他方法可查阅PyTorch文档

    查询图结构属性

    DGLGraph对象提供了多种查询图形结构属性的方法。

    查询节点数量和边的数量,可通过num_nodes()num_edges()

    print(g.num_nodes())
    
    print(g.num_edges())
    
    6
    5
    

    查询图的度,度(degree)可分为入度(in_degree)和出度(out_degree)

    print(g.out_degrees(0)) # 查询节点Id为0的出度
    
    print(g.in_degrees(0))  # 查询节点Id为0的入度
    
    5
    0
    

    相关API:

    • 查询图结构相关API

    图转换

    子图相关

    DGL提供了许多API来将图转换为另一个图,例如提取子图可以使用subgraph()node_subgraph()edge_subgraph()

    # 使用图g中的节点0、节点1和节点3中导出子图。node_subgraph()和subgraph同义
    subgraph1 = g.subgraph([0, 1, 3])
    
    # 使用图g中的边0、边1和边3中导出子图。
    subgraph2 = g.edge_subgraph([0, 1, 3])
    
    print("subgraph1\n", subgraph1)
    print()
    print("subgraph2\n", subgraph2)
    
    subgraph1
     Graph(num_nodes=3, num_edges=2,
          ndata_schemes={'x': Scheme(shape=(5,), dtype=torch.float32), '_ID': Scheme(shape=(), dtype=torch.int64)}
          edata_schemes={'x': Scheme(shape=(5,), dtype=torch.float32), '_ID': Scheme(shape=(), dtype=torch.int64)})
    
    subgraph2
     Graph(num_nodes=4, num_edges=3,
          ndata_schemes={'x': Scheme(shape=(5,), dtype=torch.float32), '_ID': Scheme(shape=(), dtype=torch.int64)}
          edata_schemes={'x': Scheme(shape=(5,), dtype=torch.float32), '_ID': Scheme(shape=(), dtype=torch.int64)})
    

    子图subgraph1和subgraph2拥有自己的新的节点ID和边ID

    print(subgraph1.nodes())
    
    print(subgraph1.edges(form="all"))
    
    tensor([0, 1, 2])
    (tensor([0, 0]), tensor([1, 2]), tensor([0, 1]))
    

    可通过dgl.NIDdgl.EID获取子图在初始图中的节点ID和边ID

    print(subgraph1.ndata[dgl.NID])
    
    print(subgraph1.edata[dgl.EID])
    
    tensor([0, 1, 3])
    tensor([0, 2])
    

    通过subgraphedge_subgraph提取子图的同时,原始图中的特征也会复制到该子图中:

    subgraph1.ndata["x"]
    
    tensor([[ 1.9540,  2.2756, -0.8195, -1.2689,  1.3591],
            [ 1.0453, -0.4965, -0.1211, -1.5714, -0.3815],
            [-0.4503, -1.1459,  1.4306, -0.6387, -1.3598]])
    

    相关API:

    • node_subgraph
    • subgraph
    • edge_subgraph
    • 更多API

    添加反向边

    利用dgl.add_reverse_edges可为图中的每条边添加对应的反向边,因为使用DGL创建的图默认都是有向图

    new_graph = dgl.add_reverse_edges(g)
    
    new_graph.edges()
    
    (tensor([0, 0, 0, 0, 0, 1, 2, 3, 4, 5]),
     tensor([1, 2, 3, 4, 5, 0, 0, 0, 0, 0]))
    

    相关API:

    • add_reverse_edges
    • 更多API

    加载和保存图

    我们可以通过dgl.save_graphs保存图或图列表,然后可使用dgl.load_graphs将其加载。

    # save graph
    dgl.save_graphs("graph.dgl", g)
    
    dgl.save_graphs("graphs.dgl", [g, subgraph1, subgraph2])
    

    此时目录结构:
    在这里插入图片描述

    #load graph
    g_list1, _ = dgl.load_graphs("graph.dgl")
    print(type(g_list1))
    print(g_list1)
    
    <class 'list'>
    [Graph(num_nodes=6, num_edges=5,
          ndata_schemes={'x': Scheme(shape=(5,), dtype=torch.float32)}
          edata_schemes={'x': Scheme(shape=(5,), dtype=torch.float32)})]
    
    [g, subgraph1, subgraph2], _ = dgl.load_graphs("graphs.dgl")
    print(type(g))
    print(g)
    
    <class 'dgl.heterograph.DGLHeteroGraph'>
    Graph(num_nodes=6, num_edges=5,
          ndata_schemes={'x': Scheme(shape=(5,), dtype=torch.float32)}
          edata_schemes={'x': Scheme(shape=(5,), dtype=torch.float32)})
    

    相关API:

    • dgl.save_graphs
    • dgl.load_graphs

    参考

    翻译整理自DGL