GPT-1: Generative Pretraining for Language Understanding

Michael BrenndoerferUpdated July 22, 202568 min read

Part of Language AI Handbook

GPT-1 paired generative pretraining with task-specific fine-tuning. Covers its architecture, objective, benchmark results, and role in transfer learning.

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

GPT-1

In June 2018, OpenAI released a paper titled "Improving Language Understanding by Generative Pre-Training." The model it introduced, later known as GPT-1, wasn't the largest language model of its time, nor did it immediately dominate benchmarks. But it showed that a simple recipe of unsupervised pre-training on raw text followed by supervised fine-tuning could achieve state-of-the-art results across diverse NLP tasks. This "pre-train then fine-tune" approach would become the dominant paradigm for natural language processing, reshaping how the entire field thought about model development.

GPT-1 arrived as the field was changing. Researchers knew that language models trained on large corpora learn useful representations, but the common view held that task-specific architectures were necessary for each downstream application. If you wanted to classify sentiment, you built a sentiment classifier. If you wanted to detect entailment, you designed an entailment model. Every new task required designing a new system from scratch, curating labeled data, and training it end-to-end. GPT-1 challenged this assumption. By using a single, unified transformer decoder architecture for both pre-training and fine-tuning, it showed that generative pre-training creates representations detailed enough to transfer to classification and similarity tasks, as well as entailment and question answering, with minimal architectural changes.

Think of GPT-1's pre-training as building a powerful general-purpose language engine. Just as a car engine can power vehicles of many different designs, the pre-trained transformer provides a shared foundation that can be adapted to many different downstream tasks. You don't build a new engine for each car model: you refine an existing one. GPT-1 extended this logic to language: don't build a new model for each NLP task, pre-train a shared representation and adapt it through fine-tuning.

The model was trained on the BooksCorpus dataset, roughly 800 million words spanning thousands of unpublished novels across genres. This raw, unlabeled text provided a rich training signal without any human annotation. The key insight behind the approach was that predicting the next word in a novel requires deep language understanding: you need to track characters across chapters, understand discourse coherence, resolve ambiguous pronoun references, and reason about causal and temporal relations. A model forced to predict narrative text reliably will, in the process, develop broadly useful linguistic representations.

What made GPT-1 particularly significant was its architectural simplicity. The model used a decoder-only transformer, a straightforward stack of self-attention layers with causal masking, applied uniformly at both pre-training and fine-tuning time. There were no task-specific components, no complex multi-task training objectives, and no elaborate engineering. The simple recipe was easy to reproduce and extend to larger models. This last property would prove decisive: GPT-2, GPT-3, and their successors all follow the same fundamental design, simply larger.

This chapter explores the GPT-1 architecture in detail. We'll examine its decoder-only design, understand the pre-training objective and data, walk through the fine-tuning approach that enabled transfer learning, and assess the model's impact on the trajectory of NLP research. Along the way, we'll implement the core components in PyTorch to build concrete intuition for how the system works from the ground up.

Historical Context

GPT-1 was published in June 2018, just four months before BERT (October 2018). The two models represent two competing design philosophies that shaped NLP for years. GPT-1 used a decoder-only architecture with a left-to-right (causal) language modeling objective, which is well-suited to text generation and can be scaled to long sequences. BERT used an encoder-only architecture with a masked language modeling objective. This produces bidirectional representations better suited to understanding tasks. In the short term, BERT's bidirectional approach dominated benchmarks for classification and entailment tasks. Over the long term, the GPT lineage won out: GPT-3, GPT-4, and virtually all modern large language models use decoder-only architectures, validating the scalability of GPT-1's original design choice. ELMo, released in early 2018, was a contemporary using bidirectional LSTMs, and also demonstrated the value of pre-trained language representations. This provides important validation for the general approach before the GPT and BERT era.

The Architecture

GPT-1 uses a decoder-only transformer architecture, a design choice that distinguished it from contemporary models like ELMo (which used bidirectional LSTMs) and from the later BERT (which used bidirectional transformer encoders). The decoder-only choice wasn't arbitrary: it enabled a simple, scalable pre-training objective based on next-token prediction. With a decoder-only architecture, the model processes text from left to right, predicting each token given all preceding tokens. This autoregressive structure means training is straightforward: run the sequence through the model, compute the probability of each token given its prefix, and minimize the cross-entropy loss. No special masking schemes, no separate encoder-decoder coupling, and no architectural asymmetry between training and inference.

The choice to use a decoder-only design, rather than a full encoder-decoder architecture like the original transformer from Vaswani et al. (2017), was deliberate. The encoder-decoder architecture excels at sequence-to-sequence tasks like translation, where the input and output have different structures. But GPT-1 aimed at language understanding tasks where the input is a text sequence and the output is a label or classification decision. A single unified decoder, applied to the reformatted input sequence, is simpler, requires fewer parameters for a given depth, and removes the architectural asymmetry that makes encoder-decoder models harder to scale uniformly. The key insight is that if you can reformulate all tasks as text sequences, you don't need the full encoder-decoder complexity.

The depth of the architecture reflects GPT-1's position as one of the first large transformer language models. At 12 layers, 768 hidden dimensions, and 12 attention heads, the model follows the same configuration that would later be used for BERT-Base. This allows direct architectural comparisons between the two approaches. Each attention head operates over a 64-dimensional subspace of the hidden representation (768 / 12 = 64), which provides enough capacity for different heads to specialize in different types of relationships. The four-fold expansion in the feed-forward network (768 to 3072 hidden dimensions) follows the convention established in the original transformer paper. This provides a bottleneck structure where the model can learn complex non-linear transformations of the attention output.

Understanding why these design choices work requires thinking about what the model needs to do during pre-training. At each position, the model reads all preceding tokens and must predict the most likely next token from a vocabulary of 40,000 subwords. Getting this right requires recognizing syntactic patterns, tracking semantic entities across long spans, resolving anaphora, and modeling discourse structure. Twelve layers of self-attention provide enough depth to compose these different types of information progressively, with early layers capturing local syntactic patterns and later layers capturing longer-range semantic and discourse relationships.

GPT-1 Architecture

GPT-1 consists of 12 transformer decoder layers with 12 attention heads each, a hidden dimension of 768, and a context window of 512 tokens. The model contains approximately 117 million parameters.

The architectural specifications are:

GPT-1 architectural specifications. The 4x expansion in the feed-forward network (768 → 3072) follows the original transformer design.
ParameterValue
Layers12
Hidden size (dmodeld_{model})768
Attention heads12
Head dimension64
Feed-forward size3072
Context window512 tokens
Vocabulary size40,000 (BPE)
Parameters~117M

These numbers match BERT-Base closely (which also has 12 layers, 768 hidden dimensions, and 12 heads), enabling direct comparisons. The key architectural difference lies in the attention pattern: GPT-1 uses causal masking where each position can only attend to previous positions, while BERT uses bidirectional attention where each position attends to the full sequence.

Transformer Decoder Stack

Each layer in GPT-1 follows the standard transformer decoder block pattern. The input passes through masked multi-head self-attention, then a position-wise feed-forward network, with residual connections and layer normalization around each sublayer. The residual connections are important: they allow gradient to flow directly back through the network without passing through the attention and feed-forward operations, which prevents the vanishing gradient problem that would otherwise make deep networks difficult to train. Layer normalization stabilizes the activations at each sublayer. This keeps the signal entering each layer has consistent scale regardless of the scale of the gradients produced by training. Together, these two techniques allow GPT-1 to be trained to depths that would have been impractical with earlier architectures.

The GPT-1 paper uses post-normalization (LayerNorm applied after the residual addition), which was the convention inherited from the original transformer. Later models, including GPT-2 and GPT-3, switched to pre-normalization (LayerNorm applied to the input before attention and feed-forward), which provides more stable training at larger scales. This seemingly minor architectural detail turns out to matter significantly at scale: pre-normalization smooths optimization, allowing higher learning rates and more reliable training convergence for very deep or very wide models.

