VerifiedarXiv:1710.1090326 min
Architecture · Graph learning

GAT: Graph Attention Networks

A node weights each neighbor by a learned score, not by node degree.

A graph attention layer scores every edge from the two nodes' features, normalizes the scores with a softmax inside each neighborhood, and averages neighbor features with those weights. Nothing in the layer depends on the graph it was trained on.

Explaining the paperGraph Attention NetworksVeličković, Cucurull, Casanova, Romero, Liò, Bengio · ICLR 2018 · arXiv:1710.10903 ↗

Two learned vectors and a softmax turn a graph convolution's fixed neighbor weights into weights computed from the features, edge by edge.

The task is node classification. A graph has NN nodes, each carrying a feature vector h⃗i∈RF\vec h_i \in \mathbb{R}^F, and a few nodes carry a label. On the Cora citation graph that is 2,708 papers, a 1,433-dimensional bag-of-words vector per paper, 5,429 citation edges, 7 topic classes, and labels on 140 papers, 20 per class. The model is scored on 1,000 of the remaining papers. A graph convolutional network (GCN) does this by replacing each node's features with a weighted sum over the node and its neighbors, where the weight on edge (i,j)(i, j) is 1/didj1/\sqrt{d_i d_j}, a number set by the two degrees (self-loop included) before training starts. A paper cited by a closely related paper and a paper cited by an unrelated one get the same weight if the degrees match.

Graph attention networks replace that fixed weight with a number computed from the two nodes' features by a small function shared across every edge, then normalized across the neighborhood so the weights into any node sum to one. The paper lists what that buys: the work is parallel across edges and across nodes, a node with three neighbors and a node with three hundred use the same parameters, and because no parameter has a size tied to the graph, a trained layer runs unchanged on a graph it never saw. On the protein-protein interaction (PPI) benchmark the test graphs are held out of training entirely, and the model reaches a micro-averaged F1 score (precision and recall pooled over every node and label) of 0.973, against 0.768 for the strongest GraphSAGE the authors could configure.

The layer takes six equations: a score per edge, (1) and (3); a masked softmax that turns scores into weights, (2); a weighted sum, (4); and two ways of combining several attention heads, (5) and (6). After those, this page walks a property of the scoring function that the paper did not notice and a later paper named, the training setup on 140 labels, and the results with their margins measured in points.

Scoring one neighbor

A layer maps the input features h⃗i∈RF\vec h_i \in \mathbb{R}^F of every node to output features h⃗i′∈RF′\vec h'_i \in \mathbb{R}^{F'}. The first step is a linear map W∈RF′×F\mathbf W \in \mathbb{R}^{F' \times F} applied to every node with the same weights. On Cora's first layer F=1433F = 1433 and F′=8F' = 8, so W\mathbf W is 8 × 1,433, 11,464 weights shared by all 2,708 nodes, and Wh⃗j\mathbf W \vec h_j is an 8-vector per node. The score of neighbor jj for node ii is a function of the two projected vectors:

eij=a(Wh⃗i,Wh⃗j)e_{ij} = a(\mathbf W \vec h_i, \mathbf W \vec h_j)
(1)

The paper reads eije_{ij} as the importance of node jj's features to node ii. The function aa is a single-layer network: concatenate the two 8-vectors into a 16-vector, take its dot product with a learned vector a⃗∈R2F′\vec{\mathbf a} \in \mathbb{R}^{2F'}, and pass the result through a LeakyReLU with negative slope 0.2 (the identity for positive inputs; negative inputs are multiplied by 0.2). With the softmax of the next section folded in, the paper's fully expanded form is:

αij=exp⁡(LeakyReLU(a⃗T[Wh⃗i ∥ Wh⃗j]))∑k∈Niexp⁡(LeakyReLU(a⃗T[Wh⃗i ∥ Wh⃗k]))\alpha_{ij} = \frac{\exp\big(\mathrm{LeakyReLU}\big(\vec{\mathbf a}^{T}[\mathbf W \vec h_i \,\|\, \mathbf W \vec h_j]\big)\big)}{\sum_{k \in \mathcal N_i} \exp\big(\mathrm{LeakyReLU}\big(\vec{\mathbf a}^{T}[\mathbf W \vec h_i \,\|\, \mathbf W \vec h_k]\big)\big)}
(3)

