1_first.py 4.89 KB
Newer Older
Minjie Wang's avatar
Minjie Wang committed
1
"""
Minjie Wang's avatar
Minjie Wang committed
2
3
.. currentmodule:: dgl

4
DGL at a Glance
Minjie Wang's avatar
Minjie Wang committed
5
6
=========================

Minjie Wang's avatar
Minjie Wang committed
7
8
**Author**: `Minjie Wang <https://jermainewang.github.io/>`_, Quan Gan, `Jake
Zhao <https://cs.nyu.edu/~jakezhao/>`_, Zheng Zhang
9

Minjie Wang's avatar
Minjie Wang committed
10
The goal of this tutorial:
11

Minjie Wang's avatar
Minjie Wang committed
12
13
14
15
- Understand how DGL builds a graph from a high level.
- Perform simple computation on graphs.

At the end of this tutorial, we hope you get a brief feeling of how DGL works.
Minjie Wang's avatar
Minjie Wang committed
16
17
"""

Minjie Wang's avatar
Minjie Wang committed
18
19
20
21
22
23
24
25
26
27
28
29
###############################################################################
# Why DGL?
# ----------------
# DGL is designed to bring **machine learning** closer to **graph-structured
# data**. Specifically DGL enables trouble-free implementation of graph neural
# network (GNN) model family. Unlike PyTorch or Tensorflow, DGL provides
# friendly APIs to perform the fundamental operations in GNNs such as message
# passing and reduction. Through DGL, we hope to benefit both researchers
# trying out new ideas and engineers in production. 
#
# *This tutorial assumes basic familiarity with networkx.*

Minjie Wang's avatar
Minjie Wang committed
30
###############################################################################
31
32
# Building a graph
# ----------------
Minjie Wang's avatar
Minjie Wang committed
33
34
35
36
#
# A graph is built using :class:`~dgl.DGLGraph` class.
# Here as a toy example, we define a toy graph with two nodes then assign
# features on nodes and edges:
Minjie Wang's avatar
Minjie Wang committed
37

38
39
import torch as th
import networkx as nx
Minjie Wang's avatar
Minjie Wang committed
40
import dgl
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55

def a_boring_graph():
    g = dgl.DGLGraph()
    g.add_nodes(2)
    g.add_edge(1, 0)

    # node and edge features
    x = th.tensor([[0.0, 0.0], [1.0, 2.0]])
    w = th.tensor([2]).float()
    g.ndata['x'] = x
    g.edata['w'] = w

    return g

###############################################################################
Minjie Wang's avatar
Minjie Wang committed
56
57
# We can also convert a graph defined by `networkx
# <https://networkx.github.io/documentation/stable/>`_ to DGL:
58
59
60
61

def an_interesting_graph():
    import networkx as nx

Minjie Wang's avatar
Minjie Wang committed
62
    N = 70
63
64
65
66
67
68
69
70
71
72
73
    g = nx.erdos_renyi_graph(N, 0.1)
    g = dgl.DGLGraph(g)

    x = th.randn(N, 6)
    w = th.randn(g.number_of_edges(), 1)
    g.ndata['x'] = x
    g.edata['w'] = w

    return g

###############################################################################
Minjie Wang's avatar
Minjie Wang committed
74
#  By default, DGLGraph object is directional:
75
76
77
78
79
80
81
82
83
84
85

g_boring = a_boring_graph()
g_better = an_interesting_graph()

import matplotlib.pyplot as plt
nx.draw(g_better.to_networkx(), node_size=50, node_color=[[.5, .5, .5,]])
plt.show()

###############################################################################
# Define Computation
# ------------------
Minjie Wang's avatar
Minjie Wang committed
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# The canonical functionality of DGL is to provide efficient message passing
# and merging on graphs. It is implemented by using a message passing interface
# powered by the scatter-gather paradigm (i.e. a mailbox metaphor).
#
# To give an intuitive example, suppose we have one node :math:`v` , together with
# many incoming edges: :math:`e_i\in\mathcal{N}(v)`. Each node and edge is
# tagged with their own feature. Now, we can perform one iteration of message
# passing and merging by the following routine:
#
# - Each edge :math:`e_i` passes the information along into the node :math:`v`, by
#   ``send_source``.
# - A ``reduce`` operation is triggered to gather these messages
#   sent from the edges, by ``simple_reduce``.
# - ``readout`` function is called eventually to yield the updated feature on
#   :math:`v`.
#
# A graphical demonstration is displayed below, followed by a complete
# implementation.
104
#
Minjie Wang's avatar
Minjie Wang committed
105
106
107
108
109
# .. image:: https://drive.google.com/uc?export=view&id=1rc9cR0Iw96m_wjS55V9LJOJ4RpQBja15
#    :height: 300px
#    :width: 400px
#    :alt: mailbox
#    :align: center
110
111
112
113
114
#

def super_useful_comp(g):

    def send_source(edges):
115
        # 1. pass the source node feature 'x' weighted by edge feature 'w'
116
117
118
        return {'msg': edges.src['x'] * edges.data['w']}

    def simple_reduce(nodes):
119
        # 2. perform reduction on received messages and update feature 'x'
120
121
122
123
124
125
126
127
128
        msgs = nodes.mailbox['msg']
        return {'x': msgs.sum(1) + nodes.data['x']}

    g.register_message_func(send_source)
    g.register_reduce_func(simple_reduce)

    g.send(g.edges())
    g.recv(g.nodes())

129
130
131
def readout(g):
    # 3. read the aggregated node feature 'x' on graph
    return th.sum(g.ndata['x'], dim=0)
132
133

###############################################################################
Minjie Wang's avatar
Minjie Wang committed
134
# See the python wrapper:
135
136

g_boring = a_boring_graph()
137
138
139
140
141
graph_sum = readout(g_boring)
print("graph sum before send() and recv() is: ", graph_sum)
super_useful_comp(g_boring)
graph_sum = readout(g_boring)
print("graph sum after send() and recv() is: ", graph_sum)
142
143

g_better = an_interesting_graph()
144
145
146
147
148
graph_sum = readout(g_better)
print("graph sum before send() and recv() is: ", graph_sum)
super_useful_comp(g_better)
graph_sum = readout(g_better)
print("graph sum after send() and recv() is: ", graph_sum)
149
150
151
152

###############################################################################
# Next steps
# ----------
Minjie Wang's avatar
Minjie Wang committed
153
154
# In the :doc:`next tutorial <2_basics>`, we will go through some more basics
# of DGL, such as reading and writing node/edge features.