AI Knowledge Tree

Gated FFNs: SwiGLU and GeGLU

Replace the transformer block's ReLU MLP with a gated linear unit, derive the SwiGLU and GeGLU forms, and see why the 2/3 width rule keeps the parameter count fixed.

⏱ 26 minPrerequisites:The transformer block

The position-wise feed-forward network (FFN) inside a transformer block is, in the original design, a two-layer MLP with a ReLU in the middle. Modern LLMs (PaLM, LLaMA, Mistral) replace it with a gated variant that consistently lowers loss at equal compute[1]. This lesson derives that variant and the width adjustment that makes the comparison fair.

1. The baseline FFN

For a token representation x∈Rdx \in \mathbb{R}^{d} (here d=dmodeld = d_{\text{model}}), the original FFN is

FFN(x)=W2 ϕ(W1x),W1∈Rdff×d,  W2∈Rd×dff,\text{FFN}(x) = W_2 \,\phi(W_1 x), \qquad W_1 \in \mathbb{R}^{d_{ff}\times d}, \; W_2 \in \mathbb{R}^{d\times d_{ff}},

where ϕ\phi is an elementwise activation (ReLU in the 2017 model) and dffd_{ff} is the hidden width, conventionally dff=4dd_{ff} = 4d. Ignoring biases, this costs

PFFN=2 d dff=8d2P_{\text{FFN}} = 2\,d\,d_{ff} = 8d^2

parameters.

2. The gated linear unit

A gated linear unit (GLU) splits the first projection into two: one branch produces values, the other produces a multiplicative gate that decides, per coordinate, how much of the value to pass. With two projections W,V∈Rdff×dW, V \in \mathbb{R}^{d_{ff}\times d},

GLU(x)=(Wx)⊙σ(Vx),\text{GLU}(x) = (W x) \odot \sigma(V x),

where ⊙\odot is the elementwise (Hadamard) product and σ\sigma is the logistic sigmoid. The gate σ(Vx)∈(0,1)dff\sigma(Vx) \in (0,1)^{d_{ff}} attenuates each hidden coordinate.

Swapping the gate nonlinearity gives the named variants. With the Swish (also called SiLU) function Swish(z)=z σ(z)\text{Swish}(z) = z\,\sigma(z):

SwiGLU(x)=(Wx)⊙Swish(Vx).\text{SwiGLU}(x) = (W x) \odot \text{Swish}(V x).

With the Gaussian error linear unit GELU(z)=z Φ(z)\text{GELU}(z) = z\,\Phi(z), where Φ\Phi is the standard normal CDF:

GeGLU(x)=(Wx)⊙GELU(Vx).\text{GeGLU}(x) = (W x) \odot \text{GELU}(V x).

The full block then applies a third matrix W2W_2 to project back to dd:

FFNSwiGLU(x)=W2((W1x)⊙Swish(W3x)),W1,W3∈Rdff×d,  W2∈Rd×dff.\text{FFN}_{\text{SwiGLU}}(x) = W_2\big( (W_1 x) \odot \text{Swish}(W_3 x) \big), \qquad W_1, W_3 \in \mathbb{R}^{d_{ff}\times d},\; W_2 \in \mathbb{R}^{d\times d_{ff}}.

What the gate buys is per-coordinate control that a plain ReLU MLP cannot express. Take one hidden coordinate with value branch W1x=2.0W_1 x = 2.0 and watch the SwiGLU output as the gate pre-activation W3xW_3 x swings sign:

  • Gate open. W3x=+3W_3 x = +3 gives Swish(3)=3 σ(3)≈2.858\text{Swish}(3) = 3\,\sigma(3) \approx 2.858, so the coordinate passes through amplified: 2.0×2.858≈5.722.0 \times 2.858 \approx 5.72.
  • Gate shut. W3x=−3W_3 x = -3 gives Swish(−3)≈−0.142\text{Swish}(-3) \approx -0.142, so the same value branch is squeezed to 2.0×(−0.142)≈−0.2852.0 \times (-0.142) \approx -0.285, near zero.

The value W1x=2.0W_1 x = 2.0 is identical in both rows; only the gate input differs, and it moves the output across a factor of twenty. A ReLU MLP would key the gate to the same coordinate's own sign; the GLU lets a separate projection W3W_3 decide, per coordinate, how much of the value to let through.

3. The 2/3 width rule

The gated FFN uses three weight matrices instead of two, so a naive swap at dff=4dd_{ff}=4d raises the parameter count by 50%. To compare architectures at equal size, shrink the hidden width. The gated count is

Pgated=3 d dff.P_{\text{gated}} = 3\,d\,d_{ff}.

Setting Pgated=PFFN=8d2P_{\text{gated}} = P_{\text{FFN}} = 8d^2 and solving:

3 d dff=8d2  ⟹  dff=83d=23⋅4d.3\,d\,d_{ff} = 8d^2 \;\Longrightarrow\; d_{ff} = \tfrac{8}{3}d = \tfrac{2}{3}\cdot 4d.

The new hidden width is two-thirds of the old one. This is why LLaMA reports dff≈83dd_{ff} \approx \tfrac{8}{3}d (rounded to a convenient multiple) rather than 4d4d: it holds parameters and FLOPs fixed so the gain is attributable to the gating, not to extra capacity.

Modern transformers replace ReLU with smooth gated activations; their building blocks GELU and Swish are smooth, non-monotonic curves that pass a little negative signal.
Modern transformers replace ReLU with smooth gated activations; their building blocks GELU and Swish are smooth, non-monotonic curves that pass a little negative signal.

