The feed-forward network
Here is a question that sounds like a trick. Attention lets every token gather information from every other token, with learned, input-dependent weights. Why does a Transformer block need anything else?
Look at what attention outputs. For each token, it returns a weighted average of value vectors, and each value vector is a linear projection of a token's stream. Attention is superb at moving information between positions, but once the weights are fixed, what it computes about the moved information is linear. You met the precise version of this worry at the end of §4.7. A stack of pure self-attention layers, with no skip connections and no MLPs, collapses toward a rank-1 output (every token ending up with the same vector) doubly exponentially fast in depth (Dong, Cordonnier & Loukas, 2021). The skip connections of §5.1 are half of the cure, and the MLP is the other half.
So every block pairs attention with a second sublayer, a small multilayer perceptron applied to each token on its own. It is the plainest component in the Transformer and holds about two thirds of its parameters. By the end of this section you will be able to write it in three variants, count it exactly, explain why nearly every modern LLM uses a gated version with a strange hidden size like 11,008, and read it as a key-value memory that stores much of what the model knows.
The MLP sublayer, applied to each token
For one token's stream vector , written as a row, the feed-forward network (FFN) is
where is the hidden width, and are biases, and is an elementwise nonlinearity. For a sequence the same weights are applied to every row, , which is why it is often called position-wise. No information crosses between tokens here. That is attention's job.
In plain words, project each token up into a wider space, apply a nonlinearity there, and project back down to the stream.
Counting it
The FFN has parameters. The original Transformer used and , an expansion ratio of 4, and almost every dense model since kept that ratio or something matched to it. With ,
since attention has four projections (, see §4.5). So the FFN is two thirds of every block's weights. Its compute is in the same proportion, because a matrix multiply costs 2 FLOPs per weight per token (one multiply, one add). Forward, the FFN costs FLOPs per token against for attention's projections.
A worked example with GPT-2 small, and . The FFN has parameters per layer, and the attention sublayer has . Across 12 layers the FFNs hold about 56.7 million of the model's 124 million parameters. Section 5.6 counts the rest of the block, and §6.2 the rest of the model.
Why a ratio of 4? There is no theorem. Vaswani et al. chose it, and it has survived because wider hidden layers buy capacity cheaply. The FFN is a dense matrix multiply, the operation GPUs do best, so adding hidden units costs little wall-clock time per parameter. Mixture-of-experts models (Chapter 13) push the same idea further by keeping many FFNs and activating only a few per token.
Activation functions, from ReLU to GELU and SiLU
The original Transformer used ReLU, . BERT and GPT-2 switched to GELU, and LLaMA-style models use SiLU inside a gate. Here is where GELU comes from, because its definition explains its shape.
Hendrycks & Gimpel (2016) started from dropout. Dropout multiplies a unit's input by a random 0 or 1. Suppose instead the mask depends on the input itself, , where is the standard normal CDF, so larger inputs are more likely to be kept. The expected output is
In plain words, GELU passes an input through with a probability that rises smoothly from 0 to 1 as the input grows, and returns the average.
For large positive , and GELU is the identity. For large negative , it is 0. In between it is smooth and dips slightly below zero, reaching its minimum of about at . Its derivative is , which is positive for every input above about , zero only at the minimum, and slightly negative below it, where it fades smoothly toward zero (it never drops below about ). Compare that with ReLU, whose gradient is exactly zero for every negative input, so a unit that drifts negative on all inputs can stop learning forever (a "dead" unit).
Computing used to be slow, so the paper gives an approximation that GPT-2 and many codebases use,
Its maximum error is about . The paper also gives a cruder sigmoid form, , which is off by about near (the last line of the cell below). Both errors are small, but not zero, and a model trained with one variant should be run with the same one.
The SiLU, with the logistic sigmoid, is the same idea with the logistic CDF in place of the Gaussian one. It was named in the GELU paper, used in reinforcement learning by Elfwing et al. (2018), and rediscovered by an automated search as "Swish" (Ramachandran et al., 2017, who proposed , of which SiLU is the case ). Its minimum is about at .
One more activation is worth knowing, because it keeps turning up in efficient recipes. So et al. (2021) searched over Transformer components for language modeling, and one of the two changes their search found most useful was squared ReLU, . It keeps ReLU's exact zeros, so most hidden units are exactly off for any given token, while growing faster than linearly for large inputs. NVIDIA's Nemotron-4 models use it. Like the choice between ReLU and GELU, this is an empirical finding about what trains well, not a derived optimum.
GELU, exact and approximate
Write gelu(x) (the exact erf form) and gelu_tanh(x) (the tanh approximation) for NumPy arrays of any shape. NumPy has no vectorized erf, so use np.vectorize(math.erf) or scipy.special.erf.
The FFN forward pass and its parameter count
Write ffn(X, W1, b1, W2, b2) using the tanh GELU (as GPT-2 does) for X of shape (..., d), and ffn_param_count(d, d_ff, bias=True, gated=False). A gated FFN (next subsection) has three -sized matrices, and its biases (when present) are . An ungated one has two matrices and biases .
Gated linear units and SwiGLU
In 2020 Noam Shazeer ran a simple experiment. Replace the FFN's first layer with a gated linear unit (Dauphin et al., 2017), which computes two projections and multiplies them elementwise, one passed through a nonlinearity,
We call the gate projection, the up projection, and the down projection, the names used in the Hugging Face LLaMA code (gate_proj, up_proj, down_proj). Meta's original code calls the same three matrices w1, w3, and w2. Shazeer tried other functions in place of the sigmoid and dropped the biases. The variant that took over the field uses SiLU (he called it Swish),
In plain words, compute two different linear features of the token, squash one of them into a soft on/off switch, use it to scale the other, and project back down.
Matching the parameter count, the 8/3 rule
A gated FFN has three matrices instead of two. To compare fairly, Shazeer shrank the hidden width so the parameter count (and the FLOPs) stayed the same. Setting gives
For his baseline that meant instead of 3072. LLaMA uses the same rule, then rounds up to a multiple of 256 so the matrices tile nicely on GPUs. For , , the integer part is , and rounding up to a multiple of 256 gives . That is where LLaMA-7B's odd hidden size comes from. Later models multiply by an extra factor before rounding and round to coarser multiples. LLaMA 2 70B and LLaMA 3 use a factor of 1.3 with multiples of 4,096 or 1,024, giving 28,672 for and 14,336 for .
What gating bought
Shazeer trained T5-base-sized models on the span-filling task, with every variant matched in parameters and compute. The held-out log-perplexities after 524,288 steps (lower is better, from his Table 1) are below.
| FFN variant | hidden layer | log-perplexity |
|---|---|---|
| ReLU (baseline) | 1.677 | |
| GELU | 1.679 | |
| Swish | 1.683 | |
| GLU | 1.663 | |
| Bilinear | 1.648 | |
| ReGLU | 1.645 | |
| GEGLU | 1.633 | |
| SwiGLU | 1.636 |
Two things jump out. Changing the activation alone (ReLU, GELU, Swish) barely matters, while every gated variant wins. And the bilinear layer, which has no nonlinearity at all apart from the product, beats all three ungated ones. The paper's conclusion famously declines to explain the result and attributes it to "divine benevolence". This is an empirical finding, and the best explanations we have are hypotheses.
Multiplicative interactions. A gated unit computes a product of two linear functions of the input, a second-order feature that an ungated unit would need several units to approximate. A linear path for gradients. The up branch is linear in the input, so gradients flow through it without passing through a saturating nonlinearity, much as the gates of an LSTM (§0.8) protect the cell state. Input-dependent feature selection. The gate decides, token by token, which hidden features are active, which is a soft version of the sparsity that mixture-of-experts makes explicit.
PaLM, LLaMA, Mistral, Qwen, and DeepSeek use SwiGLU. Gemma and T5 v1.1 use GEGLU. Because is shrunk to compensate, the gate costs nothing extra, and the FLOPs per token stay at .
A LLaMA-style SwiGLU FFN
Implement the two pieces you would write for a LLaMA-style model.
swiglu_ffn(X, W_gate, W_up, W_down)computes forXof shape(..., d), with no biases. SiLU is .llama_hidden_dim(d, multiple_of=256, ffn_dim_multiplier=None)returns the hidden width. Start fromint(2 * (4 * d) / 3), multiply byffn_dim_multiplierand takeintagain if one is given, then round up to a multiple ofmultiple_of.
The backward pass of a gated FFN
If you are asked to backpropagate through SwiGLU, name every intermediate first. With , , , , and , and with given, the chain rule (§0.2) gives, in order,
then , , and , the sum because feeds both branches. The SiLU derivative follows from ,
In plain words, the gate and the up branch each receive the hidden gradient scaled by the other branch's value (the product rule), the gate's share is further scaled by SiLU's slope, and the input collects gradient from both branches.
Backpropagate through SwiGLU
Write swiglu_backward(dY, X, W_gate, W_up, W_down) returning (dX, dW_gate, dW_up, dW_down) for X of shape (N, d) and dY of shape (N, d). Recompute the forward intermediates inside the function.
The FFN is a key-value memory
Now rewrite the FFN in a way that changes how you see it. Let be the -th column of and the -th row of . Then is the vector of dot products , and multiplying by sums the rows of weighted by the hidden activations,
In plain words, the FFN holds memories. Each memory has a key that is compared with the current token, and a value that is added to the stream in proportion to how strongly the key matched.
Put this next to attention, with . The shape is the same. The differences are what make them complementary. Attention's keys and values come from the tokens in the context and change with every input. The FFN's keys and values are parameters, the same for every input, so they store knowledge learned in training. And attention's weights are normalized by a softmax to sum to one, while the FFN's are unnormalized and mostly near zero, so many memories can fire at once or none at all. Sukhbaatar et al. (2019) took the analogy literally and replaced the FFN with attention over learned "persistent" key-value vectors, without losing quality.
Geva et al. (2021) then checked whether real language models use their FFNs this way. They found that individual keys in a trained model fire on human-interpretable patterns in the input prefixes (shallow layers on surface patterns, like a particular word ending a phrase, upper layers on semantic ones, like a topic). Projecting a value vector through the output embedding gives a distribution over the vocabulary, and in upper layers it tends to concentrate on the tokens likely to follow the key's pattern. The layer's output is a composition of many memories, which later layers refine through the residual stream. Meng et al. (2022) located factual associations ("the Eiffel Tower is in Paris") in middle-layer FFNs and edited them with a single rank-one update to . These are empirical findings about trained models, not theorems, and real memories are messier than a lookup table. Many units respond to several unrelated patterns, a symptom of superposition, the packing of more features than neurons into one layer.
Here is a hand-built FFN that stores three facts, so you can see the mechanism with nothing learned.
The query "Tokyo" activates only its own key, and the write points at "Japan". The token "the" matches nothing above the threshold and writes nothing. A trained FFN does this with thousands of overlapping, superposed memories and smooth activations, but the bookkeeping is the same. The widget lets you move the query and watch memories fire.
Decompose an FFN into its memories
Write ffn_memories(x, W1, b1, W2, k) for a ReLU FFN without output bias. For one token x of shape (d,), return (coef, top, partial) where coef (shape (d_ff,)) holds every memory's activation , top is an int array of the k memories with the largest activations (largest first), and partial is the sum of just those k memories' contributions .
In PyTorch
This is the FFN as LLaMA writes it, with the three projections named as in its code. Note the absence of biases and the hidden size computed by the rule you implemented.
| FFN | matrices | params at matched size | activations | used by |
|---|---|---|---|---|
| ReLU MLP | 2 | () | ReLU | original Transformer, T5 v1.0 |
| GELU MLP | 2 | GELU (tanh or exact) | BERT, GPT-2, GPT-3 | |
| squared-ReLU MLP | 2 | Primer, Nemotron-4 | ||
| GEGLU | 3 | () | GELU gate times linear | T5 v1.1, Gemma |
| SwiGLU | 3 | () | SiLU gate times linear | PaLM, LLaMA, Mistral, Qwen, DeepSeek |
| mixture of experts | 3 per expert | many times , few active | SwiGLU per expert | Mixtral, DeepSeek-V3 |
Read more
- Shazeer (2020). GLU Variants Improve Transformer. The matched comparison of gated FFNs, in four pages.
- Hendrycks & Gimpel (2016). Gaussian Error Linear Units (GELUs). The derivation of GELU, its approximations, and the naming of SiLU.
- Dauphin, Fan, Auli & Grangier (2017). Language Modeling with Gated Convolutional Networks. Where the gated linear unit comes from.
- Geva, Schuster, Berant & Levy (2021). Transformer Feed-Forward Layers Are Key-Value Memories. The memory view, tested on a trained language model.
- Meng, Bau, Andonian & Belinkov (2022). Locating and Editing Factual Associations in GPT. Facts in mid-layer FFNs, and editing them.
- Dong, Cordonnier & Loukas (2021). Attention is Not All You Need. Why pure attention collapses without MLPs and skips.
- Sukhbaatar et al. (2019). Augmenting Self-attention with Persistent Memory. Replacing the FFN with attention over learned keys and values.
- So et al. (2021). Primer, Searching for Efficient Transformers for Language Modeling. The architecture search that found squared ReLU.