Here ∥\| is concatenation and Ni\mathcal N_i is the neighborhood of ii. The dot product with a concatenation splits into two dot products. Write a⃗=[a⃗1;a⃗2]\vec{\mathbf a} = [\vec{\mathbf a}_1; \vec{\mathbf a}_2] with each half in RF′\mathbb{R}^{F'}; then

a⃗T[Wh⃗i ∥ Wh⃗j]=a⃗1TWh⃗i⏟si+a⃗2TWh⃗j⏟tj,eij=LeakyReLU(si+tj).\vec{\mathbf a}^{T}[\mathbf W \vec h_i \,\|\, \mathbf W \vec h_j] = \underbrace{\vec{\mathbf a}_1^{T}\mathbf W \vec h_i}_{s_i} + \underbrace{\vec{\mathbf a}_2^{T}\mathbf W \vec h_j}_{t_j}, \qquad e_{ij} = \mathrm{LeakyReLU}(s_i + t_j).a⃗T[Wh⃗i ∥ Wh⃗j]=a⃗1TWh⃗i⏟si+a⃗2TWh⃗j⏟tj,eij=LeakyReLU(si+tj).\begin{gathered} \vec{\mathbf a}^{T}[\mathbf W \vec h_i \,\|\, \mathbf W \vec h_j] = \underbrace{\vec{\mathbf a}_1^{T}\mathbf W \vec h_i}_{s_i} + \underbrace{\vec{\mathbf a}_2^{T}\mathbf W \vec h_j}_{t_j}, \\ e_{ij} = \mathrm{LeakyReLU}(s_i + t_j). \end{gathered}

The official code computes it this way: two 1 × 1 convolutions over the projected features produce ss and tt as one number per node, and adding ss as a column to tt as a row gives every si+tjs_i + t_j at once. So the per-node work is two dot products of length 8, and the per-edge work is one addition and one LeakyReLU. A node's own sis_i is the same for all its neighbors; what separates the neighbors is tjt_j, the projection of each neighbor's features onto a⃗2\vec{\mathbf a}_2.

For a worked row, take a node ii with four neighbors, so five members of the neighborhood once ii itself is included (the next section says why it is). Suppose si=0.40s_i = 0.40 and the five tt values are 0.25 for ii itself and 0.90, −0.30, 0.10, −1.20 for the neighbors. The sums are 0.65, 1.30, 0.10, 0.50, −0.80, and the LeakyReLU leaves the positive ones alone and multiplies −0.80 by 0.2, giving scores of 0.65, 1.30, 0.10, 0.50, −0.16. A plain ReLU would have sent −0.80 to exactly 0 and given that neighbor a zero gradient into a⃗\vec{\mathbf a}; the paper does not state its reason for the leaky variant, and this is the natural one. Since the LeakyReLU is monotone it never reorders the neighbors; it compresses the negative side of the scale, so the softmax takes less weight away from low-scoring neighbors than it would from the raw sums.

In the figure below the plane is the projected feature space, each amber point is one neighbor's Wh⃗j\mathbf W \vec h_j, and the amber arrow is a⃗2\vec{\mathbf a}_2. The dashed lines are lines of equal tjt_j, perpendicular to the arrow. Drag a neighbor along the arrow and its score and weight rise; drag it along a dashed line and nothing changes. The figure's second slider (the first rotates a⃗2\vec{\mathbf a}_2) scales the whole vector a⃗\vec{\mathbf a}; at zero every score is equal and every weight is 1/6, which is the constant-attention baseline the paper uses as a control in the PPI experiment.

Figure 1 · one node scores its neighborhood
35°
|a| = 1.50
The query node i and five neighbors in the projected feature plane. Each edge is drawn with width equal to its weight α_ij, and the table lists the score e_ij and the weight for every member of the closed neighborhood, including i itself. Rotate a₂ with the first slider, drag any neighbor, or scale a to zero to recover uniform weights.

Masking and the softmax

Equation (1) as written could score every pair of nodes, and the paper says so: in its most general form every node attends to every other node and the graph structure is dropped entirely. The structure enters by computing eije_{ij} only for j∈Nij \in \mathcal N_i, the first-order neighbors of ii, with ii itself included. The paper calls this masked attention. The scores are then normalized within the neighborhood so they are comparable across nodes:

αij=softmaxj(eij)=exp⁡(eij)∑k∈Niexp⁡(eik)\alpha_{ij} = \mathrm{softmax}_j(e_{ij}) = \frac{\exp(e_{ij})}{\sum_{k \in \mathcal N_i} \exp(e_{ik})}
(2)

For the worked row, the exponentials of 0.65, 1.30, 0.10, 0.50, −0.16 are 1.916, 3.669, 1.105, 1.649, 0.852, their sum is 9.191, and dividing gives weights of 0.208 for the node itself and 0.399, 0.120, 0.179, 0.093 for the neighbors. Every weight is positive and the five sum to one. The neighbor with tj=0.90t_j = 0.90 takes almost 40% of the row; the neighbor at −1.20 keeps 9%, since the leaky slope kept its score close to the others.

The code does the masking with a dense matrix. It computes all N×NN \times N scores, adds a bias matrix that is 0 on every edge and self-loop and −10⁹ everywhere else, and takes the softmax of the sum; the exponential of a score near −10⁹ underflows to exactly 0, so non-neighbors receive weight 0 and each row still sums to 1 over the true neighborhood. The self-loops come from adding the identity to the adjacency matrix before the mask is built. On Cora that matrix has 2,708² = 7,333,264 entries, of which about 13,600 (two per edge plus one per node) are inside the mask, and at 4 bytes per entry it costs 29.3 MB per head, 235 MB for the eight heads of the first layer. Pubmed has 19,717 nodes, so its dense score matrix has 388.8 million entries and costs 1.56 GB per head. That is why the authors wrote a sparse variant of the layer. Their framework, as the paper says, only supports sparse multiplication of rank-2 tensors, which limits that variant to one graph at a time.

Two properties of the result are used below. The weights are asymmetric: eij=LeakyReLU(si+tj)e_{ij} = \mathrm{LeakyReLU}(s_i + t_j) while eji=LeakyReLU(sj+ti)e_{ji} = \mathrm{LeakyReLU}(s_j + t_i), and the two rows are normalized separately, so αij\alpha_{ij} and αji\alpha_{ji} generally differ. And the graph need not be undirected: for a directed graph the code leaves αij\alpha_{ij} out whenever the edge j→ij \to i is absent, and nothing else changes. The figure shows the three matrices in the code's order: dense scores, the mask, and the softmax of their sum. Click an off-diagonal cell to add or remove an edge and watch the two affected rows renormalize, and hover a cell to compare αij\alpha_{ij} with αji\alpha_{ji}.

Figure 2 · dense scores, a mask, a row-wise softmax
A seven-node graph and its 7 × 7 attention matrix. The tabs show the dense scores computed for every pair, the bias matrix (0 on edges and self-loops, −1e9 elsewhere), and the resulting weights, whose rows sum to 1 in the Σ column. Click a node to draw its incoming weights as edge widths; click a cell to toggle that edge.

The paper gives the cost of one head as O(∣V∣FF′+∣E∣F′)O(|V| F F' + |E| F'): the projection of every node, plus the weighted sum over every edge. On Cora the projection is 2,708 × 1,433 × 8, about 31.0 million multiply-adds, and the aggregation over the 13,600 mask entries is about 109,000, so the projection dominates and the cost matches a GCN layer of the same width. There is no eigendecomposition and no matrix inverse anywhere; spectral methods need the eigenbasis of the graph Laplacian, which is what ties them to one graph.

The layer output

With the weights in hand, node ii's new features are the weighted sum of its neighbors' projected features, followed by a nonlinearity σ\sigma:

h⃗i′=σ(∑j∈Niαij Wh⃗j)\vec h'_i = \sigma\Big(\sum_{j \in \mathcal N_i} \alpha_{ij}\, \mathbf W \vec h_j\Big)
(4)

For the worked row that is

h⃗i′=ELU(0.208 Wh⃗i+0.399 Wh⃗1+0.120 Wh⃗2+0.179 Wh⃗3+0.093 Wh⃗4),\vec h'_i = \mathrm{ELU}\big(0.208\,\mathbf W \vec h_i + 0.399\,\mathbf W \vec h_1 + 0.120\,\mathbf W \vec h_2 + 0.179\,\mathbf W \vec h_3 + 0.093\,\mathbf W \vec h_4\big),h⃗i′=ELU(0.208 Wh⃗i+0.399 Wh⃗1+0.120 Wh⃗2+0.179 Wh⃗3+0.093 Wh⃗4),\begin{aligned} \vec h'_i = \mathrm{ELU}\big(&0.208\,\mathbf W \vec h_i + 0.399\,\mathbf W \vec h_1 + 0.120\,\mathbf W \vec h_2 \\ &+ 0.179\,\mathbf W \vec h_3 + 0.093\,\mathbf W \vec h_4\big), \end{aligned}

an 8-vector, with an ELU (exponential linear unit: the identity for positive inputs, e^x − 1 below zero) as the hidden layer's nonlinearity. The code adds a bias vector before the nonlinearity, which equation (4) omits. The same W\mathbf W that produced the scores produces the values being summed, so one matrix does the work that a Transformer splits across query, key and value projections.

Set this next to the GCN rule over the same closed neighborhood,

h⃗i′=σ(∑j∈Ni1didj Wh⃗j).\vec h'_i = \sigma\Big(\sum_{j \in \mathcal N_i} \frac{1}{\sqrt{d_i d_j}}\, \mathbf W \vec h_j\Big).

The shapes match line for line; the only change is the coefficient in front of each neighbor, a fixed function of two degrees in the GCN and a learned function of two feature vectors here. The paper's constant-attention control, a(x,y)=1a(x, y) = 1, sits between the two: every score is equal, so the softmax gives each member of the closed neighborhood 1/∣Ni∣1/|\mathcal N_i|, a plain mean.

The whole head, in the shapes the code uses:

# one attention head: N nodes, F features in, F' features out
Wh    = h @ W.T                      # [N, F']  shared projection (eq. 1)
s     = Wh @ a1                      # [N]      query half of a^T[Wh_i || Wh_j]
t     = Wh @ a2                      # [N]      neighbor half
e     = leaky_relu(s[:, None] + t[None, :], 0.2)   # [N, N]  every pair (eq. 3)
e     = e + mask                     # 0 on edges and self-loops, -1e9 elsewhere
alpha = softmax(e, axis=1)           # [N, N]  each row sums to 1 over N_i (eq. 2)
alpha = dropout(alpha, p=0.6)        # training only: a random sub-neighborhood
h_out = elu(alpha @ Wh + b)          # [N, F']  eq. 4 (the code adds a bias b)

Gradients reach W\mathbf W through two routes. The loss is a cross-entropy on the 140 labeled nodes. Each labeled node's logits depend on W\mathbf W through the summed values Wh⃗j\mathbf W \vec h_j and, separately, through the scores that set αij\alpha_{ij}; the attention vector a⃗\vec{\mathbf a} gets gradient only through the softmax. An unlabeled neighbor contributes its features to a labeled node's output, so its projection is in the computation graph and the shared W\mathbf W learns from it, as in a GCN. The weight count of a head is F′F+2F′F' F + 2F', 11,480 on Cora's first layer before the code's bias terms, with no term in NN or in the edge count, which is the whole reason the same weights can be applied to a different graph.

Several heads, concatenated or averaged

One head computes one set of weights per neighborhood. The paper runs KK heads in parallel, each with its own Wk\mathbf W^k and a⃗k\vec{\mathbf a}^k, and in a hidden layer concatenates their outputs:

h⃗i′=∥k=1K σ(∑j∈Niαijk Wkh⃗j)\vec h'_i = \Big\Vert_{k=1}^{K}\ \sigma\Big(\sum_{j \in \mathcal N_i} \alpha^k_{ij}\, \mathbf W^k \vec h_j\Big)
(5)

The output has KF′K F' features. Cora's first layer uses K=8K = 8 heads of F′=8F' = 8, so each node leaves the layer with 64 features, and the layer holds 8 × 11,480 = 91,840 parameters. Each head weights the same neighborhood differently, since each has its own a⃗2k\vec{\mathbf a}^k_2 to project onto. The paper's stated reason for several heads is that they stabilize training, following the Transformer; it reports no ablation over KK.

In the output layer concatenation would leave KCK C logits for CC classes, so the paper averages the heads instead and applies the final nonlinearity (a softmax over classes, or a sigmoid per label) after the average:

h⃗i′=σ(1K∑k=1K∑j∈Niαijk Wkh⃗j)\vec h'_i = \sigma\Big(\frac{1}{K}\sum_{k=1}^{K}\sum_{j \in \mathcal N_i} \alpha^k_{ij}\, \mathbf W^k \vec h_j\Big)
(6)

Cora's output layer is a single head with C=7C = 7 outputs: W\mathbf W is 7 × 64 and a⃗\vec{\mathbf a} has 14 entries, 462 parameters. Pubmed uses 8 output heads averaged; the PPI model uses 6 output heads of 121 outputs each. The figure draws one edge fan per head and the resulting output vector under each rule. At K=1K = 1 the two rules coincide.

Figure 3 · K heads, two ways to combine them
K = 8
Each head owns a color, an edge fan whose widths are that head's weights, and a block of 8 output cells. The hidden-layer rule (5) concatenates the blocks into K·8 features; the output-layer rule (6) averages them into 8. Slide K from 1 to 8; the paper's Cora setting is K = 8, F' = 8.

Every node ranks its neighbors the same way

The paper says its attention closely follows Bahdanau, Cho and Bengio (2015). Their alignment score is v⃗aTtanh⁡(Was⃗+Uah⃗)\vec v_a^{T}\tanh(\mathbf W_a \vec s + \mathbf U_a \vec h): a nonlinearity applied to the sum of two projections, then a dot product with a learned vector. Equation (3) has the two steps in the other order, a dot product first and the LeakyReLU after it.

Fix a node ii. Its score for neighbor jj is LeakyReLU(si+tj)\mathrm{LeakyReLU}(s_i + t_j), and sis_i is the same number for every neighbor. LeakyReLU is monotone increasing, so if tj>tkt_j > t_k then eij>eike_{ij} > e_{ik}, and the softmax preserves order, so αij>αik\alpha_{ij} > \alpha_{ik}. The comparison never involved ii. Every node in the graph ranks the nodes it can see by the same single number, tj=a⃗2TWh⃗jt_j = \vec{\mathbf a}_2^{T}\mathbf W \vec h_j. What can vary between nodes is how peaked the weights are: sis_i shifts every sum toward or away from the kink at zero, which stretches or compresses the gaps between scores. Brody, Alon and Yahav (2022) named this static attention, proved that no choice of W\mathbf W and a⃗\vec{\mathbf a} escapes it, and showed that restoring Bahdanau's order, a⃗TLeakyReLU(W[h⃗i ∥ h⃗j])\vec{\mathbf a}^{T}\mathrm{LeakyReLU}(\mathbf W[\vec h_i \,\|\, \vec h_j]), lets the ranking depend on the query at the same cost. They call the result GATv2.

The figure has two query nodes that share five neighbors. Under the GAT tab, drag either query anywhere and the rank numbers over the two bar charts stay identical; only the bar heights change. Under the GATv2 tab the orders come apart as the queries move.

Figure 4 · static versus dynamic attention
Queries A and B attend over the same five neighbors. Bars are each query's weights, with a rank above each bar. GAT: the rank order is the same for both queries wherever they sit. GATv2 (nonlinearity inside the projection): the orders can differ. Drag A or B.

Training on 140 labels

The transductive experiments (the test nodes and the whole graph are visible during training; only their labels are hidden) follow the Planetoid split of Yang et al. (2016): on Cora, 140 labeled nodes for training, 500 for validation, 1,000 for testing, with every node's features and the full graph visible throughout. The model is two layers, the first with 8 heads of 8 features and an ELU, the second a single head with 7 outputs and a softmax, 92,302 weights in total. Training uses Adam at learning rate 0.005, Glorot initialization (weights drawn with variance 2 / (fan-in + fan-out)), an L2 penalty of 0.0005 on the weights, and early stopping with a patience of 100 epochs on validation loss and accuracy together. Citeseer reuses the Cora settings. Pubmed, with 60 labeled nodes, needed 8 averaged output heads, an L2 penalty of 0.001, and learning rate 0.01.

# the Cora model: 1433 -> 8 heads x 8 -> 7 classes
h1 = concat([head_k(x, adj) for k in range(8)])     # [2708, 64], ELU inside
logits = head_out(h1, adj)                          # [2708, 7], no nonlinearity
loss = cross_entropy(softmax(logits)[train_idx], y[train_idx])   # 140 nodes
loss += 0.0005 * sum(w**2 for w in params)          # L2, all parameters
# backprop reaches W^k, a^k, b^k of both layers through alpha and through Wh

Dropout at p=0.6p = 0.6 is applied to both layers' inputs and also to the normalized attention coefficients themselves. Each training step keeps each αij\alpha_{ij} with probability 0.4 and scales the survivors by 1/(1−p)=2.51/(1 - p) = 2.5, so a node aggregates a random subset of its neighborhood and the surviving weights no longer sum to one, though their expectation does. The paper describes this as exposing each node to a stochastically sampled neighborhood at every iteration. The code also applies the input dropout a second time to the projected features Wh⃗\mathbf W \vec h before they are summed. At test time nothing is dropped and the weights of (2) are used as computed. Slide pp in the figure to the paper's 0.6 and resample a few times; then push it to 0.9, where most steps drop nearly the whole neighborhood.

Figure 5 · dropout on the attention coefficients
p = 0.60
One node, six neighbors, a self-loop. Each coefficient survives with probability 1 − p and is scaled by 1/(1 − p); dropped edges are dashed. The readout sums the surviving weights, which equals 1 only at p = 0. Resample to draw a new mask; the paper trains at p = 0.6.

The inductive experiment (the model is scored on graphs it never saw in training) uses the protein-protein interaction dataset: 24 graphs of human tissues, 56,944 nodes and 818,716 edges in all, 50 features per node, and 121 binary labels per node from gene ontology, so a node can carry several labels. Twenty graphs train, two validate, two test, and the test graphs are never seen during training. The model is three layers: two layers of 4 heads × 256 features with ELU, a skip connection across the middle layer in the style of a residual network, and an output layer of 6 heads × 121 averaged and passed through a sigmoid. With 44,906 training nodes the authors used no dropout and no L2 penalty, and trained on batches of two graphs. The control is the same network with a(x,y)=1a(x, y) = 1, the constant-attention model.

Results and their margins

On the citation graphs the paper reports mean test accuracy over 100 runs. Cora: 83.0 ± 0.7 against 81.5 for the published GCN and 81.4 ± 0.5 for GCN-64*, the authors' own 64-feature GCN with the better of ReLU and ELU. Citeseer: 72.5 ± 0.7 against 70.3 and 70.9 ± 0.5. Pubmed: 79.0 ± 0.3 against 79.0 and 79.0 ± 0.3, a tie. The paper states the margins over GCNs as 1.5% on Cora and 1.6% on Citeseer. Both are percentage points, and each is measured against the best GCN variant in its column: 83.0 − 81.5 on Cora, and 72.5 − 70.9 on Citeseer, where the margin over the published GCN would be 2.2 points. A 1.5-point margin with a run-to-run standard deviation of 0.7 is about two standard deviations.

On PPI, GAT reaches a micro-F1 of 0.973 ± 0.002. The same architecture with constant attention, Const-GAT, reaches 0.934 ± 0.006, so the learned weights account for 3.9 points. The best GraphSAGE the authors could build, a three-layer LSTM aggregator with 512, 512 and 726 features, reaches 0.768, and the published GraphSAGE-LSTM 0.612. Of the 20.5-point gap to GraphSAGE*, 16.6 points are already present in Const-GAT, which shares GAT's 1,024-wide layers, skip connection, and view of the full neighborhood; the paper attributes the gap to observing the entire neighborhood, since GraphSAGE samples a fixed-size subset of it.

Figure 6 · Tables 2 and 3
One dataset per tab. GAT in teal, GCN-style aggregators (GCN, GCN-64*, GraphSAGE-GCN, Const-GAT) in amber, everything else muted; whiskers are the reported standard deviations. Pubmed is the tie; PPI is the 3.9-point attention ablation.

The paper also plots a t-SNE (a two-dimensional embedding made for visualization) of the first layer's 64-dimensional features on Cora, colored by class, with edge thickness set to the attention weight averaged over the eight heads. The classes separate into visible clusters. On what the weights mean, the paper says that interpreting them will require domain knowledge about the dataset and leaves it to future work.

Costs and limits

The dense implementation stores an N×NN \times N matrix per head, which is what the memory arithmetic of the masking section priced at 1.56 GB per head on Pubmed. The sparse implementation removes that but, in the authors' framework, handles one graph per batch. The receptive field is bounded by depth, one hop per layer, the same limit a GCN has, and the paper points to skip connections as the way to add layers. Parallelizing across all edges repeats the projection of a node once per edge it touches unless the projection is cached per node, which the code does and a distributed implementation would have to arrange. The layer uses no edge features, and the paper evaluates node classification only; graph classification, edge features, and larger batches are the listed extensions.

The paper's list omits the static ranking shown earlier, in the section on how every node ranks its neighbors. Because the LeakyReLU sits outside the dot product, a trained GAT assigns every node the same neighbor ranking, and any task that needs node ii to prefer neighbor jj while node kk prefers ll, with jj and ll both visible to each, is outside what the scoring function can represent. GATv2 changes one line of the layer, applies the nonlinearity before the dot product with a⃗\vec{\mathbf a}, and keeps the cost at O(∣V∣FF′+∣E∣F′)O(|V| F F' + |E| F').

Provenance Verified against primary literatureHow we verify
Veličković et al. (2018)Equations (1) to (6) and the LeakyReLU slope 0.2 (Section 2.1); complexity O(|V|FF' + |E|F'), the sparse-variant and batching notes (Section 2.2); dataset sizes (Table 1); architectures, dropout 0.6 on inputs and attention coefficients, L2 0.0005 / 0.001, Adam 0.005 / 0.01, patience 100, PPI skip connection and batch of 2 graphs (Section 3.3); Tables 2 and 3 and the stated margins (Section 3.4).
PetarV-/GAT (official code)utils/layers.py 11: W as a bias-free 1×1 convolution; 14 to 16: f_1 + transpose(f_2), the a_1 / a_2 split with dense N×N logits; 17: softmax(leaky_relu(logits) + bias_mat); 19 to 22: dropout on the coefficients and again on the projected features; 24 to 25: alpha @ Wh plus a bias; 34: the nonlinearity. utils/process.py 14 to 25: self-loops via adj + I, bias = −1e9 × (1 − mask). models/gat.py 24 to 29: output heads averaged (add_n / n_heads). execute_cora.py 13 to 21: lr 0.005, l2_coef 0.0005, hid_units [8], n_heads [8, 1], patience 100, ELU; attn_drop = ffd_drop = 0.6.
Bahdanau, Cho & Bengio (2015)Appendix A.1.2: a(s_{i−1}, h_j) = v_a^T tanh(W_a s_{i−1} + U_a h_j), the nonlinearity inside the projection.
Brody, Alon & Yahav (2022)Static attention: the ranking of attention scores is unconditioned on the query node; GATv2 changes the order of operations and is strictly more expressive at the same cost.
Kipf & Welling (2017)The GCN propagation rule with weights 1/sqrt(d_i d_j) over the closed neighborhood; the 81.5 / 70.3 / 79.0 baselines.
Hamilton, Ying & Leskovec (2017)GraphSAGE: fixed-size sampled neighborhoods, the mean / LSTM / pool aggregators, and the PPI preprocessing and baselines.
Vaswani et al. (2017)Multi-head attention with concatenated heads, the model the paper cites for stabilizing training.
Monti et al. (2017)MoNet: GAT is the instance with pseudo-coordinates u(x, y) = f(x) || f(y) and softmax(MLP(u)) weights (Section 2.2).
correctionThe paper says its attention mechanism closely follows Bahdanau et al. (2015). It does not: Bahdanau's score is v_a^T tanh(W_a s + U_a h), with the nonlinearity inside the projection, while equation (3) applies LeakyReLU after the dot product with a. Because a^T[Wh_i || Wh_j] splits into a_1^T Wh_i + a_2^T Wh_j and LeakyReLU is monotone, every node ranks its neighbors in the same order, by a_2^T Wh_j alone (Brody, Alon and Yahav 2022 call this static attention; GATv2 restores Bahdanau's order). Separately, the margins in Section 3.4 are percentage points, and the Citeseer figure of 1.6 is taken against the authors' own GCN-64* (70.9), not the published GCN (70.3), which would give 2.2.

