Appendix A — Environment Setup
Everything in this book runs in one of three places:
- Your browser. Every interactive widget is self-contained — nothing to install, nothing to run.
- A Python environment. Every measurement in this book was run on Python 3.14.5. The pinned environment needs Python 3.12 or later — NumPy 2.5.2 and SciPy 1.18.1 both declare
Requires-Python >=3.12— and 3.14.5 is the version the numbers came from; the interpreters in between have not all been tested. - A local model server. Parts IV–VII call a model. Every measurement in those parts used
ollamaon a laptop rather than a hosted API, so that reproducing them needs no paid API calls and does not depend on a provider’s current model version. It is not free of everything — you need the disk, the memory and the wall-clock time in the budget table below.
A.1 Local setup
python -m venv .venv && source .venv/bin/activate
pip install -r requirements-chapters.txtOr with uv, which is faster and — because every top-level dependency is pinned with == — resolves the same direct versions (the file does not lock transitive dependencies):
uv venv && source .venv/bin/activate
uv pip install -r requirements-chapters.txtThe repository also has a requirements.txt, and it is a different thing: the handful of packages that render the book. Installing that one will not give you the chapter code.
Below is what requirements-chapters.txt pins. Each version is the one a chapter’s own “The stack these numbers came from” table reports, and where two chapters disagree both are shown, because that disagreement is a fact about the book rather than something to average away.
| package | version | used by |
|---|---|---|
numpy |
2.5.2 | almost everything numeric |
pandas |
3.0.5 | the corpus-shaping chapters |
scikit-learn |
1.9.0 | Chapter 4, Chapter 12 |
scipy |
1.18.0 / 1.18.1 | Chapter 22’s sizing arithmetic; take the later one |
imbalanced-learn |
0.14.2 | Chapter 12’s resampling |
transformers |
5.15.0 / 5.15.1 | Chapter 13, Chapter 15, Chapter 16 |
torch |
2.13.0 | the models those chapters fine-tune — see Section A.2 |
datasets |
5.0.1 | every corpus the book loads |
sentence-transformers |
5.7.0 / 6.0.0 | Chapter 3, Chapter 19; the 6.0 rows are later chapters |
sacrebleu |
2.6.0 | Chapter 15 |
seqeval |
1.2.2 | Chapter 13’s span scoring |
sklearn-crfsuite |
0.5.0 | Chapter 13’s CRF |
snowballstemmer |
3.1.1 | Chapter 16 |
rouge-score |
0.1.2 | Chapter 14 — read that chapter before trusting it |
datasketch |
2.0.0 | Chapter 5’s near-duplicate detection |
umap-learn |
0.5.12 | Chapter 11 |
ollama |
0.24.0 | the local model server every Part IV–VII measurement calls |
pytest |
9.1.1 | running the book’s own checks |
Two packages that used to be in this table are not measurement dependencies and have been moved out: matplotlib and jupyter render the book rather than produce any number in it.
Pin these rather than taking latest. Several of the book’s findings are about specific tool behaviour — Chapter 14’s ROUGE tokenizer bug, Chapter 16’s lowercasing failures — and a newer version may have fixed the very thing a chapter is demonstrating. That is a good outcome for the world and a confusing one mid-exercise.
A.2 Accelerators
pip install torch resolves to a different wheel on every platform, and the fine-tuning chapters produce slightly different numbers on different backends. The book’s fine-tuning and embedding measurements ran on Apple Silicon through PyTorch’s MPS backend — four chapters say so in their own version tables — so that is the configuration the numbers came from.
- Apple Silicon.
pip install torchis enough; MPS is built in. SettingPYTORCH_ENABLE_MPS_FALLBACK=1avoids a hard failure on the few operations that still have no MPS kernel. - NVIDIA. Install the CUDA wheel explicitly rather than letting
pipchoose, or you may silently get the CPU build:pip install torch==2.13.0 --index-url https://download.pytorch.org/whl/cu126. - CPU only. The code runs, memory permitting. The fine-tuning chapters take several times longer, and results agree up to the small numerical differences below.
Expect small numerical differences across backends. If a fine-tuning result in Chapter 13 or Chapter 15 is a point or two from the book’s, the backend is the first thing to check, but not the only one. Package versions and the random seed can move a result too — Chapter 13 reports single runs at seed 42.
A.3 A local model
Parts IV–VII need a model to call. Install ollama, then pull the models the chapters you want actually used:
ollama pull qwen3.5:9b # ~6 GB — most of the book's measurements
ollama pull llama3.2:3b # ~2 GB — the small-model rows and the serving chapters
ollama pull gemma3:27b # ~17 GB — needs roughly 20 GB of memory
ollama pull qwen3.6:35b # ~21 GB — needs roughly 24 GB of memory
ollama pull nomic-embed-text # ~0.3 GB — the gateway chapter's embedding path
ollama pull qwen2.5:7b # ~4.7 GB — chapters 35, 36 and 38, and the first call below
ollama serve # skip if it is already running as a serviceThe desktop app and the Homebrew or systemd service both start the server already, and a second ollama serve will simply fail with an address-in-use error. curl -s http://127.0.0.1:11434/api/version tells you which case you are in.
The book used ollama 0.24.0. Which model a chapter used is in its status callout, and the distribution is lopsided:
| model | chapters that measured with it |
|---|---|
qwen3.5:9b |
12, 13, 14, 15, 17, 18, 20, 22, 23, 24, 25, 26, 27, 29, 30, 38 — the default, and the one to pull first |
llama3.2:3b |
12, 18, 31, 33, 34, 38 |
gemma3:27b |
12, 14, 21, 22, 38 |
qwen3.6:35b |
7, 12 |
qwen2.5:7b |
35, 36, 38 |
nomic-embed-text |
32 |
If memory is tight, pull the first two and skip the rest. Many chapters that use a large model also report a smaller one, but not all — Chapter 21’s vision experiment used only the 27B model — so check a chapter’s status callout before assuming a small-model row exists.
Everything talks to the HTTP API directly:
curl -s http://127.0.0.1:11434/api/generate \
-d '{"model":"qwen2.5:7b","prompt":"Merhaba","stream":false}'Two flags worth knowing before you debug something for an hour. "format": "json" forces parseable output and removes a whole class of scoring bug. And "think": false matters for reasoning models — with thinking on, ollama returns the reasoning in a separate thinking field, and if the model spends its token budget there the response field comes back empty, which scores as zero and looks like a catastrophic quality result. Chapter 38’s measurement hit exactly that. An empty response is a symptom rather than a rule, so read both fields, check done_reason — length means you hit the cap — and raise num_predict before concluding anything about quality. The same applies to "format": "json": it constrains the shape of a completed generation, and a truncated one is still unparseable.
A.4 What this costs in disk and memory
Worth knowing before the first pull rather than after.
| you want to run | disk | memory |
|---|---|---|
| Parts I–III (no model server) | ~4 GB | 8 GB |
Adding the measurements that used qwen3.5:9b |
~10 GB | 16 GB |
Adding llama3.2:3b, nomic-embed-text and qwen2.5:7b |
~17 GB | 16 GB |
Adding gemma3:27b |
~34 GB | 20 GB+ |
Adding qwen3.6:35b as well |
~55 GB | 24 GB+ |
Memory here is what the model needs resident, and on a unified-memory machine that is the same pool your editor is using. Chapter 31 explains why the number that actually binds is the KV cache rather than the weights, and why the context length you configure is a memory decision.
A.5 Colab
Colab is the shortest path to a GPU for the fine-tuning chapters, and the notebooks are not published yet — the badges are on the roadmap rather than in the book, so for now copy the code blocks. The local-model chapters do not work on Colab’s free tier without adaptation; substitute a hosted API and expect your numbers to differ from the book’s, which is itself a useful lesson about pinning.
A.6 Windows
The book’s measurements were run on macOS and Linux, so Windows is the platform this appendix has tested least. Nothing here is Windows-specific in principle; three things differ in practice.
Activate the virtual environment with .venv\Scripts\activate rather than source. Use WSL2 if anything fights you — the book’s measurements were run on macOS and Linux, and WSL2 is the shortest path to matching them. And set PYTHONUTF8=1, because Windows still defaults some file reads to a non-UTF-8 encoding, which mangles Turkish text silently. That last one is Chapter 16’s argument arriving before you have even loaded a model.
A.7 Getting help
Open a GitHub issue with the chapter name in the title. If a number in the book does not reproduce, that is worth an issue — say which chapter, which package and model versions you have, which accelerator backend, and what you got. The first three are usually the answer.