Position-Wise Feed-Forward Networks
Imagine a Transformer block that only mixes information between tokens through attention. There is no room for a token to individually transform its own representation. Attention decides what to look at. But something else must decide what to do with what was seen. That is the job of the position-wise feed-forward network (FFN). This is the sublayer sitting right after Multi-Head Attention in every encoder and decoder block. It accounts for roughly two-thirds of a Transformer's parameters. Yet it is often glossed over as "just an MLP." The problem the FFN solves is simple to state. Attention output is a weighted average of value vectors. This is fundamentally a linear, position-agnostic mixing operation across the sequence. Linear mixing alone cannot introduce new features or sharpen decisions. It also cannot perform non-linear transformations of a token's content. Every real system built on Transformers — BERT, GPT, T5, Vision Transformers — relies on the FFN. It injects non-linearity and expands representational capacity, token by token, independent of sequence length. The big picture is that a Transformer block alternates between two very different kinds of computation. These are attention (token-to-token, linear-in-values, permutation-equivariant mixing) and the FFN (token-to-itself, non-linear, position-independent transformation). This division of labor makes the architecture both expressive and parallelizable. Attention handles context, the FFN handles computation. This article gives a precise definition of the position-wise FFN. It works through its algorithmic structure and parameter count. It derives its computational complexity honestly. It traces its role in the residual stream. Finally, it previews how it interacts with the surrounding Transformer Encoder Stack.
- The FFN is a two-layer MLP applied identically and independently to every token's vector — hence "position-wise."
- It supplies the non-linearity that attention (a linear combination of values) cannot provide on its own.
- The hidden dimension is typically 4× the model dimension, giving the FFN most of a Transformer's parameters.
- It runs in parallel across all positions: no cross-token computation happens inside it.
- Complexity is time and parameter space, linear in sequence length .
- Residual connections and layer normalization wrap the FFN, stabilizing training of deep stacks.
The position-wise feed-forward network applies the exact same non-linear MLP to every token vector independently, giving each position the computational depth that linear attention alone cannot provide.
The idea
The position-wise feed-forward network is a sublayer that maps each token's -dimensional vector through a two-layer multilayer perceptron (MLP), with a non-linear activation between the layers, applied identically at every sequence position. Formally, for a token representation ,
where , , and is a non-linear activation — originally ReLU, later GELU or Swish/SwiGLU variants in modern models. The inner dimension is usually (e.g. in the original Transformer; in BERT-base). The crucial qualifier is "position-wise": the same weight matrices are reused at every position in the sequence, but there is no interaction between positions inside this sublayer. If the input to the block is a matrix (one row per token), the FFN is applied row-by-row:
This is mathematically equivalent to two back-to-back convolutions across the sequence dimension — a framing used in the original "Attention Is All You Need" paper, which is exactly why it is called position-wise rather than sequence-wise: it behaves like a kernel-size-1 convolution, sliding independently over each position with shared weights. Contrast this with the Multi-Head Attention sublayer that precedes it in each block: attention computes a weighted combination of other tokens' values, an operation that is linear in the value vectors and whose only source of adaptivity is the attention weights themselves. Stacking two linear operations (attention's value-mixing, followed by nothing) would collapse into an expressively limited linear map. The FFN's non-linearity is what allows the network to compute genuinely new features — logical AND/OR-like combinations, thresholding, sparse activation patterns — that a purely linear attention mechanism cannot represent. This is the same reason a plain linear regression stack collapses to a single linear layer without non-linear activations between them; the FFN is where the Transformer earns its non-linear expressive power.
How it works
Each Transformer block (encoder or decoder) applies attention, then the FFN, each wrapped in a residual connection and a normalization step. The full block, following the standard post-norm formulation, is: ``` z = LayerNorm(x + MultiHeadAttention(x)) y = LayerNorm(z + FFN(z)) ``` (Modern implementations often use pre-norm, applying LayerNorm before the sublayer instead — a design detail orthogonal to the FFN's internal computation.) The FFN sublayer itself, expanded into pseudocode operating on a batch of sequences: ``` function FeedForward(X, W1, b1, W2, b2):
# X: tensor of shape (batch, seq_len, d_model)
# W1: (d_model, d_ff), b1: (d_ff,)
# W2: (d_ff, d_model), b2: (d_model,) H = X @ W1 + b1 # shape (batch, seq_len, d_ff) H = activation(H) # elementwise, e.g. ReLU(x) = max(0, x) Y = H @ W2 + b2 # shape (batch, seq_len, d_model) return Y # same shape as X function TransformerBlock(X, params): A = MultiHeadAttention(X, X, X, params.attn) # self-attention Z = LayerNorm(X + A, params.ln1) F = FeedForward(Z, params.W1, params.b1, params.W2, params.b2) Y = LayerNorm(Z + F, params.ln2) return Y ``` Walking through the shapes makes the "position-wise" property concrete. The input `X` has shape `(batch, seq_len, d_model)`. The matrix multiply `X @ W1` broadcasts `W1` across the `batch` and `seq_len` axes — every one of the `batch seq_len` token vectors is multiplied by the same `W1`, independently. There is no operation here that reads from position and position simultaneously; that cross-position mixing already happened in the attention sublayer, and it will happen again in the next block's attention sublayer, but not inside this FFN. Each token's forward pass through the FFN is: 1. <strong>Expand</strong>: project from up to (typically wider), giving the network a larger "workspace" to compute intermediate features. 2. <strong>Activate</strong>: apply a pointwise non-linearity (ReLU, GELU, or a gated variant like SwiGLU) to each of the hidden units. 3. <strong>Contract</strong>: project back down from to , so the output can be added back into the residual stream. Because step 1 and step 3 are ordinary matrix multiplications, and step 2 is elementwise, the entire computation for all positions can be done as a single* batched matrix multiply of shape , rather than separate small operations — this is what makes the FFN extremely GPU-friendly.
Complexity & correctness
Time complexity. For a single token vector, the FFN performs a matrix multiply ( multiply-adds) followed by a matrix multiply (another ). For a sequence of length , since the same computation repeats at every position independently, the total cost is
With , this is — linear in sequence length, in sharp contrast to the self-attention sublayer's cost, which grows quadratically because attention must compute pairwise interactions between all token pairs. This asymmetry matters a great deal in practice: for short-to-moderate sequences the FFN can dominate total FLOPs (since and is small), but for very long sequences attention's term eventually dominates. Understanding which sublayer is the bottleneck is essential when deciding whether to optimize attention (e.g. with sparse or linear-attention variants) or the FFN (e.g. with mixture-of-experts routing).
Space complexity. The parameters are and , giving weights (plus biases, negligible in comparison). With , this is parameters per FFN sublayer, versus roughly for the multi-head attention sublayer's four projection matrices (, each ). This is precisely why the FFN sublayers account for about two-thirds of a Transformer's total parameter count, a fact often surprising to newcomers who assume attention "is" the Transformer. The activation memory during the forward pass requires storing the intermediate hidden tensor of shape , which is larger than the token representations themselves — a real consideration for memory-constrained training, motivating techniques like activation checkpointing.
Correctness / why this design works. The argument for the FFN's necessity is an expressivity argument, not a convergence proof, and it rests on two facts. Fact 1 (attention alone is a linear map in its values). Self-attention output for token is , a convex combination (in ) of linearly-projected value vectors. For fixed attention weights , this is an affine function of the token embeddings. Composing this with the residual add and LayerNorm (which is a nonlinear but position-wise renormalization, not a feature-mixing nonlinearity) does not introduce the kind of nonlinear feature interaction that a hidden-layer MLP provides. Fact 2 (a composition of purely linear sublayers cannot exceed linear expressivity). If every sublayer in a stack were linear, the entire depth- network would collapse to a single linear transformation (a composition of linear maps is linear), regardless of — exactly the classical argument for why deep linear networks gain no expressive power over depth. The universal approximation theorem for two-layer MLPs (Cybenko, 1989; Hornik, 1991) guarantees that a single hidden layer with a suitable non-linearity and sufficient width can approximate any continuous function on a compact domain arbitrarily well. Placing such an MLP after every attention sublayer therefore ensures each block can, in principle, compute an arbitrary non-linear transformation of the (already contextualized) token vector, rather than being limited to affine recombination. Together these facts justify the architectural necessity of the FFN: it is not an arbitrary add-on but the component responsible for the network's non-linear representational capacity, applied at the finest possible granularity — one token at a time — so that its cost and expressive power scale with rather than .
Worked example
Take a toy setting with , , and a 3-token sequence output from the attention + Add&Norm step, :
Suppose and (for illustration, using a simplified weight and a bias of on every hidden unit) produce the pre-activation matrix . We do not need the exact numeric entries of to see the mechanism — only that each row of is multiplied against the same , independently:
| step | token 1 (row 1) | token 2 (row 2) | token 3 (row 3) |
|---|---|---|---|
| input | |||
| pre-activation (shape 8) | e.g. | e.g. | e.g. |
| after ReLU | zero out negatives | zero out negatives | zero out negatives |
| output (shape 4) |
The key observation, verified by the shapes above: computing never reads or . If we permuted the rows of (swapped token 1 and token 3), the FFN output rows would simply permute the same way — and would swap, with no numerical change to their values. This is the formal signature of "position-wise": the FFN commutes with row permutations of its input, i.e. it is a permutation-equivariant, in fact a completely position-decoupled, operation. Contrast this with what would happen if we permuted the rows of before the attention sublayer instead: the attention weights depend on pairwise dot products across positions, so permuting rows there changes which tokens attend to which, and the output values genuinely differ in a way that depends on the new arrangement of context, not merely a relabeling. Numerically, using ReLU as , note that token 2's pre-activation had a strongly negative first entry (), which gets zeroed — that hidden unit contributes nothing to , while it may have contributed heavily to (whose corresponding entry was , i.e. active). This is precisely the non-linear, content-dependent gating that a linear attention-only stack cannot replicate: different tokens activate different subsets of the hidden units, letting the network compute qualitatively different functions per token content, not just different weighted averages of the same value vectors.
Common pitfalls & traps
| Pitfall | Why it happens | Consequence |
|---|---|---|
| Assuming the FFN mixes information across tokens | Confusing it with attention, since both are "sublayers" in a block | Misjudging what causes cross-token effects when debugging attribution or interpretability probes |
| Using too small (e.g. ) | Under-provisioning the "expansion" ratio | Severely bottlenecks the non-linear capacity of the block, hurting downstream task performance |
| Forgetting the residual connection around the FFN | Implementing instead of | Gradient signal cannot flow directly through identity path; deep stacks fail to train |
| Sharing FFN weights across layers (not just across positions) | Misreading "shared across positions" as "shared across the whole network" | Drastically under-parameterizes the model; each layer needs its own |
| Ignoring FFN's parameter dominance when profiling | Assuming attention is the compute/memory bottleneck by default | Wasted optimization effort on attention (e.g. sparsifying it) when the FFN (e.g. via mixture-of-experts) is the real cost driver |
| Choosing activation without checking model family | Assuming ReLU everywhere | GELU, SwiGLU, and gated variants materially change behavior and must match the pretrained checkpoint |
Pioneers & history
The FFN sublayer's mathematical ancestry runs through decades of neural network research on multilayer perceptrons and universal approximation, before being crystallized as a specific architectural component in the Transformer.
Origins · 1 minAshish Vaswani and how this was discovered
Where this matters
Every major Transformer-based system — Multi-Head Attention-based encoders like BERT, decoder-only language models like the GPT family, encoder-decoder systems like T5, and Vision Transformers applied to images — includes a position-wise FFN in each block, making it one of the most reused computational primitives in modern deep learning. Because the FFN dominates parameter count, it is also the primary target of parameter-efficiency and scaling research: Mixture-of-Experts (MoE) architectures such as Switch Transformer and Mixtral replace the single dense FFN with a bank of expert FFNs and a routing mechanism, letting models scale total parameters far beyond what a dense FFN could afford while keeping the compute per token roughly fixed. Techniques like LoRA and adapter modules frequently target the FFN's weight matrices for efficient fine-tuning, since they hold the bulk of the model's task-specific capacity. Understanding the FFN is also a prerequisite for understanding why the Transformer Encoder Stack scales the way it does in both parameters and FLOPs, and it directly informs engineering decisions in production inference systems, where FFN matrix multiplies are the dominant target for kernel fusion, quantization, and hardware-specific optimization (e.g. batching FFN computation across all tokens and all sequences in a batch into one large matrix multiply for maximal GPU utilization).
Ask the tutor: How does replacing the dense FFN with a Mixture-of-Experts layer change the complexity and training dynamics of a Transformer block?
Why is it called "position-wise" instead of just "feed-forward layer"?
The qualifier distinguishes this sublayer from a generic dense layer that might operate on a flattened, whole-sequence representation. "Position-wise" emphasizes that the exact same two-layer MLP, with the same weights, is applied separately to each position in the sequence, as if you sliced the sequence into individual token vectors and ran each one through an identical small network. This is mathematically equivalent to a convolution across the sequence axis: same kernel, applied at every location, with zero receptive field beyond that single position. The name signals that there is no cross-token computation happening inside this particular sublayer, in contrast to attention.
Does the FFN use different weights at every layer of the Transformer stack?
Yes. "Position-wise" only means the weights are shared across positions within one layer's FFN — not across layers. Each of the blocks in a Transformer stack has its own independent for its FFN sublayer. So a 12-layer BERT-base model has 12 separate FFN sublayers, each with its own roughly parameters, contributing to the total parameter budget. Only within a single layer's FFN is the same transformation reused for every token in the sequence, which is what keeps the FFN's cost linear in sequence length rather than growing per unique position.
Why is usually chosen as 4 times ?
The 4× expansion ratio was an empirical choice in the original Transformer paper (512 → 2048) that balances expressive capacity against compute and memory cost, and it has persisted through most subsequent architectures (768 → 3072 in BERT-base, and similar ratios in GPT-family models). A wider hidden layer gives more "room" for the non-linear activation to carve out complex decision boundaries per token, per the universal approximation theorem's dependence on hidden width, but doubling roughly doubles FFN FLOPs and parameters. The 4× ratio is a widely validated sweet spot rather than a mathematically derived optimum, and some architectures (e.g. certain gated-activation variants) use a somewhat smaller ratio to compensate for the extra gating projection's added parameters.
How does the FFN interact with the residual stream and LayerNorm?
The FFN's output is never used on its own; it is added back to its own input via a residual connection, then normalized: in the post-norm formulation, or in the pre-norm formulation used by most modern large language models. The residual connection lets gradients flow through an identity path during backpropagation, which is essential for training very deep stacks (dozens of layers) without vanishing gradients. LayerNorm rescales each token vector to have stable mean and variance, preventing the FFN's expansion-then-contraction from causing activation magnitudes to explode or shrink across layers.
Is the position-wise FFN the same thing as a fully connected layer in a CNN or plain MLP classifier?
It uses the same basic building block — a linear layer, a non-linearity, another linear layer — but the usage pattern differs. A plain MLP classifier typically takes one fixed-size input vector and produces one output. The Transformer's FFN instead takes a sequence of vectors (one per token) and applies the identical small MLP independently to each one, producing a same-shaped sequence of outputs. It is best understood as a batched, weight-shared MLP applied per token, equivalent to a convolution along the sequence dimension, rather than a single classifier processing one flattened input.
Why does the FFN dominate parameter count compared to attention?
For model dimension , the four attention projection matrices () each cost parameters, totaling roughly per layer. The FFN, with expansion ratio 4, has two matrices of size , totaling parameters per layer — twice the attention cost. Summed over all layers in a deep Transformer, FFN sublayers typically account for around two-thirds of total parameters, which is why techniques for scaling model capacity efficiently, such as Mixture-of-Experts, specifically target the FFN sublayer rather than attention.
What activation functions are used in the FFN besides ReLU, and why change them?
The original Transformer used ReLU, , which is simple but has a "dead zone" for negative inputs where gradients are exactly zero. GELU (Gaussian Error Linear Unit) offers a smoother, probabilistic gating that tends to improve optimization dynamics and is used in BERT and GPT-2/3. More recent architectures use gated variants like SwiGLU or GeGLU, which introduce an extra elementwise gating projection multiplying the activated branch, empirically improving quality per parameter at the cost of a third weight matrix. The choice of activation must match what a pretrained checkpoint was trained with, since substituting a different activation post hoc changes the function computed by every FFN sublayer.