公式ドキュメント学DGLフレームワークの3日目について--図の2、3について


主な参考:https://docs.dgl.ai/guide/graph-graphs-nodes-edges.html
DGLGraph図の作成
前にdglを使うと言いました.DGLGraph()図を作成するいくつかの方法.ここではdglを用いる.graph()はDGLGraph図を作成することもできます.
dglと.DGLGraph((u,v))類似、dgl.graph((u,v))では、uとvはそれぞれヘッダノードリストとテールノードリストであり、リストの対応する位置の要素はエッジを決定する.
# edges 0->1, 0->2, 0->3, 1->3
u, v = th.tensor([0, 0, 0, 1]), th.tensor([1, 2, 3, 3])
g = dgl.graph((u, v))
print(g) # number of nodes are inferred from the max node IDs in the given edges

出力ノードIDs
# Node IDs
print(g.nodes())

作成時と同様に、ヘッドノードリストとテールノードリストの形式でエッジを出力します.
# Edge end nodes
print(g.edges())

出力エッジの詳細は、ヘッダノードリストとテールノードリストのほか、エッジのIDsもあります.
# Edge end nodes and edge IDs
print(g.edges(form='all'))

分離ノードがある場合は、エッジの作成時に設定ノードの数を表示する必要があります.
# If the node with the largest ID is isolated (meaning no edges),
# then one needs to explicitly set the number of nodes
g = dgl.graph((u, v), num_nodes=8)

一方向図を双方向図に変換することもできます
bg = dgl.to_bidirected(g)
bg.edges()

IDsの格納ビット数
DGLは、ノードおよびエッジのIDsを格納するために32ビットまたは64ビット整数を選択することができる.1つの図のノード数またはエッジ数が2 31−1 2^{31}−1 231−1未満の場合、32−bit整数を使用してメモリを節約する.DGLのデフォルトでは64-bit整数が使用され、作成時に手動で設定したり、long()、int()で変更したりできます.
g32 = dgl.graph(edges, idtype=th.int32)  # create a int32 graph
print(g32.idtype)

g64_2 = g32.long()  # convert to int64
print(g64_2.idtype)

g32_2 = g64.int()  # convert to int32
print(g32_2.idtype)

ノードとエッジのフィーチャー
1.g.ndata[‘x’]を使用して、ノードにフィーチャーを追加したり、ノードフィーチャーにアクセスしたりすることができます.
2.g.edata[‘x’]を使用して、エッジにフィーチャーを追加またはアクセスできます.
3.数値型のみを特徴とすることができ、スカラー、ベクトル、テンソルとすることができる
4.ノードフィーチャー名はエッジフィーチャー名と重複可能
5.同じ名前のフィーチャーには、同じ次元とタイプしかありません.
6.加重マップでは、エッジフィーチャーとしてウェイトを使用できます.
外部データからDGLGraph図を構築する
1.SciPy疎行列とNetworkX図から作成できます.
import dgl
import torch as th
import scipy.sparse as sp
spmat = sp.rand(100, 100, density=0.05) # 5% nonzero entries
dgl.from_scipy(spmat)                   # from SciPy

import networkx as nx
nx_g = nx.path_graph(5) # a chain 0-1-2-3-4
dgl.from_networkx(nx_g) # from networkx


注意nx.path_graph(5)変換された図には8つのエッジがあり、これはNetworkX図が無方向図であり、DGLGraphが有方向図であり、1つの無方向エッジが2つの有方向エッジに回転するためである.
このような状況を避けるにはnetworkxが必要である.DiGraph()は、図面を構築します.
nxg = nx.DiGraph([(2, 1), (1, 2), (2, 3), (0, 0)])
dgl.from_networkx(nxg)


2.ディスクから図1をロード)CSV形式であってもよい
2)JSON/GML形式
3)DGL Binary形式はこの2つのAPI,dglを用いる.save_graphs(), dgl.load_graphs()は、図の保存とロードを実現します.
異構図
異構図には、異なるタイプのノードとエッジがあります.
異構図の作成
フォーマットは、「リレーションシップ:ノードメタグループ」です.「リレーションシップ」の具体的な形式は、[ヘッダノードタイプ、エッジタイプ、テールノードタイプ];ノードタプルの具体的な形式は、UとVがそれぞれヘッダノードリストとテールノードリストを表す([U],[V])である.
import dgl
import torch as th

# 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]))
}
g = dgl.heterograph(graph_data)
print(g.ntypes)
# ['disease', 'drug', 'gene']
print(g.etypes)
# ['interacts', 'interacts', 'treats']
print(g.canonical_etypes)
# [('drug', 'interacts', 'drug'),
#  ('drug', 'interacts', 'gene'),
#  ('drug', 'treats', 'disease')]

同構図と二部図は特殊な異構図とすることができる.
# 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)})

