GPT-2 · RoBERTa Lab · Part IV — On your machine
15

Lab
guide

Every command, every script, every file. The reference chapter to come back to later — and the summary of everything that was measured.

Chapter 15 of 15 Reference

1 Start here

Where to download

The lab scripts, the course server, the dependency list and the installation instructions are in the course's public repository: github.com/Rafhael-Oliveira-IA/conceitos-gpt. If you do not use git, you can download everything as a .zip file. The models are not in the repository, because they add up to 13.2 GB: the tools/download_models.py script downloads all seven straight from Hugging Face.

# open PowerShell in the repository root and run, in order:

.venv\Scripts\python.exe lab\01_tokenizer.py
.venv\Scripts\python.exe lab\02_embeddings.py
.venv\Scripts\python.exe lab\03_attention.py
.venv\Scripts\python.exe lab\04_multihead_mask.py
.venv\Scripts\python.exe lab\05_block.py
.venv\Scripts\python.exe lab\06_scale.py
.venv\Scripts\python.exe lab\07_decoding.py
.venv\Scripts\python.exe lab\08_perplexity.py
.venv\Scripts\python.exe lab\09_detector.py
.venv\Scripts\python.exe lab\10_original_code.py

# lab 11 needs the server. In ANOTHER terminal:
.venv\Scripts\python.exe server\app.py
# and then:
.venv\Scripts\python.exe lab\11_api.py

Labs 06 and 08 load gpt2-xl (6 GB of RAM, ~3 min). If you are in a hurry or short on memory, append rapido:

.venv\Scripts\python.exe lab\06_scale.py rapido

2 Index: chapter → lab

No.ChapterScriptThe main experiment
01Tokenization and BPE01_tokenizer.pythe cost of Portuguese; three incompatible tokenizers
02Embeddings02_embeddings.pyneighbors of " Brazil"; wpe learned order on its own
03Attention03_attention.pysoftmax saturation without √dk
04Multi-head and mask04_multihead_mask.pythe proof of causality — difference exactly 0.00
05The Transformer block05_block.pyPre-LN vs Post-LN; the logit lens
06Architecture and scale06_scale.pythe exact parameter formula; in-context learning
07Decoding07_decoding.pytop-p nucleus from 1 to 5,548 tokens; 80% repetition in greedy
08Perplexity08_perplexity.pymonotonic scaling; noise is easier than shuffled text
09GPT-1 → GPT-206 and 08PPL 46 → 21.7 at the same size
10RoBERTa and MLM04, section 3the encoder changes everything when you touch the end
11Encoder vs decoder04, section 3the same proof, read from both sides
12The detector09_detector.pymodern LLM passes as human at 99.9%
13Original code10_original_code.pythe first 25 BPE merges; JS = Python
14Serving models11_api.pythe generate→detect cycle; the semantic-search failure

3 File layout

GPT-2\
├── .venv\                      Python 3.14 + torch 2.14 (CPU) + transformers 5
├── models\hf\                  the 7 models, 13.2 GB in safetensors
├── repos\
│   ├── gpt-2\                  original TensorFlow code (for READING)
│   ├── GPT-3-Encoder\          JS tokenizer + vocab.bpe + encoder.json
│   └── gpt-3\                  175B samples and corpus statistics
├── lab\
│   ├── common.py                shared module — loads and configures everything
│   └── 01..11_*.py             the experiments
├── server\app.py             API compatible with TGI and TEI
├── tools\
│   ├── style.css               typography of the chapters
│   ├── generate_pdfs.py           HTML -> PDF (headless Chrome + page numbering)
│   ├── download_models.py       model download
│   └── verify.py            smoke test of the 7 models
├── src\conceitos_gpt-1-gpt-2\  HTML source of the 16 chapters (eng\ = English)
├── src\conceitos_antevisao\    the theory of the ELLM (Antivision experiment)
├── pdfs\gpt-1-gpt-2\          << the finished chapters; pdfs\antevisao\ those of the project
└── out\                        experiment outputs

Maintenance commands

# check that the 7 models load
.venv\Scripts\python.exe tools\verify.py

# regenerate all PDFs after editing an HTML
.venv\Scripts\python.exe tools\generate_pdfs.py

# regenerate just one
.venv\Scripts\python.exe tools\generate_pdfs.py 07

4 The model aliases

All scripts use short aliases, defined in lab/common.py:

AliasHugging Face repositoryRAM
gpt1openai-community/openai-gpt0.4 GB
gpt2openai-community/gpt20.5 GB
gpt2-mediumopenai-community/gpt2-medium1.3 GB
gpt2-largeopenai-community/gpt2-large2.9 GB
gpt2-xlopenai-community/gpt2-xl5.8 GB
det-baseopenai-community/roberta-base-openai-detector0.5 GB
det-largeopenai-community/roberta-large-openai-detector1.4 GB
# to write your own experiments
import common
tok, mod      = common.carregar_gerador("gpt2-medium")
tok, mod, rot = comum.carregar_detector("det-base")
tok, mod      = comum.carregar_base("gpt2", atencoes=True)