Questions you might still have

?

Is a GAT layer a Transformer layer restricted to the edges of the graph?
The masked softmax is the same idea, and the paper presents its general form (every node attends to every node) as the case with the graph structure dropped. The scoring differs: a Transformer takes a scaled dot product between separate query and key projections, GAT takes a LeakyReLU of a linear function of the two projected features and uses one matrix W for query, key and value. A GAT layer also has no feed-forward sublayer and no layer normalization. The Attention Is All You Need explainer on this site covers the Transformer side.

?

Why is the node itself inside its own neighborhood?
Equation (4) sums only over j in N_i. Without the self-loop a node’s own features would not appear in its output at all, and a node with no neighbors would output nothing. The official code adds the identity to the adjacency matrix before building the mask, and the same convention appears in the graph convolutional network it builds on.

?

How far can a node see?
One hop per layer. The two-layer Cora model combines features from nodes up to two edges away, and the paper notes the receptive field is bounded by depth, as for GCNs, and suggests skip connections as the way to go deeper. The three-layer PPI model already uses one skip connection across its middle layer.

?

Is Const-GAT the same thing as a GCN?
Not exactly. With a(x, y) = 1 every score is equal and the softmax gives 1/|N_i| to every member of the closed neighborhood, a plain mean. A GCN weights edge (i, j) by 1/sqrt(d_i d_j), which depends on both degrees and does not sum to one across a row. The paper calls Const-GAT a GCN-like inductive operator, and it serves as the control that isolates what the learned weights add: 3.9 micro-F1 points on PPI.

