Transformer block

Reference code openai/gpt-2 @ 9b63575, huggingface/transformers @ 71c6f69, configuration openai-community/gpt2 @ 607a30d · checkpoint tensors not independently counted · How to read

GPT-2 pre-normalized transformer block

  1. x n passes through layer norm, attention, and residual dropout on the straight computation axis.
  2. A separate identity bypass carries x n beneath attention and rejoins at the first addition.
  3. x prime n passes through the second layer norm, MLP, and residual dropout on the same axis.
  4. A second identity bypass carries x prime n beneath the MLP and rejoins at the second addition to produce x n plus 1.

Transformer block

Pre-MLP LayerNorm

×

learnednorm(x, 'ln_2')

Center and scale each position’s features, then apply learned gain and bias.

μd(x)=1d∑j=1dxjσd2(x)=1d∑j=1d(xj−μd(x))2y=γ2⊙x−μd(x)σd2(x)+ε+β2ε=10−5\begin{aligned}\mu_d(x)&=\frac{1}{d}\sum_{j=1}^d x_j\\\sigma_d^2(x)&=\frac{1}{d}\sum_{j=1}^d(x_j-\mu_d(x))^2\\y&=\gamma_{2}\odot\frac{x-\mu_d(x)}{\sqrt{\sigma_d^2(x)+\varepsilon}}+\beta_{2}\\\varepsilon&=10^{-5}\end{aligned}
in
xn′x_n' [B batch, T positions, 768 d]
out
Z2Z_2 [B batch, T positions, 768 d]
parameters
1,536 · × 12 blocks = 18,432
Parameters

1,536 parameters per instance.

Exact per-instance accounting
ComponentCalculationParameters
Learned gain768768768
Learned bias768768768
Per-instance total1,536

Each normalization instance owns its learned gain and bias vectors.

Across 12 independent blocks: 1,536×12=18,4321{,}536 \times 12 = 18{,}432 parameters.

Derived from the configured feature width; checkpoint tensors have not been independently counted.

Explanation
one token · 8 illustrative featuresbeforeaftermean 1.50 → 0
Eight invented features of one token, before and after centering and division by √(variance + 10⁻⁵). The learned gain and bias are not applied in this example. Illustrative values.
Codemodel.py 28–38, 128 · modeling_gpt2.py 254, 303–305
model.py 28–38
def norm(x, scope, *, axis=-1, epsilon=1e-5):
    """Normalize to mean = 0, std = 1, then do a diagonal affine transform."""
    with tf.variable_scope(scope):
        n_state = x.shape[-1].value
        g = tf.get_variable('g', [n_state], initializer=tf.constant_initializer(1))
        b = tf.get_variable('b', [n_state], initializer=tf.constant_initializer(0))
        u = tf.reduce_mean(x, axis=axis, keepdims=True)
        s = tf.reduce_mean(tf.square(x-u), axis=axis, keepdims=True)
        x = (x - u) * tf.rsqrt(s + epsilon)
        x = x*g + b
        return x
model.py 128
        m = mlp(norm(x, 'ln_2'), 'mlp', nx*4, hparams=hparams)
modeling_gpt2.py 254
        self.ln_2 = nn.LayerNorm(hidden_size, eps=config.layer_norm_epsilon)
modeling_gpt2.py 303–305
        residual = hidden_states
        hidden_states = self.ln_2(hidden_states)
        feed_forward_hidden_states = self.mlp(hidden_states)
Sources2

Direct evidence

The second normalization appears directly inside the MLP call.

openai · openai/gpt-2 / src/model.py
Pinned revision 9b63575ef427 ↗ · lines 28–128

Read code excerpt
def norm(x, scope, *, axis=-1, epsilon=1e-5):
    """Normalize to mean = 0, std = 1, then do a diagonal affine transform."""
    with tf.variable_scope(scope):
        n_state = x.shape[-1].value
        g = tf.get_variable('g', [n_state], initializer=tf.constant_initializer(1))
        b = tf.get_variable('b', [n_state], initializer=tf.constant_initializer(0))
        u = tf.reduce_mean(x, axis=axis, keepdims=True)
        s = tf.reduce_mean(tf.square(x-u), axis=axis, keepdims=True)
        x = (x - u) * tf.rsqrt(s + epsilon)
        x = x*g + b
        return x

… lines 39–127 omitted …

        m = mlp(norm(x, 'ln_2'), 'mlp', nx*4, hparams=hparams)

Direct evidence

A second nn.LayerNorm instance precedes the MLP.

transformers · huggingface/transformers / src/transformers/models/gpt2/modeling_gpt2.py
Pinned revision 71c6f699ac9b ↗ · lines 254–305

Read code excerpt
        self.ln_2 = nn.LayerNorm(hidden_size, eps=config.layer_norm_epsilon)

… lines 255–302 omitted …

        residual = hidden_states
        hidden_states = self.ln_2(hidden_states)
        feed_forward_hidden_states = self.mlp(hidden_states)