VerifiedarXiv:1609.0290730 min
Graph neural networks · Architecture

GCN: Semi-Supervised Classification with Graph Convolutional Networks

Mix each node's features with its neighbors', and 140 labels are enough to classify every node of a 2,708-node graph.

A graph convolutional network multiplies the node features by a normalized adjacency matrix before each weight matrix. Kipf and Welling derive that matrix from spectral graph theory, and two such layers beat every baseline they tested on four node-classification benchmarks.

Explaining the paperSemi-Supervised Classification with Graph Convolutional NetworksKipf, Welling · University of Amsterdam · ICLR 2017 · arXiv:1609.02907 ↗

You have a citation network: 2,708 papers, 5,429 citation links, and a subject label on 20 papers per subject. Predict the subject of the other 2,568.

A paper's own text is one source of evidence for its subject. Its citations are another: papers mostly cite papers in the same field. A classifier that reads only the text throws the second source away, and with 140 labels it has little to learn from. Kipf and Welling build a neural network that takes both inputs, the feature vector on every node and the adjacency matrix of the graph, and train it with labels on only a few nodes.1

Each layer of the network replaces every node's feature vector with a weighted sum of its own vector and its neighbors', multiplies the result by a learned weight matrix, and applies a ReLU. Two of those layers and a softmax score 81.5% on Cora, ahead of every method the paper compares against. The rest of this page explains, in order: the older approach the paper replaces (a smoothness penalty in the loss); the layer itself, with a worked example; where its particular weights come from (graph frequencies, a Chebyshev filter, and two approximations); the training setup; the results; why the model stays at two layers; and a second reading of the layer as a trainable version of the Weisfeiler-Lehman graph test.

The task: label a graph from a few nodes

A graph has NN nodes. Each node carries a feature vector, and stacking them gives a matrix X∈RN×CX\in\mathbb{R}^{N\times C} with CC features per node. On Cora a node is a paper and its feature vector is a 0/1 bag-of-words over a 1,433-word vocabulary, so XX is 2708×14332708\times 1433. The edges go in the adjacency matrix A∈RN×NA\in\mathbb{R}^{N\times N}, with Aij=1A_{ij}=1 when nodes ii and jj are linked and 0 otherwise (the method also accepts positive edge weights in place of the 1s). The graphs here are undirected, so AA is symmetric. A small set of nodes has a class label; the job is to predict the class of every other node.

The setting is transductive: the whole graph is available during training, including every edge and the feature vectors of the unlabeled nodes. Only their labels are hidden, and the test nodes are nodes of this same graph. A transductive model can use an unlabeled neighbor's features when it predicts a labeled node, which is how the method spreads 140 labels across 2,708 nodes. It also means the trained model is tied to this graph; producing embeddings for nodes that were not present at training time is the job of a later method, GraphSAGE.5

The paper uses four datasets with the splits of the Planetoid benchmark (Yang, Cohen and Salakhutdinov, 2016). Cora has 2,708 nodes, 5,429 edges, 7 classes and 1,433 features, and trains on 20 labels per class: 140 labeled nodes, a label rate of 0.052. Citeseer (3,327 nodes, 6 classes) and Pubmed are citation networks of the same kind. NELL is a knowledge graph trained with a single labeled example per class, a label rate of 0.001. Every citation dataset is scored on 1,000 held-out labeled nodes, and a further 500 labeled nodes serve as a validation set for choosing hyperparameters, never for training.

Laplacian regularization, the approach GCN replaces

Before this paper, the standard way to use the graph in semi-supervised learning was a penalty term in the loss that makes linked nodes receive similar predictions:

L=L0+λ Lreg,Lreg=∑i,jAij ∥f(Xi)−f(Xj)∥2=f(X)⊤Δ f(X)\mathcal{L} = \mathcal{L}_0 + \lambda\,\mathcal{L}_{\text{reg}}, \qquad \mathcal{L}_{\text{reg}} = \sum_{i,j} A_{ij}\,\big\lVert f(X_i) - f(X_j) \big\rVert^2 = f(X)^\top \Delta\, f(X)L=L0+λ Lreg,Lreg=∑i,jAij ∥f(Xi)−f(Xj)∥2=f(X)⊤Δ f(X)\begin{aligned} \mathcal{L} &= \mathcal{L}_0 + \lambda\,\mathcal{L}_{\text{reg}}, \\ \mathcal{L}_{\text{reg}} &= \sum_{i,j} A_{ij}\,\big\lVert f(X_i) - f(X_j) \big\rVert^2 = f(X)^\top \Delta\, f(X) \end{aligned}
(1)

L0\mathcal{L}_0 is the supervised loss on the labeled nodes, ff is any classifier applied to one node's features at a time, and λ\lambda weights the penalty. The penalty adds, for every edge, the squared difference between the two endpoints' predictions. If two linked papers get a predicted probability of 0.9 and 0.2 for the same subject, that edge contributes (0.9−0.2)2=0.49(0.9-0.2)^2=0.49, and gradient descent pushes the two predictions toward each other. The right-hand form writes the same sum with Δ=D−A\Delta = D - A, the unnormalized graph Laplacian, where DD is the diagonal degree matrix (DiiD_{ii} is the number of edges at node ii). Row ii of Δf\Delta f equals DiiD_{ii} times the gap between fif_i and the mean of its neighbors' values, so the quadratic form f⊤Δff^\top\Delta f measures total disagreement along edges.2