4. Worked check

The block below builds a ReLU FFN and a parameter-matched SwiGLU FFN, confirms their parameter counts agree, and runs one forward pass.

python · numpy
import numpy as np

def swish(z):
    return z / (1.0 + np.exp(-z))

d = 512
d_ff_relu = 4 * d
d_ff_glu = (8 * d) // 3        # the 2/3 rule, rounded down

# baseline ReLU FFN
W1 = np.random.randn(d_ff_relu, d) * 0.02
W2 = np.random.randn(d, d_ff_relu) * 0.02
relu_params = W1.size + W2.size

# parameter-matched SwiGLU FFN (three matrices)
Wg = np.random.randn(d_ff_glu, d) * 0.02   # value branch
Wv = np.random.randn(d_ff_glu, d) * 0.02   # gate branch
Wo = np.random.randn(d, d_ff_glu) * 0.02
glu_params = Wg.size + Wv.size + Wo.size

x = np.random.randn(d)
relu_out = W2 @ np.maximum(0.0, W1 @ x)
glu_out = Wo @ ((Wg @ x) * swish(Wv @ x))

print("ReLU FFN params:  ", relu_params)
print("SwiGLU FFN params:", glu_params)
print("ratio:", round(glu_params / relu_params, 3))
print("output shapes:", relu_out.shape, glu_out.shape)

The two parameter counts land within rounding of each other (ratio near 1.0), so any loss difference between the architectures is a difference in form, not in size.

Exercises

Exercise 1. With Swish defined as Swish(z)=z σ(z)\text{Swish}(z) = z\,\sigma(z), compute the SwiGLU output of one hidden coordinate whose value branch is W1x=2.0W_1 x = 2.0, for gate inputs W3x=+3W_3 x = +3 and W3x=−3W_3 x = -3. (σ(3)≈0.9526\sigma(3) \approx 0.9526, σ(−3)≈0.0474\sigma(-3) \approx 0.0474.)

Solution

Step 1. Evaluate the gate. With the gate open,

Swish(3)=3⋅σ(3)=3⋅0.9526=2.8577.\text{Swish}(3) = 3 \cdot \sigma(3) = 3 \cdot 0.9526 = 2.8577.

With the gate shut,

Swish(−3)=−3⋅σ(−3)=−3⋅0.0474=−0.1423.\text{Swish}(-3) = -3 \cdot \sigma(-3) = -3 \cdot 0.0474 = -0.1423.

Step 2. SwiGLU multiplies the value branch by the gate, (W1x) Swish(W3x)(W_1 x)\,\text{Swish}(W_3 x):

2.0⋅2.8577=5.7154,2.0⋅(−0.1423)=−0.2846.2.0 \cdot 2.8577 = 5.7154, \qquad 2.0 \cdot (-0.1423) = -0.2846.

Step 3. The value branch is 2.02.0 in both cases; only W3xW_3 x changed sign, and the output swings from 5.725.72 to near zero. A separate projection W3W_3 controls how much of each coordinate passes, which a plain ReLU MLP cannot express per-coordinate.

Exercise 2. Derive the 2/3 width rule. A baseline ReLU FFN with hidden width dff=4dd_{ff} = 4d has two weight matrices; a gated FFN has three. Find the gated hidden width dff′d_{ff}' that holds the parameter count fixed.

Solution

Step 1. Ignoring biases, the ReLU FFN costs PFFN=2d dff=2d(4d)=8d2P_{\text{FFN}} = 2 d\, d_{ff} = 2d(4d) = 8d^2.

Step 2. The gated FFN has three matrices of size dff′×dd_{ff}' \times d (or its transpose), so Pgated=3d dff′P_{\text{gated}} = 3 d\, d_{ff}'.

Step 3. Set the costs equal and solve for dff′d_{ff}':

3d dff′=8d2  ⟹  dff′=83d=23⋅4d.3 d\, d_{ff}' = 8 d^2 \;\Longrightarrow\; d_{ff}' = \frac{8}{3} d = \frac{2}{3}\cdot 4d.

The gated hidden width is two-thirds of 4d4d, which is why LLaMA reports dff≈83dd_{ff} \approx \tfrac{8}{3}d: it matches parameters and FLOPs so any gain is attributable to the gating, not extra capacity.

Exercise 3 (code). Build a ReLU FFN at dff=4dd_{ff} = 4d and a SwiGLU FFN at the 2/3 width, and confirm their parameter counts agree within rounding (ratio close to 11).

Solution
python · numpy
import numpy as np

d = 512
d_ff_relu = 4 * d
d_ff_glu = (8 * d) // 3          # 2/3 rule, rounded down -> 1365

# ReLU FFN: two matrices of size d x d_ff
relu_params = 2 * d * d_ff_relu
# SwiGLU FFN: three matrices of size d x d_ff'
glu_params = 3 * d * d_ff_glu

ratio = glu_params / relu_params
assert d_ff_glu == 1365                    # floor(8*512/3)
assert abs(ratio - 1.0) < 0.01             # matched within rounding
print("relu", relu_params, "glu", glu_params, "ratio", round(ratio, 4))

The two counts differ only by the floor in 8d/38d/3, so the ratio sits at about 0.99980.9998: the gated block spends the same budget as the ReLU block, isolating the effect of gating.

Next, multi-head latent attention attacks the other half of the block, compressing the attention KV cache the same way this lesson reshaped the FFN.


References

  1. [1]Shazeer, N. (2020). "GLU variants improve transformer (SwiGLU/GeGLU)". arXiv:2002.05202↩