In[4]:
Code
import torch.nn as nn


class GPT1Layer(nn.Module):
    """Single transformer decoder layer as used in GPT-1."""

    def __init__(
        self,
        hidden_size: int = 768,
        num_heads: int = 12,
        intermediate_size: int = 3072,
        dropout: float = 0.1,
    ):
        super().__init__()
        self.attention = nn.MultiheadAttention(
            embed_dim=hidden_size,
            num_heads=num_heads,
            dropout=dropout,
            batch_first=True,
        )
        self.feed_forward = nn.Sequential(
            nn.Linear(hidden_size, intermediate_size),
            nn.GELU(),
            nn.Linear(intermediate_size, hidden_size),
            nn.Dropout(dropout),
        )
        self.norm1 = nn.LayerNorm(hidden_size)
        self.norm2 = nn.LayerNorm(hidden_size)
        self.dropout = nn.Dropout(dropout)

    def forward(
        self,
        x: torch.Tensor,
        attn_mask: torch.Tensor | None = None,
    ) -> torch.Tensor:
        # Self-attention with residual (post-norm)
        attn_out, _ = self.attention(x, x, x, attn_mask=attn_mask)
        x = self.norm1(x + self.dropout(attn_out))

        # Feed-forward with residual (post-norm)
        ff_out = self.feed_forward(x)
        x = self.norm2(x + ff_out)

        return x

GPT-1 uses GELU activation in the feed-forward network rather than ReLU. GELU provides a smoother non-linearity that empirically improves training dynamics in transformer models. The activation function multiplies each input value by the probability that a standard normal random variable would be less than that value:

GELU(x)=xΦ(x)\text{GELU}(x) = x \cdot \Phi(x)

where:

  • xx: the input value to the activation function
  • Φ(x)\Phi(x): the cumulative distribution function (CDF) of the standard normal distribution, which gives the probability that a standard Gaussian random variable ZN(0,1)Z \sim \mathcal{N}(0, 1) is less than xx
  • GELU(x)\text{GELU}(x): the output, which smoothly transitions between suppressing small/negative values and passing large positive values

This formulation creates a smooth gating effect. For large positive xx, Φ(x)1\Phi(x) \approx 1, so the output is approximately xx. For large negative xx, Φ(x)0\Phi(x) \approx 0, so the output is approximately 0. Unlike ReLU's hard cutoff at zero, GELU provides a gradual transition that can improve gradient flow during training.

Out[5]:
Visualization
Line plot comparing GELU and ReLU activation functions, showing GELU's smooth curve versus ReLU's sharp corner at zero.
Comparison of GELU and ReLU activation functions. GELU provides a smooth transition around zero, while ReLU has a hard cutoff. The smooth gradient of GELU near zero helps maintain gradient flow during training, avoiding the 'dying ReLU' problem where neurons become permanently inactive.

Input Representation

GPT-1's input representation combines token embeddings with learned position embeddings. Unlike the sinusoidal positional encodings from the original transformer paper, GPT-1 learns position embeddings during training. This allows the model to discover position-specific patterns relevant to its training data. Sinusoidal embeddings follow a fixed mathematical formula based on sine and cosine functions of position and dimension indices, which ensures that the model can generalize to positions it hasn't seen during training. Learned embeddings, by contrast, are just parameters initialized randomly and updated via gradient descent, which means they can specialize to the position-dependent patterns in the training data but cannot necessarily generalize to positions outside the training context window.

The decision to use learned rather than sinusoidal position embeddings was motivated by empirical performance rather than theoretical considerations. In practice, for sequences within the training context length, learned embeddings typically match or slightly outperform sinusoidal embeddings. The key practical constraint is that learned embeddings are strictly limited to the training context length: GPT-1 trained on sequences up to 512 tokens cannot use position embeddings for positions beyond 512, while sinusoidal embeddings could in principle be applied to arbitrarily long sequences. This became a significant architectural constraint as the field moved toward longer-context models.

The token embeddings themselves are 768-dimensional vectors, one per entry in the 40,000-token BPE vocabulary. These embeddings are initialized randomly and trained end-to-end alongside all other model parameters. After pre-training, these embeddings encode rich semantic and syntactic information about each token's typical linguistic context, capturing relationships that go far beyond simple word similarity. The position embeddings add a second 768-dimensional vector that encodes where in the sequence a token appears, allowing the model to distinguish between "the cat chased the dog" and "the dog chased the cat" even though both contain the same tokens in a bag-of-words representation.

In[6]:
Code
class GPT1Embeddings(nn.Module):
    """Token and position embeddings for GPT-1."""

    def __init__(
        self,
        vocab_size: int = 40000,
        hidden_size: int = 768,
        max_positions: int = 512,
        dropout: float = 0.1,
    ):
        super().__init__()
        self.token_embeddings = nn.Embedding(vocab_size, hidden_size)
        self.position_embeddings = nn.Embedding(max_positions, hidden_size)
        self.dropout = nn.Dropout(dropout)

        # Register position indices as buffer
        self.register_buffer(
            "position_ids", torch.arange(max_positions).unsqueeze(0)
        )

    def forward(self, input_ids: torch.Tensor) -> torch.Tensor:
        seq_len = input_ids.size(1)
        position_ids = self.position_ids[:, :seq_len]

        token_emb = self.token_embeddings(input_ids)
        position_emb = self.position_embeddings(position_ids)

        embeddings = token_emb + position_emb
        return self.dropout(embeddings)
Out[7]:
Console
Input shape: torch.Size([2, 10])
Output shape: torch.Size([2, 10, 768])
Embedding dimension: 768

The embedding layer turns input token IDs into 768-dimensional vectors. Adding position embeddings directly to token embeddings (rather than concatenating) keeps the hidden dimension constant throughout the network. This matches the original transformer design.

Out[8]:
Visualization
Heatmap of token embedding values for five positions and eight dimensions, followed by a plus sign.
Token embeddings for five example positions across the first eight dimensions. Each row is the learned vector associated with that token identity.
Heatmap of learned position embedding values for five positions and eight dimensions, followed by an equals sign.
Learned position embeddings for the same five positions and eight dimensions. Adding this matrix to the token matrix makes otherwise identical token identities position-sensitive.
Heatmap of the element-wise sum of token and position embeddings with a value colorbar.
Element-wise sum of the token and position matrices. The shared color scale shows how the combined GPT-1 input preserves contributions from both sources.

Causal Masking

The defining characteristic of GPT-1's decoder architecture is causal masking. During the forward pass, each token can only attend to tokens at earlier positions in the sequence. This constraint ensures that the model cannot "cheat" by looking at future tokens when predicting the next token. Think of it as the difference between reading a sentence left to right, word by word, versus reading the whole sentence and then predicting what each word "should be." The causal constraint forces the model to develop predictive representations based only on information it would realistically have access to at each position.

Without causal masking, a language model could trivially achieve perfect next-token prediction training accuracy by simply looking at the token it is supposed to predict. The mask prevents this shortcut. Every position must base its prediction purely on left context, forcing the model to learn the statistical regularities of language rather than memorizing a lookup table. This is implemented as a simple upper-triangular mask applied to the attention score matrix before the softmax: positions in the upper triangle are set to negative infinity, which causes softmax to assign them exactly zero attention weight.

The causal constraint has an important consequence for how information flows through the model. At position ii, the attention mechanism can gather information from any subset of positions 0,1,,i0, 1, \ldots, i, weighting each by relevance. This means that the model can perform long-range lookups, attending back to relevant words far earlier in the sequence, without violating the causal ordering. The multi-head structure allows different heads to perform different lookup strategies simultaneously: one head might specialize in recent context, another in syntactic dependencies, and another in thematic coherence across the full available history.