メタグラフは異構図のアーキテクチャ(本体)を表す
メタグラフには、各タイプのノードとその間の各タイプのエッジしかありません.
print(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')])
print(g.metagraph().edges())
# OutMultiEdgeDataView([('drug', 'drug'), ('drug', 'gene'), ('drug', 'disease')])

操作の種類
1.ノードとエッジへのアクセスには、ノードとエッジのタイプを明確にする必要があります.
2.ノードとエッジの特徴にアクセスする際にg.nodes[‘node_type’]を使用する.Data[‘feat_name’]とg.edges[‘edge_type’].data[‘feat_name’].
# Get the number of all nodes in the graph
print(g.num_nodes())
# 10
# Get the number of drug nodes
print(g.num_nodes('drug'))
# 3
# Nodes of different types have separate IDs,
# hence not well-defined without a type specified
print(g.nodes())
# DGLError: Node type name must be specified if there are more than one node types.
print(g.nodes('drug'))
# tensor([0, 1, 2])

3.図に1つのノードまたはエッジタイプしかない場合、明示的なタイプは必要ありません.
g = dgl.heterograph({
     
('drug', 'interacts', 'drug'): (th.tensor([0, 1]), th.tensor([1, 2])),
...    ('drug', 'is similar', 'drug'): (th.tensor([0, 1]), th.tensor([2, 3]))
... })
print(g.nodes())
# tensor([0, 1, 2, 3])
 # To set/get feature with a single type, no need to use the new syntax
g.ndata['hv'] = th.ones(4, 1)

エッジタイプサブマップ
特定の関係のみを含むサブマップを異構図から抽出すると、エッジタイプサブマップが構成されます.
g = dgl.heterograph({
     
('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]))
})
g.nodes['drug'].data['hv'] = th.ones(3, 1)

# Retain relations ('drug', 'interacts', 'drug') and ('drug', 'treats', 'disease')
# All nodes for 'drug' and 'disease' will be retained
eg = dgl.edge_type_subgraph(g, [('drug', 'interacts', 'drug'),
                                 ('drug', 'treats', 'disease')])
print(eg)
# Graph(num_nodes={'disease': 3, 'drug': 3},
#       num_edges={('drug', 'interacts', 'drug'): 2, ('drug', 'treats', 'disease'): 1},
#       metagraph=[('drug', 'drug', 'interacts'), ('drug', 'disease', 'treats')])
# The associated features will be copied as well
print(eg.nodes['drug'].data['hv'])
# tensor([[1.],
#         [1.],
#         [1.]])

異構図を同構図にする
dglを使用します.DGLGraph.to_homogeneous().すべてのタイプのノードとエッジは0から再番号付けされます.指定したフィーチャーをマージします.
g = dgl.heterograph({
     
    ('drug', 'interacts', 'drug'): (th.tensor([0, 1]), th.tensor([1, 2])),
    ('drug', 'treats', 'disease'): (th.tensor([1]), th.tensor([2]))})
g.nodes['drug'].data['hv'] = th.zeros(3, 1)
g.nodes['disease'].data['hv'] = th.ones(3, 1)
g.edges['interacts'].data['he'] = th.zeros(2, 1)
g.edges['treats'].data['he'] = th.zeros(1, 2)

# By default, it does not merge any features
hg = dgl.to_homogeneous(g)
print('hv' in hg.ndata)
# False

# Copy edge features
# For feature copy, it expects features to have
# the same size and dtype across node/edge types
hg = dgl.to_homogeneous(g, edata=['he'])
# DGLError: Cannot concatenate column ‘he’ with shape Scheme(shape=(2,), dtype=torch.float32) and shape Scheme(shape=(1,), dtype=torch.float32)

# Copy node features
hg = dgl.to_homogeneous(g, ndata=['hv'])
print(hg.ndata['hv'])
# tensor([[1.],
#         [1.],
#         [1.],
#         [0.],
#         [0.],
#         [0.]])

GPUでDGLGraphを使う
DGLGraphを構築する際に2つのGPUテンソルを伝達する2つの方法がある.もう1つの方法は、まずCPU上にDGLGraphを構築し、その後to()を介してGPUにコピーすることである.
なお、GPU上のDGLGraphはGPU上の特徴データのみを受け入れる
import dgl
import torch as th
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
print(g.device)
# device(type='cpu')
cuda_g = g.to('cuda:0')  # accepts any device objects from backend framework
print(cuda_g.device)
# device(type='cuda', index=0)
print(cuda_g.ndata['x'].device)       # feature data is copied to GPU too
# device(type='cuda', index=0)

# A graph constructed from GPU tensors is also on GPU
u, v = u.to('cuda:0'), v.to('cuda:0')
g = dgl.graph((u, v))
print(g.device)
# device(type='cuda', index=0)