Frontend Labs
⋯

62. Experiment hygiene: seeds, configs, notebooks, and reproducibility

62.1 Seeds

import os
import random
import numpy as np

def seed_everything(seed: int) -> None:
    random.seed(seed)
    np.random.seed(seed)                    # legacy global RNG; prefer np.random.default_rng(seed)
    os.environ["PYTHONHASHSEED"] = str(seed)   # only affects subprocesses started after this
    try:
        import torch
        torch.manual_seed(seed)             # CPU and all GPUs
        torch.use_deterministic_algorithms(True, warn_only=True)
    except ImportError:
        pass

seed_everything(42)

Seeds make a run repeatable on the same hardware and library versions. They do not make results trustworthy: report the mean and spread over several seeds, because a single lucky seed can make a worse model look better.

62.2 Configs as frozen dataclasses

import argparse
import json
from dataclasses import dataclass, asdict, fields

@dataclass(frozen=True)
class Config:
    lr: float = 3e-4
    batch_size: int = 64
    epochs: int = 10
    seed: int = 42
    data: str = "corpus.jsonl"

def parse() -> Config:
    p = argparse.ArgumentParser()
    for f in fields(Config):
        p.add_argument(f"--{f.name.replace('_', '-')}", type=type(f.default), default=f.default)
    return Config(**vars(p.parse_args([])))     # pass sys.argv[1:] in real use

cfg = parse()
print(json.dumps(asdict(cfg)))                  # save next to every run's outputs

Every run should write its config, the git commit (git rev-parse HEAD), the uv.lock hash, and its metrics into its own output directory. That is what lets you answer "which settings produced this model?" three months later. Experiment trackers (MLflow, Weights & Biases, TensorBoard) automate the bookkeeping.

62.3 Notebooks: for exploring, not for shipping

Jupyter notebooks are excellent for exploration: load data, plot it, try an idea, see the result inline. They are poor as the source of truth: cells run out of order, hidden state survives deleted cells, diffs are JSON noise, and outputs (sometimes including secrets) are saved in the file.

The workflow that works: explore in a notebook; move anything you will run twice into a module under src/ with tests; import that module back into the notebook. "Restart kernel and run all" must succeed before you trust a notebook's result. jupytext stores notebooks as .py files for clean diffs, and nbstripout removes outputs on commit.

62.4 Evaluation sets are code

For any model, and especially for LLM apps, keep a versioned file of inputs with expected outputs (or grading criteria), and a script that scores the current system against it. Run it on every change, like the tests in Ch 20. Without it, every prompt or retrieval tweak is a guess. The AI guide Ch 49 shows how to build one.


Generated from real-life-python-guide.md · 8 Oct 2026 16:36