Feed-Forward Networks & Normalization
FFN architectures (ReLU, GELU, SwiGLU), LayerNorm vs RMSNorm, residual connections, and Pre-Norm vs Post-Norm.
Every Transformer block has two sub-layers: attention and FFN. This chapter covers the FFN side β the βexpand-then-compressβ network that processes each token independently β plus the normalization and residual connections that make deep networks trainable.
1. The FFN: Expand and Compress
Standard FFN
The original Transformer FFN:
Shape flow:
The βexpand-then-compressβ design: up-project to (expand the representational space), apply non-linearity, then down-project back to (compress). This bottleneck structure gives each token a chance to process information in a higher-dimensional space.
Activation Functions
| Function | Formula | Properties |
|---|---|---|
| ReLU | Simple, but βdead neuronsβ (zero gradient for ) | |
| GELU | Smooth approximation of ReLU, used in BERT/GPT-2 | |
| Swish/SiLU | Smooth, non-monotonic, used in SwiGLU |
Where is the Gaussian CDF and is the sigmoid function.
SwiGLU: The Modern Standard
Most modern LLMs (LLaMA, Qwen, Mistral, DeepSeek) use SwiGLU:
The gating mechanism: instead of applying the same activation to all dimensions, the model learns a per-dimension gate that controls which information passes through. produces gate signals, produces candidate values, element-wise multiply selects what to keep.
Impact on parameter count: SwiGLU has 3 matrices (gate, up, down) instead of 2. To maintain similar total parameters, is reduced from to approximately .
| FFN Type | Matrices | (for 7B, ) | Params per block |
|---|---|---|---|
| Standard (ReLU/GELU) | 2 | ||
| SwiGLU | 3 |
Activation Memory Cost
SwiGLU produces large intermediate tensors that must be saved for the backward pass:
- Gate output:
- Up output:
- Gate activation output:
Total activation memory per block FFN: bytes (BF16).
For LLaMA-2-7B (, ): 3 imes 4096 imes 11008 imes 2 pprox 258 MB per block, Γ 32 blocks = 8.3 GB of activation memory. This is why activation checkpointing is essential for training.
FFN as a Knowledge Store
Recent research (βTransformer Feed-Forward Layers Are Key-Value Memoriesβ, Geva et al. 2021) shows that FFN layers function as learned key-value memories: the up-projection keys match input patterns, and the down-projection values store associated information. This is why:
- MoE experts can specialize in different domains (each expert stores different knowledge)
- Larger FFN dimensions improve factual recall
- Knowledge editing techniques target FFN weights specifically
2. Residual Connections
Every sub-layer in a Transformer is wrapped with a residual (skip) connection:
Why? In a deep network, gradients must flow through many layers. Without residuals, the gradient of layer 1 is a product of many Jacobians β likely to vanish or explode. The residual creates a gradient highway:
The identity matrix ensures gradients always have a direct path, even if the sub-layerβs gradient is small. This is why Transformers can be 100+ layers deep.
3. Layer Normalization
LayerNorm
Normalizes across the hidden dimension for each token independently:
Where and . Learnable parameters: scale and shift (both size ).
RMSNorm
Used by LLaMA, Qwen, Mistral β skips mean centering:
Only learnable parameters (just the scale , no shift ).
Why RMSNorm won: ~10-15% faster than LayerNorm (fewer operations β no mean computation, no shift) with comparable model quality. The mean centering in LayerNorm turns out to be unnecessary for most LLM architectures.
Pre-Norm vs Post-Norm
Two ways to arrange normalization in a Transformer block:
Post-Norm (original Transformer):
x β Attention β Add(x, Β·) β LayerNorm β FFN β Add(Β·, Β·) β LayerNorm β out
Pre-Norm (modern LLMs):
x β LayerNorm β Attention β Add(x, Β·) β LayerNorm β FFN β Add(Β·, Β·) β out
Pre-Norm is now standard because:
- More stable training β gradients are normalized before each sub-layer
- Enables training deeper models without careful learning rate tuning
- Used by GPT-2/3, LLaMA, Qwen, Mistral, and virtually all modern LLMs
The tradeoff: Post-Norm can achieve slightly better final quality with careful training, but Pre-Norm is much easier to train at scale.
4. Putting It Together: One Decoder Block
class DecoderBlock(nn.Module):
def __init__(self, d_model, num_heads, d_ff):
super().__init__()
self.norm1 = RMSNorm(d_model)
self.attn = MultiHeadSelfAttention(d_model, num_heads)
self.norm2 = RMSNorm(d_model)
self.ffn = SwiGLU_FFN(d_model, d_ff)
def forward(self, x, mask=None):
# Pre-Norm + Attention + Residual
x = x + self.attn(self.norm1(x), mask)
# Pre-Norm + FFN + Residual
x = x + self.ffn(self.norm2(x))
return x
Data flow with shapes ():
Input x: (B, S, 4096)
β RMSNorm β (B, S, 4096)
β Attention β (B, S, 4096)
β + x (residual) β (B, S, 4096)
β RMSNorm β (B, S, 4096)
β SwiGLU FFN:
β W_gate: (B, S, 4096) Γ (4096, 11008) β (B, S, 11008)
β W_up: (B, S, 4096) Γ (4096, 11008) β (B, S, 11008)
β Swish(gate) β up β (B, S, 11008)
β W_down: (B, S, 11008) Γ (11008, 4096) β (B, S, 4096)
β + x (residual) β (B, S, 4096)
Output: (B, S, 4096)
Self-Check
- Explain the βexpand-then-compressβ design of FFN and why
- Explain how SwiGLU gating works and why it has 3 weight matrices
- Explain why with SwiGLU instead of
- Explain why residual connections prevent gradient vanishing
- Explain the difference between LayerNorm and RMSNorm
- Explain Pre-Norm vs Post-Norm and why Pre-Norm is standard