In[9]:
Code
def create_causal_mask(seq_len: int) -> torch.Tensor:
    """
    Create a causal attention mask.

    Returns a mask where True indicates positions to block.
    """
    mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1)
    return mask.bool()
Out[10]:
Visualization
Triangular heatmap showing causal mask with lower triangle green and upper triangle red.
GPT-1's causal attention mask. Green cells allow attention (the query can see that key position). Red cells block attention (future positions). Each token can only attend to itself and previous tokens, enforcing left-to-right information flow.

The triangular pattern shows that position 0 can only attend to itself, position 1 can attend to positions 0 and 1, and so on. Position 7 (the last position) can attend to all positions. This asymmetry means that later positions have access to more context, which is why language models typically generate text from left to right.

Out[12]:
Visualization
Heatmap of attention weights showing the triangular causal pattern with varying intensity.
Attention weights from layer 1 of GPT-2 for the sentence ''The cat sat on the mat''. Each row shows where that token attends. The causal mask is visible as zeros in the upper triangle. Different attention heads (shown here for head 0) learn to capture different relationships: some focus on adjacent tokens, others on syntactically related words.

Complete Model Architecture

Assembling the components, the complete GPT-1 architecture stacks 12 decoder layers between the embedding layer and a final language modeling head. The flow through the model is: input token IDs go through the combined token and position embedding layer to produce a sequence of 768-dimensional vectors; these pass through 12 transformer decoder layers, each applying causal self-attention followed by a feed-forward network with residual connections and layer normalization; the output of the final decoder layer passes through a final layer normalization; and the resulting representations are projected to vocabulary logits via the weight-tied output matrix. The architecture is entirely sequential in the depth dimension (layer 2 can only run after layer 1 finishes) but parallel within each layer (all positions in the sequence are processed simultaneously).

Weight tying is an important detail worth understanding. The output projection layer (which maps the 768-dimensional hidden state to 40,000 vocabulary logits) uses the same weight matrix as the input token embeddings, but transposed. This means the model learns a single 40,000 × 768 matrix that is used both to map token IDs to embeddings at the input and to map hidden states back to vocabulary scores at the output. The justification is that the input and output embedding spaces should be coherent: if "cat" has a certain embedding as input, then the model should also assign a high score to "cat" at the output when its hidden state is similar to the "cat" embedding. Weight tying enforces this coherence structurally and has been consistently shown to improve performance across language model architectures.

In[13]:
Code
class GPT1Model(nn.Module):
    """Complete GPT-1 architecture."""

    def __init__(
        self,
        vocab_size: int = 40000,
        hidden_size: int = 768,
        num_layers: int = 12,
        num_heads: int = 12,
        intermediate_size: int = 3072,
        max_positions: int = 512,
        dropout: float = 0.1,
    ):
        super().__init__()
        self.embeddings = GPT1Embeddings(
            vocab_size, hidden_size, max_positions, dropout
        )
        self.layers = nn.ModuleList(
            [
                GPT1Layer(hidden_size, num_heads, intermediate_size, dropout)
                for _ in range(num_layers)
            ]
        )
        self.ln_f = nn.LayerNorm(hidden_size)
        self.lm_head = nn.Linear(hidden_size, vocab_size, bias=False)

        # Weight tying: share embeddings with output projection
        self.lm_head.weight = self.embeddings.token_embeddings.weight

    def forward(
        self,
        input_ids: torch.Tensor,
        return_hidden_states: bool = False,
    ) -> dict[str, torch.Tensor]:
        seq_len = input_ids.size(1)
        attn_mask = create_causal_mask(seq_len).to(input_ids.device)

        hidden_states = self.embeddings(input_ids)
        all_hidden_states = [hidden_states] if return_hidden_states else None

        for layer in self.layers:
            hidden_states = layer(hidden_states, attn_mask)
            if return_hidden_states:
                all_hidden_states.append(hidden_states)

        hidden_states = self.ln_f(hidden_states)
        logits = self.lm_head(hidden_states)

        output = {"logits": logits, "last_hidden_state": hidden_states}
        if return_hidden_states:
            output["hidden_states"] = all_hidden_states

        return output
Out[14]:
Console
Total parameters: 116,169,216

Input shape: torch.Size([2, 32])
Logits shape: torch.Size([2, 32, 40000])
Hidden state shape: torch.Size([2, 32, 768])

The model contains approximately 117 million parameters. Note the weight tying between the input token embeddings and the output projection layer (lm_head). This technique reduces parameters by about 30 million (40,000 vocabulary × 768 dimensions) and has been shown to improve performance by enforcing consistency between how tokens are represented at input and predicted at output.

Out[15]:
Visualization
Horizontal bar chart showing parameter counts for each component of GPT-1.
Parameter distribution across GPT-1 components. Token embeddings dominate due to the large vocabulary (40K tokens x 768 dimensions). The 12 transformer layers contain the bulk of compute-relevant parameters. Weight tying eliminates the separate LM head embedding.

Worked Example: Forward Pass Through a Tiny GPT

Before diving into pre-training, let's trace a concrete forward pass through a minimal GPT-1-like model to build intuition for how information flows. We'll use a tiny 2-layer model with 4-dimensional embeddings and a vocabulary of 6 tokens, small enough to reason about numerically.

Suppose our vocabulary is {the, cat, sat, on, mat, [EOS]} with token IDs 0 through 5. Our input is the sequence [the, cat, sat], corresponding to token IDs [0, 1, 2].

Step 1: Token and Position Embedding Lookup. We look up the 4-dimensional embedding vector for each token, and the 4-dimensional position embedding for each position, then add them:

ei=TokenEmb[xi]+PosEmb[i]\mathbf{e}_i = \text{TokenEmb}[x_i] + \text{PosEmb}[i]

where xix_i is the token ID at position ii. Say the result is:

h0(0)=[0.2,0.1,0.5,0.3]("the" at position 0)h1(0)=[0.8,0.3,0.2,0.6]("cat" at position 1)h2(0)=[0.1,0.7,0.4,0.3]("sat" at position 2)\begin{aligned} \mathbf{h}_0^{(0)} &= [0.2, -0.1, 0.5, 0.3] \quad \text{("the" at position 0)} \\ \mathbf{h}_1^{(0)} &= [0.8, 0.3, -0.2, 0.6] \quad \text{("cat" at position 1)} \\ \mathbf{h}_2^{(0)} &= [-0.1, 0.7, 0.4, -0.3] \quad \text{("sat" at position 2)} \end{aligned}

Step 2: Causal Self-Attention (Layer 1). We compute queries Q=H(0)WQ\mathbf{Q} = \mathbf{H}^{(0)} W_Q, keys K=H(0)WK\mathbf{K} = \mathbf{H}^{(0)} W_K, and values V=H(0)WV\mathbf{V} = \mathbf{H}^{(0)} W_V where H(0)\mathbf{H}^{(0)} is the 3×43 \times 4 matrix of input embeddings. The attention scores are:

Sij=qikjdkS_{ij} = \frac{\mathbf{q}_i \cdot \mathbf{k}_j}{\sqrt{d_k}}

where dk=4d_k = 4 (the head dimension). We then apply the causal mask: positions where j>ij > i are set to -\infty before the softmax, so that token ii only attends to positions 00 through ii. After softmax, the attention weights for position 2 ("sat") might look like [α20,α21,α22][\alpha_{20}, \alpha_{21}, \alpha_{22}] with α20+α21+α22=1\alpha_{20} + \alpha_{21} + \alpha_{22} = 1. The output for position 2 is the weighted sum α20v0+α21v1+α22v2\alpha_{20} \mathbf{v}_0 + \alpha_{21} \mathbf{v}_1 + \alpha_{22} \mathbf{v}_2, which blends information from "the", "cat", and "sat" according to their relevance.

Step 3: Feed-Forward Network. The attention output passes through a two-layer feed-forward network with GELU activation. For a hidden dimension of 16 (4x expansion), this computes:

FFN(h)=W2GELU(W1h+b1)+b2\text{FFN}(\mathbf{h}) = W_2 \cdot \text{GELU}(W_1 \mathbf{h} + \mathbf{b}_1) + \mathbf{b}_2

Each token is processed independently by the FFN, allowing the model to apply a non-linear transformation to each position's representation after the attention aggregation step.

Step 4: Repeat for Layer 2. The output of Layer 1 becomes the input to Layer 2, which applies another round of causal self-attention and feed-forward processing. After 2 layers, we apply a final LayerNorm and multiply by the weight-tied output matrix (which is the transpose of the token embedding matrix) to get logits over the vocabulary.

Step 5: Compute Loss. The model's logit vector at position 0 is used to predict the token at position 1 ("cat"), the logit vector at position 1 predicts position 2 ("sat"), and the logit vector at position 2 predicts the next token ("on", ID=3). We apply softmax to each logit vector and compute cross-entropy against the correct targets. The total loss is the average of these three per-position losses. Backpropagation then updates all parameters to increase the probability of the correct continuations.

The key insight from this trace is that the model performs n1n - 1 next-token predictions simultaneously in a single forward pass. This efficiency, called teacher forcing, is why autoregressive language models train much faster than they might seem: every token in every training sequence contributes a training signal.

Pre-Training Objective

GPT-1's pre-training objective is straightforward: predict the next token given all previous tokens. This is the standard language modeling objective, also called causal language modeling or autoregressive language modeling. Its elegance lies in how much linguistic knowledge it implicitly requires. To predict the next word in a sentence, the model must understand syntax (subject-verb agreement, grammatical case), semantics (word meaning and contextual sense), discourse (what the passage is about, what entities are in play), and pragmatics (what continuation would be coherent given the genre and register of the text). No single one of these abilities is directly trained: they all emerge as instrumental to the core prediction task.

The language modeling objective also provides very dense training signal. For a sequence of nn tokens, the model makes n1n - 1 predictions during the forward pass (each position predicts its successor). This means every token in every training example contributes gradient information to every forward pass. Compare this to supervised learning approaches that might have a single label for an entire document: GPT-1's pre-training extracts far more signal from each training example, making efficient use of the BooksCorpus data.

Another important property of the language modeling objective is its generality. Unlike masked language modeling (used in BERT), which requires specific masking strategies and produces a model optimized for filling in blanks, causal language modeling produces a model optimized for sequentially generating or continuing text. This generality is part of why the GPT architecture scaled so effectively: the training objective remained valid and informative regardless of how large the model became or how much data it trained on. There was no need to change the training procedure as the model grew from 117M to 1.5B to 175B parameters.

Language Modeling Objective

Given a sequence of tokens (x1,x2,,xn)(x_1, x_2, \ldots, x_n), the model learns to maximize the likelihood of each token given its prefix: i=1nlogP(xix1,,xi1)\sum_{i=1}^{n} \log P(x_i | x_1, \ldots, x_{i-1}).

For a sequence of tokens x=(x1,x2,,xn)\mathbf{x} = (x_1, x_2, \ldots, x_n), the pre-training objective is to maximize:

LLM(x)=i=1nlogP(xix1,x2,,xi1;Θ)\mathcal{L}_{\text{LM}}(\mathbf{x}) = \sum_{i=1}^{n} \log P(x_i | x_1, x_2, \ldots, x_{i-1}; \Theta)

where:

  • LLM\mathcal{L}_{\text{LM}}: the language modeling loss function (log-likelihood to maximize)
  • x\mathbf{x}: the input sequence of nn tokens
  • xix_i: the token at position ii
  • P(xix1,,xi1;Θ)P(x_i | x_1, \ldots, x_{i-1}; \Theta): the probability of token xix_i given all preceding tokens, parameterized by model weights Θ\Theta
  • Θ\Theta: all learnable parameters of the model (embeddings, attention weights, feed-forward weights)

In practice, this is implemented as cross-entropy loss between the model's predicted distribution over the vocabulary and the actual next token at each position:

In[16]:
Code
import torch.nn.functional as F


def compute_lm_loss(
    model: GPT1Model,
    input_ids: torch.Tensor,
) -> torch.Tensor:
    """
    Compute the language modeling loss.

    The model predicts the next token at each position,
    and we compute cross-entropy against the actual next token.
    """
    # Get logits from model
    outputs = model(input_ids)
    logits = outputs["logits"]

    # Shift: logits[i] predicts input_ids[i+1]
    shift_logits = logits[:, :-1, :].contiguous()
    shift_labels = input_ids[:, 1:].contiguous()

    # Flatten and compute cross-entropy
    loss = F.cross_entropy(
        shift_logits.view(-1, shift_logits.size(-1)),
        shift_labels.view(-1),
    )

    return loss
Out[17]:
Console
Batch size: 4, Sequence length: 64
Language modeling loss: 312.4927
Perplexity: inf

The loss on random input is approximately log(40000)10.6\log(40000) \approx 10.6, which corresponds to perplexity equal to the vocabulary size. This is expected for an untrained model that assigns roughly uniform probability across the vocabulary. Training drives this loss down as the model learns to predict more accurately.

Out[18]:
Visualization
Dual-axis line plot showing loss decreasing and perplexity decreasing during training.
Relationship between cross-entropy loss and perplexity during language model training. Perplexity = exp(loss) represents the effective vocabulary size the model is choosing from. An untrained model on a 40K vocabulary has perplexity around 40K (loss around 10.6). A well-trained model typically achieves perplexity of 20-30 on held-out text.

Pre-Training Data

GPT-1 was pre-trained on the BooksCorpus dataset, which contains approximately 7,000 unpublished books totaling about 800 million words. The BooksCorpus was chosen for its long-range coherent text, spanning many pages of continuous narrative. This differs from datasets like Wikipedia, where articles are relatively short and self-contained. In Wikipedia, the maximum coherent narrative length is typically a few paragraphs within a section. In BooksCorpus, the model needed to track characters and plotlines while following themes across thousands of tokens, which is precisely the kind of long-range dependency that makes the learned representations useful for downstream tasks.

The choice to use unpublished books (as opposed to published books) was partly motivated by licensing considerations: unpublished books posted to sites like Smashwords were more freely available. The genre distribution skewed toward romance and fiction, which introduced certain biases into the learned representations. For instance, the model learned more about interpersonal relationships and emotions, including informal dialogue, than it would have from a more balanced corpus. Subsequent models like GPT-2 and GPT-3 used more diverse web-scraped data to address this distribution problem, producing more balanced and general-purpose representations.

The BPE tokenizer trained on the BooksCorpus uses 40,000 merge operations, producing a vocabulary that balances coverage and sequence length. Common words like "the" and "cat" receive single tokens, while rare or morphologically complex words are split into subwords. For instance, "revolutionized" might become "revolution" + "ized", and "transformer" might be a single token if it appears frequently enough in the training data. This subword tokenization allows the model to handle any input text, including words not seen during training, by decomposing them into known subword units. The 40,000 merge vocabulary was chosen as a reasonable tradeoff: larger vocabularies reduce average sequence length but require more embedding parameters and make the output projection harder to learn.

Key characteristics of the pre-training setup:

  • Dataset: BooksCorpus (~800M words from ~7,000 books)
  • Tokenization: Byte Pair Encoding (BPE) with 40,000 merge operations
  • Context window: 512 tokens per training example
  • Batch size: 64 sequences
  • Training steps: 100 epochs over the dataset
  • Optimizer: Adam with learning rate 2.5e-4, linear warmup over 2,000 steps, cosine annealing

The choice of BooksCorpus enabled the model to learn long-range dependencies across paragraphs and chapters. This was critical for the transfer learning hypothesis: if the model learned to predict coherent narratives, it might develop representations useful for understanding meaning, not just local syntax.

