PyTorch : DGL Tutorials : Basics : DGL 基本 (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 06/03/2019
* 本ページは、DGL のドキュメント DGL at a Glance を翻訳した上で適宜、補足説明したものです:
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
DGL Tutorials : Basics : DGL 基本
このチュートリアルの目標は :
- グラフを作成する。
- ノードとエッジ表現を読み書きする。
グラフ作成
DGLGraph の設計は他のグラフ・ライブラリの影響を受けています。実際に、networkx からグラフを作成してそれを DGLGraph に変換することができます、逆もまた同様です :
import networkx as nx import dgl g_nx = nx.petersen_graph() g_dgl = dgl.DGLGraph(g_nx) import matplotlib.pyplot as plt plt.subplot(121) nx.draw(g_nx, with_labels=True) plt.subplot(122) nx.draw(g_dgl.to_networkx(), with_labels=True) plt.show()

これらは同じグラフです、DGLGraph が常に有向であることを除いて。
DGL 自身のインターフェイスを呼び出すことによりグラフを作成することもできます。
今はスターグラフを構築しましょう。DGLGraph ノードは 0 から number_of_nodes() の整数の連続する範囲で add_nodes を呼び出すことで拡大できます。DGLGraph エッジはそれらの追加の順序にあります。エッジはノードと大体同じ方法でアクセスされることに注意してください、エッジ・ブロードキャスティングの一つの特別な特徴を除いて :
import dgl
import torch as th
g = dgl.DGLGraph()
g.add_nodes(10)
# a couple edges one-by-one
for i in range(1, 4):
g.add_edge(i, 0)
# a few more with a paired list
src = list(range(5, 8)); dst = [0]*3
g.add_edges(src, dst)
# finish with a pair of tensors
src = th.tensor([8, 9]); dst = th.tensor([0, 0])
g.add_edges(src, dst)
# edge broadcasting will do star graph in one go!
g.clear(); g.add_nodes(10)
src = th.tensor(list(range(1, 10)));
g.add_edges(src, 0)
import networkx as nx
import matplotlib.pyplot as plt
nx.draw(g.to_networkx(), with_labels=True)
plt.show()

特徴割り当て
DGLGraph のノードとエッジに特徴を割り当てることもできます。特徴は、フィールドと呼ばれる、名前 (文字列) と tensor の辞書として表わされます。
次のコードスニペットは各ノードにベクトル (len=3) を割り当てます。
import dgl import torch as th x = th.randn(10, 3) g.ndata['x'] = x
ndata は総てのノードのステートにアクセスするためのシンタックスシュガーで、ステートはユーザ定義辞書にとどまるコンテナ・データにストアされます。
print(g.ndata['x'] == g.nodes[:].data['x']) # access node set with integer, list, or integer tensor g.nodes[0].data['x'] = th.zeros(1, 3) g.nodes[[0, 1, 2]].data['x'] = th.zeros(3, 3) g.nodes[th.tensor([0, 1, 2])].data['x'] = th.zeros(3, 3)
tensor([[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1],
[1, 1, 1]], dtype=torch.uint8)
エッジ特徴の割り当てはノード特徴のそれに類似の流儀です、エッジのエンドポイントを指定することによってもそれを行えることを除いて。
g.edata['w'] = th.randn(9, 2) # access edge set with IDs in integer, list, or integer tensor g.edges[1].data['w'] = th.randn(1, 2) g.edges[[0, 1, 2]].data['w'] = th.zeros(3, 2) g.edges[th.tensor([0, 1, 2])].data['w'] = th.zeros(3, 2) # one can also access the edges by giving endpoints g.edges[1, 0].data['w'] = th.ones(1, 2) # edge 1 -> 0 g.edges[[1, 2, 3], [0, 0, 0]].data['w'] = th.ones(3, 2) # edges [1, 2, 3] -> 0
割り当ての後、各ノード/エッジ・フィールドはそのフィールド値の shape とデータ型 (dtype) を含むスキームと関連付けられます。
print(g.node_attr_schemes()) g.ndata['x'] = th.zeros((10, 4)) print(g.node_attr_schemes())
{'x': Scheme(shape=(3,), dtype=torch.float32)}
{'x': Scheme(shape=(4,), dtype=torch.float32)}
One can also remove node/edge states from the graph.
This is particularly useful to save memory during inference.
g.ndata.pop('x')
g.edata.pop('w')
多重グラフ
多くのグラフ・アプリケーションは多重エッジを必要とします。これを可能にするために、DGLGraph を multigraph=True で構築します。
g_multi = dgl.DGLGraph(multigraph=True) g_multi.add_nodes(10) g_multi.ndata['x'] = th.randn(10, 2) g_multi.add_edges(list(range(1, 10)), 0) g_multi.add_edge(1, 0) # two edges on 1->0 g_multi.edata['w'] = th.randn(10, 2) g_multi.edges[1].data['w'] = th.zeros(1, 2) print(g_multi.edges())
(tensor([1, 2, 3, 4, 5, 6, 7, 8, 9, 1]), tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]))
多重グラフのエッジはその接続ノード $u$ と $v$ を使用して一意に識別できません ; エッジ id を問い合わせるには edge_id インターフェイスを使用します。
eid_10 = g_multi.edge_id(1, 0) g_multi.edges[eid_10].data['w'] = th.ones(len(eid_10), 2) print(g_multi.edata['w'])
tensor([[ 1.0000, 1.0000],
[ 0.0000, 0.0000],
[-0.9387, 0.3229],
[ 1.0725, 1.3638],
[ 0.3663, -0.2904],
[-0.0331, -0.4775],
[ 2.4536, -0.4485],
[ 1.7595, 1.5181],
[ 2.0224, 0.3583],
[ 1.0000, 1.0000]])
Note
- ノードとエッジは追加できますが除去できません; 除去は将来的にサポートします。
- 異なるスキームの特徴を更新するとき個々のノード (or ノード部分セット) 上でエラーを上げます。
以上