Before you start
Write one GraphSAGE layer with the mean aggregator.
A GCN mixes a node's own features into the same average as its neighbours. GraphSAGE keeps them apart. It transforms the node's own features with one weight matrix and the mean of its neighbours' features with another, then adds the two:
neigh_mean[v] = mean of H[u] over the neighbours u of v
H_new[v] = relu(H[v] @ W_self + neigh_mean[v] @ W_neigh)
Because it only needs a node's neighbours, GraphSAGE can embed nodes that were not in the training graph.
A node with no neighbours has a neighbour mean of zero.
def sage_layer(A, H, W_self, W_neigh):
Input
A = np.array([[0, 1, 0],
[1, 0, 1],
[0, 1, 0]])
H = np.array([[1.0, 0.0],
[0.0, 1.0],
[1.0, 1.0]])
W_self = np.eye(2)
W_neigh = np.array([[0.5, 0.0],
[0.0, -1.0]])
sage_layer(A, H, W_self, W_neigh)
Output
array([[1. , 0. ],
[0.5, 0.5],
[1. , 0. ]])
Reasoning
Node 1 has neighbours 0 and 2, so its neighbour mean is [1, 0.5]. That maps
to [0.5, -0.5], and adding its own [0, 1] gives [0.5, 0.5]. Node 0 has
only node 1, with mean [0, 1], which maps to [0, -1]. Adding [1, 0] gives
[1, -1], and the ReLU makes it [1, 0].
A is a 0/1 adjacency matrix with zeros on the diagonal. Do not add self
loops.H has shape (n, d_in), and both weight matrices have shape
(d_in, d_out).Check runs the visible cases against a fresh kernel. Submit runs the hidden ones too.
⇧↵run cell