🌙 30-Day AI Ramadan Series  ·  Day 26 of 30
Deep Dive· Mar 16, 2026· 25 min read· Transformers · NLP

BERT vs GPT:
Encoders, Decoders & What They're For

Same transformer architecture. Same attention mechanism. Same positional encodings. But BERT reads the whole sentence at once while GPT only ever looks left. That single difference — bidirectional vs causal attention — splits the world of language models into two families with completely different strengths, training objectives, and use cases. This guide explains both from the ground up: what they see, how they're trained, what they're good at, and how every major model since 2018 fits into one of these two families.

← Back to Blog ☰ Categories

Two students take the same exam.
One can flip to any page — reading forward, backward, skipping around.
The other can only read left to right, never peeking ahead.

The first student is better at understanding. The second is better at writing.

BERT is the first student. GPT is the second.
Same exam. Same knowledge. Completely different strategies.

01 — One Architecture, Two Families

In Day 24 we built the full transformer architecture. In Day 25 we added positional encodings. The transformer is now complete — but here's something remarkable: BERT and GPT are both transformers. They use the same multi-head attention, the same feed-forward blocks, the same layer norm and residual connections. The difference between them is not the architecture — it's what part of the sequence each token is allowed to see during training.

🔍 Non-Tech Analogy: Two Kinds of Reader

Imagine you're trying to understand a mystery novel. A bidirectional reader (BERT) reads the whole book at once — they can see the ending when analysing chapter 1, and they can see chapter 1 when analysing the ending. They build a complete, context-rich understanding of every sentence from all directions.

A left-to-right reader (GPT) reads strictly page by page — they can never look ahead. When they reach chapter 5, they only know what happened in chapters 1–4. But this constraint turns out to be incredibly useful: because they've learned to predict what comes next, they can write the novel themselves.

Understanding vs writing. Reading vs generating. That's the BERT/GPT split.

This distinction flows from a single change in the attention mask. When computing self-attention, the mask determines which positions each token can attend to:

BERT — Bidirectional (full attention)

Every token sees every other token

GPT — Causal (left-to-right only)

Each token only sees itself and what came before

That grid is not just a visual — it's literally the attention mask applied before the softmax in Day 24. BERT sets all mask values to 0 (attend everywhere). GPT sets the upper triangle to −∞ (block future tokens). Everything else — the Q/K/V projections, multi-head attention, FFN layers, residuals — is identical.

02 — BERT: The Encoder

What BERT Is

BERT (Bidirectional Encoder Representations from Transformers — Google, 2018) is an encoder-only transformer. It takes a sequence of tokens and produces a rich contextual embedding for each token — a representation that captures the meaning of that token in the context of the entire sentence, both what comes before and what comes after.

📚 Non-Tech Analogy: The Proofreader

A proofreader reads the entire document before correcting a single word. When they get to the word "bank" in sentence 3, they've already read sentence 10 — which mentions "a river" — so they know it means riverbank, not a financial institution. They understand every word in full context.

BERT is the proofreader. It reads the whole sentence before assigning meaning to any word. The embedding BERT produces for "bank" in "The fish swam past the bank" is completely different from the embedding for "bank" in "I deposited money at the bank." Same word, totally different vectors — because BERT saw both the fish and the money before deciding.

BERT's Pre-Training: Masked Language Modelling (MLM)

BERT was pre-trained on two tasks simultaneously. The first and most important is Masked Language Modelling (MLM): randomly hide 15% of tokens in the input by replacing them with a special [MASK] token, then train the model to predict what the hidden tokens were.

Input: "The cat [MASK] on the [MASK]."
Target: predict "sat" and "mat"

Loss = CrossEntropy( BERT_output[masked_pos], true_token_id )

15% of tokens are masked each training step
Of those 15%: 80% replaced with [MASK], 10% random token, 10% unchanged
(The 10% variations prevent the model from only learning [MASK] positions)

To predict "sat," the model must understand both the subject ("The cat") and the destination ("on the [MASK]"). It cannot rely on just looking left — it must use both sides. This forces BERT to build genuinely bidirectional representations. After pre-training on 3.3 billion words, every layer of BERT learned something deep about language: syntax, coreference, semantic relationships, named entities — all encoded in the token embeddings.

The second task is Next Sentence Prediction (NSP): given two sentences A and B, predict whether B actually follows A in the original document or was randomly sampled. This teaches BERT cross-sentence relationships — important for tasks like question answering where the question and passage are both inputs.

