Character Tokenizer & Vocabulary Mapping
Extracts 65 unique characters from Tiny Shakespeare corpus.
Bidirectional O(1) character-to-integer translation in memory.
Converts full text corpus into contiguous 1D PyTorch int64 Tensor.
The Big Idea
Following the architectural plan introduced in Lesson 1.1, our first task is to bridge human language and tensor math. Computers and neural networks are high-speed numerical calculators: they understand additions and matrix multiplications, but they have zero concept of the letter 'H' or the word 'Apple'. Before a neural network can process a single word, human text must be converted into numbers. A tokenizer is the secret decoder ring that translates raw characters into discrete integer IDs and back again.
Commercial LLMs like GPT-4 use Byte-Pair Encoding (BPE), which compresses text into 50,000 subwords. While efficient for training on trillions of web pages, BPE introduces confusing tokenization artifacts and hides the math behind complex heuristics. By building a character-level tokenizer on Shakespeare's plays, our entire vocabulary is exactly 65 characters: every letter, punctuation mark, and newline.
We build two simple lookup dictionaries: stoi (string to integer) and itos (integer to string). Encoding transforms a string like 'Dropout' into [16, 43, 50, 51, 50, 56, 55]. Decoding reconstructs those integer IDs back into readable text. Once converted, the entire corpus becomes a 1D PyTorch tensor of integers ready for training.
Jargon Buster: Plain-English Translations
- Vocabulary Size (V): The total count of unique discrete symbols the model knows (65 characters in Tiny Shakespeare). If a character is not in this vocabulary, the model cannot read or write it.
- stoi (String to Integer): A Python dictionary mapping every character key to its unique integer index from 0 to V - 1.
- itos (Integer to String): The reverse dictionary mapping each integer index back to its original character.
- torch.LongTensor: PyTorch's 64-bit signed integer tensor format (torch.long). Embedding layers strictly require integer indices, not floating-point numbers.
📥 Download the Training Dataset (input.txt)
Running the code on your local computer? Download the standard 1.1MB Tiny Shakespeare corpus or grab the full project starter pack.
Architecture Blueprint & Tensor Mechanics
The tokenizer extracts all unique characters, sorts them deterministically, and builds bidirectional mapping dictionaries before converting strings into PyTorch LongTensors.
import torch
# Raw training text (e.g. Tiny Shakespeare)
text = "First Citizen:\nBefore we proceed any further, hear me speak."
# 1. Extract sorted unique characters across the corpus
chars = sorted(list(set(text)))
vocab_size = len(chars)
print(f"Vocabulary Size: {vocab_size}")
# 2. Build bidirectional lookup dictionaries
stoi = {ch: i for i, ch in enumerate(chars)} # char -> integer
itos = {i: ch for i, ch in enumerate(chars)} # integer -> char
# 3. Encoder: takes a string and outputs a list of integer IDs
encode = lambda s: [stoi[c] for c in s]
# 4. Decoder: takes a list of integers and outputs the decoded string
decode = lambda l: ''.join([itos[i] for i in l])
# Verification test
sample_text = "Dropout Developer"
encoded_tokens = encode(sample_text)
decoded_text = decode(encoded_tokens)
print(f"Original: '{sample_text}'")
print(f"Encoded: {encoded_tokens}")
print(f"Decoded: '{decoded_text}'")
# 5. Convert the entire dataset into a 1D PyTorch integer tensor
data = torch.tensor(encode(text), dtype=torch.long)
print(f"Dataset tensor shape: {data.shape}, dtype: {data.dtype}")
Beginner Traps & Gotchas
1. KeyError on unseen out-of-vocabulary characters
The Gotcha: If a user inputs a character or emoji not present during training, stoi[c] raises a fatal KeyError.
The Fix: Use stoi.get(c, default_id) or filter unknown characters before feeding them into encode().
2. Creating the data tensor with default float32 dtype
The Gotcha: Calling torch.tensor(encoded) without specifying dtype=torch.long can create float tensors, causing PyTorch embedding lookups to crash.
The Fix: Explicitly pass dtype=torch.long when converting token lists to PyTorch tensors.