Appendix A — Environment Setup

Appendix status: drafted. Versions here are the ones the book’s measurements were actually run with, so that you start from the same stack a chapter’s numbers came from. That brings you close to those numbers without guaranteeing the same digits: sub-dependencies are not locked, not every Python version has been tested, and accelerators differ slightly. Each is covered below.

Everything in this book runs in one of three places:

A.1 Local setup

python -m venv .venv && source .venv/bin/activate
pip install -r requirements-chapters.txt

Or 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.txt

The 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.

Pinned versions, as measured
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 torch is enough; MPS is built in. Setting PYTORCH_ENABLE_MPS_FALLBACK=1 avoids a hard failure on the few operations that still have no MPS kernel.
  • NVIDIA. Install the CUDA wheel explicitly rather than letting pip choose, 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 service

The 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:

Which chapter needs which model
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.

Budget before you start
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.