The [CLS] Token — BERT's Summary Vector

BERT prepends a special [CLS] (classification) token to every input. After passing through all transformer layers, the final embedding of this token aggregates information from the entire sequence — it becomes a sentence-level representation. For classification tasks, you attach a small linear head on top of [CLS] and fine-tune. The rest of BERT's weights don't need to change much — they already understand language remarkably well.

Input format: [CLS] token_1 token_2 ... token_n [SEP]
For sentence pairs: [CLS] sentence_A [SEP] sentence_B [SEP]

Classification: Linear( BERT_output[CLS] ) → logits
BERT_output[CLS] ∈ ℝ^768 (base) or ℝ^1024 (large)

BERT Fine-Tuning: One Pre-trained Model, Any Task

The pre-train/fine-tune paradigm BERT introduced was revolutionary: train once on massive unlabelled text, then fine-tune on small labelled datasets for any specific task. A single BERT-base model reached state-of-the-art on 11 NLP benchmarks simultaneously in 2018 — sentiment analysis, named entity recognition, question answering, textual entailment, and more. The key insight: language understanding is universal. A model that deeply understands language in general can quickly learn any language task with a small additional training signal.

TaskWhat you attach to BERTWhat you fine-tune on
Text classification
sentiment, spam, topic
Linear layer on [CLS]Labelled sentences (hundreds–thousands)
Named entity recognition
find names, dates, orgs
Linear layer on each token outputTagged text (BIO labels per token)
Question answering
SQuAD-style extractive
Two linear heads (start, end position)(question, passage, answer_span) triples
Sentence similarity
duplicate detection, NLI
Linear layer on [CLS] with two sentencesSentence pairs with similarity labels
Semantic search / embeddings
RAG retrieval, clustering
Mean-pool all token outputs (Sentence-BERT)Contrastive learning on similar pairs

03 — GPT: The Decoder

What GPT Is

GPT (Generative Pre-trained Transformer — OpenAI, 2018) is a decoder-only transformer. It takes a sequence of tokens and, one token at a time, predicts the next one. The causal mask ensures that when predicting token at position n, it can only see tokens 1 through n−1 — never anything after. This constraint is what makes generation possible.

✍️ Non-Tech Analogy: The Author

An author writing a novel never knows what they'll write in chapter 10 when they're writing chapter 1. They write word by word, sentence by sentence, each new word informed only by everything that came before. The constraint "you can't look ahead" is not a weakness — it's exactly what writing requires.

GPT is the author. It reads everything it's written so far and asks: "Given all of this, what word comes next?" Train it on enough text — billions of words of books, articles, code, conversations — and it learns the statistical patterns of human language so thoroughly that its "next word guesses" become coherent paragraphs, then essays, then code, then multi-step reasoning.

GPT's Pre-Training: Causal Language Modelling (CLM)

GPT's training objective is beautifully simple: predict the next token. Given a sequence of tokens, maximise the probability of each token given all preceding tokens. No masking tricks, no special tokens — just next-token prediction across the entire training corpus.

Training sequence: "The cat sat on the mat"

Step 1: given ["The"] → predict "cat"
Step 2: given ["The", "cat"] → predict "sat"
Step 3: given ["The","cat","sat"]→ predict "on"
... and so on for every position

Loss = − (1/T) Σ log P(token_t | token_1, ..., token_{t-1})
T = sequence length. This is the language modelling objective.

This objective is strikingly powerful because it provides a training signal at every position in every sequence. A 1,024-token sequence generates 1,024 training examples in one forward pass. And the task is hard enough to force the model to learn everything about language: grammar (wrong grammar is less probable), facts (wrong facts are less probable), logic (incoherent continuations are less probable), and style — all emerge as side effects of trying to predict what word comes next.

Generation: How GPT Produces Text

At inference time, GPT generates text autoregressively — one token at a time, feeding each newly generated token back as input for the next step:

Step 1
Input: "The capital of France is" → sample "Paris" (highest probability)
Step 2
Input: "The capital of France is Paris" → sample "."
Step 3
Input: "The capital of France is Paris." → sample "It" (continues…)

The sampling strategy matters enormously here. Greedy decoding (always pick the highest probability token) produces repetitive, boring text. Temperature scaling (divide logits by T before softmax) controls randomness — low T makes text more deterministic, high T more creative/random. Top-k sampling (only sample from the top-k tokens) and nucleus sampling / top-p (sample from the smallest set of tokens whose cumulative probability exceeds p) are used by GPT-3, GPT-4, and most modern LLMs.

