A from-scratch implementation of a GPT-style Transformer language model built entirely with PyTorch. This project follows the decoder-only Transformer architecture (the same architecture behind ChatGPT, Claude, and Gemini) to learn and generate text character by character.
| Property | Value |
|---|---|
| Total Parameters | 10.8 Million |
| Architecture | Decoder-Only Transformer (GPT-style) |
| Embedding Dimension | 384 |
| Attention Heads | 6 |
| Transformer Blocks (Layers) | 6 |
| Context Window (Block Size) | 256 characters |
| Dropout | 0.2 |
| Vocabulary Size | ~87 (unique characters in the training text) |
| Tokenization | Character-Level |
| Optimizer | AdamW |
| Learning Rate | 3e-4 |
The model is built from the following components, stacked together to form a complete Transformer:
Input Text
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Token Embedding โ Each character โ 384-dim vector
โ + Position Embedding โ Each position โ 384-dim vector
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Transformer Block x6 โ โโโ This block is repeated 6 times
โ โโโโโโโโโโโโโโโโโโโโโ โ
โ โ Layer Norm โ โ
โ โ Multi-Head Attn โ โ 6 heads, each looking at 64 dimensions
โ โ + Residual Conn โ โ
โ โโโโโโโโโโโโโโโโโโโโโค โ
โ โ Layer Norm โ โ
โ โ FeedForward (MLP) โ โ 384 โ 1536 โ 384 (4x expansion)
โ โ + Residual Conn โ โ
โ โโโโโโโโโโโโโโโโโโโโโ โ
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Final Layer Norm โ
โ Linear Head โ Logits โ 384 โ vocab_size (predicts next char)
โโโโโโโโโโโโโโโโโโโโโโโโโโโ
- Token Embedding: Converts each character (like
'h','e','l') into a list of 384 numbers that the neural network can understand. - Position Embedding: Tells the model where each character is in the sentence. Without this, the model wouldn't know if
'h'is the 1st character or the 100th. - Multi-Head Self-Attention: This is the brain of the Transformer. Each "head" looks at the sentence from a different angle, figuring out which characters are related to each other. For example, in the word
"the", the'e'learns to pay attention to't'and'h'before it. - FeedForward Network: After the attention heads gather information, this layer lets each character "think" about what it learned. It expands the 384 numbers to 1536 (to give it more room to think), and then compresses it back to 384.
- Residual Connections (
x + ...): These are shortcuts that let information flow directly through the network without getting lost. Without them, deep networks (6 layers) would forget what they learned in the early layers. - Layer Normalization: Keeps the numbers inside the network from becoming too big or too small, which helps the model train smoothly.
- Dropout (0.2): Randomly turns off 20% of the neurons during training. This forces the model to not rely on any single neuron and makes it generalize better (prevents overfitting).
This is one of the most important design decisions in this project. Here's why character-level was chosen:
| Feature | Character-Level (This Project) | BPE (e.g., tiktoken / cl100k_base) |
|---|---|---|
| Vocabulary Size | ~87 tokens | ~100,277 tokens |
| What is a "token"? | A single character ('a', 'b', ' ') |
A word or subword ('hello', ' the', 'ing') |
| Embedding Table Size | 87 ร 384 = 33,408 parameters | 100,277 ร 384 = 38,506,368 parameters |
| Memory for Embeddings | ~130 KB | ~147 MB |
When we first tried to use BPE tokenization (using tiktoken's cl100k_base encoder with 100,277 tokens), the very first layer of the model tried to create a matrix of size 100,277 ร 100,277. Here's the math:
100,277 ร 100,277 = 10,055,476,729 numbers
10,055,476,729 ร 4 bytes (Float32) = ~40 GB of RAM โ
Caution
40 GB just for one layer! Most laptops have 8-16 GB of total RAM. The computer immediately crashes with:
RuntimeError: DefaultCPUAllocator: not enough memory: you tried to allocate 40221906916 bytes.
| Advantage | Explanation |
|---|---|
| Tiny vocabulary | Only ~87 unique characters โ all layers stay small and fast |
| No external dependencies | No need for tiktoken or sentencepiece libraries |
| Easy to understand | You can literally see what each "token" is โ it's just a letter! |
| Trains on any hardware | Runs on a laptop CPU in minutes, or a basic GPU in seconds |
| Great for learning | Focuses your attention on the Transformer architecture, not tokenization complexity |
BPE becomes essential when you scale up to production-level models. At that point, you would use an embedding_dim much smaller than vocab_size (e.g., nn.Embedding(100277, 384) instead of nn.Embedding(100277, 100277)), which brings memory down to a manageable ~147 MB. Models like GPT-2, GPT-3, and ChatGPT all use BPE.
pip install torchImportant
For GPU acceleration, install the CUDA-enabled version of PyTorch instead:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118You can verify GPU access with:
import torch
print(torch.cuda.is_available()) # Should print: True
print(torch.cuda.get_device_name(0)) # Should print your GPU namepython bigram.pyThis will:
- Load and tokenize
book.txt(character-level) - Split the data into 90% training / 10% validation
- Train the Transformer for 5,000 iterations
- Print training and validation loss every 500 steps
- Generate 500 characters of new text at the end
10.805847 M parameters
step 0 : train loss 4.5360, val loss 4.5367
step 500 : train loss 2.4375, val loss 2.4548
step 1000 : train loss 1.4382, val loss 1.4550
...
step 4500 : train loss 0.4839, val loss 0.4998
[Generated text will appear here]
Tip
This model trains much faster on a GPU. If you don't have an NVIDIA GPU, or if your laptop is running out of memory, we strongly recommend running this on Google Colab, which gives you a free GPU!
- Go to Google Colab
- Click "New Notebook"
- Go to Runtime โ Change runtime type โ Select "T4 GPU"
- Upload
book.txtto Colab (drag and drop into the file panel on the left) - Copy-paste the entire
bigram.pycode into a cell and run it
| Feature | Your Laptop (MX450) | Google Colab (T4 GPU) |
|---|---|---|
| GPU Memory (VRAM) | 2 GB | 15 GB |
| GPU Speed | ~3.5 TFLOPS | ~8.1 TFLOPS |
| Cost | Free (your electricity) | Free (Google's electricity) |
| Training Time (5000 iters) | ~5-10 minutes | ~1-2 minutes |
| Can scale to bigger models? | Limited by 2 GB VRAM | Can handle 100M+ parameter models |
With Colab's T4 GPU, you can experiment with larger models by increasing n_embd, n_head, n_layer, and block_size without worrying about running out of memory.
LLM/
โโโ bigram.py # The main Transformer model (this is the complete, runnable script)
โโโ book.txt # Training data (~700K characters of text)
โโโ llm.ipynb # Jupyter Notebook with step-by-step exploration and experiments
โโโ imp.txt # Personal notes and reference snippets
โโโ README.md # You are here!
A language model is an AI that predicts the next word (or character) in a sequence. If you give it "The cat sat on the", it tries to predict "mat". By doing this millions of times during training, it learns the patterns and structure of language.
A Transformer is a type of neural network architecture introduced in the 2017 paper "Attention Is All You Need". Before Transformers, AI models processed text one word at a time (sequentially). Transformers process all words at once (in parallel) using a mechanism called Self-Attention, which makes them dramatically faster and more powerful.
Imagine you're reading the sentence: "The animal didn't cross the street because it was too tired."
What does "it" refer to? The animal or the street? You instantly know it's the animal. Self-Attention is the mechanism that lets the AI figure this out too โ by letting every word "look at" every other word and decide which ones are relevant.
Parameters are the numbers inside the neural network that get adjusted during training. Think of them as the "brain cells" of the AI. More parameters = more capacity to learn complex patterns. For comparison:
- This model: 10.8 Million parameters
- GPT-2 (Small): 124 Million parameters
- GPT-3: 175 Billion parameters
- GPT-4: Estimated 1.7+ Trillion parameters
Taking a language model from a prototype to a production-grade AI system involves several key engineering milestones:
โโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Evaluation Metrics โ โโโโบ โ 2. Fine-Tuning โ โโโโบ โ 3. Production Hosting โ
โ (Track Performance) โ โ (Customize Behavior) โ โ (Deploy as a Web App) โ
โโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโโโโโโโ
As a coder, how do you know if your model is actually getting smarter during training?
- Train vs. Validation Loss: The primary health check. If your training loss drops but validation loss starts rising, your model is overfitting (memorizing text instead of learning language rules).
-
Perplexity (
$PPL = e^{\text{Loss}}$ ): The standard benchmark in NLP. It measures how "surprised" the model is when reading new text. A lower score means better, more confident predictions. -
Sample Prompt Probing: Test the model at regular checkpoints with fixed prompts (e.g.,
"Once upon a time","The king said") and log them (via TensorBoard or Weights & Biases) to visually evaluate improvements in grammar, coherence, and repetition.
- Supervised Fine-Tuning (SFT / Instruction Tuning): Train the base language model on structured prompt-response pairs (
{"instruction": "...", "response": "..."}) to turn a text-completion model into an interactive conversational assistant. - LoRA (Low-Rank Adaptation) & QLoRA: Fine-tune only a fraction (<1%) of the parameters by injecting low-rank decomposition matrices, enabling efficient domain adaptation on consumer GPUs.
- Preference Alignment (DPO / RLHF): Use Direct Preference Optimization (DPO) to teach the model to prefer helpful, safe, and coherent responses over low-quality completions.
- High-Performance Inference: Serve the model using specialized engines like vLLM, TGI (Text Generation Inference), or Ollama with continuous batching and PagedAttention.
- FastAPI Backend: Build lightweight REST/WebSocket APIs with real-time token streaming via Server-Sent Events (SSE).
- Interactive Web Demo: Create user-facing chat UIs with Gradio or Streamlit for quick demos and user testing.
- Containerization & Cloud Hosting: Package the application with Docker and deploy to platforms like Hugging Face Spaces, RunPod, or AWS/GCP.