skip to content

Graph Neural Networks

Learning on graphs with GCN, GraphSAGE and GAT: gather from neighbours, aggregate, update, repeat. Interviewers probe it because a graph has no fixed neighbour count and no canonical node order.

on this pageshow

explore

questions

27

Why does a GCN normalize the neighbour sum by node degree instead of summing raw feature vectors?

level: juniorimportance: must knowfreq 70%

answer

  1. degree changes the scale
  2. hub nodes versus ordinary nodes
  3. sum versus average of neighbours
  4. one over the square root of both degrees
  5. self-loop counts in the degree

basics

~20 s

A raw neighbour sum scales with how many neighbours a node has, so hubs produce huge activations and ordinary nodes tiny ones. Dividing each edge's contribution by sqrt(d_i * d_j) keeps every node's aggregate on a comparable scale.

solid answer

~40 s

One graph convolution layer rebuilds each node's vector from its neighbourhood, so the aggregation step sets the scale. If you just sum, an account with 3,000,000 followers gets an aggregate three million times larger than an account with one: the layer encodes degree as raw magnitude, and the scale compounds as you stack layers. The standard fix is symmetric normalization. Take `A~ = A + I` (adjacency plus self-loops), let `D~` be its degree matrix, and propagate with `D~^-1/2 A~ D~^-1/2`, so the edge from `j` into `i` carries weight `1 / sqrt(d~_i * d~_j)`. That damps the receiver's degree *and* the sender's, so a celebrity's message is discounted everywhere it appears. Row normalization `D~^-1 A~` is the simpler alternative, a plain neighbourhood average, but it only normalizes the receiver.

code

python · 13 lines
python
import math

def coef(d_i, d_j):
    # symmetric-normalization edge weight; degrees already include the self-loop
    return 1.0 / math.sqrt(d_i * d_j)

ordinary = 11          # 10 followers + self-loop
celebrity = 3_000_001  # 3,000,000 followers + self-loop

print("ordinary <- ordinary :", round(coef(ordinary, ordinary), 6))
print("ordinary <- celebrity:", round(coef(ordinary, celebrity), 9))
print("celebrity <- ordinary:", round(coef(celebrity, ordinary), 9))
print("row-normalized weight:", round(1.0 / ordinary, 6))

go deeper

for a junior

Be ready to state what one layer does: combine the neighbours' vectors, multiply by a weight matrix shared across all nodes, apply a nonlinearity — and say why the combining step divides by degree instead of just summing.

for a middle

Explain the propagation matrix D^-1/2 (A + I) D^-1/2 term by term: why the sender's degree appears as well as the receiver's, what the added identity contributes, and how row normalization differs.

for a senior

Show you notice the cost. Normalization erases degree, which is often the very signal you want in fraud or influence problems, so you decide deliberately whether to feed a degree feature back in.

for a principal

Own the framing that the aggregation coefficient is a modelling assumption about the domain — how much a link from a broadcaster should count — and defend choosing it per graph rather than inheriting a default.

