Position-wise feed-forward network

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

Transformer block › MLP

Feature projection

×

learnedconv1d(h, 'c_proj', nx)

Returns the transformed features to residual width as the update.

Δmlp=gW2+b2{\htmlData{light=mlp-output mlp-proj}{\Delta_{\mathrm{mlp}}}}={\htmlData{light=activated gelu}{g}}W_2+b_2
in
gg [B batch, T positions, 3072 d_ff]
out
Δmlp\Delta_{\mathrm{mlp}} [B batch, T positions, 768 d]
parameters
2,360,064 · × 12 blocks = 28,320,768
Parameters

2,360,064 parameters per instance.

Exact per-instance accounting
ComponentCalculationParameters
Weight matrix3,072×7683{,}072 \times 7682,359,296
Output bias768768768
Per-instance total2,360,064

The reference module holds the weight input by output, [in, out].

Across 12 independent blocks: 2,360,064×12=28,320,7682{,}360{,}064 \times 12 = 28{,}320{,}768 parameters.

Derived from the configured matrix dimensions; checkpoint tensors have not been independently counted.

Codemodel.py 50–56, 118–120 · modeling_gpt2.py 233–236, 239–243
model.py 50–56
def conv1d(x, scope, nf, *, w_init_stdev=0.02):
    with tf.variable_scope(scope):
        *start, nx = shape_list(x)
        w = tf.get_variable('w', [1, nx, nf], initializer=tf.random_normal_initializer(stddev=w_init_stdev))
        b = tf.get_variable('b', [nf], initializer=tf.constant_initializer(0))
        c = tf.reshape(tf.matmul(tf.reshape(x, [-1, nx]), tf.reshape(w, [-1, nf]))+b, start+[nf])
        return c
model.py 118–120
        h = gelu(conv1d(x, 'c_fc', n_state))
        h2 = conv1d(h, 'c_proj', nx)
        return h2
modeling_gpt2.py 233–236
        self.c_fc = Conv1D(intermediate_size, embed_dim)
        self.c_proj = Conv1D(embed_dim, intermediate_size)
        self.act = ACT2FN[config.activation_function]
        self.dropout = nn.Dropout(config.resid_pdrop)
modeling_gpt2.py 239–243
        hidden_states = self.c_fc(hidden_states)
        hidden_states = self.act(hidden_states)
        hidden_states = self.c_proj(hidden_states)
        hidden_states = self.dropout(hidden_states)
        return hidden_states
Sources3

Direct evidence

The released projection helper owns a learned matrix and output bias and applies them to the last feature axis.

linear-operation · openai/gpt-2 / src/model.py
Pinned revision 9b63575ef427 ↗ · lines 50–56

Read code excerpt
def conv1d(x, scope, nf, *, w_init_stdev=0.02):
    with tf.variable_scope(scope):
        *start, nx = shape_list(x)
        w = tf.get_variable('w', [1, nx, nf], initializer=tf.random_normal_initializer(stddev=w_init_stdev))
        b = tf.get_variable('b', [nf], initializer=tf.constant_initializer(0))
        c = tf.reshape(tf.matmul(tf.reshape(x, [-1, nx]), tf.reshape(w, [-1, nf]))+b, start+[nf])
        return c

Direct evidence

The c_proj contraction maps the activated wide state back to the block width.

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

Read code excerpt
        h = gelu(conv1d(x, 'c_fc', n_state))
        h2 = conv1d(h, 'c_proj', nx)
        return h2

Direct evidence

After activation, c_proj contracts the intermediate state and returns the residual-width update.

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

Read code excerpt
        self.c_fc = Conv1D(intermediate_size, embed_dim)
        self.c_proj = Conv1D(embed_dim, intermediate_size)
        self.act = ACT2FN[config.activation_function]
        self.dropout = nn.Dropout(config.resid_pdrop)

… lines 237–238 omitted …

        hidden_states = self.c_fc(hidden_states)
        hidden_states = self.act(hidden_states)
        hidden_states = self.c_proj(hidden_states)
        hidden_states = self.dropout(hidden_states)
        return hidden_states