Before you start
Write the forward pass of one graph convolutional network (GCN) layer.
A GCN layer updates every node at once. Each node averages the features of itself and its neighbours, with the degree weighting from the normalised adjacency matrix. Then a shared weight matrix transforms the result, and a ReLU follows:
A_norm = D^(-1/2) (A + I) D^(-1/2)
H_new = relu(A_norm @ H @ W)
H has one row of features per node. Stacking k such layers lets
information travel k hops across the graph. The same W is used for every
node, which is what lets one GCN run on graphs of any size.
def gcn_layer(A, H, W):
Input
A = np.array([[0, 1],
[1, 0]])
H = np.array([[1.0, 2.0],
[3.0, 4.0]])
W = np.array([[1.0, -1.0],
[0.0, 0.5]])
gcn_layer(A, H, W)
Output
array([[2., 0.],
[2., 0.]])
Reasoning
With self loops both nodes have degree 2, so every entry of A_norm is 0.5.
A_norm @ H gives each node the average [2, 3]. Then
[2, 3] @ W = [2, -2 + 1.5] = [2, -0.5], and the ReLU clips -0.5 to 0.
A has shape (n, n), H has shape (n, d_in) and W has shape
(d_in, d_out).A is symmetric with zeros on the diagonal. Add the self loops yourself.Check runs the visible cases against a fresh kernel. Submit runs the hidden ones too.
⇧↵run cell