## The layer, in one line A graph convolution layer rebuilds every node's vector out of its own vector and its neighbours'. For node `i` with feature vector `h_i` and neighbour set `N(i)`: `h_i' = sigma( W^T * sum over j in N(i) U {i} of c_ij * h_j )` `W` is a weight matrix shared by every node in the graph, `sigma` is a nonlinearity, and `c_ij` is the coefficient the aggregation step gives the edge `j -> i`. This question is entirely about `c_ij`. ## What breaks when c_ij = 1 With `c_ij = 1` the aggregate is a plain sum, and its magnitude grows linearly with degree. In a follower graph, an account with 3,000,000 followers gets a vector roughly three million times longer than an account with one follower, before `W` is even applied. Three consequences, in order of how much they hurt: 1. **Degree leaks in as magnitude.** Two nodes with identical neighbourhoods in *composition* but different neighbourhood *size* get wildly different embeddings. Whatever the classifier learns downstream, it is partly reading degree off the vector norm — and it reads it in an uncontrolled, unnormalized way. 2. **Scale compounds with depth.** Stack two layers and the hub's aggregate has been multiplied by a degree-sized factor twice. Activations for hubs blow up while leaf nodes stay near zero, so a single learning rate cannot suit both, and gradients are just as skewed. 3. **Optimization gets miserable.** Batches mix nodes whose activations differ by orders of magnitude; a rectifier passes the blow-up straight through, and saturating nonlinearities pin hubs at their ceiling. ## The two normalizations **Row normalization**, `D~^-1 A~`, sets `c_ij = 1 / d~_i` for every neighbour. The coefficients sum to exactly one, so the aggregate is a genuine average of the neighbourhood: "what does a typical neighbour look like". It normalizes the *receiver* only. **Symmetric normalization**, `D~^-1/2 A~ D~^-1/2`, sets `c_ij = 1 / sqrt(d~_i * d~_j)`. Here the *sender's* degree matters too. A celebrity node reaches every one of its followers with a coefficient shrunk by `1/sqrt(3,000,001)`, so a message from a node that broadcasts to millions counts for very little in any single recipient's update — the intuition being that a link from someone who links to everyone carries less information than a link from someone selective. The weights no longer sum to one, so this is not literally an average; what it buys is a propagation matrix whose largest eigenvalue is at most 1, so repeated application does not amplify the signal. Both are defensible. Symmetric is the common default in the classic two-layer setup; row normalization is easier to explain and is the natural choice if you genuinely want "the mean neighbour". ## Why the self-loop is inside the normalization `A~ = A + I` puts the node itself into its own neighbourhood, so `h_i` survives the aggregation instead of being discarded. It has a second, mundane benefit: an isolated node has degree zero in `A`, which makes `D^-1` and `D^-1/2` undefined. With the self-loop its degree is one, the row is well defined, and the node simply passes its own features through. Note that `d~_i = d_i + 1` — the degrees used in the coefficients include the self-loop. ## A worked setting On a citation network — classify each paper's topic from a bag-of-words feature vector, with roughly 20 labelled papers per class and a two-layer network over the whole graph — normalization is what makes the labelled signal spread usefully. A heavily cited survey paper has hundreds of edges; unnormalized, it would dominate the aggregate of every paper that cites it and drag their representations toward one blurry point. Normalized, it contributes in proportion to how selective the link is. ## The cost you should name Normalization deliberately erases degree from the aggregate's scale. Sometimes degree is exactly the signal — follower count for influence, transaction count for fraud, citation count for impact. The right move is not to skip normalization; it is to put degree back in as an explicit node feature (typically `log(1 + degree)`, so the value range is sane) and let the model learn what to do with it. ## Misconceptions worth avoiding - "The nonlinearity will handle the scale." A rectifier is unbounded and passes the blow-up through unchanged. - "Sum and average differ by a constant, and `W` can absorb it." The constant is per-node — it is the degree — so no single weight matrix can absorb it. - "Symmetric normalization means dividing by the node's own degree." That is row normalization; the symmetric form takes the geometric mean of both endpoints' degrees. - "Normalization is only about avoiding numerical overflow." It is mainly about not letting degree masquerade as feature magnitude.

  • What does row normalization D^-1 (A + I) do differently from the symmetric version?
    Row normalization gives every neighbour weight `1/d~_i`, so the coefficients sum to one and the aggregate is a true neighbourhood mean — but it only accounts for the receiving node's degree. The symmetric form uses `1/sqrt(d~_i * d~_j)`, which additionally discounts messages from high-degree senders, so a node that links to everyone influences each recipient less.
  • If node degree is genuinely predictive in your domain, how do you keep that signal after normalizing?
    Add it back as an explicit feature. Append `log(1 + degree)` — and any other structural statistic you trust, such as a clustering coefficient — to each node's input vector. The propagation stays scale-stable, and the model can learn a deliberate, bounded use of degree instead of reading it off an activation's magnitude.
  • What breaks if a node has no neighbours and you skip the self-loop?
    Its row of the adjacency matrix is all zeros, so its aggregate is the zero vector and its own features never reach the next layer. Worse, its degree is zero, so `D^-1` and `D^-1/2` are undefined. Adding `I` gives it degree one and it simply propagates itself.

Reading a recommendation letter: one from a referee who writes ten a year says more than one from a referee who signs a million. Symmetric normalization discounts by how much both the writer and the reader are involved.

saying these in an interview costs you the question

  • Says the nonlinearity will absorb the scale difference
  • Claims summing and averaging give the same embedding up to a constant
  • Divides only by the receiving node's degree and calls it symmetric
  • Forgets the self-loop, so a node's own features disappear
  • Treats normalization as purely a numerical-overflow guard
  • Ignores that normalization throws away a possibly predictive degree signal

context

open as a page

How is a graph encoded as the input to a graph neural network?

level: juniorimportance: must knowfreq 62%