Out[19]:
Visualization
Horizontal bar chart showing token counts per word for a sample sentence.
BPE tokenization of sample text showing how words are split into subwords. Common words like 'the' remain whole, while rare words like 'transformer' may be split. The token count per word varies based on word frequency in the training corpus. BPE balances vocabulary size against sequence length.

Visualizing Pre-Training Dynamics

Let's visualize how next-token prediction works during pre-training. At each position, the model outputs a probability distribution over the vocabulary, and training pushes this distribution toward placing high probability on the actual next token:

Out[20]:
Visualization
Diagram showing input tokens flowing through the model to produce probability distributions for next token prediction.
Next-token prediction during pre-training. The model processes each token position and predicts a distribution over the vocabulary. Cross-entropy loss measures how well the predicted distribution matches the actual next token. Through training, the model learns to place higher probability on correct continuations.

The key insight is that this objective provides dense supervision: every position in every training sequence contributes a gradient signal. Unlike masked language modeling (used in BERT), where only 15% of tokens are predicted, causal language modeling uses every token as a training signal. This makes efficient use of the training data.

Out[21]:
Visualization
Bar chart showing token probabilities with Paris having the highest probability.
Next-token probability distribution from a pre-trained GPT-2 model. Given the context 'The capital of France is', the model assigns high probability to 'Paris' and related tokens. The long tail shows the model maintains probability mass across many plausible continuations, with most tokens receiving near-zero probability.

Fine-Tuning Approach

GPT-1's fine-tuning approach was central to its success. Rather than designing task-specific architectures, the same pre-trained model was adapted to each task with minimal modifications: add a simple classifier head and fine-tune all parameters end-to-end. This simplicity was part of what made the approach so powerful. Previous work on transfer learning in NLP often involved complex procedures: train an ELMo model, freeze its weights, concatenate its outputs with task-specific features, train the task-specific layers. GPT-1 replaced this elaborate pipeline with a clean two-step process: pre-train everything on text, then fine-tune everything on the task.

The key design principle governing fine-tuning is parameter efficiency. Because the pre-trained model already encodes rich linguistic knowledge, the fine-tuning step needs to accomplish very little: it needs to steer the model's existing representations toward task-relevant distinctions, not learn language from scratch. This is why fine-tuning requires only a few epochs and a low learning rate. The model starts from a near-optimal initialization for language understanding tasks, and fine-tuning makes small adjustments to specialize its behavior. A higher learning rate would risk overwriting the pre-trained knowledge, a phenomenon called catastrophic forgetting, where gradient steps driven by task-specific data push the parameters far enough from their pre-trained values that the general language understanding is lost.

The auxiliary language modeling loss during fine-tuning addresses catastrophic forgetting directly. By including the pre-training objective in the fine-tuning loss (with a coefficient λ=0.5\lambda = 0.5), the model is penalized for drifting too far from its pre-trained behavior. The task-specific labels push the model toward the task, while the language modeling objective acts as an anchor, keeping the representations close to their pre-trained values. This regularization effect is particularly valuable for small fine-tuning datasets, where the task labels alone would quickly overfit the small amount of labeled data.

Input Transformation

The central design choice was to transform each task into a format compatible with the language model's interface. All tasks were converted into sequences of tokens that the model processes left-to-right. This is a non-trivial design challenge: different NLP tasks have very different input structures. Sentiment classification takes a single text. Entailment takes two texts with a logical relationship between them. Similarity takes two texts that should be compared. Multiple-choice question answering takes a context passage and several candidate answers. GPT-1 provides a unified solution: represent all inputs as linear sequences with special delimiter tokens marking the boundaries between text segments.

The special tokens, [Start], [Delim], and [Extract], are added to the vocabulary and their embeddings are learned from scratch during fine-tuning. The [Start] token signals the beginning of a new example. The [Delim] token separates two text segments (e.g., premise from hypothesis in entailment, or context from answer in QA). The [Extract] token (sometimes called the classification token) appears at the end of the sequence, and its final hidden-state representation is used as the input to the classification head. Because of causal attention, the [Extract] token's representation aggregates information from all preceding tokens. This provides a summary of the entire input.

Out[22]:
Visualization
Diagram showing how classification, entailment, similarity, and QA tasks are formatted as token sequences.
GPT-1 input transformation for different NLP tasks. Each task is converted into a token sequence with special delimiters. The final token's representation is used for classification. This unified format allows a single model to handle diverse tasks.

The input transformations follow a consistent pattern:

  • Classification: [Start] text [Extract], where the representation at [Extract] is used for classification
  • Entailment: [Start] premise [Delim] hypothesis [Extract], which determines if premise entails hypothesis
  • Similarity: [Start] text1 [Delim] text2 [Extract], processing both orderings and averaging
  • Multiple Choice/QA: [Start] context [Delim] answer [Extract], scoring each answer independently with softmax over scores

The [Extract] token (sometimes called [CLS] in other models) is a special token whose final representation is used for the classification head. Because of causal attention, this token's representation aggregates information from the entire preceding sequence.

Fine-Tuning Loss

During fine-tuning, GPT-1 uses a combined objective that includes both the task-specific loss and a language modeling auxiliary loss. The combined loss is computed by adding a fraction of the pre-training language modeling objective to the primary task-specific objective:

Lfinetune=Ltask(yx)+λLLM(x)\mathcal{L}_{\text{finetune}} = \mathcal{L}_{\text{task}}(y | \mathbf{x}) + \lambda \cdot \mathcal{L}_{\text{LM}}(\mathbf{x})

where:

  • Ltask\mathcal{L}_{\text{task}}: the task-specific loss (e.g., cross-entropy for classification)
  • yy: the ground truth label for the task
  • x\mathbf{x}: the input sequence
  • λ\lambda: the auxiliary loss weight (set to 0.5 in the original paper)
  • LLM\mathcal{L}_{\text{LM}}: the language modeling loss on the input, computed identically to the pre-training objective

Why does this formula make sense? Notice that LLM(x)\mathcal{L}_{\text{LM}}(\mathbf{x}) depends on x\mathbf{x} but not on yy: it measures how well the model can predict the tokens in the input sequence, regardless of the task label. This loss is computable for any text sequence, supervised or not. During fine-tuning, the task loss Ltask\mathcal{L}_{\text{task}} pushes the model toward correct task predictions, while LLM\mathcal{L}_{\text{LM}} simultaneously pushes the model to maintain its ability to predict tokens in the input. The coefficient λ=0.5\lambda = 0.5 means the language modeling objective receives half the weight of the task objective, strong enough to regularize but not so strong as to prevent task learning.

The auxiliary language modeling loss serves two purposes. First, it acts as a regularizer, preventing the model from forgetting useful language patterns during fine-tuning. A model fine-tuned with only task supervision may rapidly overfit the task-specific data, especially for small datasets, while simultaneously degrading at language modeling. The auxiliary loss prevents this degradation. Second, it provides additional gradient signal, particularly useful when task-specific training data is limited. When only a few hundred labeled examples are available, the language modeling objective on the input tokens provides thousands of additional gradient signals per batch, effectively augmenting the training signal.