?

Why does Pubmed tie with GCN?
The paper does not say. Pubmed has 60 training nodes and only 3 classes, and the authors needed 8 averaged output heads and double the L2 penalty to train there at all. Our reading, not the paper’s claim: with that little supervision, the extra freedom of learned edge weights brings nothing the fixed degree weights did not already provide.

?

Can I read the attention weights as explanations?
Only with care. The paper defers interpretation to future work, and the static-ranking result gives a concrete reason: the order in which a node weights its neighbors is set by a single number per neighbor, a_2 dot W h_j, that does not depend on the node doing the weighting. A thick edge in the paper’s Figure 2 says more about the target node than about the pair. GATv2 (Brody, Alon and Yahav, 2022) fixes the ordering by moving the nonlinearity inside the projection.

?

How do current libraries avoid the N by N matrix?
They never build it. With the edges stored as a list, s_i + t_j is computed once per edge, the softmax is taken per destination node over that node’s incoming edges (a segment softmax), and the weighted sum is a scatter-add. Memory is then proportional to the edge count rather than to N squared, which is the O(|E| F’) term of the paper’s own complexity bound. PyTorch Geometric and DGL both implement the layer this way.

?

What makes the layer usable on a graph it never saw?
Nothing in the trained parameters has a size tied to the graph: W is F’ by F, a is 2F’, and the mask is rebuilt from whatever adjacency is given at run time. The PPI experiment tests exactly this, with two graphs held out entirely from training. Spectral methods, by contrast, define their filters on the eigenbasis of one particular graph Laplacian.

