x and y it learns from. This module is about data — where it comes from, how you load it with Hugging Face, how you batch it, and the crucial text step: tokenization, turning words into numbers a model can actually eat.A dataset is just a big table of examples: inputs (x) paired with correct answers (y). The model studies these pairs to learn the pattern. That's it — no magic.
You rarely make datasets by hand. Hugging Face hosts thousands, free, loaded in one line. It's the "GitHub of datasets and models."
from datasets import load_dataset
# download a real sentiment dataset in one line
data = load_dataset("imdb")
print(data) # train / test splits
print(data["train"][0]) # {'text': '...', 'label': 1}Click through examples like you would after loading one. Real datasets are just rows of x → y. (Simulated preview of what load_dataset gives you.)
A model can't read letters — only numbers. A tokenizer does two jobs: (1) split text into chunks called tokens, and (2) map each token to a number (its ID) from a fixed vocabulary. (You met this conceptually in fundamentals Module 12 — here it's the real tool.)
Modern tokenizers don't split on whole words — they use sub-words (a method called BPE). Common words stay whole ("the"), but rare/long words break into pieces: "tokenization" → "token" + "ization". This handles any word (even typos or new words) with a small vocabulary. Notice: 1 token ≠ 1 word — roughly 1 token ≈ ¾ of a word in English.
from transformers import AutoTokenizer
tok = AutoTokenizer.from_pretrained("gpt2")
text = "Today is a mesmerizing day with lot's of memories"
ids = tok(text)["input_ids"]
tokens = tok.convert_ids_to_tokens(ids)
print(ids)
print(tokens)
print(list(zip(ids, tokens))) # pair every ID with its token
print(tok.decode(ids))Ġ is GPT-2's visible marker for a space before the token. For example, Ġis means " is". The marker disappears when the tokens are decoded back into normal text.
8888 maps to the single vocabulary token Today:
[(8888, 'Today'), (318, 'Ġis'), (257, 'Ġa'), (46814, 'Ġmesmer'), (2890, 'izing'), (1110, 'Ġday'), (351, 'Ġwith'), (1256, 'Ġlot'), (338, "'s"), (286, 'Ġof'), (9846, 'Ġmemories')]
Token IDs are vocabulary lookup numbers, not semantic categories. Therefore, 8888 does not belong to a special “Today words” group. Its relevant unit is the exact token Today; nearby ID numbers do not necessarily represent related words.
Type anything and watch it split into tokens with IDs — the way a real tokenizer would. Try a long/rare word and see it break into sub-word pieces.
This matters for real reasons: API costs and context limits are counted in tokens, not words. Slide the word count and see the token estimate (~1.33 tokens per word).
From Module 3 you know why to split. Here's how — slide the split and see the proportions. The standard is roughly 80 / 10 / 10.
# split a dataset 80/20 (then split the 20 into val/test)
split = data["train"].train_test_split(test_size=0.2)
train = split["train"] # 80%
temp = split["test"].train_test_split(test_size=0.5)
val, test = temp["train"], temp["test"] # 10% / 10%You don't feed one example at a time (too slow) or all at once (too much memory). You feed batches — small groups. The batch size is how many examples per training step. PyTorch's DataLoader handles this.
from torch.utils.data import DataLoader
loader = DataLoader(train, batch_size=32, shuffle=True)
for batch in loader: # the loop from Module 3 iterates batches
pred = model(batch["x"])
... # forward, loss, backward, stepPut the steps of a real data pipeline in the right order. Click them in sequence — from raw text to a batch the model can train on.
Here is the full journey from raw rows to model updates. The numbers stay visible so you can see what changes at each stage.
Validation: check performance during development without updating weights. Final test: evaluate the finished model once on unseen data.
The tokenizer stops at integer IDs. GPT-2's embedding layer uses each ID as a row number in its learned lookup table and returns one 768-number vector per token.
Tokenizer: text → IDs. Embedding layer: IDs → vectors. The vector values shown in the illustration are shortened examples; run the code below to see GPT-2's real values.
from transformers import AutoTokenizer, AutoModel
tokenizer = AutoTokenizer.from_pretrained("gpt2")
model = AutoModel.from_pretrained("gpt2")
text = "Today is sunny"
inputs = tokenizer(text, return_tensors="pt")
ids = inputs["input_ids"]
tokens = tokenizer.convert_ids_to_tokens(ids[0])
# Each ID selects one row from GPT-2's embedding table.
embedding_layer = model.get_input_embeddings()
vectors = embedding_layer(ids)
print("Tokens:", tokens)
print("IDs:", ids)
print("Vector tensor shape:", vectors.shape)
# torch.Size([1, 3, 768])
for token, token_id, vector in zip(tokens, ids[0], vectors[0]):
print(f"\n{token!r} (ID {token_id.item()})")
print("First 10 of 768 numbers:", vector[:10])
# ID 8888 directly retrieves the same vector as "Today".
today_vector = embedding_layer.weight[8888]
print("\nToday vector shape:", today_vector.shape)
# torch.Size([768])x → y; load real ones in one line with Hugging Face (load_dataset). Text must be tokenized: split into sub-word tokens (BPE) and mapped to numeric IDs — remember 1 token ≈ ¾ word, and that's what API costs/context limits count. Split data into train/val/test (~80/10/10), and feed it in batches via a DataLoader. The pipeline: load → tokenize → split → batch → train.Next up → Module 5: makemore — a name generator. Now you have all the pieces (tensors, autograd, training loop, data). We combine them to build a real character-level model from scratch that invents new names — the concepts from fundamentals Modules 5–8, in working PyTorch.