In[23]:
Code
class GPT1ForClassification(nn.Module):
    """GPT-1 with classification head for fine-tuning."""

    def __init__(
        self,
        base_model: GPT1Model,
        num_classes: int,
        extract_token_id: int = 40001,  # Special [Extract] token
    ):
        super().__init__()
        self.base_model = base_model
        self.classifier = nn.Linear(768, num_classes)
        self.extract_token_id = extract_token_id

    def forward(
        self,
        input_ids: torch.Tensor,
        labels: torch.Tensor | None = None,
        lm_weight: float = 0.5,
    ) -> dict[str, torch.Tensor]:
        outputs = self.base_model(input_ids)
        logits = outputs["logits"]
        hidden_states = outputs["last_hidden_state"]

        # Find [Extract] token positions (last token in each sequence)
        batch_size, seq_len = input_ids.shape
        extract_positions = (input_ids == self.extract_token_id).float()

        # If no extract token found, use last position
        if extract_positions.sum() == 0:
            extract_hidden = hidden_states[:, -1, :]
        else:
            # Get hidden state at extract token position
            extract_idx = extract_positions.argmax(dim=1)
            extract_hidden = hidden_states[
                torch.arange(batch_size), extract_idx
            ]

        # Classification logits
        class_logits = self.classifier(extract_hidden)

        result = {"class_logits": class_logits, "lm_logits": logits}

        if labels is not None:
            # Task loss (classification)
            task_loss = F.cross_entropy(class_logits, labels)

            # LM loss (auxiliary)
            shift_logits = logits[:, :-1, :].contiguous()
            shift_labels = input_ids[:, 1:].contiguous()
            lm_loss = F.cross_entropy(
                shift_logits.view(-1, shift_logits.size(-1)),
                shift_labels.view(-1),
            )

            # Combined loss
            total_loss = task_loss + lm_weight * lm_loss
            result["loss"] = total_loss
            result["task_loss"] = task_loss
            result["lm_loss"] = lm_loss

        return result
Out[24]:
Console
Classification logits shape: torch.Size([4, 3])
Total loss: 146.2779
Task loss: 1.4628
LM auxiliary loss: 289.6301

The classification head adds minimal parameters (just 768 × num_classes), keeping fine-tuning efficient. The combined loss balances learning the task while maintaining the language model's learned representations.

Fine-Tuning Hyperparameters

GPT-1 used the following hyperparameters for fine-tuning:

  • Learning rate: 6.25e-5 (lower than pre-training)
  • Batch size: 32
  • Epochs: 3 (most tasks)
  • LM auxiliary weight (λ\lambda): 0.5
  • Warmup: Linear warmup over 0.2% of training
  • Dropout: 0.1 on classifier, 0.1 in attention/residual

The lower learning rate prevents catastrophic forgetting of pre-trained knowledge. Just 3 epochs were typically sufficient because the model started from a strong initialization. This contrasts sharply with training from scratch, which might require hundreds of epochs.

Out[25]:
Visualization
Line plot comparing accuracy curves for pre-trained and randomly initialized models across training epochs.
Fine-tuning performance vs. epochs for pre-trained vs. randomly initialized models. Pre-trained models (GPT-1) reach high accuracy within 2-3 epochs, while random initialization requires many more epochs and achieves lower final performance. This demonstrates the efficiency gains from transfer learning.

Transfer Learning Results

GPT-1 demonstrated strong transfer learning across 12 diverse NLP tasks. The pre-training on BooksCorpus, despite never seeing task-specific supervision, produced representations that transferred effectively to classification and similarity tasks, as well as question answering. This result validated the central hypothesis of the paper: that a model trained purely to predict text can develop general-purpose language representations without any explicit semantic annotation.

The breadth of the transfer was striking. The same pre-trained model, fine-tuned separately, improved over the state of the art on sentiment classification (a relatively straightforward task), natural language inference (which requires logical reasoning), semantic textual similarity (which requires understanding paraphrase and meaning equivalence), commonsense reasoning (COPA), and multi-paragraph reading comprehension (RACE). These tasks were sufficiently different that it would not have been obvious, prior to GPT-1, that a single set of pre-trained representations could serve all of them well. The diversity of the gains was arguably more significant than the magnitude, because it suggested that the pre-trained representations captured something fundamental about language rather than patterns specific to any one task type.

The pattern of improvements also revealed something about what pre-training provides. The largest gains appeared on tasks with limited training data (RACE with 87,866 examples, COPA with 400 training examples) and on tasks requiring reasoning over longer contexts (reading comprehension). Tasks where large training sets already existed showed smaller improvements, consistent with the view that pre-training is most valuable when labeled data is scarce. When you have millions of labeled examples, supervised learning alone can learn the relevant patterns. When you have only hundreds or thousands, the pre-trained representations provide a strong initialization that compensates for data scarcity.

Benchmark Performance

The following table summarizes GPT-1's performance compared to previous state-of-the-art models at the time of publication (June 2018):

GPT-1 performance on various NLP benchmarks compared to previous state-of-the-art. Most improvements came from transfer learning, not architectural innovations.
TaskDatasetGPT-1Previous SOTAImprovement
ClassificationSST-291.390.2+1.1
ClassificationCoLA45.435.0+10.4
SimilaritySTS-B82.081.0+1.0
SimilarityQQP70.366.1+4.2
EntailmentMNLI82.180.6+1.5
EntailmentQNLI88.182.3+5.8
Reading Comp.RACE59.044.1+14.9
CommonsenseCOPA78.671.2+7.4

The improvements were particularly dramatic on tasks with limited training data. RACE, a reading comprehension dataset, saw a 14.9 point improvement. CoLA, a grammatical acceptability task, improved by 10.4 points. These gains suggest that pre-training captures linguistic knowledge that is difficult to learn from small supervised datasets alone.

Understanding Transfer Dynamics

Let's examine how the pre-trained model transfers knowledge. The key question is: what does the model learn during pre-training that helps with downstream tasks? The answer is not a single thing but a hierarchy of linguistic capabilities that emerge at different layers of the network. Research on probing classifiers, which train simple linear models on the representations from each layer to predict linguistic properties, has revealed a consistent pattern: lower layers capture local syntactic features like part-of-speech tags and constituent boundaries, while higher layers capture more abstract semantic and discourse properties. This hierarchical organization parallels what has been observed in convolutional neural networks for images, where earlier layers detect edges and textures while later layers detect object parts and semantic categories.

The GPT-1 paper's own ablation studies examined what happens when you fine-tune only the top kk layers and keep the bottom 12k12 - k layers frozen. Performance improves monotonically with kk: using all 12 layers beats using 11, which beats using 10, and so on. This means every layer contributes useful pre-trained knowledge to downstream performance, and there is no clear cutoff where the lower layers stop contributing. The implication is that the full depth of the pre-trained representation is relevant for transfer; top-level semantic features alone are insufficient.

The diminishing-returns pattern in the ablation also makes intuitive sense. The first few layers of pre-training produce enormous gains because they capture basic syntactic and semantic regularities that are useful for almost any NLP task. The later layers contribute more specialized discourse and reasoning capabilities that are valuable but less universally necessary. This pattern suggests that if compute is limited, the most cost-effective strategy is to invest in pre-training depth up to a point, then accept diminishing returns on additional layers.

Out[26]:
Visualization
Line plot showing downstream task accuracy as a function of number of pre-trained layers used.
Impact of pre-training depth on transfer learning. Models with more pre-training layers show better downstream performance, with the largest gains in the middle layers. This suggests that intermediate representations capture transferable linguistic abstractions.

The figure shows simulated data based on patterns from the GPT-1 paper's ablation studies. Key observations:

  • All layers contribute: Each additional pre-trained layer improves performance
  • Diminishing returns: The marginal benefit decreases as more layers are added
  • Task variation: Some tasks (like SST-2) benefit more from deeper features than others

Ablation Studies

The GPT-1 paper included several ablation studies that revealed what mattered for transfer learning. Ablation studies systematically remove or disable components of the model to measure each component's individual contribution. By comparing the full model against versions with specific components removed, researchers can distinguish which design choices contribute to performance from those that are present without affecting it. The GPT-1 ablations addressed three key questions: Does pre-training help? Does the auxiliary LM loss help? Does the transformer architecture help (compared to a simpler LSTM baseline)?

Out[27]:
Visualization
Bar chart comparing full model performance to versions without auxiliary LM loss and without pre-training.
GPT-1 ablation study results showing the contribution of different components. The auxiliary LM loss provides consistent improvement across tasks. Pre-training is essential, as random initialization performs much worse.