common.py points the cache to models\hf, turns on offline mode (nothing goes to the network), forces UTF-8 on the Windows console, disables gradients and fixes the missing labels of det-large.

5 Everything that was measured on this machine

The numbers that appear in the chapters. All reproducible with the scripts.
MeasurementResultLab
Cost of Portuguese vs English (tokens/word)1.86 vs 1.14 — 1.63×01
Neighbors of " Brazil" in wteArgentina, Portugal, Chile, Bolivia02
Softmax entropy without √dk, d=10240.022 (saturated) vs 1.1703
Causality: effect of the future on the past0.00e+00 in GPT-2; ~3e−01 in RoBERTa04
Gradient at the 1st of 40 layersPre-LN 1.5 million times larger05
KV cache gain42.2 vs 25.0 tokens/s04
Parameter-count formula0.0% error across the 5 models06
In-context learning: P(" Paris") in gpt20.032 → 0.385 with 3 examples06
Top-p nucleus (p=0.9), same parameterfrom 1 to 5,548 tokens07
4-gram repetition, greedy80% (0% in the other strategies)07
Perplexity GPT-1 → GPT-2 XL46.07 → 21.70 → 16.04 → 14.30 → 12.9308
PPL: noise vs shuffled text469 vs 3,874 (noise is easier)08
Detector against GPT-2P(human) = 0.0002 — works09
Detector against a 2026 LLMP(human) = 0.9993 — total failure09
Detector on formal human textregulation: 0.034 — false positive09
OpenAI's JS tokenizer vs Pythonidentical IDs10
Semantic search with the detectorsimilarities all at +0.99 — useless11

6 Common problems

SymptomCause and fix
UnicodeEncodeError with \u0120console in cp1252. Always run through the scripts in lab\ — common.py already forces UTF-8. If you write your own, import comum on the first line.
Running out of memory in lab 06use rapido mode, which skips the XL.
ConnectionRefused in lab 11the server is not up. Open another terminal and run server\app.py.
Warning "pooler.dense.weight UNEXPECTED"harmless. It is a leftover from RoBERTa's pre-training; the classification head reads the <s> directly (chapter 12).
Warning "attn.bias UNEXPECTED" in GPT-1harmless. It is the causal mask, which transformers recreates instead of loading from the weights.
Model trying to download somethingcommon.py sets HF_HUB_OFFLINE=1. If something tries to reach the network, it is a model outside the catalog.

7 Where to go next

You are done. Four natural paths, in order of effort:

  1. Fine-tune your own classifier. You saw that 99.5% of the detector is reused RoBERTa. Take a plain roberta-base, a labeled dataset of your own, and repeat the process from chapter 12. It is the most profitable practical skill in this course.
  2. Implement GPT-2 from scratch in PyTorch and load the official weights into it. If the output matches that of transformers, you have truly understood. Andrej Karpathy's nanoGPT is a good reference for this step — and now you can read all of it.
  3. Compare with a modern model. You already have qwen3:4b and qwen3:8b installed. Run the same perplexity and decoding tests on them and see what seven years changed — and what did not (the architecture is still the same).
  4. Build a real RAG. Lab 11 showed why the detector is no good for embeddings. Download a model trained for that (BAAI/bge-small-en, intfloat/e5-small) and redo section 4 — this time working.
What remains, if everything else is forgotten

One line separates the two families. masked_fill(futuro, -inf). Everything else — the training objective, the output format, being able to cache or not, generating or understanding — is a consequence.

Measure distributions, not anecdotes. gpt2-large "got a question wrong" and seemed worse than medium. Perplexity, over real text, showed scale behaving regularly. A sample of size 1 is not evidence.

A model only knows what it has seen. The detector works very well on GPT-2 text and fails on 2026 text — and, worse, confident in both cases. Outside the training distribution, a model's confidence means nothing.

References

The primary sources for the concepts in this chapter. The numbers in the text were measured in the lab; the ideas come from here.

Technical terms here carry their machine-learning meaning. The course glossary shows that meaning next to the others the same words have in IT.

  1. Radford, A., Wu, J., Child, R., Luan, D., Amodei, D. and Sutskever, I. (2019). Language Models are Unsupervised Multitask Learners. Technical report, OpenAI. cdn.openai.com
  2. Hugging Face. openai-community: os pesos do GPT-2 and do detector usados no laboratório. Model page. huggingface.co/openai-community

End of the course. The scripts are still there — change the prompts, break things, measure again.
That is how every number in these chapters came to be.