Kipf and Welling object to the assumption inside (1): it treats every edge as a statement that the two nodes share a label. In their words this "might restrict modeling capacity, as graph edges need not necessarily encode node similarity"; a paper can cite work from another field. Their alternative removes the penalty and puts the graph inside the model. The classifier becomes a function f(X,A)f(X,A) of the features and the adjacency matrix together, and training minimizes only L0\mathcal{L}_0 on the labeled nodes. How much a neighbor's features should count is then decided by learned weights, and because a labeled node's output is computed from its neighbors' features, the gradient of L0\mathcal{L}_0 also passes through those neighbors. The model section below walks that gradient step by step, after the layer itself and its derivation.

How a GCN layer works

One layer maps the feature matrix H(l)H^{(l)} to the next one:

H(l+1)=σ ⁣(D~−1/2A~D~−1/2 H(l) W(l))H^{(l+1)} = \sigma\!\left( \tilde{D}^{-1/2}\tilde{A}\tilde{D}^{-1/2}\, H^{(l)}\, W^{(l)} \right)
(2)

H(l)H^{(l)} has one row per node, and the first layer takes H(0)=XH^{(0)}=X. A~=A+IN\tilde{A}=A+I_N is the adjacency matrix with a self-loop added at every node, and D~\tilde{D} is its diagonal degree matrix, so d~i\tilde{d}_i is node ii's number of neighbors plus one. Write A^\hat{A} for the product D~−1/2A~D~−1/2\tilde{D}^{-1/2}\tilde{A}\tilde{D}^{-1/2}. Reading (2) from the inside out: A^H(l)\hat{A}H^{(l)} replaces each node's row by a weighted sum of the rows of its neighbors and itself; multiplying by the weight matrix W(l)W^{(l)} mixes the feature channels, the same matrix for every node; and σ\sigma is an elementwise nonlinearity, a ReLU in the paper. The only learned parameters are the W(l)W^{(l)}; the graph enters only through the fixed matrix A^\hat{A}.

The weight that node jj's row gets in node ii's sum is the matrix entry, where Ni\mathcal{N}_i is the set of node ii's neighbors:

A^ij={1/d~i d~jj=i or j∈Ni0otherwise\hat{A}_{ij} = \begin{cases} 1/\sqrt{\tilde{d}_i\,\tilde{d}_j} & j=i \text{ or } j \in \mathcal{N}_i \\ 0 & \text{otherwise} \end{cases}

A worked example on the 11-node graph of Figure 1. Node 4 is the bridge between two groups. It has three neighbors (nodes 2, 6 and 10), so d~4=4\tilde{d}_4=4; nodes 2 and 6 have five neighbors each (d~=6\tilde{d}=6) and node 10 has three (d~=4\tilde{d}=4). With one scalar feature per node, valued 0.10 on node 4, 0.85 on node 2, −0.70 on node 6 and −0.40 on node 10, node 4's new value is

h4′=0.104⋅4+0.854⋅6+−0.704⋅6+−0.404⋅4=0.025+0.174−0.143−0.100=−0.044\begin{aligned} h_4' &= \tfrac{0.10}{\sqrt{4\cdot4}} + \tfrac{0.85}{\sqrt{4\cdot6}} + \tfrac{-0.70}{\sqrt{4\cdot6}} + \tfrac{-0.40}{\sqrt{4\cdot4}} \\ &= 0.025 + 0.174 - 0.143 - 0.100 = -0.044 \end{aligned}

The four weights are 0.25, 0.204, 0.204 and 0.25, which sum to 0.908, so this is a weighted sum and not an average. A neighbor with many edges of its own gets a smaller weight: nodes 2 and 6 each count for 0.204 against node 10's 0.25. Splitting the normalization as a square root on each side means an edge between two high-degree nodes is scaled down from both ends. The plain row average would be D~−1A~\tilde{D}^{-1}\tilde{A}, with weights 1/d~i1/\tilde{d}_i that do sum to one. The paper does not discuss it; the symmetric form is what the spectral derivation in the next two sections produces.

In Figure 1, tap any node. Its edges light up, and the readout lists each contribution: the weight, the neighbor's value, and the sum that becomes the node's new feature. Tapping a node inside a group gives a value close to that group's color; the bridge node lands between them.

Figure 1 · one layer of aggregation
Each node is colored by a scalar feature (amber positive, teal negative). Tap a node: its new value is the sum ∑jhj/d~id~j\sum_j h_j/\sqrt{\tilde{d}_i\tilde{d}_j} over itself and its neighbors. On wide screens the readout lists the weighted terms (up to five); on narrow screens it shows the total.

Two questions remain about (2): why the paper calls it a convolution, and where the 1/d~id~j1/\sqrt{\tilde{d}_i\tilde{d}_j} weights and the self-loop come from. The paper answers both by starting from the definition of convolution in signal processing and approximating it.

Graph frequencies and spectral filters

On an image, a 3×3 convolution kernel applies the same nine weights at every pixel, which works because every pixel has the same eight neighbors in the same arrangement. Nodes in a graph have different numbers of neighbors and no ordering among them, so there is no direct analogue of sliding a kernel. Signal processing offers a second definition that does carry over: convolution is multiplication in the frequency domain. A graph needs a set of frequencies for that, and the Laplacian provides them. The paper uses the normalized Laplacian, a different matrix from the Δ=D−A\Delta=D-A of (1):

L=IN−D−1/2AD−1/2=UΛU⊤L = I_N - D^{-1/2} A D^{-1/2} = U \Lambda U^\top

LL is symmetric, so it has NN orthonormal eigenvectors (the columns of UU) and real eigenvalues (the diagonal of Λ\Lambda), which for this normalization lie between 0 and 2. Each eigenvector assigns one number to every node. An eigenvector with a small eigenvalue changes little across edges; the one with eigenvalue 0 is proportional to di\sqrt{d_i} at node ii, the smoothest signal the graph has. Eigenvectors with large eigenvalues change sign across most edges. The eigenvalue plays the role of a frequency, and the coefficients U⊤xU^\top x of a node signal xx in this basis are its graph Fourier transform. A spectral filter scales each frequency by its own factor and transforms back:

gθ⋆x=Ugθ(Λ)U⊤xg_\theta \star x = U g_\theta(\Lambda) U^\top x
(3)

Figure 2 colors the same 11-node graph by one eigenvector at a time. Step the slider from k=0k=0 upward. Eigenvector 1 (the Fiedler vector) is already positive on one group and negative on the other at an eigenvalue of 0.08, so the split between the two communities is a low-frequency pattern, and the highest eigenvectors alternate sign from node to node. The teal curve is the response of the operator from equation (7) below, halved: g(λ)=1−λ/2g(\lambda)=1-\lambda/2. It passes low frequencies at nearly full gain and suppresses high ones.

Figure 2 · graph frequencies and a low-pass filter
k = 1
The toy graph colored by one Laplacian eigenvector, with every eigenvalue marked on the axis below. The teal curve is the filter response g(λ)=1−λ/2g(\lambda)=1-\lambda/2. Step the eigenvector index and read its eigenvalue and gain.

Equation (3) is exact and too expensive to use. Multiplying by the dense matrix UU costs O(N2)O(N^2) per signal, and the paper notes that computing the eigendecomposition itself "might be prohibitively expensive for large graphs" (it is O(N3)O(N^3) for a dense matrix). A filter that sets an independent factor for each of the NN frequencies also mixes every node with every other node.

The way out, from Hammond, Vandergheynst and Gribonval (2011) and used for a graph CNN by Defferrard, Bresson and Vandergheynst (2016, called ChebNet), restricts gθg_\theta to a polynomial of degree KK in the eigenvalues, written in Chebyshev polynomials TkT_k (defined by T0(x)=1T_0(x)=1, T1(x)=xT_1(x)=x, Tk(x)=2xTk−1(x)−Tk−2(x)T_k(x)=2xT_{k-1}(x)-T_{k-2}(x)). The eigenvalues are first rescaled into [−1,1][-1,1], where every Chebyshev polynomial stays between −1 and 1, using the largest eigenvalue λmax⁡\lambda_{\max}:

gθ′⋆x≈∑k=0Kθk′ Tk(L~) x,L~=2λmax⁡L−INg_{\theta'} \star x \approx \sum_{k=0}^{K} \theta'_k\, T_k(\tilde{L})\, x, \qquad \tilde{L} = \frac{2}{\lambda_{\max}}L - I_N
(5)

Two properties follow. Because (UΛU⊤)k=UΛkU⊤(U\Lambda U^\top)^k = U\Lambda^k U^\top, a polynomial applied to the eigenvalues equals the same polynomial applied to the matrix, so (5) never needs UU: it is computed with KK multiplications by the sparse matrix L~\tilde{L}, at a cost of O(∣E∣)O(|\mathcal{E}|), linear in the number of edges. And entry (i,j)(i,j) of LkL^k is zero when nodes ii and jj are more than kk edges apart, so the filtered value at a node depends only on nodes within KK hops. The paper calls this property K-localized. The degree KK sets the filter's radius the way kernel size does on an image: a 3×3 kernel reaches one pixel out, and a degree-1 graph filter reaches one hop out.3

The renormalization trick: K = 1 and a self-loop

In ChebNet KK is a hyperparameter (the paper's own comparison tries K=2K=2 and K=3K=3). Kipf and Welling ask whether a layer needs more than K=1K=1. A degree-1 filter reaches one hop, and stacking two such layers reaches two hops, so depth can stand in for polynomial degree. The paper gives two reasons to prefer that. A filter with fewer parameters per layer should overfit less to local neighborhood structure on graphs whose node degrees vary widely, as citation networks and social networks do. And for a fixed compute budget, cheaper layers allow more of them.

With K=1K=1 and the further approximation λmax⁡≈2\lambda_{\max}\approx 2 (the largest possible value for the normalized Laplacian; the paper expects the trained weights to absorb the error in scale), equation (5) has two terms:

gθ′⋆x≈θ0′ x+θ1′ (L−IN) x=θ0′ x−θ1′ D−1/2AD−1/2 xg_{\theta'} \star x \approx \theta'_0\, x + \theta'_1\,(L - I_N)\,x = \theta'_0\, x - \theta'_1\, D^{-1/2} A D^{-1/2}\, x
(6)

The minus sign comes from L−IN=−D−1/2AD−1/2L - I_N = -D^{-1/2}AD^{-1/2}. The paper then ties the two parameters together, setting θ=θ0′=−θ1′\theta=\theta'_0=-\theta'_1, to reduce overfitting and the number of operations per layer. Substituting turns both terms positive:

gθ⋆x≈θ (IN+D−1/2AD−1/2) xg_\theta \star x \approx \theta\,\big( I_N + D^{-1/2} A D^{-1/2} \big)\, x
(7)

The operator in (7) keeps the node's own value with weight 1 and adds its neighbors' values with weights 1/didj1/\sqrt{d_i d_j}. Its eigenvalues lie in [0,2][0,2], and the paper names the consequence: "Repeated application of this operator can therefore lead to numerical instabilities and exploding/vanishing gradients." The top eigenvalue is exactly 2 on any connected graph, so a component of the signal along the top eigenvector doubles at every layer, growing 24=162^4=16 times over four layers, while components with eigenvalues near 0 shrink toward zero. The paper replaces the operator with one substitution, the renormalization trick:

IN+D−1/2AD−1/2  ⟶  D~−1/2A~D~−1/2,A~=A+INI_N + D^{-1/2} A D^{-1/2} \;\longrightarrow\; \tilde{D}^{-1/2}\tilde{A}\tilde{D}^{-1/2}, \qquad \tilde{A}=A+I_N

The left side normalizes the adjacency by the original degrees and then adds the identity. The right side adds the self-loops first and normalizes afterward, by degrees that now include them. Every entry changes: the diagonal goes from 1 to 1/d~i1/\tilde{d}_i, and an edge weight goes from 1/didj1/\sqrt{d_id_j} to 1/d~id~j1/\sqrt{\tilde{d}_i\tilde{d}_j}. The top eigenvalue drops to exactly 1, for this reason: A^\hat{A} has the same eigenvalues as D~−1A~\tilde{D}^{-1}\tilde{A} (the two are related by the change of basis D~1/2\tilde{D}^{1/2}), and that matrix has nonnegative rows summing to 1, so no eigenvalue exceeds 1 in magnitude and the all-ones vector has eigenvalue exactly 1. With self-loops the bottom of the spectrum stays above −1, so the whole spectrum lies in (−1,1](-1,1] and stacked layers no longer amplify the top mode.

Figure 3 shows the matrices with numbers in them, on a five-node graph: a triangle 0-1-2 with a tail 0-3-4. Switch between Eq (7) and renormalized and compare the cell for the edge 0-1. Under (7) it is 1/3⋅2=0.411/\sqrt{3\cdot2}=0.41; renormalized it is 1/4⋅3=0.291/\sqrt{4\cdot3}=0.29, and the diagonal entries drop from 1 to between 0.25 and 0.5. The eigenvalue range moves from [0.14,2][0.14, 2] to [−0.21,1][-0.21, 1]. The row-sum column shows the renormalized rows summing to between 0.91 and 1.12. The row average button shows D~−1A~\tilde{D}^{-1}\tilde{A} for comparison: its rows sum to exactly 1, it has the same eigenvalues as the renormalized matrix, and it is not symmetric.

Figure 3 · the propagation matrix, entry by entry
Five nodes, labeled with their degree including the self-loop (d~\tilde{d}). Tap a cell or a node to read the formula behind that entry; the buttons switch between the Eq (7) operator, the renormalized GCN operator, the row average D~−1A~\tilde{D}^{-1}\tilde{A} and the raw A+IA+I.

A star graph isolates the effect of degree. With a hub of degree dd joined to dd leaves, the unnormalized A+IA+I has top eigenvalue 1+d1+\sqrt{d}, which grows without bound as the hub gets bigger. The Eq (7) operator stays at 2 whatever the degree, and the renormalized operator stays at 1. In Figure 4, drag the hub degree to see the raw curve climb, and drag the layer count to see what each top eigenvalue does to a signal after that many layers: at d=9d=9 and four layers the raw operator multiplies the top mode by 44=2564^4=256, the Eq (7) operator by 16, and the renormalized one by 1.

Figure 4 · why the renormalization trick is stable
d = 9
4
Largest eigenvalue of three operators on a star graph, against the hub degree: raw A+I, the Eq (7) operator, and the renormalized GCN operator. The readout above the plot raises each one to the chosen number of layers.

Kipf and Welling justify the trick by the instability alone, and show in their ablation that it also gives the best accuracy. A spectral analysis of why the self-loop helps came two years later: Wu et al. (2019, SGC) proved that adding self-loops shrinks the largest eigenvalue of the corresponding normalized Laplacian (from about 2 to about 1.5 on Cora), which makes the filter act as a low-pass filter.4

The last step generalizes from one scalar signal to CC input channels and FF output channels. The single parameter θ\theta becomes a matrix Θ∈RC×F\Theta\in\mathbb{R}^{C\times F}:

Z=D~−1/2A~D~−1/2XΘZ = \tilde{D}^{-1/2}\tilde{A}\tilde{D}^{-1/2} X \Theta
(8)

Z∈RN×FZ\in\mathbb{R}^{N\times F} is the filtered output, and the cost is O(∣E∣FC)O(|\mathcal{E}|FC) because A~\tilde{A} is sparse. Equation (8) followed by a nonlinearity is the layer rule (2). Its 1/d~id~j1/\sqrt{\tilde{d}_i\tilde{d}_j} weights are a first-order Chebyshev filter with λmax⁡≈2\lambda_{\max}\approx2, tied parameters, and the self-loop moved inside the normalization.

The two-layer model and its training loss

The model the paper trains stacks two layers. A^=D~−1/2A~D~−1/2\hat{A}=\tilde{D}^{-1/2}\tilde{A}\tilde{D}^{-1/2} is computed once, before training, and then

Z=f(X,A)=softmax ⁣(A^  ReLU(A^ X W(0)) W(1))Z = f(X,A) = \mathrm{softmax}\!\Big( \hat{A}\;\mathrm{ReLU}\big( \hat{A}\,X\,W^{(0)} \big)\,W^{(1)} \Big)
(9)

W(0)∈RC×HW^{(0)}\in\mathbb{R}^{C\times H} maps the input features to HH hidden units, W(1)∈RH×FW^{(1)}\in\mathbb{R}^{H\times F} maps those to FF class scores, and the softmax runs over each row. On Cora that is XX of shape 2708×14332708\times1433, W(0)W^{(0)} of shape 1433×161433\times16, a hidden layer of shape 2708×162708\times16, W(1)W^{(1)} of shape 16×716\times7, and an output ZZ of shape 2708×72708\times7: one probability distribution over the 7 subjects for every paper, labeled or not. The loss is cross-entropy over the labeled nodes only:

L=−∑l∈YL∑f=1FYlf ln⁡Zlf\mathcal{L} = -\sum_{l\in\mathcal{Y}_L}\sum_{f=1}^{F} Y_{lf}\,\ln Z_{lf}
(10)

YL\mathcal{Y}_L is the set of labeled node indices, 140 of them on Cora, and YlfY_{lf} is 1 for the true class of node ll and 0 otherwise. The 140 terms reach the other 2,568 nodes through A^\hat{A}, in two steps. The output row ZlZ_l of a labeled node is computed by the second A^\hat{A} from the hidden rows of ll and its neighbors. Each of those hidden rows was computed by the first A^\hat{A} from the input features of that node and its own neighbors. So ZlZ_l depends on the features of every node within two hops of ll, and the gradient of the term for ll with respect to W(0)W^{(0)} and W(1)W^{(1)} is a sum of contributions from all of those nodes, nearly all of them unlabeled. The labels supervise the two shared weight matrices, and the same matrices then compute ZZ for the unlabeled nodes.

Figure 5 shows the two-hop reach on a small graph, Zachary's karate club (34 members, 78 friendships), with one labeled node in each of its two factions: node 0 and node 33. These two nodes have 16 and 17 neighbors. At one layer their outputs already depend on 31 of the 34 nodes; at two layers, on all 34. Tap any other node to see its own receptive field, which on this graph reaches everything within five layers, the graph's diameter. Brightness shows the size of each node's entry in the focus node's row of A^k\hat{A}^k (the two labeled nodes' rows added together, by default).

Figure 5 · what a k-layer GCN can see
k = 2
Karate club graph, colored by faction (amber, teal). Lit nodes are those within kk hops of the ringed focus nodes, the only nodes whose features enter the focus nodes' outputs after kk layers. Tap a node to focus it; the button returns to the two labeled nodes.

The forward pass and one training step look like this. A^X\hat{A}X is a sparse-times-dense product, so the whole forward pass costs O(∣E∣CHF)O(|\mathcal{E}|CHF), linear in the number of edges. Training is full-batch: the entire graph is one example, and every iteration is a gradient step on all of it.

# two-layer GCN on Cora: N=2708 nodes, C=1433 features, H=16 hidden, F=7 classes
A_t   = A + I                              # add a self-loop to every node
d_t   = A_t.sum(axis=1)                    # degrees counting the self-loop
A_hat = diag(d_t**-0.5) @ A_t @ diag(d_t**-0.5)   # sparse, computed once
X     = X / X.sum(axis=1, keepdims=True)   # row-normalize the bag-of-words rows

H = relu(A_hat @ dropout(X) @ W0)          # [2708,1433] @ [1433,16] -> [2708,16]
Z = softmax(A_hat @ dropout(H) @ W1)       # [2708,16]   @ [16,7]    -> [2708,7]

loss = cross_entropy(Z[idx_train], Y[idx_train])   # 140 labeled rows only
loss = loss + 5e-4 * 0.5 * (W0**2).sum()           # L2 on the first layer only
loss.backward(); adam.step()               # gradients reach W0 and W1

The settings, from Section 5.3 of the paper: Adam with learning rate 0.01, at most 200 epochs, early stopping with a window of 10 epochs on the validation loss, dropout rate 0.5, L2 regularization 5⋅10−45\cdot10^{-4} on the first layer, 16 hidden units, and Glorot initialization with row-normalized input features. The hyperparameters were tuned on Cora and reused unchanged for Citeseer and Pubmed. The authors' TensorFlow code (github.com/tkipf/gcn) matches these, with two details the paper leaves implicit, listed in the Provenance panel: the L2 term uses TensorFlow's l2_loss, which is half the squared norm (hence the 0.5 above), and training stops when the validation loss exceeds the mean of the previous 10 epochs.

Results on Cora, Citeseer, Pubmed and NELL

Table 2 of the paper reports accuracy of 81.5% on Cora, 70.3% on Citeseer, 79.0% on Pubmed and 66.0% on NELL, the highest of every method compared on all four. The margins over the best baseline differ a lot between datasets:

Wall-clock time to convergence is in the same table. Against Planetoid, GCN took 4 s instead of 13 s on Cora, 7 s instead of 26 s on Citeseer and 48 s instead of 185 s on NELL, roughly three to four times faster, but 38 s instead of 25 s on Pubmed. Compared with ICA, which passes predicted labels between neighbors, the paper attributes part of the gain to passing feature information in every layer.

Table 3 isolates the propagation operator. Each row trains the same model with a different matrix in place of A^\hat{A}, on the same splits. The row that drops the graph altogether, a multi-layer perceptron computing XΘX\Theta, scores 55.1% on Cora, against 81.5% for the renormalized GCN: 26.4 points of accuracy come from the graph. Among the operators that do use the graph the spread is small, from 79.2% to 81.5% on Cora, and the renormalized operator is the best on all three citation datasets. It beats Chebyshev filters with K=2K=2 (81.2%) and K=3K=3 (79.5%), which have more parameters per layer, and the first-order variants: the two-parameter model of (6) (80.0%), the single-parameter model of (7) (79.2%) and the neighbor term alone (80.5%). Figure 6 plots the table; switch datasets with the buttons.

Figure 6 · accuracy by propagation operator
Table 3 of the paper: the same two-layer model with only the propagation matrix changed. The MLP uses no graph; the renormalized GCN operator is the highest bar on every dataset. The bracket marks the gap between them.

All of these numbers come from one fixed split per dataset, the one Planetoid published. The paper also trains on 10 random splits of the same size and reports the mean and standard error: Cora 80.1 ± 0.5, Citeseer 67.9 ± 0.5, Pubmed 78.9 ± 0.7, NELL 58.4 ± 1.7. Cora drops 1.4 points from the fixed split and NELL 7.6. Shchur et al. (2018) later showed that the ranking of graph methods can change between random splits, so differences of one or two points on the fixed split, such as the Citeseer and Pubmed margins, are weak evidence on their own.7

Why GCNs stay shallow

Appendix B of the paper trains models of up to 10 layers (5-fold cross-validation on Cora, Citeseer and Pubmed using all labels, 16 units per layer, 400 epochs without early stopping). Two or three layers give the best results. Beyond seven layers, training without residual connections "can become difficult". The paper gives two reasons there: each extra layer widens the neighborhood a node draws on by one hop, and the parameter count grows with depth, which invites overfitting. Section 2.2 adds a third, which applies to the un-renormalized operator: repeated application of a matrix with eigenvalues up to 2 is numerically unstable.

Later work added a fourth explanation, now the usual one, called oversmoothing (Li, Han and Wu, 2018, and after). The word does not appear in the 2016 paper. The argument: every layer replaces a node's features with a weighted sum over its neighborhood, so after many layers the features of all nodes in a connected graph converge to the same pattern, and a classifier can no longer separate them. Figure 7 runs this on the 11-node graph with no weights and no nonlinearity, only repeated multiplication by A^\hat{A}. The input is +1 on one group and −1 on the other, and the curve tracks the gap between the two groups' mean values. It falls below half its starting value at 12 layers and to about 2% at 64.

Figure 7 · repeated aggregation erases the difference between groups
2
A two-group signal (+1 / −1) multiplied by A^\hat{A} once per layer. The curve is the gap between the groups' means as a fraction of its starting value. Drag the layer count from 0 to 64.

At 64 layers every node has the same sign. The signal is heading toward the top eigenvector of A^\hat{A}, whose entries are proportional to d~i\sqrt{\tilde{d}_i} and whose eigenvalue is 1: every other component is multiplied by an eigenvalue of magnitude below 1 at each layer and decays, while this one is kept. On this graph the second eigenvalue is about 0.94, so that component shrinks only by 0.9464≈0.020.94^{64} \approx 0.02 over 64 layers and still sets the shape at that depth: the right group's hub (degree 5) holds 5.2 times the value of a degree-2 node on the left, where the top eigenvector would give 6/3≈1.41\sqrt{6/3} \approx 1.41. The values settle onto d~i\sqrt{\tilde{d}_i} near 150 layers. (With the row average D~−1A~\tilde{D}^{-1}\tilde{A} the limit would be a constant vector instead.) A trained network has weight matrices and ReLUs between the multiplications, so the decay in a real model is not this clean. The paper's remedy for depth is a residual connection, borrowed from ResNet:

H(l+1)=σ ⁣(D~−1/2A~D~−1/2H(l)W(l))+H(l)H^{(l+1)} = \sigma\!\left(\tilde{D}^{-1/2}\tilde{A}\tilde{D}^{-1/2}H^{(l)}W^{(l)}\right) + H^{(l)}
(14)

Adding the layer's input back to its output lets each layer carry the previous representation forward, and in Appendix B the residual models stay trainable out to the 10 layers tested.

The Weisfeiler-Lehman view

Appendix A reads the layer rule a second way, with no spectral theory. The 1-dimensional Weisfeiler-Lehman algorithm is a classic test for whether two graphs could be the same graph with the nodes renamed. It gives every node a color, then repeatedly replaces each node's color with a hash of its own color and the multiset of its neighbors' colors. After a few rounds, nodes in structurally different positions usually have different colors. Replace the hash with a normalized sum, a weight matrix and a nonlinearity, and the update becomes

hi(l+1)=σ ⁣(∑j∈Ni1cij hj(l) W(l)),cij=didjh_i^{(l+1)} = \sigma\!\left( \sum_{j\in\mathcal{N}_i} \frac{1}{c_{ij}}\, h_j^{(l)}\, W^{(l)} \right), \qquad c_{ij}=\sqrt{d_i d_j}
(12)

In (12), Ni\mathcal{N}_i is the set of node ii's neighbors and did_i its size; with a self-loop counted as a neighbor this is equation (2) written for one node. The paper calls the GCN, "loosely speaking", a differentiable and parameterized generalization of the Weisfeiler-Lehman algorithm. It is weaker as a test: a weighted sum can give the same result for two different multisets of neighbor colors, where a hash would not. Xu et al. (2019, the GIN paper) proved that message-passing networks of this kind are at most as discriminative as the Weisfeiler-Lehman test, and that GCN cannot distinguish some simple structures that the test can.

The appendix uses this view to predict that a GCN with random, untrained weights already produces useful node embeddings, because the Weisfeiler-Lehman-style update separates nodes by their position in the graph. It tests the prediction on the karate club with a three-layer GCN and no node features (X=INX=I_N, so each node starts as its own one-hot vector):

Z=tanh⁡ ⁣(A^tanh⁡ ⁣(A^tanh⁡(A^XW(0))W(1))W(2))Z=\tanh\!\big(\hat{A}\tanh\!\big(\hat{A}\tanh(\hat{A}XW^{(0)})W^{(1)}\big)W^{(2)}\big)
(13)

The weight matrices are drawn at random with Glorot initialization and never trained. The random-weight embeddings are, in the paper's words, comparable to those of DeepWalk, which uses "a more expensive unsupervised training procedure".

Appendix A.2 then trains that model with one labeled node per class and watches the two-dimensional output move. Figure 8 reproduces the experiment in a smaller form, computed live in your browser: a featureless two-layer GCN with one labeled node in each of the club's two factions.6 The output starts as a cluster near the origin; press play and the two factions separate, using only the two labels and the edges.

Figure 8 · semi-supervised training on the karate club
A featureless two-layer GCN with one labeled node per faction (ringed). Each dot is a club member's 2-D output, drawn with the graph's edges and colored by true faction (amber, teal). Press play or scrub through training; reseed to start from new random weights.

Limitations the paper lists

Section 7.2 names three. Memory: full-batch training holds the whole graph and its activations, so memory grows linearly with the dataset. Mini-batch training is possible, but an exact mini-batch for a KK-layer GCN must include every node within KK hops of the batch, and the paper notes that very large, densely connected graphs may need further approximations. Directed edges and edge features: the model handles undirected graphs only, weighted or unweighted. For NELL the authors convert the directed, relation-labeled graph into an undirected bipartite graph with an extra node for each original edge.

Fixed self-weight: the approximations of Section 2 assume locality and give a node's own features the same weight as each neighbor's. The paper suggests a trade-off parameter in the self-loop,

A~=A+λIN\tilde{A} = A + \lambda I_N
(11)

learned by gradient descent, which would play the role that λ\lambda plays in the regularized loss (1). It is proposed as future work. Inductive use, on graphs or nodes unseen in training, is outside its scope altogether.

Provenance Verified against primary literatureHow we verify
Kipf & Welling (2017), Sec. 2Equations (2)-(8) as printed. The normalized Laplacian and the renormalization substitution are unnumbered in the paper; this page mirrors its numbering, so (4) is referenced but not displayed.
Hammond et al. (2011)Chebyshev polynomial approximation of spectral graph filters; a degree-K polynomial filter is exactly K-hop localized.
Defferrard et al. (2016, ChebNet)The Chebyshev graph CNN that GCN truncates to K = 1.
Bruna et al. (2014)Spectral graph convolutional networks, the line of work the paper builds on.
Yang et al. (2016, Planetoid)The Cora / Citeseer / Pubmed / NELL splits and the baseline numbers in Table 2.
tkipf/gcn, gcn/utils.py lines 122-134A_hat is built as normalize_adj(adj + sp.eye(N)), with D~^-1/2 applied on both sides: the renormalized symmetric operator. Input features are row-normalized (lines 112-119).
tkipf/gcn, gcn/models.py lines 146-149; gcn/train.py line 98Weight decay 5e-4 applies to the first layer only, via tf.nn.l2_loss, which is half the squared norm. Early stopping fires when the validation loss exceeds the mean of the previous 10 epochs.
Wu et al. (2019, SGC)Later spectral proof that self-loops shrink the largest eigenvalue (about 2 to about 1.5 on Cora) and make the filter low-pass. Kipf & Welling justify the trick only by the instability.
Xu et al. (2019, GIN)Message-passing GNNs are at most as discriminative as the 1-WL test; GCN fails on some simple structures. Not a claim of the GCN paper, which says only "loosely speaking" a generalization.
Zachary (1977); Appendix A.2The paper's karate experiment uses the 3-layer model (13), four modularity-based classes, and 300 Adam steps at lr 0.01. Figure 8 here uses two layers and the two real factions (footnote 6).
correctionThe usual explanation for why GCNs stay shallow is oversmoothing. That word never appears in the 2016 paper, which gives three different reasons: each layer widens a node's receptive field by one hop, parameters grow with depth and overfit, and the un-renormalized operator is numerically unstable when stacked. Oversmoothing is a 2018-and-later reframing (Li, Han & Wu 2018; NT & Maehara 2019; Oono & Suzuki 2020). This page uses it in Figure 7 and labels it as later work.

Questions you might still have

?

If the loss only scores a few labeled nodes, how does the model learn anything about the rest?
A labeled node's output is computed from the features of every node within two hops, so the gradient of its loss term flows back through those unlabeled nodes into the two shared weight matrices. The 140 Cora labels train W0 and W1; the same W0 and W1, applied through A_hat, then classify all 2,708 nodes.

?

Is a GCN layer just averaging each node with its neighbors?
It is a weighted sum over the node and its neighbors with weight 1/sqrt(d~_i d~_j), and the weights into a node do not sum to one (0.908 for the bridge node in Figure 1). The row average D~^-1 A~ is a different operator that the paper does not use; its symmetric form comes out of the spectral derivation.

?

Why not stack twenty layers, like an image network?
In the paper's Appendix B, two or three layers work best and models deeper than seven become hard to train without residual connections. The paper blames the growing receptive field and overfitting. Later work adds oversmoothing: repeated multiplication by A_hat drives every node toward the same pattern, as Figure 7 shows.

?

Do I need the spectral theory to implement a GCN?
No. The implementation is a sparse matrix A_hat computed once from A, and two sparse-dense products in the forward pass. The spectral derivation explains where the 1/sqrt(d~_i d~_j) weights and the self-loop come from, and why the operation is called a convolution.

?

Can a trained GCN classify nodes in a new graph?
Not as published. The model is transductive: it trains with the whole graph present and predicts nodes of that same graph. GraphSAGE (Hamilton, Ying and Leskovec, 2017) learns aggregation functions that produce embeddings for unseen nodes.

?

How is a GCN different from attention over neighbors?
In a GCN the weight on each neighbor is fixed by the graph, 1/sqrt(d~_i d~_j), before training. Attention-based graph networks such as GAT compute a weight for each edge from the two nodes' features, the way attention in a Transformer weights tokens.

Footnotes & further reading

  1. The paper: Thomas N. Kipf and Max Welling, Semi-Supervised Classification with Graph Convolutional Networks (ICLR 2017; arXiv September 2016). Reference code: github.com/tkipf/gcn. ↩
  2. On Eq (1): the paper prints Lreg=∑i,jAij∥fi−fj∥2=f⊤Δf\mathcal{L}_{\text{reg}}=\sum_{i,j}A_{ij}\lVert f_i-f_j\rVert^2=f^\top\Delta f, but the exact identity carries a factor of one half, f⊤Δf=12∑i,jAij∥fi−fj∥2f^\top\Delta f=\tfrac12\sum_{i,j}A_{ij}\lVert f_i-f_j\rVert^2, because the double sum counts every edge twice. The constant is absorbed into λ\lambda. ↩
  3. Hammond, Vandergheynst & Gribonval, Wavelets on Graphs via Spectral Graph Theory (2011); Defferrard, Bresson & Vandergheynst, Convolutional Neural Networks on Graphs with Fast Localized Spectral Filtering (ChebNet, 2016). As printed, the sums in Eqs (4)–(5) run over k=0,…,Kk=0,\dots,K, which is K+1K+1 terms, while the text says θ′∈RK\theta'\in\mathbb{R}^K; reproduced here as written. The bound λmax⁡≤2\lambda_{\max}\le 2 for the normalized Laplacian, with equality exactly when a connected component is bipartite, is standard spectral graph theory and not stated in the paper. ↩
  4. Wu et al., Simplifying Graph Convolutional Networks (SGC, 2019), which generalizes the self-loop to A~=A+γI\tilde{A}=A+\gamma I and also shows that removing the nonlinearities, leaving a fixed low-pass filter followed by logistic regression, costs little accuracy on these benchmarks. ↩
  5. Hamilton, Ying & Leskovec, Inductive Representation Learning on Large Graphs (GraphSAGE, 2017). The oversmoothing analyses: Li, Han & Wu, Deeper Insights into Graph Convolutional Networks (2018); NT & Maehara (2019); Oono & Suzuki (ICLR 2020). The expressivity bound is Xu, Hu, Leskovec & Jegelka, How Powerful Are Graph Neural Networks? (GIN, 2019). ↩
  6. The paper describes the karate club as 34 nodes and 154 edges; the standard Zachary (1977) network, used in Figures 5 and 8, has 78 undirected edges (156 if each direction is counted). The paper's experiment uses a three-layer tanh GCN with 4 hidden units, four classes from modularity-based clustering, one label per class, and 300 iterations of Adam at learning rate 0.01. Figure 8 departs from that setup: two GCN layers (8 tanh hidden units, linear 2-D output) with a linear softmax classifier on the 2-D output, the two ground-truth factions with node 0 and node 33 as the labeled examples, and plain gradient descent with weight decay. ↩
  7. Shchur et al., Pitfalls of Graph Neural Network Evaluation (2018). The benchmark split is from Yang, Cohen & Salakhutdinov, Revisiting Semi-Supervised Learning with Graph Embeddings (Planetoid, 2016). ↩