Back to .md Directory

An Introduction to Transformers

Presents a slide deck introducing transformer architecture, attention mechanisms, and a PyTorch implementation from scratch.

May 2, 2026
0 downloads
1 views
ai
View source

What this file does

Presents a slide deck introducing transformer architecture, attention mechanisms, and a PyTorch implementation from scratch.

When to use it

  • Teaching or learning the fundamentals of transformers and attention
  • Building a minimal transformer model in PyTorch for experimentation
  • Creating a presentation or workshop on modern NLP architectures
  • Understanding the math behind query-key-value attention and masking

Assumes this stack

PythonPyTorchspaCyNumPy

marp: false theme: default size: 4K paginate: true

bg right:25% 90% Plot of context rot

Before we start

Repository with slides and (Python) code: https://github.com/krometis/transformers

Consider running setup commands now - package downloads and installation can take time


bg right:25% 85% Picture from the 1980s Transformers cartoons (the talk is not actually about this)

An Introduction to Transformers

Justin Krometis | Virginia Tech

January 28, 2026


bg right:30% 90% Picture of me and my family at my Ph.D. graduation

About Me

  • Hokie x 3 (Ph.D., Math, 2018)
  • Research Associate Professor with VT National Security Institute
  • Previously:
    • Computational Scientist with Advanced Research Computing
    • Senior Transportation Analyst with IEM, Inc.

bg right:30% 70% Major AI logos

Why Transformers?

  • Introduced by Google researchers in 2017
  • State of the art in natural language processing
  • The advance that enabled the modern AI explosion

bg right:30% 70% Major AI logos

Why Transformers?

  • Introduced by Google researchers in 2017
  • State of the art in natural language processing
  • The advance that enabled the modern AI explosion
    • GPT: Generative Pre-trained Transformer

bg right:30% 80% Transformer diagram from the Attention is All You Need paper that introduced them

What is a Transformer?

  • Model for understanding and generating sequential data
  • Developed for natural language processing, e.g., text translation
    • Use has grown since (vision, audio)
  • Key innovation: Attention

<small><i>Reference: Vaswani, et al. "Attention Is All You Need." 2017. https://arxiv.org/abs/1706.03762.</i></small>


Background


Linear Models

Given:

  • Inputs $\mathbf{x} \in \mathbb{R}^{n}$
  • A matrix (weights) $W \in \mathbb{R}^{m \times n}$
  • Intercepts (biases) $\mathbf{b} \in \mathbb{R}^{m}$

We compute output $\mathbf{y} \in \mathbb{R}^{m}$: $$\mathbf{y} = W \mathbf{x} + \mathbf{b}$$


<!--![bg right:30% 80% Plot of various activation functions](figures/activations.png)-->

A Simple Nonlinear Model

As before, we compute: $$\mathbf{z} = W \mathbf{x} + \mathbf{b}$$

But now we pass the result through a nonlinear function $f: \mathbb{R}^{m}\to \mathbb{R}^{m}$: $$\mathbf{y} = f(\mathbf{z})$$


<!--![bg 80% Simple neural network diagram](figures/nn.png)-->

Feedforward Neural Networks

80% Simple neural network diagram


Transformers


bg right:30% 80% Transformer diagram from the Attention is All You Need paper that introduced them

What is a Transformer?

Key components:

  • Embedding: Represent inputs and outputs
  • Attention: Identify relationships that matter
  • Feedforward: Turn inputs into outputs

Simplification:

  • Focus on GPT models
  • Same input/output space (no encoder)

Embedding

  • Machine learning models work through math
  • But operate in non-mathematical applications (text, audio, images)
  • How do we translate non-numeric inputs and outputs into numbers?

Answer: Embeddings

(Note: Feature selection or extraction is a key consideration beyond NLP or transformers)


Embedding (Continued)

  • Map inputs into tokens
  • Map tokens into (high-dimensional) vectors of numbers
  • Vectors that are close together should conceptually similar
  • Tokens that are different or unrelated should be far apart

Key metric: Cosine similarity: $$S_c(\mathbf{v}_1,\mathbf{v}_2) = \frac{\mathbf{v}_1 \cdot \mathbf{v}_2}{| \mathbf{v}_1 | | \mathbf{v}_2 | }$$


Embedding - Example (continued)

import numpy as np
import spacy

def cosine_similarity(v1,v2):
    return np.dot(v1,v2) / ( np.linalg.norm(v1) * np.linalg.norm(v2) )

nlp = spacy.load("en_core_web_lg")
doc1 = nlp("Computational Modeling and Data Analytics")
doc2 = nlp("Academy of Data Science")

cos_sim = np.zeros((len(doc1),len(doc2)))
for i,token1 in enumerate(doc1):
    for j,token2 in enumerate(doc2):
        cos_sim[i,j] = cosine_similarity(token1.vector,token2.vector)

Example Similarities

<style scoped> p { text-align: center; } </style>

50% Heatmap showing cosine similarity


Example Similarities ( :koala: :kangaroo: )

<style scoped> p { text-align: center; } </style>

50% Heatmap showing cosine similarity with additional entries