The ablations reveal:

  • Pre-training drives the gains: Without pre-training, performance drops 5-15 points across tasks
  • Auxiliary LM loss helps: The language modeling objective during fine-tuning provides consistent improvement, especially on smaller datasets
  • Transformer architecture matters: Comparisons with LSTM-based models showed the transformer's self-attention mechanism was important for capturing long-range dependencies
Out[28]:
Visualization
Line plot showing accuracy vs auxiliary LM weight for small, medium, and large datasets.
Effect of auxiliary LM loss weight on fine-tuning performance across different dataset sizes. Higher weights provide stronger regularization, which helps more on smaller datasets by preventing overfitting. The optimal weight of 0.5 balances task learning with representation preservation.

Working with GPT-1-Era Models

While the original GPT-1 model isn't readily available, we can use GPT-2 (its direct successor with the same architecture, just larger) to demonstrate the concepts. GPT-2 Small has nearly identical architecture to GPT-1 but was trained on more data.

Out[29]:
Console
GPT-2 Model Configuration (similar to GPT-1):
  Vocabulary size: 50,257
  Hidden size: 768
  Number of layers: 12
  Number of heads: 12
  Context window: 1024
  Total parameters: 124,439,808

Generating Text

The pre-trained model can generate coherent text continuations:

In[30]:
Code
def generate_text(prompt, max_new_tokens=20):
    """Generate text continuation using the pre-trained model (greedy decoding)."""
    inputs = tokenizer(prompt, return_tensors="pt")

    with torch.no_grad():
        outputs = gpt2_model.generate(
            inputs["input_ids"],
            max_new_tokens=max_new_tokens,
            do_sample=False,
            pad_token_id=tokenizer.eos_token_id,
        )

    generated_text = tokenizer.decode(outputs[0], skip_special_tokens=True)
    return generated_text

The model generates coherent continuations because it learned to predict likely next tokens during pre-training. The quality of these completions reflects the knowledge captured from the training corpus.

Extracting Representations for Transfer

For transfer learning, we extract the hidden states at specific positions to use as input features for downstream classifiers:

In[31]:
Code
def extract_representations(texts, layer=-1):
    """
    Extract representations from a specific layer.

    Args:
        texts: List of input texts
        layer: Which layer to extract from (-1 = last layer)

    Returns:
        Tensor of representations, shape (num_texts, hidden_size)
    """
    inputs = tokenizer(
        texts,
        return_tensors="pt",
        padding=True,
        truncation=True,
        max_length=512,
    )

    with torch.no_grad():
        outputs = gpt2_model(
            input_ids=inputs["input_ids"],
            attention_mask=inputs["attention_mask"],
            output_hidden_states=True,
        )

    # Get hidden states from specified layer
    hidden_states = outputs.hidden_states[layer]

    # Use last non-padding token's representation
    seq_lengths = inputs["attention_mask"].sum(dim=1) - 1
    batch_size = hidden_states.size(0)
    representations = hidden_states[torch.arange(batch_size), seq_lengths]

    return representations
Out[32]:
Console
Extracted representations shape: torch.Size([3, 768])
Representation dimension: 768

Cosine similarities between representations:
  Text 1 vs Text 2: 0.9777
  Text 1 vs Text 3: 0.9967
  Text 2 vs Text 3: 0.9669

These final-token representations contain contextual information, but their raw cosine similarities can remain uniformly high. GPT-2 was trained for next-token prediction, not to produce a calibrated sentence-embedding space. The comparison below makes that limitation visible: small relative differences exist, but a dedicated pooling strategy or sentence-level fine-tuning is needed before treating these vectors as semantic similarity scores.

Out[33]:
Visualization
Heatmap showing pairwise cosine similarities between five raw GPT-2 final-token representations, all close to one.
Cosine similarity between raw final-token representations from GPT-2. The vectors cluster tightly near 1.0, and the narrowed color scale exposes only small relative differences. This illustrates why an autoregressive language model's hidden states should not be treated as calibrated sentence embeddings without suitable pooling or sentence-level fine-tuning.

Layer-wise Representations

Different layers capture different levels of abstraction. Let's visualize how representations evolve through the network:

Out[34]:
Visualization
Heatmap showing cosine similarity between all pairs of layer representations.
Cosine similarity between layer representations for the same text. Adjacent layers are highly similar (near 1.0), but similarity decreases as layer distance increases. This suggests gradual transformation of representations through the network.

The similarity matrix reveals the structure of information flow through the network. Early layers remain close to the embedding space, while deeper layers transform representations more dramatically. For transfer learning, intermediate layers often provide the best features because they capture generalizable linguistic patterns without becoming too specialized to the pre-training objective.

Limitations and Impact

GPT-1 established the "pre-train then fine-tune" paradigm, but it came with significant limitations that subsequent work addressed. These limitations matter as historical record and as the motivation for research directions that followed, including BERT, GPT-2, GPT-3, and the instruction-tuned models that dominate current NLP.

The 512-token context window restricted the model to relatively short documents. Question answering over long passages or multi-document reasoning required chunking text, potentially losing context across chunks. Consider a task like answering questions about a 2,000-word article: GPT-1 must process the article in overlapping windows and somehow combine the evidence across chunks, a brittle and information-lossy process. Subsequent models like GPT-2 (1024 tokens), GPT-3 (2048 tokens), and modern long-context models (100K+ tokens) progressively addressed this limitation. The underlying technical challenge is that self-attention scales quadratically with sequence length in both compute and memory, so extending context requires either hardware improvements, architectural modifications (like sparse attention), or both.

The fine-tuning approach, while effective, required separate training runs and separate model instances for each downstream task. If you needed to deploy GPT-1 for both sentiment analysis and question answering, you needed two fine-tuned models, each taking significant compute and storage. At the scale of GPT-1 (117M parameters), this was manageable, but at the scale of GPT-3 (175B parameters), maintaining dozens of task-specific fine-tuned copies becomes impractical. This motivated research into few-shot and zero-shot learning, where a single frozen model handles diverse tasks through prompting alone, and parameter-efficient fine-tuning methods like LoRA and adapters that modify only a small fraction of the parameters.

The pre-training data introduced biases that are difficult to fully characterize. BooksCorpus skews heavily toward romance and fiction written in English, published between roughly 2010 and 2016. The model reflects cultural assumptions and stereotypes, along with the linguistic patterns embedded in that genre. It may perform differently on text from different domains, time periods, languages, or cultural contexts, and it may encode and amplify social biases present in the fiction corpus. This prompted serious research into data curation, bias evaluation, and debiasing techniques that continues to this day. The lesson was that the training data distribution shapes the model's behavior in deep ways, and choosing the right data is as important as choosing the right architecture.

Despite these limitations, GPT-1 changed subsequent NLP research. It showed definitively that unsupervised pre-training on raw text produces representations that transfer effectively to diverse supervised tasks, validating a hypothesis that had been tentatively explored by earlier work on word embeddings and ELMo but never demonstrated at the level of complete sentence understanding. This result led researchers toward a new approach: invest compute in large-scale pre-training and adapt through fine-tuning, rather than designing task-specific architectures for each application. The simplicity and effectiveness of this recipe made it immediately reproducible by the broader research community, accelerating progress across the entire field.

GPT-1 also established the decoder-only transformer as a viable architecture for language understanding, not just generation. While BERT (released four months later) temporarily shifted attention to encoder-only models for understanding tasks because bidirectional attention seemed advantageous for classification, the trajectory from GPT-1 through GPT-2 and GPT-3 showed that sufficiently large decoder models could match or exceed encoder performance on understanding tasks while retaining generation capabilities. This insight, that you don't need to choose between a model that understands and a model that generates, because a sufficiently powerful decoder does both, proved to be one of the most consequential results in recent NLP history. We explore the scaling behavior that made this possible in the next chapter on GPT-2.