Footnotes & further reading

  1. The paper: Veličković, Cucurull, Casanova, Romero, Liò and Bengio, Graph Attention Networks (ICLR 2018). Official TensorFlow code; line numbers in the Provenance panel refer to its master branch.
  2. The graph convolution it replaces: Kipf and Welling, Semi-Supervised Classification with Graph Convolutional Networks (ICLR 2017), explained on this site at Graph Convolutional Networks.
  3. The attention the paper cites: Bahdanau, Cho and Bengio, Neural Machine Translation by Jointly Learning to Align and Translate (ICLR 2015), explained at Neural Machine Translation by Jointly Learning. The multi-head form: Vaswani et al., Attention Is All You Need (NeurIPS 2017), explained at Attention Is All You Need.
  4. Static versus dynamic attention and GATv2: Brody, Alon and Yahav, How Attentive are Graph Attention Networks? (ICLR 2022).
  5. The inductive baseline: Hamilton, Ying and Leskovec, Inductive Representation Learning on Large Graphs (GraphSAGE, NeurIPS 2017). The PPI graphs come from Zitnik and Leskovec (2017), preprocessed by GraphSAGE.
  6. The framework GAT is an instance of: Monti et al., Geometric deep learning on graphs and manifolds using mixture model CNNs (CVPR 2017).