Skip to content
AI360Xpert
Core ML

Feed-Forward Networks

Expand every position to a wider hidden dimension, apply a nonlinearity, then project back down — the transformer's second sub-layer, working on each position entirely on its own.

Every position is expanded to a wider hidden dimension, passed through a nonlinearity, then projected back down — the same two matrices applied independently at every position
Every position is expanded to a wider hidden dimension, passed through a nonlinearity, then projected back down — the same two matrices applied independently at every position

Why Does This Exist?

Self-attention is, on its own, a surprisingly limited operation: it's fundamentally a weighted average of value vectors. Weighted averages, however cleverly weighted, are still linear combinations of existing information — attention can route information between positions, deciding which tokens' values to blend and by how much, but it can't transform a single position's content into something qualitatively new. A layer built purely from attention, stacked repeatedly, is still mostly rearranging and re-weighting the same information over and over.

The transformer block's second sub-layer exists to do the part attention structurally can't: take each position's representation, on its own, and pass it through a genuine nonlinear transformation. Attention decides what to gather from where; the feed-forward network decides what to do with what's been gathered.

Think of It Like This

A researcher who gathers sources, then thinks alone

Self-attention is a researcher walking around a room, listening to several colleagues, and building a weighted synthesis of what they said — a blend, however clever, of existing opinions. The feed-forward network is the same researcher then going back to their own desk, closing the door, and thinking hard about that synthesis alone, transforming it into a genuinely new conclusion nobody in the room said outright.

One step is about gathering the right inputs from the right people. The other is about doing real, private cognitive work on what was gathered. A transformer block needs both, in sequence, every single layer.

How It Actually Works

Up-project, activate, down-project

The feed-forward network is applied identically and independently at every position in the sequence — no position influences another inside this sub-layer, which is the exact opposite of what attention just did. For a token representation xx of dimension dd:

FFN(x)=W2σ(W1x+b1)+b2\text{FFN}(x) = W_2 \, \sigma(W_1 x + b_1) + b_2

W1W_1 projects up from dimension dd to a wider hidden dimension — commonly 4d4d, as shown in the diagram — σ\sigma is a nonlinear activation function applied elementwise, and W2W_2 projects back down to dd. The widening isn't incidental: a narrow bottleneck limits how much the nonlinearity can actually reshape the representation, so the hidden layer is deliberately given more room than the input or output need, purely as working space for the transformation.

Why "position-wise" is the load-bearing detail

The same W1W_1, b1b_1, W2W_2, b2b_2 are reused at every position in the sequence — one token's feed-forward computation never reads another token's representation. That's a deliberate division of labor within the block: mixing information across positions is entirely attention's job; transforming information within a position is entirely the feed-forward network's job. Splitting those two responsibilities into two separate sub-layers, rather than one sub-layer doing both, is part of why the transformer block generalizes as well as it does — each sub-layer has one clear job.

A useful way to think about what it stores

One interpretation, borne out by later interpretability work, treats the feed-forward layer as a large key-value memory: rows of W1W_1 act like keys that detect specific patterns in the input, and the corresponding rows of W2W_2 act like values that get added to the output when that pattern fires. Under this view, a large fraction of what a transformer "knows" — factual associations, in particular — lives in the weights of its feed-forward layers rather than in attention, which is more about deciding what to look at than what to remember. This isn't the only lens, but it's a genuinely useful one for reasoning about where a transformer's raw parameter count actually goes.

The activation function detail worth knowing

Modern transformers largely favor gated variants like SwiGLU over a plain ReLU or GELU feed-forward network: instead of one up-projection followed by an activation, a gated FFN computes two up-projections and multiplies one, passed through an activation, elementwise against the other, before the down-projection. That's a separate design refinement with its own page's worth of detail, but the shape of the sub-layer — up, transform, down, applied per position — stays the same regardless of which specific activation sits inside it.

Show Me the Code

The up-project, activate, down-project sequence, applied identically to every row of a batch of token representations.

import numpy as np

def gelu(x: np.ndarray) -> np.ndarray:    return 0.5 * x * (1.0 + np.tanh(np.sqrt(2.0 / np.pi) * (x + 0.044715 * x ** 3)))

def feed_forward(x: np.ndarray, w1: np.ndarray, b1: np.ndarray, w2: np.ndarray, b2: np.ndarray) -> np.ndarray:    hidden = gelu(x @ w1 + b1)     # (n, d) -> (n, 4d), same W1 applied to every row    return hidden @ w2 + b2         # (n, 4d) -> (n, d), same W2 applied to every row

rng = np.random.default_rng(0)x = rng.normal(size=(4, 8))                            # 4 tokens, dim 8w1, b1 = rng.normal(scale=0.3, size=(8, 32)), np.zeros(32)   # up-project to 4xw2, b2 = rng.normal(scale=0.3, size=(32, 8)), np.zeros(8)    # down-project back to 8out = feed_forward(x, w1, b1, w2, b2)print(out.shape)  # -> (4, 8) — same shape in and out, one row transformed independently of the rest

Change row 2 of x and only row 2 of out changes — there's no matrix in this function that lets one row's computation see another row's input, which is exactly the "position-wise" claim made concrete.

Watch Out For

Assuming the feed-forward layer mixes information across positions

Because the feed-forward network sits right after attention in the block, it's easy to assume some cross-position mixing happens there too. It doesn't, by construction — W1W_1 and W2W_2 are applied identically to every row of the input matrix, with each row computed entirely independently of every other row. Any cross-position mixing in a transformer block comes exclusively from the attention sub-layer; conflating the two sub-layers' jobs leads to a wrong mental model of where information actually flows between tokens.

Underestimating how much of the parameter budget this sub-layer owns

Because attention gets most of the conceptual attention (deliberately), it's easy to underestimate that the feed-forward sub-layer typically holds the majority of a transformer's parameters — the 4d×d4d \times d and d×4dd \times 4d matrices are larger than the attention projections at the same hidden dimension. When budgeting compute or memory for a custom transformer, or when reasoning about where quantization or pruning will have the biggest effect, the feed-forward layers are usually the larger target, not attention.

The Quick Version

  • Self-attention routes information between positions via weighted averaging; it can't transform a single position's content into something new.
  • The feed-forward network up-projects each position to a wider hidden dimension, applies a nonlinearity, and projects back down.
  • The same weights apply identically and independently to every position — no cross-position mixing happens in this sub-layer.
  • One useful interpretation treats it as a key-value memory, where much of a transformer's factual knowledge is thought to live.
  • It typically holds the majority of a transformer's total parameters, more than the attention sub-layer at the same dimension.
  • Transformer Architecture is where the feed-forward network sits as the second of two sub-layers in every block.
  • Self-Attention is the first sub-layer, responsible for the cross-position mixing this page's layer doesn't do.
  • Pre-Norm vs Post-Norm covers how this sub-layer is wrapped with normalization and a residual connection inside the block.
  • Multi-Layer Perceptron is the general architecture this page's up-project-activate-down-project shape is a specific instance of.

Related concepts