Out[35]:
Visualization
Dual-axis bar chart showing parameter count and context window growth across GPT versions.
Evolution of GPT model scale over time. Both context window and parameter count have grown exponentially. GPT-1's 512-token window and 117M parameters seem modest compared to GPT-4's estimated 1.7T parameters and 128K context window. This scaling has been central to capability improvements.

The fine-tuning approach, while effective, required task-specific training data and produced separate models for each task. A single GPT-1 model could not simultaneously perform classification and translation, as well as question answering. This motivated research into zero-shot and few-shot learning, culminating in GPT-3's in-context learning capabilities where a single model handles diverse tasks through careful prompting alone.

The model's 117M parameters, substantial for 2018, proved small relative to what was possible. The scaling hypothesis, later formalized in neural scaling laws, showed that larger models trained on more data consistently improved performance. GPT-2 (1.5B parameters) and GPT-3 (175B parameters) validated this direction, though also raised concerns about compute accessibility and environmental impact.

The pre-training data (BooksCorpus) introduced biases present in published fiction. The model reflected patterns and stereotypes, as well as perspectives found in those texts. This prompted research into data curation, debiasing techniques, and more careful evaluation of model behavior across different demographic groups.

Despite these limitations, GPT-1 had significant impact. It showed that unsupervised pre-training on raw text produces representations that transfer effectively to diverse supervised tasks. This finding shifted NLP toward a new approach: instead of designing task-specific architectures, invest compute in large-scale pre-training and adapt through fine-tuning. The simplicity of this recipe, combined with its effectiveness, made it the dominant paradigm.

GPT-1 also established the decoder-only transformer as a viable architecture for language understanding, not just generation. While BERT (released four months later) temporarily shifted attention to encoder-only models for understanding tasks, the trajectory from GPT-1 through GPT-2 and GPT-3 demonstrated that sufficiently large decoder models could match or exceed encoder performance on understanding tasks while also enabling generation.

Key Parameters

When working with GPT-1-era models for transfer learning, these parameters have the greatest impact on performance. Understanding why each parameter matters requires thinking about the two-phase nature of the approach: the pre-trained model is a carefully optimized starting point, and fine-tuning is a controlled perturbation of that starting point toward a task-specific objective. The goal is to move far enough to specialize for the task but not so far as to destroy the general-purpose representations.

  • Learning rate: Fine-tuning typically uses 1-2 orders of magnitude lower learning rate than pre-training (e.g., 2-6e-5 vs 2.5e-4). Higher rates risk catastrophic forgetting of pre-trained knowledge. The intuition is that the pre-trained model already resides in a good region of parameter space; large gradient steps would carry it far from that region before the task-specific signal can guide it back to a good local optimum.

  • Epochs: 2-4 epochs usually suffice for fine-tuning. Unlike training from scratch, the model starts from a strong initialization and quickly adapts to the task. Training for more epochs tends to overfit the fine-tuning data, especially for small datasets, as the model begins to memorize training examples rather than generalize.

  • Batch size: 16-32 is typical for fine-tuning. Larger batches can speed training but may require learning rate adjustment. For very small fine-tuning datasets (under 1,000 examples), smaller batches with more gradient steps may help by providing more frequent parameter updates.

  • Auxiliary LM weight (λ\lambda): 0.5 as recommended in the paper, but can be tuned per task. Higher values provide more regularization, useful for smaller datasets. On very large fine-tuning datasets (100K+ examples), you can often reduce λ\lambda or set it to zero, since the abundant labeled data reduces the risk of overfitting.

  • Dropout: 0.1 in attention and feed-forward layers. Can be increased for very small fine-tuning datasets to prevent overfitting. The interaction between dropout and auxiliary LM loss means that both regularization mechanisms together can be more effective than either alone.

  • Layer selection: For feature extraction (frozen model), intermediate layers (6-9 for a 12-layer model) often outperform the final layer, which becomes specialized for next-token prediction. The final layer's representations are optimized for language modeling, which may not align with the feature requirements of your downstream task. Intermediate layers retain more general-purpose linguistic structure.

  • Warmup: Linear warmup over 0.2% of training steps helps stabilize early training when fine-tuning. Warmup prevents large early gradient steps (which can destabilize the pre-trained representations) by gradually increasing the learning rate from a near-zero value to the target rate over the first few hundred steps.

Summary

GPT-1 introduced a powerful recipe for language understanding: pre-train a transformer decoder on large-scale text using next-token prediction, then fine-tune on downstream tasks with minimal architectural changes. The key contributions and takeaways include:

  • Unified architecture: A single 12-layer transformer decoder handles both pre-training and diverse downstream tasks. The same model structure enables text generation and classification.

  • Generative pre-training: The simple objective of predicting the next token, applied at scale to BooksCorpus, produces representations rich enough for transfer learning across classification and entailment, along with similarity and question answering.

  • Input transformation: Different tasks are reformulated as sequences with special delimiters ([Start], [Delim], [Extract]), allowing the same model to process various input formats.

  • Auxiliary objectives: Including language modeling loss during fine-tuning (λ=0.5\lambda = 0.5) improves transfer by regularizing against forgetting.

  • Transfer across tasks: Pre-training on narrative text transferred to formal reasoning tasks (RACE, COPA). This shows that language modeling captures general linguistic competence.

GPT-1 set the stage for the scaling revolution that followed. GPT-2 scaled the approach 10x, GPT-3 scaled it 1000x, and subsequent models have pushed further still. But the core insights, decoder-only architecture, pre-training on raw text, fine-tuning for tasks, remain foundational to how we build language AI today.

Quiz

Ready to test your understanding? Take this quick quiz to reinforce what you've learned about GPT-1's architecture, pre-training, and fine-tuning approach.

GPT-1 Architecture and Pre-Training

Question 1 of 100 of 10 completed
How many transformer decoder layers does GPT-1 have?

Comments

No comments yet. Be the first to share your thoughts!

Reference

Citation details

Cite or share this article.

BIBTEXAcademic
@misc{brenndoerfer2025gpt1-2, author = {Michael Brenndoerfer}, title = {GPT-1: Generative Pretraining for Language Understanding}, year = {2025}, url = {https://mbrenndoerfer.com/writing/gpt-1-generative-pretraining-language-understanding}, organization = {mbrenndoerfer.com}, note = {Accessed: 2026-09-15} }
APAAcademic
Michael Brenndoerfer (2025). GPT-1: Generative Pretraining for Language Understanding. Retrieved from https://mbrenndoerfer.com/writing/gpt-1-generative-pretraining-language-understanding
MLAAcademic
Michael Brenndoerfer. "GPT-1: Generative Pretraining for Language Understanding." 2026. Web. September 15, 2026. <https://mbrenndoerfer.com/writing/gpt-1-generative-pretraining-language-understanding>.
CHICAGOAcademic
Michael Brenndoerfer. "GPT-1: Generative Pretraining for Language Understanding." Accessed September 15, 2026. https://mbrenndoerfer.com/writing/gpt-1-generative-pretraining-language-understanding.
HARVARDAcademic
Michael Brenndoerfer (2025) 'GPT-1: Generative Pretraining for Language Understanding'. Available at: https://mbrenndoerfer.com/writing/gpt-1-generative-pretraining-language-understanding (Accessed: September 15, 2026).
SimpleBasic
Michael Brenndoerfer (2025). GPT-1: Generative Pretraining for Language Understanding. https://mbrenndoerfer.com/writing/gpt-1-generative-pretraining-language-understanding

About the author

Continue with the full handbook

This chapter is part of Language AI Handbook. Use the handbook page to browse the complete table of contents and continue reading in sequence.

Explore Language AI Handbook
Newsletter

Stay up to date

Get articles, book updates, and news delivered to your inbox.

No spam, unsubscribe anytime.

or

Join the community

Sign in to remove popups, track your reading progress, and join the discussion.