Why Attention?

Imagine completing the sentence:

The Virginia Polytechnic Institute and State University, commonly referred to as Virginia Tech (VT), is a public land-grant research university...

[several paragraphs of text]

Under the leadership of seventh president ...

Traditional (pre-transformer) models for text prediction would struggle to connect "president" with "Virginia Tech".

Need: Model that can communicate information across long distances in the sequence


Quick Aside: Masking

A partial sentence with eight words:

The Academy of Data Science teaches students to...

Actually presents eight training opportunities:

  • The ...
  • The Academy ...
  • ...
  • The Academy of Data Science teaches students ...
  • The Academy of Data Science teaches students to ...

bg right:30% 80% Heat map of mask - lower triangle is yellow (true) and upper triangle is purple (false)

Masking, Continued

Goal:

  • Leverage all sequences for efficiency

Requirement:

  • Predictions should only be influenced by preceding words

Implementation:

  • Add a lower-triangular "mask" to the connections between words

Attention

Three key concepts:

  • Query: What information do I need?
  • Key: What information do I contain?
  • Value: What will I add if you find me interesting?

All three are linear maps from the embedding $X \in \mathbb{R}^{d_{\text{embed}}\times d_{\text{context}}}$: $$Q = W_q X, \quad K = W_k X, \quad V = W_v X$$

Note: $W_q, W_k \in \mathbb{R}^{d_k \times d_{\text{embed}}}$ and $W_v \in \mathbb{R}^{d_v \times d_{\text{embed}}}$ all learned in training


Masked Dot-product Attention

$$ A(Q,K,V) = \text{Softmax}\left( M\left( \frac{1}{\sqrt{d_k}} Q K^T \right) \right) V $$

Step-by-step:

  • $Q K^T$ finds the queries and keys that best match
  • Divide by $\sqrt{d_k}$ to mitigate scaling effects
  • $M(\cdot)$ applies the mask
  • $\text{Softmax}(\cdot)$ converts to weights (formula: $e^{x_i}/\sum_j e^{x_j}$)
  • Multiply by $V$ to get weighted values

Example Implementation (PyTorch)

import torch, torch.nn as nn, torch.nn.functional as F

def attention(q,k,v):
    mask    = torch.tril( torch.ones(q.shape[-2],q.shape[-2]) ).bool()
    qkT     = torch.matmul( q, k.transpose(-2,-1) ) / (q.shape[-1]**0.5)
    qkT_msk = qkT.masked_fill_(~mask, value=float("-inf"))
    weights = F.softmax(qkT_msk,-1)
    att     = torch.matmul(weights,v)
    return att

Example Implementation (PyTorch Class, 1)

import torch, torch.nn as nn, torch.nn.functional as F

class SelfAttentionHead(nn.Module):

    def __init__(self, d_embed, d_cntxt, d_k, d_v):
        super().__init__()
        
        self.d_k   = d_k
        #trainable maps
        self.query = nn.Linear(d_embed,d_k,bias=False)
        self.key   = nn.Linear(d_embed,d_k,bias=False)
        self.value = nn.Linear(d_embed,d_v,bias=False)
        #not trainable mask
        self.register_buffer('mask', torch.tril( torch.ones(d_cntxt,d_cntxt) ).bool())

Example Implementation (PyTorch Class, 2)

    def attention(self,q,k,v):
        qkT     = torch.matmul( q, k.transpose(-2,-1) )
        qkT_scl = qkT / torch.sqrt(torch.tensor(self.d_k))
        qkT_msk = qkT_scl.masked_fill_(~self.mask, value=float("-inf"))
        weights = F.softmax(qkT_msk,-1)
        att     = torch.matmul(weights,v)
        return att

    def forward(self,x):
        q = query(x)
        k = key(x)
        v = value(x)
        
        return self.attention(q,k,v)

bg right:30% 90% Plot of context rot

Notes

  • Capture longer-distance connections
    • Up to the context window length $d_{\text{context}}$
  • More scalable/parallelizable
    • No recurrence or convolutions
  • Attention scales like square of context window $d_{\text{context}}^2$
    • "Context rot"<!--: Deterioration on tasks as context window scales-->

<i>Ref: Modarressi, et al. "NoLiMa: Long-Context Evaluation Beyond Literal Matching." 2025. https://arxiv.org/abs/2502.05167.</i>


bg right:30% 80% Transformer diagram from the Attention is All You Need paper that introduced them

Completing the Transformer

  1. Multi-head attention: Multiple blocks in parallel & concatenate
  2. Linear layer to re-inflate to embedding dimension
  3. Feedforward layer
  4. Iterate several attention blocks (deeper network)
  5. Positional encoding
  6. Training practicalities
    • "Skip" (residual) connections to retain information deeper in network
    • Layer normalization to mitigate gradients
    • Dropout to reduce overfitting

Multi-head Attention

