A multi-project repository of machine-learning task demonstrations, organized as a portfolio of self-contained ML experiments. Active experiments live under notebooks/[task]-[dataset]-[model]-[framework]/; each experiment directory contains its notebook(s) and README, with gitignored data/ and runs/ directories created as needed by runtime downloads and training/evaluation runs.
This repo serves three overlapping purposes:
- Personal lab — a place to prototype new ML tasks quickly.
- Portfolio — each task folder reads as a standalone demonstration of a technique.
- Educational resource — notebooks include narrative explanations alongside code.
Paradigms covered (see §4.1 for the per-task mapping): image classification (numpy from-scratch + PyTorch FFNN), tabular classification + regression, GNNs on graphs (pytorch-geometric GraphSAGE / GraphConv / GAT — node classification, link prediction, community detection), NLP (spaCy + NLTK pipelines, BPE tokenizer), transformer LM with sampling stack, diffusion (DDPM), preference alignment (DPO), self-supervised (I-JEPA), Mixture-of-Experts, PEFT (LoRA / DoRA), quantization (PTQ + QAT), pruning, knowledge distillation, model surgery (Net2Net), autoencoders, clustering.
A shared PyTorch toolkit (nnx, thekaveh-nnx on PyPI) provides reusable training-loop, dataset, and visualization primitives that the notebooks consume. Library and tasks co-evolve: each new task lands its required nnx additions upstream first (thekaveh/NNx), then ml-eng-lab bumps the pinned version here. YAGNI applies — no speculative abstractions in nnx.
ml-eng-lab/
├── README.md (this file)
├── CONTRIBUTING.md (workflow + conventions)
├── CHANGELOG.md (release notes)
├── Makefile (papermill tier targets)
├── docs/ (env/runtime docs, dependency contracts, findings, maintenance log)
├── mkdocs.yml (generated documentation site)
├── requirements.txt + torch-*.txt (pip deps; thekaveh-nnx[lm]==0.2.0)
├── scripts/ (jupyterhub start, verifier, notebook edit/import helpers)
├── deploy/ (genai-vanilla compose override)
├── tests/ (pytest: nnx_surface contract + verifier + helpers)
├── vendor/genai-vanilla/ (git submodule, JupyterHub stack)
└── notebooks/ (21 active task folders plus notebooks/archive/)
See CHANGELOG.md for release history; per-task folders are linked from §4.1 Active, and secondary docs are linked from §10 Other documentation.
This branch configures a generated MkDocs site for https://thekaveh.github.io/ml-eng-lab/;
the GitHub Pages workflow will publish it after the workflow lands on main.
Four ways to run these notebooks, ordered from managed runtime to local execution.
As of genai-vanilla 10f8402 (pinned in vendor/genai-vanilla), the jupyterhub image natively ships the ml-eng-lab dependency set, thekaveh-nnx[lm]==0.2.0, and the two NLP model assets. Two paths, pick by need:
Default — standalone genai-vanilla + VS Code Mode 2 (works for tier-covered notebooks from a current genai-vanilla checkout; one tier-covered exception remains: notebooks/image_classification-mnist-ffnn-numpy/notebook.ipynb imports sibling .py modules from its own folder and needs the persistence variant below. The quantization notebook is still manual-only under torch>=2.5 + torchao>=0.17):
cd ~/repos/genai-vanilla && ./start.sh
# Open any ml-eng-lab notebook locally in VS Code, then:
# Cmd-Shift-P → Jupyter: Specify Jupyter Server for Connections →
# http://localhost:63081/?token=<JUPYTERHUB_TOKEN>Persistence variant — wrapper script + bind-mount (required for the from-scratch image_classification-mnist-ffnn-numpy notebook + host-side ./data//./runs/ persistence):
git submodule update --init --recursive # one-time, for vendor/genai-vanilla
scripts/start-jupyterhub.shSee docs/jupyterhub-integration.md (full two-path walkthrough) and docs/vscode-remote-access.md.
docker build -t ml-eng-lab .
docker run -p 8888:8888 -v "$(pwd):/home/jovyan/work" --shm-size=4g ml-eng-lab--shm-size=4g is the minimum for the GNN notebooks; see docs/env-setup.md §2 for more.
python -m venv .venv && source .venv/bin/activate
make install-torch-stack
pip install -r requirements.txt # pulls thekaveh-nnx[lm]==0.2.0 from PyPI
make nlp-assets # one-time spaCy + NLTK assets used by the 2 NLP Tier-A notebooks
jupyter labSee docs/env-setup.md for environment details.
Click Code → Codespaces → Create codespace on main on github.com/thekaveh/ml-eng-lab. After ~2-3 minutes of one-time dep install you have a browser-based VS Code (or JupyterLab — see below) with the 21 active task folders available and 28 of 29 active notebooks runnable under the pinned environment.
Why this path was added. The §3.1 / §3.2 / §3.3 paths each require ~10-15 minutes of first-time setup on a new machine (Docker pulls, git submodule update --init --recursive for vendor/genai-vanilla, pip installs against the requirements manifests, make nlp-assets predownloads for spaCy + NLTK). They also each have a coupling cost: §3.1 depends on the genai-vanilla image's pip layer staying in sync with ml-eng-lab's requirements.txt (the former nnx-pytorch[lm] → thekaveh-nnx[lm]==0.2.0 drift is the kind of image/repo mismatch this maintenance loop checks for); §3.2 and §3.3 require local Docker / a working venv on the dev's machine. Codespaces eliminates both: the .devcontainer/devcontainer.json declaratively bakes the install recipe (so the dep set is auto-synced to requirements.txt, torch-core-requirements.txt, and torch-requirements.txt during Codespace creation via postCreateCommand, with no image-rebuild loop), and the repo is auto-cloned into /workspaces/ml-eng-lab inside the container.
Scenarios this supports:
- Onboarding a new contributor — they click "Create codespace" and have a working env in ~2-3 minutes, no local install at all.
- Running a notebook on a larger host without local install (the smallest Codespace machine is 2-core / 8 GB RAM — comparable to a low-end laptop, sufficient for every Tier-A notebook; bump to 4-core / 16 GB if any Tier-B sweep feels slow).
- Short exploratory run without polluting the local Python env.
- The
notebooks/image_classification-mnist-ffnn-numpy/notebook.ipynbedge case (it imports sibling.pymodules from its own folder) works natively — Codespaces clones the repo into the container's/workspaces/ml-eng-lab, so the kernel sees those files without needing the §3.1 wrapper-and-bind-mount path'sscripts/start-jupyterhub.sh.
Scenarios this does NOT support:
- GPU workloads — GitHub deprecated GPU Codespaces 2025-08-29 (Azure NCv3 retirement). The few GPU-benefiting notebooks (heaviest is
self_supervised-fmnist-jepa-pytorch) still run on CPU here, just slowly; for real GPU you want a separate path (Modalfunction.spawn, a self-hosted GPU box behind Jupyter Enterprise Gateway, or Vertex AI Workbench / Colab Enterprise). - Data persistence across Codespace deletions — anything written to
./data/or./runs/is gone when the Codespace is deleted (Codespaces are intended to be cheap and disposable). Commit any results you want to keep, or use Codespaces' "prebuild" feature if dep install time becomes a bottleneck. - The quantization-mnist-ffnn-pytorch notebook still won't run here — it has the same
torch.int1vstorch==2.4.1incompatibility documented in its task README and in docs/dependency-contracts.md (manual-only).
How to use:
- On github.com/thekaveh/ml-eng-lab → green Code button → Codespaces tab → Create codespace on main.
- Wait ~2-3 min for
postCreateCommandto runmake codespace-setup(= Torch-first dependency install +make nlp-assets). Progress is visible in the terminal panel. - Open any notebook. You can either:
- Stay in VS Code (browser) — the Jupyter / Python extensions are preinstalled per the devcontainer config; works for the 28 tier-covered active notebooks. The quantization notebook is manual-only under
torch>=2.5. - Switch to JupyterLab — click the dropdown next to "Open" on github.com → choose JupyterLab. To make JupyterLab the single-click default for all your codespaces, go to github.com/settings/codespaces → Editor preference → JupyterLab.
- Stay in VS Code (browser) — the Jupyter / Python extensions are preinstalled per the devcontainer config; works for the 28 tier-covered active notebooks. The quantization notebook is manual-only under
See .devcontainer/devcontainer.json for the exact image + extension set, and Makefile codespace-setup target for the Codespaces/venv install recipe. The §3.2 Docker path bakes the same Torch-first dependency order into Dockerfile. Free-tier Codespaces (60 core-hours/month on personal accounts, 90 on Pro) is enough for typical solo-maintainer usage.
| Folder | Task | Dataset | Model | Framework |
|---|---|---|---|---|
| notebooks/image_classification-mnist-ffnn-numpy/ | Image classification | MNIST | Feed-forward NN (from scratch) | NumPy |
| notebooks/image_classification-mnist-ffnn-pytorch/ | Image classification | MNIST | Feed-forward NN | PyTorch (via nnx) |
| notebooks/node_classification-reddit-gnn-pyg/ | Node classification | Reddit2 | GNN (GraphConv, GraphSAGE, GAT) | PyTorch Geometric (via nnx) |
| notebooks/tabular_classification-iris-mlp-pytorch/ | Tabular classification | Iris | Feed-forward NN | PyTorch (via nnx) |
| notebooks/model_surgery-mnist-ffnn-pytorch/ | Model surgery (Net2Net) | MNIST | Feed-forward NN | PyTorch (via nnx) |
| notebooks/quantization-mnist-ffnn-pytorch/ | Quantization (PTQ + QAT) | MNIST | Feed-forward NN | PyTorch (via nnx) + torchao |
| notebooks/pruning-mnist-ffnn-pytorch/ | Pruning (magnitude sparsity sweep) | MNIST | Feed-forward NN | PyTorch (via nnx) |
| notebooks/knowledge_distillation-mnist-ffnn-pytorch/ | Knowledge distillation (born-again) | MNIST | Feed-forward NN | PyTorch (via nnx) |
| notebooks/text_generation-tinyshakespeare-transformer-pytorch/ | Text generation (autoregressive LM) | TinyShakespeare (embedded) | Decoder-only transformer | PyTorch (via nnx) |
| notebooks/peft-mnist-to-fmnist-dora-vs-lora-pytorch/ | PEFT cross-task adaptation (LoRA vs DoRA) | MNIST → Fashion-MNIST | Feed-forward NN + LoRA / DoRA adapters | PyTorch (via nnx) |
| notebooks/dim_reduction-iris-autoencoder-pytorch/ | Dimensionality reduction (PCA vs autoencoder) | Iris | Autoencoder (FFN with input_dim==output_dim) | PyTorch (via nnx) + sklearn |
| notebooks/tabular_regression-diabetes-mlp-pytorch/ | Tabular regression | Diabetes | Feed-forward MLP + sklearn baselines | PyTorch (via nnx) + sklearn |
| notebooks/diffusion-mnist-ddpm-pytorch/ | Generative (DDPM diffusion) | MNIST | DiffusionMLP denoiser (no U-Net) | PyTorch (via nnx) |
| notebooks/moe-fmnist-mixture-of-experts-pytorch/ | Mixture-of-Experts classification | Fashion-MNIST | FeedFwdNN + MoELinear (4 experts, top-2 routing) | PyTorch (via nnx) |
| notebooks/clustering-iris-kmeans-vs-ae-pytorch/ | Unsupervised clustering | Iris | KMeans on raw features vs on AE latent | PyTorch (via nnx) + sklearn |
| notebooks/link_prediction-karate-graphsage-pyg/ | Link prediction (GNN encoder) | Zachary Karate Club | GraphSAGE + dot-product scorer | PyTorch Geometric |
| notebooks/community_detection-karate-louvain-vs-gnn-pyg/ | Community detection (classical vs GNN) | Zachary Karate Club | Louvain vs GraphSAGE+KMeans | PyTorch Geometric + python-louvain |
| notebooks/text_classification-agnews-spacy-mlp-pytorch/ | Text classification (4-topic) | Embedded AG-News-style corpus | spaCy + bag-of-words + MLP | PyTorch (via nnx) + spaCy + sklearn |
| notebooks/sentiment_classification-vader-mlp-pytorch/ | Sentiment classification (rule vs neural) | Embedded review corpus | VADER (lexicon) vs MLP | PyTorch (via nnx) + nltk + spaCy + sklearn |
| notebooks/preference_alignment-toy-dpo-pytorch/ | Preference alignment (DPO) | Embedded 16-triplet preference corpus | Tiny TransformerNN (ref + policy) | PyTorch (via nnx) |
| notebooks/self_supervised-fmnist-jepa-pytorch/ | Self-supervised (I-JEPA) + linear probe | Fashion-MNIST | ViT + EMA target + JEPA predictor | PyTorch (via nnx) |
Tip: GitHub may show "Unable to render code block" on output cells with large matplotlib PNGs. Browse this repo on nbviewer for full rendering of any notebook.
| Folder | Task | Dataset | Model | Framework |
|---|---|---|---|---|
| notebooks/archive/codexglue_summarization/ | Code summarization (22 experiments) | CodeXGLUE | Transformers | HuggingFace |
See §8 Roadmap.
Notebooks are tiered by execution cost:
| Tier | What it is | Re-run policy |
|---|---|---|
| A | Cheap (<5 min) | make run-tier-a re-runs and refreshes outputs. Verified in CI on every PR. Tier-A notebooks also accept a SMOKE_TEST papermill parameter (default 0 = full run). |
| B | Moderate (model-selection sweeps) | Original outputs preserved. make smoke-tier-b runs SMOKE_TEST=1 and writes to /tmp/: the parameterized image_classification-mnist-ffnn-pytorch notebook shrinks its sweep, and the 4 phase2 reddit notebooks run smoke-truncated epochs/subsets (notebook4 also reduces fanout). |
| C | Expensive (main GPU training) | Historical Aug-2023 GPU training-run outputs preserved as artifact. make smoke-tier-c runs CPU with SMOKE_TEST=1 to validate the pipeline without overwriting outputs. |
Tier-B/C smoke targets write the executed notebook copies under /tmp/ml-smoke, but papermill intentionally runs each notebook from its own task directory so relative paths behave like an interactive run. Training and evaluation may therefore create ignored task-local ./data/ or ./runs/ artifacts even when source notebook outputs are preserved; committed output text such as Run saved to ./runs/... describes that notebook-local runtime location, not files guaranteed to exist in a clean checkout.
See docs/env-setup.md for the tier mapping.
Throughout this README, NNx refers to the GitHub project; the importable Python package is lowercase nnx; the PyPI distribution is thekaveh-nnx.
The library is consumed via PyPI — thekaveh-nnx[lm]==0.2.0 is pinned in requirements.txt (since 2026-06-14, replacing the prior git-submodule editable install). The [lm] extra pulls the BPE tokenizer + datasets backbone for the two notebooks that call train_bpe/NNTokenizerParams (notebooks/text_generation-tinyshakespeare-transformer-pytorch/notebook.ipynb and notebooks/preference_alignment-toy-dpo-pytorch/notebook.ipynb); without it both ImportError (issue #12). Notebooks import via from nnx.X import Y exactly as before — only the distribution name and install mechanism changed.
To extend nnx for a new task:
- Open a PR against
thekaveh/NNxwith the new feature + a smoke test. - After merge, wait for the next NNx release cut (or, for editable iteration during the design phase: clone
thekaveh/NNxoutside the ml-eng-lab tree andpip install -e <path-to-clone>[lm]into your venv). - Bump the pinned version in
requirements.txthere (e.g.thekaveh-nnx[lm]==0.2.1); open a PR. Tier-A papermill CI re-runs the Tier-A list against the new version; runmake smoke-tier-b,make smoke-tier-c, and manual quantization validation when the NNx change touches those surfaces — same validation discipline as the prior submodule-pointer-bump workflow.
See CONTRIBUTING.md for the full workflow. Key points:
- Each active task is a self-contained directory under
notebooks/using the[task]-[dataset]-[model]-[framework]naming convention. Notasks/subdirectory. - Shared library code lives in
nnx(the PyPI-installedthekaveh-nnxpackage), not a localcommon/. - Notebooks are saved with executed cells (outputs included) for active tasks.
- Tier-C notebooks have their Aug-2023 outputs preserved; never re-execute them in place.
notebooks/archive/is read-only.
The tabular_classification-iris-mlp-pytorch task added in 2026-05-28 seeds the tabular_classification-titanic-xgboost-sklearn roadmap entry below.
Future tasks planned (each will become a new notebooks/<task>/ directory):
-
image_classification-cifar10-resnet-pytorch -
tabular_classification-titanic-xgboost-sklearn -
text_classification-imdb-distilbert-hf— distinct from the shippednotebooks/text_classification-agnews-spacy-mlp-pytorch/(pre-transformer baseline); this entry is specifically the DistilBERT fine-tune / PEFT continuation. -
link_prediction-citation-graphsage-pyg— distinct from the shippednotebooks/link_prediction-karate-graphsage-pyg/(small-graph smoke); this entry is on a real citation network. -
time_series_forecasting-electricity-tft-pytorch -
anomaly_detection-creditcard-autoencoder-pytorch -
recommendation-movielens-mf-pytorch -
generative-mnist-vae-pytorch— distinct from the shippednotebooks/diffusion-mnist-ddpm-pytorch/; VAEs and diffusion are different generative families. -
reinforcement_learning-cartpole-dqn-pytorch -
diffusion-mnist-ddpm-pytorch— shipped 2026-05-29 in PR #4.
Adding a new task: see the "Adding a new task folder" section in CONTRIBUTING.md.
MIT. See LICENSE.
The README is the entry point; the items below are the hub's index of secondary documentation.
- CONTRIBUTING.md — workflow, conventions, "Adding a new task folder" recipe, verifier+pytest gates.
- CHANGELOG.md — Keep-a-Changelog release notes.
- docs/env-setup.md — the four setup paths (jupyterhub / Docker / venv / Codespaces), GPU notes, Tier mapping.
- docs/jupyterhub-integration.md — primary runtime (vendored
genai-vanillaJupyterHub stack). - docs/vscode-remote-access.md — VS Code remote-attach modes.
- docs/dependency-contracts.md — dependency audit ledger, Torch-stack pin rationale, NNx/genai-vanilla consumed contracts, manual-only quantization contract, and external asset notes.
- docs/architecture.md — system/context view for the notebook lab, verifier, CI, runtime environments, and documentation site.
- docs/diagrams/README.md — provenance and regeneration contract for embedded architecture diagrams.
- docs/maintenance/overnight-2026-07-04.md — current overnight maintenance pass log and issue tracker.
- docs/maintenance/overnight-2026-07-02.md — historical overnight maintenance run that reached its hard cap.
- docs/maintenance/notebooks-reorganization-design.md — completed design record for the
notebooks/<task>/layout and archive move. - docs/maintenance/notebooks-reorganization-implementation.md — completed implementation record for the notebook/archive reorganization and runtime-path contract.
- docs/FINDINGS-NNX.md — issue log for the
thekaveh-nnxlibrary (append findings here; do not edit nnx directly via this repo — fixes land upstream atthekaveh/NNx). - docs/FINDINGS-VENDOR.md — same, for the
vendor/genai-vanillasubmodule.
- notebooks/archive/README.md — preserved Aug-2023 codexglue summarization experiments (22 runs); read-only.