basics

~20 s

A graph reaches the model as a node feature matrix — one row of features per node — plus an edge list of connected node id pairs, and optionally an edge feature matrix. Node ids are addresses, not values.

open as a page

In graph neural networks, what separates transductive from inductive training?

level: juniorimportance: must knowfreq 74%

basics

~20 s

Transductive training assumes every node you will ever score was already in the graph when the model was fitted. Inductive training learns a function of node features and neighbourhoods, so a node added later can be scored without refitting.

open as a page

What are the three steps of one message-passing round in a graph neural network?

level: juniorimportance: must knowfreq 76%

basics

~20 s

One round has three steps: each neighbour builds a message from its state and the connecting edge; the node pools those messages with an order-free aggregator; a learned update then combines the pooled vector with the node's own previous state.

open as a page

What is the difference between permutation invariance and equivariance for a graph model?

level: middleimportance: must knowfreq 54%

basics

~20 s

Permutation invariance means relabelling the nodes leaves the output unchanged, which is what a single graph-level prediction requires. Equivariance means the output moves with the relabelling: per-node predictions keep their values but come back in the new node order.

open as a page

Why does mini-batching a 3-layer GNN on a high-degree graph cause neighbour explosion?

level: middleimportance: must knowfreq 63%

basics

~20 s

Each message-passing layer adds one hop to a node's receptive field, so a batch holds degree-to-the-power-of-layers nodes per seed. At average degree 100 with three layers that is about a million nodes for one seed, which fixed per-hop fanout caps.

open as a page

Why does sum aggregation distinguish neighbourhoods that mean and max aggregation cannot?

level: middleimportance: must knowfreq 60%

basics

~20 s

A neighbourhood is a multiset, and only sum keeps both which features appear and how many times. Mean keeps proportions but loses counts; max keeps only extremes. Sum is the more distinguishing aggregator, which is why GIN uses it.

open as a page

How does a graph attention layer compute per-neighbour coefficients, and what is the softmax taken over?

level: middleimportance: must knowfreq 62%

basics

~20 s

A graph attention layer scores each edge from its two endpoints' transformed feature vectors using a small learned function, then softmax-normalizes those scores over only that node's own neighbourhood, so each node's incoming weights are positive and sum to one.

open as a page

What is over-smoothing in a deep graph neural network, and how would you detect it?

level: middleimportance: must knowfreq 62%

basics

~20 s

Over-smoothing is node embeddings collapsing toward one another as message-passing layers stack, because repeated neighbourhood averaging acts as a low-pass filter. Detect it by logging mean pairwise cosine similarity between node embeddings, which climbs toward 1.0 with depth.

open as a page

In GNN link prediction, what does a bilinear score buy over a plain dot product of two node vectors?

level: middleimportance: must knowfreq 58%

basics

~20 s

A dot product of two node vectors is symmetric and parameter-free, expressing one undirected notion of similarity. A bilinear score adds a learned matrix per relation, so it can be asymmetric and score several edge types from one shared embedding set.

open as a page

How does node2vec turn a graph with no node features into one vector per node?

level: middleimportance: must knowfreq 72%

basics

~20 s

node2vec samples many random walks starting from every node, treats each walk as a sentence of node ids, and trains a skip-gram objective so that nodes co-occurring inside a sliding window over those walks get similar vectors.

open as a page

Why must held-out test edges be deleted from a GNN's message-passing graph, not just from its labels?

level: seniorimportance: must knowfreq 42%

basics

~20 s

A single round of message passing copies each endpoint's features along the edge itself, so an edge left in the adjacency is read off rather than predicted. Delete held-out edges from the graph as well as the labels, and remove both stored directions.

open as a page

Why does an article created after node2vec training has run have no vector at all?

level: seniorimportance: must knowfreq 58%

basics

~20 s

node2vec learns a lookup table with one row per node id, not a function of a node's edges. A node that appeared in no sampled walk has no row, and nothing can compute one, so serving it requires a refit.

open as a page

In a graph-level GNN, what does a sum or mean readout over the node vectors do?

level: juniorimportance: should knowfreq 54%

basics

~20 s

A readout collapses the whole set of node vectors into one fixed-size graph vector that the graph-level head consumes. Summing or averaging works for graphs of any size and ignores node order, so relabelling the nodes cannot change the prediction.

open as a page

Why does GraphSAGE concatenate a node's own vector with the neighbour aggregate?

level: middleimportance: should knowfreq 45%

basics