class MultiHeadAttentionLayer(nn.Module):
    '''Defines a layer of multihead attention'''
    def __init__(self, n_head, d_embed, d_cntxt, d_k, d_v):
        super().__init__()
        
        #list of attention heads to be run side by side
        self.attnHeads = [ SelfAttentionHead(d_embed,d_cntxt,d_k,d_v) for _ in range(n_head) ]
        #projection back to the embedding dimension
        self.toEmbed   = nn.Linear(d_v*n_head,d_embed)
        
    def forward(self,x):
        #run all heads and concatenate
        out = torch.cat([ head(x) for head in self.attnHeads],-1)
        #run the linear layer to project back to the embedding dimension
        out = self.toEmbed(out)
        return out

Transformer Block

class TransformerBlock(nn.Module):
    '''Defines a block of a transformer model'''
    def __init__(self, n_head, d_embed, d_cntxt, d_k, d_v):
        super().__init__()
        
        #multi-head attention layer
        self.multiHead = MultiHeadAttentionLayer(n_head,d_embed,d_cntxt,d_k,d_v)
        #feedforward layer
        self.ffw = nn.Sequential(
            nn.Linear(d_embed,d_embed*4),
            nn.ReLU(),
            nn.Linear(d_embed*4,d_embed),
        )
        #layer normalizations
        self.norm1 = nn.LayerNorm(d_embed)
        self.norm2 = nn.LayerNorm(d_embed)
        
    def forward(self,x):
        #run multi-head attention w/ residual connection & layer norm
        x = self.norm1( x + self.multiHead(x) )
        #run feedforward layer w/ residual connection & layer norm
        x = self.norm2( x + self.ffw(x) )
        return x

Transformer: Initialization

class TransformerModel(nn.Module):
    '''
    Defines a transformer model
    '''
    def __init__(self, n_layer, n_head, d_vocab, d_embed, d_cntxt, d_k, d_v, pe_orig=True):
        super().__init__()
        
        #blocks (each multi-head attention + feedforward)
        self.blocks  = nn.Sequential(*[ 
            TransformerBlock(n_head,d_embed,d_cntxt,d_k,d_v) 
            for _ in range(n_layer) 
        ])
        
        #linear layer to return to vocab size
        self.toVocab = nn.Linear(d_embed,d_vocab)
        
        #not trainable mask
        self.register_buffer('p_embed', self.pos_embed(d_cntxt,d_embed,original=pe_orig) )

Transformer: Position Embedding

    def pos_embed(self,d_cntxt,d_embed,original=True):
        p_embed = torch.zeros(d_cntxt,d_embed)
        if original:
            #PE(pos,2i  ) = sin((pos/10000)^(2i/d_embed))
            #PE(pos,2i+1) = cos((pos/10000)^(2i/d_embed))
            den = torch.pow(10000,-torch.arange(0,d_embed,2)/d_embed)
        else:
            #regular fourier basis seems more sane?
            den = 2*torch.pi*torch.arange(0,d_embed,2)/d_embed
        pos = torch.arange(d_cntxt)
        ang = torch.outer(pos,den)
        p_embed[:, ::2] = torch.sin(ang)
        p_embed[:,1::2] = torch.cos(ang)
        return p_embed

Transformer: Forward & Prediction

    def forward(self,x):
        #add positional embedding
        x = x + self.p_embed
        #run blocks
        attn_out = self.blocks(x)
        #run linear layer
        logits = self.toVocab(attn_out)
        #convert to probabilities
        probs  = F.softmax(logits,-1)
        return probs #for training should add loss here
    
    def predict(self,x):
        #get probabilities associated with last entry in context
        probs = self(x)[:,-1,:]
        #draw to get a prediction (probabilistic!)
        idx = torch.multinomial(probs, num_samples=1)
        return idx

Conclusions


Summary

  • Transformer: New (<10 years) model underlying much of the AI boom
    • GPT: Generative Pretrained Transformer
  • Attention: A mechanism for connecting sequential data
    • Allows connections across long distances
    • Highly parallel

Onward

70% Plot of parameter growth in AI models. The original transformer model in 2017 is orders of magnitude smaller than modern models.

<it>Ref: Maslej, et al. “The AI Index 2025 Annual Report,” Stanford University. April 2025. https://arxiv.org/abs/2504.07139.</it>


bg right:25% 90% Plot of context rot

Hands On

  • Implementation: Run or tinker with the code shown earlier :keyboard:
  • Embeddings: Explore embeddings and cosine similarity :bar_chart:
  • Transformers: Visualize attention in 3rd party models :brain:
  • Activations: Plot activation functions :yawning_face:

Repository: https://github.com/krometis/transformers

What's inside

40 slides, 6 code examples (PyTorch classes for attention, multi-head attention, transformer block, full model), 3 mathematical formulas.

Change this for your project

  • Replace nlp = spacy.load("en_core_web_lg") with your own spaCy model or embedding method
  • Replace https://github.com/krometis/transformers with your own repository URL
  • Replace figures/ paths with your own figure directory or remove image references

Where it goes

Keep it in your repository where the agent or team that needs it will read it.

Worth borrowing

  • Using a slide deck as a literate programming document with runnable code snippets
  • Building a transformer incrementally from attention head to full model with residual connections and layer norm

Related Documents