6 min read Deep Learning

Introduction to Transformer Architecture

Transformers have fundamentally changed how we approach sequence modeling, becoming the foundation of virtually all modern NLP systems. Introduced in the seminal paper “Attention Is All You Need” (2017), this architecture solved key limitations of RNNs while enabling unprecedented scale.

Why Transformers Matter

Before transformers, sequence models relied on recurrent connections (RNNs, LSTMs) that processed data sequentially. This created two major problems:

  1. No parallelization: Each timestep depends on the previous, limiting GPU utilization
  2. Long-range dependencies: Information from early timesteps gets diluted as it propagates through the sequence

Transformers solve both by using attention mechanisms that can directly relate any position to any other position, regardless of distance.

The Attention Mechanism

At the heart of transformers is scaled dot-product attention:

import torch
import torch.nn as nn
import math

def scaled_dot_product_attention(Q, K, V, mask=None):
    """
    Q: Queries (batch_size, seq_len, d_k)
    K: Keys (batch_size, seq_len, d_k)
    V: Values (batch_size, seq_len, d_v)
    """
    d_k = Q.size(-1)

    # Compute attention scores
    scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(d_k)

    # Apply mask (for causal attention in decoders)
    if mask is not None:
        scores = scores.masked_fill(mask == 0, float('-inf'))

    # Softmax to get attention weights
    attention_weights = torch.softmax(scores, dim=-1)

    # Weighted sum of values
    output = torch.matmul(attention_weights, V)

    return output, attention_weights

The scaling factor sqrt(d_k) prevents dot products from growing too large in high dimensions, which would push softmax into regions with small gradients.

Multi-Head Attention

Rather than performing attention once, transformers use multiple attention heads that learn different types of relationships:

class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super().__init__()
        assert d_model % num_heads == 0

        self.d_model = d_model
        self.num_heads = num_heads
        self.d_k = d_model // num_heads

        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)

    def forward(self, query, key, value, mask=None):
        batch_size = query.size(0)

        # Linear projections and reshape for multi-head
        Q = self.W_q(query).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_k(key).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_v(value).view(batch_size, -1, self.num_heads, self.d_k).transpose(1, 2)

        # Apply attention
        attention_output, weights = scaled_dot_product_attention(Q, K, V, mask)

        # Concatenate heads and final linear
        attention_output = attention_output.transpose(1, 2).contiguous().view(
            batch_size, -1, self.d_model
        )

        return self.W_o(attention_output)

Multiple heads allow the model to jointly attend to information from different representation subspaces—one head might track syntactic relationships while another focuses on semantic similarity.

Positional Encoding

Unlike RNNs, transformers have no inherent sense of sequence order. Positional encodings inject position information into the input embeddings:

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, max_seq_length=5000):
        super().__init__()

        pe = torch.zeros(max_seq_length, d_model)
        position = torch.arange(0, max_seq_length, dtype=torch.float).unsqueeze(1)

        div_term = torch.exp(
            torch.arange(0, d_model, 2).float() *
            (-math.log(10000.0) / d_model)
        )

        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)

        self.register_buffer('pe', pe.unsqueeze(0))

    def forward(self, x):
        return x + self.pe[:, :x.size(1)]

The sinusoidal functions allow the model to learn relative positions—PE(pos + k) can be represented as a linear function of PE(pos).

The Complete Transformer Block

A transformer layer combines attention with feed-forward networks and residual connections:

class TransformerBlock(nn.Module):
    def __init__(self, d_model, num_heads, d_ff, dropout=0.1):
        super().__init__()
        self.attention = MultiHeadAttention(d_model, num_heads)
        self.feed_forward = nn.Sequential(
            nn.Linear(d_model, d_ff),
            nn.ReLU(),
            nn.Linear(d_ff, d_model)
        )
        self.norm1 = nn.LayerNorm(d_model)
        self.norm2 = nn.LayerNorm(d_model)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, mask=None):
        # Self-attention with residual
        attn_output = self.attention(x, x, x, mask)
        x = self.norm1(x + self.dropout(attn_output))

        # Feed-forward with residual
        ff_output = self.feed_forward(x)
        x = self.norm2(x + self.dropout(ff_output))

        return x

Key design choices:

  • LayerNorm before sublayers (Pre-LN): More stable training for deep models
  • Residual connections: Enable gradient flow in deep networks
  • Dropout: Regularization to prevent overfitting

Encoder-Decoder Architecture

The original transformer uses separate encoder and decoder stacks:

Encoder: Processes input sequence bidirectionally, creating contextualized representations

Decoder: Generates output autoregressively with:

  • Masked self-attention (can’t look at future tokens)
  • Cross-attention to encoder outputs

Modern variants simplify this:

  • BERT: Encoder-only, trained with masked language modeling
  • GPT: Decoder-only, trained with causal language modeling
  • T5: Full encoder-decoder for sequence-to-sequence tasks

Applications Beyond NLP

Transformers have expanded far beyond text:

Vision Transformers (ViT): Treat image patches as sequences, achieving state-of-the-art results on ImageNet

Multimodal Models: CLIP, DALL-E, and GPT-4V combine vision and language

Protein Folding: AlphaFold uses transformer variants for predicting 3D structures

Time Series: Informer and Autoformer adapt attention for temporal data

Training Considerations

Warmup Schedule: Transformers require learning rate warmup to stabilize early training:

# Linear warmup then decay
scheduler = torch.optim.lr_scheduler.LambdaLR(
    optimizer,
    lr_lambda=lambda step: min(step / warmup_steps, 1.0) *
                          (0.5 * (1 + math.cos(math.pi * step / total_steps)))
)

Gradient Accumulation: Essential for training with limited GPU memory

Mixed Precision: FP16 training is standard for large transformers

Scaling Laws

Transformers exhibit predictable scaling relationships:

  • Loss ∝ Model Size^(-0.076): Larger models generalize better
  • Loss ∝ Dataset Size^(-0.095): More data continues to help
  • Loss ∝ Compute^(-0.050): Returns diminish but remain positive

These relationships have driven the development of models with hundreds of billions of parameters.

Modern Variants

Efficient Attention:

  • FlashAttention: Memory-efficient exact attention
  • Linear Attention: Approximate attention in O(n) time
  • Sparse Attention: Only attend to local windows or strided patterns

Parameter Efficiency:

  • LoRA: Low-rank adaptation for fine-tuning
  • Prefix Tuning: Learnable prompt embeddings
  • QLoRA: Quantized LoRA for consumer GPU fine-tuning

Conclusion

Transformers represent a paradigm shift in machine learning—from sequential processing to parallelizable attention. Their flexibility and scalability have made them the dominant architecture across modalities.

Understanding transformers is essential for modern ML practitioners. The concepts—attention, positional encoding, multi-head processing—appear in virtually every state-of-the-art system.

For those building with transformers today, frameworks like Hugging Face Transformers provide pre-trained models and easy fine-tuning APIs, while libraries like DeepSpeed and Megatron-LM enable training at massive scale.

Back to top