~20 s

Concatenation keeps a node's own features in their own slots, so the layer learns separate weights for what the node looks like and what its neighbours look like. Averaging blends the two signals into a single inseparable one.

open as a page

Why do graph attention networks concatenate multiple heads in hidden layers but average them at the output?

level: middleimportance: should knowfreq 42%

basics

~20 s

Hidden layers concatenate heads because the extra width carries several independent weightings of the same neighbourhood and steadies training. The final layer must emit exactly one value per target, so its heads are averaged first and the output nonlinearity applied after.

open as a page

In GraphSAGE, when does the max-pooling aggregator beat the mean over sampled neighbours?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Max-pooling wins when a rare, salient neighbour is the signal: each sampled neighbour passes through a small learned layer and the aggregate is an elementwise max, so one distinctive neighbour survives. A mean dilutes it.

open as a page

A 50-node graph flattened to a 2,500-dim MLP input trains well but fails on held-out graphs. Why?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Flattening ties every weight to a fixed slot, so the model learns one arbitrary node numbering rather than structure. The same graph written in another order becomes a different input, and a fixed width cannot hold a variable neighbourhood.

open as a page

How does cluster-based subgraph mini-batching train a GNN on a 200-million-node graph?

level: seniorimportance: should knowfreq 44%

basics

~20 s

Partition the graph once into dense clusters that minimise cut edges, then make each mini-batch one or a few whole clusters and propagate inside that subgraph only. Neighbourhoods stay bounded, but every cross-partition edge is dropped for that step.

open as a page

How do you choose the number of message-passing rounds in a graph neural network?

level: seniorimportance: should knowfreq 46%

basics

~20 s

k rounds give a node a receptive field of exactly k hops, so pick k to match the distance at which the label's evidence lives, then confirm it with a small validation sweep. Most production graph models land at two or three.

open as a page

On which graphs does learned neighbour attention beat degree-normalized averaging, and where does it not help?

level: seniorimportance: should knowfreq 50%

basics

~20 s

Learned attention pays off when neighbours differ in relevance in a way the node features actually reveal — misleading edges, hub nodes, wildly uneven degrees. Where neighbours are interchangeable or features carry no signal, fixed degree-based weights match it for less cost.

open as a page

How does over-squashing differ from over-smoothing in a graph neural network?

level: seniorimportance: should knowfreq 38%

basics

~20 s

Over-smoothing is a loss of contrast: node representations converge as averaging rounds stack. Over-squashing is a loss of capacity in transit: an exponentially growing neighbourhood is funnelled through bottleneck edges into fixed-width vectors, so distant evidence never arrives intact.

open as a page

How do you sample negative edges to train a link-prediction GNN on a very sparse graph?

level: seniorimportance: should knowfreq 46%

basics

~20 s

Nearly every node pair in a sparse graph is a non-edge, so uniformly drawn negatives are trivially easy. Draw them matched to node degree or from two-hop neighbourhoods, filter out known edges, and expect the positive-to-negative ratio to distort predicted probabilities.

open as a page

Your graph network must use evidence six hops away, but accuracy drops past three layers — how do you design for it?

level: principalimportance: should knowfreq 30%

basics

~20 s

Treat it as two problems: over-smoothing at depth and a reach problem. Make depth survivable with a jumping-knowledge readout and initial-residual connections, then shorten the distance itself by targeted rewiring or coarsening, re-measuring after each move.

open as a page

What hand-built graph features would you demand as a baseline before funding a GNN?

level: principalimportance: should knowfreq 38%

basics

~20 s

A few per-node structural columns fed to a plain tabular classifier: in-degree and out-degree, a PageRank score, triangle count and clustering coefficient. It trains in minutes, stays interpretable, and gives the proposal a number to beat.

open as a page

Your node2vec vectors cluster friend groups, but you need bridge accounts to look alike — what do you change?

level: seniorimportance: nice to knowfreq 36%

basics

~20 s

Raise node2vec's in-out parameter q above one. Walks then stay in the source's immediate neighbourhood instead of wandering outward, so vectors encode structural role rather than community membership, and two brokers in unrelated groups land near each other.

open as a page

Can a graph attention model's coefficients be handed to a clinician as the explanation for a prediction?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Attention coefficients are not a causal explanation. They are per-head, per-layer relative weights over already-mixed neighbour vectors, showing where the model allocated weight rather than what changed the prediction. Validate any such claim with edge-removal counterfactuals first.

open as a page