04 — The Attention Mask: The One Real Difference

Everything above comes down to a single change in the attention computation. Here is the exact mask difference:

BERT (bidirectional) — no mask:
scores = Q · Kᵀ / √d_k
weights = softmax(scores) ← every token can attend to every other token

GPT (causal) — upper triangle masked:
mask[i, j] = 0 if j ≤ i (token j is at or before token i → allowed)
mask[i, j] = −∞ if j > i (token j is after token i → blocked)
weights = softmax(scores + mask) ← future tokens get weight 0

This one mask is the entire architectural difference between BERT and GPT. Both use:

The mask determines the pre-training objective — bidirectional attention enables MLM, causal attention enables CLM — and the pre-training objective determines what the model is good at.

05 — BERT vs GPT: Head-to-Head

Dimension BERT Encoder GPT Decoder
Attention direction Bidirectional — every token sees every other Causal (left-to-right) — each token sees only past tokens
Training objective Masked Language Modelling (MLM): predict hidden tokens Causal Language Modelling (CLM): predict next token
Can generate text? ✗ No — no autoregressive mechanism ✓ Yes — designed for generation
Context quality ✓ Full bidirectional — richest representations ~ One-directional — weaker for understanding tasks
Best use cases Classification, NER, QA (extractive), semantic search, embeddings Text generation, chat, code, summarisation, instruction following
Fine-tuning paradigm Add small head to [CLS] or token outputs; fine-tune on small labelled data Instruction fine-tuning (IFT) + RLHF; few-shot via prompting
Scales to very large? ~ Limited — largest BERT variants ~350M params ✓ Yes — GPT-3 175B, GPT-4 ~1T, LLaMA-3 405B
Key models (2018–2026) BERT, RoBERTa, ALBERT, DeBERTa, Sentence-BERT, BGE, E5 GPT-2/3/4, Claude, LLaMA (all), Mistral, Gemma, Falcon, Qwen
Typical parameter count 110M (base) – 350M (large) 1.5B – 405B+ (modern LLMs)
Training data requirement Moderate — BERT trained on ~3.3B words (Wikipedia + BookCorpus) Massive — GPT-3 trained on ~300B tokens; LLaMA-3 on 15T tokens

06 — The Third Family: Encoder-Decoder (T5, BART)

There's a third architecture that combines both: the encoder-decoder (or seq2seq) transformer. It uses a BERT-style encoder to read and understand the input, and a GPT-style decoder to generate the output. The decoder can attend to all encoder outputs via cross-attention — a third type of attention head that reads from the encoder's representations while generating.

🌍 Non-Tech Analogy: The Translator

A translator reads the entire French sentence first (encoder — bidirectional, full understanding), then writes the English translation word by word (decoder — left-to-right generation). While writing, they can refer back to any part of the French original at any time (cross-attention). The encoding and generation are separate but connected phases.

Encoder-Decoder flow:

1. Encoder reads full input sequence → rich contextual embeddings (bidirectional)
2. Decoder generates output token by token (causal)
3. At each decode step, cross-attention lets the decoder query the encoder outputs

Cross-attention: Q from decoder, K and V from encoder
Decoder "asks questions" of the encoder's full-context representations
Architecture Examples Best for Weakness
Encoder-only BERT, RoBERTa, DeBERTa, E5, BGE Understanding, classification, retrieval, embeddings Cannot generate text at all
Decoder-only GPT-2/3/4, Claude, LLaMA, Mistral, Gemma Generation, chat, code, reasoning, instruction-following Weaker on pure understanding tasks without prompting tricks
Encoder-Decoder T5, BART, mT5, FLAN-T5, mBART Translation, summarisation, conditional generation More complex, higher memory at inference, smaller ecosystem

07 — Why the Industry Converged on Decoder-Only

By 2023 the industry had converged overwhelmingly on decoder-only models for general-purpose LLMs — GPT-4, Claude, LLaMA, Mistral, Gemma, Falcon, Qwen. BERT-family models are still dominant for embedding and retrieval. But for the "chat with an AI" use case, decoder-only won. Here's why:

🔢 Scaling efficiency
Next-token prediction scales smoothly and predictably with compute and data — the Chinchilla scaling laws hold cleanly. MLM (BERT's objective) uses only 15% of tokens per pass as training signal; CLM uses 100%. Decoder-only models extract more learning per token.
🎯 Universal objective
A single training task — predict next token — handles every downstream task through prompting: classification becomes "answer Q/A/B/C", summarisation becomes "summarise:", code becomes generating the continuation. No task-specific architectures needed.
🚀 Emergent versatility
At sufficient scale (>7B parameters), decoder-only models can perform classification, extraction, and Q&A tasks traditionally dominated by encoders — simply by prompting them correctly. The capability gap with encoders shrinks as decoder models scale up.
💬 Instruction following
Instruction fine-tuning (IFT) and RLHF work naturally on top of CLM because both are framed as text continuation. "User: summarise this. Assistant: [generated text]" is just next-token prediction with a specific format. BERT cannot natively do this.
📌 BERT Is Not Dead — It Still Wins at Retrieval

Encoder-only models dominate wherever you need embeddings — fixed-size vector representations of text for search, clustering, or retrieval. BERT's bidirectional representations are denser and more semantically rich than decoder-only representations for the same parameter count. Models like BGE, E5, GTE, and Sentence-BERT are still the backbone of every production RAG pipeline (Day 29) and semantic search system. The key insight: for retrieval, you embed millions of documents offline and query them later — generation is irrelevant. Encoder-only models are 10–100× cheaper to run at that scale than 7B+ decoder models.

08 — Notable Models in Each Family

Encoder-Only — The BERT Family

ModelYearKey improvement over BERT
BERT-base2018The original. 110M params. Trained on Wikipedia + BookCorpus.
RoBERTa2019Removed NSP task, used dynamic masking, trained on 10× more data. Consistently beats BERT on benchmarks.
ALBERT2020Parameter sharing across layers — 89% fewer params than BERT-large with comparable performance.
DeBERTa2020Disentangled attention (content and position separate). Best BERT-style model on GLUE for years.
Sentence-BERT2019Fine-tuned with siamese networks for sentence embeddings. Still widely used for semantic search.
BGE / E5 / GTE2023–24State-of-the-art text embedding models. Used in RAG pipelines, vector databases, and search.

Decoder-Only — The GPT Family

ModelYearKey milestone
GPT-12018Proved pre-training + fine-tuning works for language. 117M params.
GPT-220191.5B params. Coherent paragraph generation. "Too dangerous to release" (then released).
GPT-32020175B params. Few-shot prompting. Demonstrated emergent reasoning. Changed the field.
LLaMA-1/2/32023–24Open-weight. LLaMA-3 70B matches GPT-4-level quality on many tasks. 15T training tokens.
Mistral 7B2023Outperforms LLaMA-2 13B at 7B params. Sliding window attention. Apache 2.0 license.
Claude (Anthropic)2023–26Constitutional AI training. Strong at reasoning, coding, and long context (200k+).
Gemma / Qwen / Falcon2023–24Open-weight decoder-only models from Google, Alibaba, and TII. Multilingual focus.

Encoder-Decoder — The T5 Family

ModelYearKey milestone
T52019Framed every NLP task as text-to-text. Trained on C4 dataset. Unified framework for NLP.
BART2019Pre-trained by corrupting text and learning to reconstruct it. Excellent for summarisation.
FLAN-T52022T5 fine-tuned on 1,800+ instruction tasks. Outperforms GPT-3 on many tasks at 11B params.
mT5 / mBART2021Multilingual T5/BART variants. Still widely used for machine translation.

09 — Practical Decision Guide: Which to Use?

🧭 Quick Decision Framework

Do you need to generate text? → Decoder-only (GPT-style) or Encoder-Decoder (T5-style)
Do you need fixed-size embeddings for search/retrieval? → Encoder-only (BERT-style)
Do you need to classify, label, or extract from existing text? → Either — BERT for small data, decoder-only LLM with prompting for zero-shot

Your taskBest architectureWhy
Sentiment classification (with labelled data)BERTFine-tune on [CLS] output. Needs only hundreds of examples.
Named entity recognitionBERTToken-level output head. Bidirectional context critical for tagging.
Semantic search / document retrievalBERT (Sentence-BERT / BGE)Dense embeddings. Run offline on millions of docs cheaply.
Chatbot / conversational AIGPT decoder-onlyNatural next-token generation, instruction fine-tuning.
Code generation / completionGPT decoder-onlyCausal generation mirrors how code is written left-to-right.
Summarisation (abstractive)T5/BART or GPTSeq2seq natural fit; large decoder-only also works via prompting.
Machine translationmT5 / mBARTEncoder-decoder designed for this. Cross-attention from source to target.
Zero-shot classification (no labels)GPT large decoder-onlyPrompt engineering: "Is this review positive or negative? Answer:"
RAG retrieval componentBERT (BGE / E5)Embed documents for vector DB. 10–100× cheaper than LLM at scale.
RAG generation componentGPT decoder-onlyGenerate grounded response from retrieved context.

10 — Code: Both Architectures Side by Side

A minimal BERT-style encoder and GPT-style decoder in PyTorch, showing the exact difference in the attention mask.

import torch
import torch.nn as nn
import torch.nn.functional as F
import math

# ─────────────────────────────────────────────────────────────────────────
# Shared transformer block (identical for both BERT and GPT)
# ─────────────────────────────────────────────────────────────────────────
class TransformerBlock(nn.Module):
    def __init__(self, d_model=128, n_heads=4, d_ff=512, dropout=0.1):
        super().__init__()
        self.attn  = nn.MultiheadAttention(d_model, n_heads, dropout=dropout, batch_first=True)
        self.ff    = nn.Sequential(nn.Linear(d_model, d_ff), nn.GELU(), nn.Linear(d_ff, d_model))
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.drop  = nn.Dropout(dropout)

    def forward(self, x, attn_mask=None):
        # Pre-LN + residual (modern stable training variant)
        x_norm = self.norm1(x)
        attn_out, _ = self.attn(x_norm, x_norm, x_norm, attn_mask=attn_mask)
        x = x + self.drop(attn_out)
        x = x + self.drop(self.ff(self.norm2(x)))
        return x


# ─────────────────────────────────────────────────────────────────────────
# BERT-style encoder — bidirectional, no mask
# ─────────────────────────────────────────────────────────────────────────
class BERTEncoder(nn.Module):
    def __init__(self, vocab_size=30522, d_model=128, n_layers=4,
                 n_heads=4, max_len=512):
        super().__init__()
        self.tok_emb = nn.Embedding(vocab_size, d_model)
        self.pos_emb = nn.Embedding(max_len, d_model)  # learned absolute PE (BERT-style)
        self.layers  = nn.ModuleList([TransformerBlock(d_model, n_heads) for _ in range(n_layers)])
        self.norm    = nn.LayerNorm(d_model)

    def forward(self, token_ids):
        B, T = token_ids.shape
        positions = torch.arange(T, device=token_ids.device)
        x = self.tok_emb(token_ids) + self.pos_emb(positions)
        for layer in self.layers:
            x = layer(x, attn_mask=None)   # ← NO MASK: full bidirectional attention
        return self.norm(x)   # (B, T, d_model) — all token representations


# ─────────────────────────────────────────────────────────────────────────
# GPT-style decoder — causal (left-to-right) mask
# ─────────────────────────────────────────────────────────────────────────
class GPTDecoder(nn.Module):
    def __init__(self, vocab_size=50257, d_model=128, n_layers=4,
                 n_heads=4, max_len=1024):
        super().__init__()
        self.tok_emb = nn.Embedding(vocab_size, d_model)
        self.pos_emb = nn.Embedding(max_len, d_model)
        self.layers  = nn.ModuleList([TransformerBlock(d_model, n_heads) for _ in range(n_layers)])
        self.norm    = nn.LayerNorm(d_model)
        self.lm_head = nn.Linear(d_model, vocab_size, bias=False)  # predicts next token

    def get_causal_mask(self, T, device):
        # Upper triangle = -inf: token at position i cannot see positions j > i
        return torch.triu(torch.full((T, T), float('-inf'), device=device), diagonal=1)

    def forward(self, token_ids):
        B, T = token_ids.shape
        positions = torch.arange(T, device=token_ids.device)
        x = self.tok_emb(token_ids) + self.pos_emb(positions)
        mask = self.get_causal_mask(T, token_ids.device)
        for layer in self.layers:
            x = layer(x, attn_mask=mask)  # ← CAUSAL MASK: only attend left
        x = self.norm(x)
        return self.lm_head(x)   # (B, T, vocab_size) — next-token logits

    @torch.no_grad()
    def generate(self, prompt_ids, max_new_tokens=20, temperature=1.0):
        """Simple autoregressive generation with temperature sampling."""
        ids = prompt_ids.clone()
        for _ in range(max_new_tokens):
            logits = self(ids)              # (1, T, vocab)
            next_logits = logits[:, -1, :] / temperature   # last position
            probs = F.softmax(next_logits, dim=-1)
            next_id = torch.multinomial(probs, num_samples=1)
            ids = torch.cat([ids, next_id], dim=1)          # append and loop
        return ids


# ─────────────────────────────────────────────────────────────────────────
# BERT classification head (add on top for fine-tuning)
# ─────────────────────────────────────────────────────────────────────────
class BERTClassifier(nn.Module):
    def __init__(self, encoder, num_classes=2, d_model=128):
        super().__init__()
        self.encoder = encoder
        self.head = nn.Linear(d_model, num_classes)

    def forward(self, token_ids):
        out = self.encoder(token_ids)     # (B, T, d_model)
        cls_repr = out[:, 0, :]           # [CLS] token is at position 0
        return self.head(cls_repr)         # (B, num_classes) — classification logits


# ─────────────────────────────────────────────────────────────────────────
# Sanity checks
# ─────────────────────────────────────────────────────────────────────────
B, T = 2, 16   # batch=2, sequence_length=16
fake_input = torch.randint(0, 1000, (B, T))

bert = BERTEncoder(vocab_size=1000, d_model=128)
gpt  = GPTDecoder(vocab_size=1000, d_model=128)
clf  = BERTClassifier(bert, num_classes=3)

bert_out   = bert(fake_input)
gpt_logits = gpt(fake_input)
clf_out    = clf(fake_input)

# Check causal mask: position 0 should only attend to position 0
mask = gpt.get_causal_mask(4, 'cpu')

print(f"BERT output:         {bert_out.shape}   ← (batch, seq, d_model)")
print(f"GPT logits:          {gpt_logits.shape}  ← (batch, seq, vocab_size)")
print(f"Classifier output:   {clf_out.shape}    ← (batch, num_classes)")
print(f"\nCausal mask (4×4):\n{mask}")
print(f"\nBERT params:  {sum(p.numel() for p in bert.parameters()):,}")
print(f"GPT params:   {sum(p.numel() for p in gpt.parameters()):,}")
── BERT vs GPT Architecture Sanity Check ──────────────────────────────
BERT output:          torch.Size([2, 16, 128])   ← (batch, seq, d_model)
GPT logits:           torch.Size([2, 16, 1000])   ← (batch, seq, vocab_size)
Classifier output:    torch.Size([2, 3])        ← (batch, num_classes)

Causal mask (4×4):
tensor([[ 0., -inf, -inf, -inf],
        [ 0., 0., -inf, -inf],
        [ 0., 0., 0., -inf],
        [ 0., 0., 0., 0.]])

BERT params:   4,072,832 ← encoder only, no LM head
GPT params:    4,200,960 ← includes LM head (vocab_size × d_model)

11 — A Thought to Sit With

💬 For You to Consider

BERT reads everything at once and is excellent at understanding. GPT reads left to right and is excellent at generating. Humans do both simultaneously — we understand and generate at the same time, in real-time conversation, without switching modes.

Is the encoder/decoder split a fundamental architectural truth about the nature of language tasks — or just a practical consequence of training objectives that happened to work well? Could a single architecture truly do both as well as specialised ones? And if the industry has converged on decoder-only for almost everything, what does that say about the relationship between generation and understanding?

12 — Coming Up Next

Tomorrow — Day 27: Tokenization Deep Dive. We've been using tokenizers throughout the series without fully opening the black box. Day 27 goes inside: Byte-Pair Encoding (BPE) — how GPT builds its vocabulary; WordPiece — how BERT does it differently; SentencePiece — the language-agnostic approach used by LLaMA and T5; and why the same word tokenizes into completely different numbers of tokens across models — with direct consequences for cost, context length, and multilingual performance.

13 — Go Deeper

📄 BERT: Pre-training of Deep Bidirectional Transformers — Devlin et al. (2018)
The original BERT paper. Section 3 (model architecture) and Section 4 (fine-tuning) are the essential parts. Table 1 showing 11 GLUE benchmark improvements simultaneously is one of the most impressive result tables in NLP history.

📄 Improving Language Understanding by Generative Pre-Training — Radford et al. (2018)
The original GPT-1 paper. Short and readable. Section 3 explains the pre-training/fine-tuning paradigm that the entire field adopted.

📄 RoBERTa: A Robustly Optimized BERT Pretraining Approach — Liu et al. (2019)
Shows that BERT was undertrained. Removing NSP, increasing batch size, and training longer produces consistent improvements. Section 4 is a clean ablation study worth reading.

📄 Exploring the Limits of Transfer Learning with T5 — Raffel et al. (2019)
Unifies every NLP task as text-to-text. The most rigorous comparison of architectures, objectives, and scales ever published. Section 3 is a masterclass in ablation study design.

▶ BERT explained — Andrej Karpathy / various
Karpathy's "Let's build GPT from scratch" on YouTube is the clearest derivation of the decoder architecture available. Highly recommended alongside this post.

🧠 Check Your Understanding
1. BERT and GPT use the same transformer architecture. What is the single concrete difference that makes BERT an encoder and GPT a decoder?
2. What is Masked Language Modelling (MLM) and why does it force BERT to learn bidirectional representations?
3. Why can GPT generate text but BERT cannot? Explain the architectural reason.
4. Why did the industry converge on decoder-only models for general-purpose LLMs, even though BERT-style encoders often produce better representations per parameter?
5. You are building a system that: (a) retrieves the top-5 relevant documents from a 10-million-document corpus, then (b) generates a grounded answer from those documents. Which architecture would you use for each component and why?
⚡ Quick Recap — BERT vs GPT
  1. Same architecture, one difference: BERT and GPT are both transformer stacks with identical attention, FFN, residual, and norm components. The only architectural difference is the attention mask — BERT uses no mask (bidirectional), GPT uses a causal upper-triangle mask (left-to-right only).
  2. BERT (encoder-only): every token attends to every other token. Trained with Masked Language Modelling (MLM) — predict 15% hidden tokens using both left and right context. Produces rich contextual representations. Cannot generate text.
  3. GPT (decoder-only): each token only attends to itself and previous tokens. Trained with Causal Language Modelling (CLM) — predict the next token from all preceding tokens. Generates text autoregressively. Cannot use future context.
  4. BERT fine-tuning: add a small task-specific head (linear layer on [CLS] or token outputs) and fine-tune on small labelled datasets. The pre-trained weights transfer extremely well — hundreds of labelled examples often suffice.
  5. GPT generation: append the sampled token to the input and repeat. Temperature controls randomness. Top-k / nucleus (top-p) sampling prevents degenerate outputs. KV-cache (Day 24) makes this efficient at scale.
  6. Encoder-Decoder (T5, BART): combines both — a BERT-style encoder reads the input, a GPT-style decoder generates the output with cross-attention to the encoder. Best for translation and conditional summarisation.
  7. Why decoder-only won for LLMs: CLM uses 100% of tokens as training signal (vs 15% for MLM). Next-token prediction scales cleanly. Universal objective handles all tasks via prompting. Compatible with instruction fine-tuning and RLHF.
  8. BERT still wins at retrieval: for embedding-based semantic search and RAG retrieval, encoder-only models (BGE, E5, Sentence-BERT) produce better dense vectors and are 10–100× cheaper to run at scale than decoder-only models.
  9. Key model families: BERT → RoBERTa → DeBERTa → BGE/E5 (encoder); GPT-1 → GPT-3 → GPT-4 / LLaMA → Claude / Mistral / Gemma (decoder); T5 → FLAN-T5 / BART → mT5 (encoder-decoder).
  10. Decision rule: embedding/retrieval/classification with labelled data → encoder. Generation/chat/code/zero-shot → decoder. Translation/summarisation with seq2seq format → encoder-decoder.
🎯 Interview Questions
  1. What is the difference between an encoder and a decoder in the transformer architecture?
    An encoder uses bidirectional (full) attention — every token can attend to every other token. It maps an input sequence to a sequence of contextual representations. A decoder uses causal (unidirectional) attention — each token can only attend to itself and previous tokens. It maps a sequence to next-token probability distributions and generates text autoregressively. Same transformer blocks, different attention mask. BERT is encoder-only; GPT is decoder-only; T5 combines both.
  2. What is the difference between Masked Language Modelling (MLM) and Causal Language Modelling (CLM)?
    MLM (BERT): randomly mask 15% of input tokens and predict them using the surrounding context from both directions. Training signal covers 15% of tokens per pass. Forces the model to build bidirectional representations but cannot be used for generation. CLM (GPT): predict the next token given all preceding tokens, for every position in the sequence. Training signal covers 100% of tokens per pass — significantly more efficient. Scales cleanly. Enables autoregressive generation but can only use left context. The choice of objective determines the attention pattern and ultimately what the model can and cannot do.
  3. Why are encoder-only models (BERT) preferred for semantic search and retrieval, even in a world dominated by decoder-only LLMs?
    Three reasons: (1) Representation quality — BERT's bidirectional attention produces richer, more semantically complete fixed-size embeddings than decoder-only models' one-directional representations at the same parameter count. For retrieval, you need a single vector that captures the full meaning of a document. (2) Cost at scale — embedding 10M documents with a 110M-parameter BERT costs a fraction of running a 7B decoder-only model for the same. Embeddings are computed offline once and reused. (3) Task alignment — semantic search doesn't require generation. Running a full generative LLM to produce embeddings is wasteful — the generation head is never used. BGE, E5, and Sentence-BERT are purpose-built for this and significantly outperform decoder-only models at equivalent cost on retrieval benchmarks.
  4. What is the [CLS] token in BERT and how is it used for classification?
    BERT prepends a special [CLS] (classification) token to every input. During pre-training with NSP, [CLS]'s final representation is trained to capture sentence-level information — it aggregates context from the entire sequence through attention across all layers. For fine-tuning on classification tasks, a linear layer is attached to the final [CLS] embedding: logits = W · BERT_output[CLS] + b, where W ∈ ℝ^(num_classes × d_model). The full model (BERT + linear head) is then fine-tuned end-to-end on the labelled task data. [CLS] is not inherently special architecturally — it's just a token that BERT learns during pre-training to aggregate global information because the NSP objective requires it. In practice, mean-pooling all token outputs often performs equally well or better for sentence embeddings, which is why Sentence-BERT uses mean-pooling instead of [CLS].
  5. A company wants to build a customer support system that: (1) classifies incoming tickets into 12 categories, (2) generates personalised responses. What model architecture would you recommend for each and why?
    Task (1) — classification: use a fine-tuned BERT-style encoder (BERT, RoBERTa, or DeBERTa). Reasons: with labelled ticket data available, fine-tuning an encoder on [CLS] output is highly sample-efficient (hundreds of examples per category typically sufficient), computationally cheap at inference (110M–350M params, runs fast on CPU or small GPU), and produces excellent accuracy for classification. A 12-class linear head on top of RoBERTa would be the first choice. Alternative: if labelled data is very limited (<50 examples/class), prompt a decoder-only LLM for zero-shot/few-shot classification instead. Task (2) — generation: use a fine-tuned decoder-only LLM (LLaMA-3 7B/8B or Mistral 7B). Reasons: generating personalised natural-language responses requires autoregressive generation, which only decoder-only models support. Fine-tune with instruction-following data (customer support Q&A pairs) to ground the model in company policies and tone. The two components run independently — the classifier routes the ticket and the LLM generates the response. This hybrid encoder (fast, cheap classification) + decoder (rich generation) architecture is the industry standard for production customer support AI systems.
📎 Attachments & Further Reading

📄 BERT: Pre-training of Deep Bidirectional Transformers — Devlin et al. (2018)
The paper that established the pre-train/fine-tune paradigm. Table 1 (11 GLUE tasks improved simultaneously) is still remarkable. Sections 3–4 cover architecture and fine-tuning clearly.

📄 RoBERTa — Liu et al. (2019)
BERT was undertrained. RoBERTa shows that removing NSP, using dynamic masking, and training longer consistently improves all tasks. Essential for understanding what actually matters in BERT pre-training.

📄 Exploring the Limits of Transfer Learning with T5 — Raffel et al. (2019)
The most thorough architecture + objective comparison in NLP. Unifies everything as text-to-text. Section 3's ablation table is the best guide to understanding what choices matter and why.

▶ Let's build GPT from scratch — Andrej Karpathy (2023)
YouTube · 2hr · The clearest hands-on derivation of the decoder architecture available. Builds a miniGPT from scratch in ~250 lines of PyTorch. Essential viewing for anyone who wants to truly understand how GPT works.

🔗 The Illustrated BERT — Jay Alammar
Visual step-by-step walkthrough of BERT's pre-training and fine-tuning. The diagrams for MLM, NSP, and the fine-tuning paradigm are the best available.

#BERT#GPT#Encoder#Decoder#MLM#CLM#Transformer#PreTraining#FineTuning#T5#BART#RoBERTa#LLaMA#NLP#31DaysOfAI#Ramadan2026
← Day 25 Positional Encodings