Skip to content

thekaveh/ml-eng-lab

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

471 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ml-eng-lab — personal ML lab

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.

1. Overview

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.

2. Repository layout

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.

3. Quick start

Four ways to run these notebooks, ordered from managed runtime to local execution.

3.1. genai-vanilla jupyterhub (recommended)

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

See docs/jupyterhub-integration.md (full two-path walkthrough) and docs/vscode-remote-access.md.

3.2. Local Docker

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.

3.3. Local venv

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 lab

See docs/env-setup.md for environment details.

3.4. GitHub Codespaces (zero-click cloud dev)

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.ipynb edge case (it imports sibling .py modules 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's scripts/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 (Modal function.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.int1 vs torch==2.4.1 incompatibility documented in its task README and in docs/dependency-contracts.md (manual-only).

How to use:

  1. On github.com/thekaveh/ml-eng-lab → green Code button → Codespaces tab → Create codespace on main.
  2. Wait ~2-3 min for postCreateCommand to run make codespace-setup (= Torch-first dependency install + make nlp-assets). Progress is visible in the terminal panel.
  3. 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.

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.

4. Tasks

4.1. Active

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.

4.2. Archived

Folder Task Dataset Model Framework
notebooks/archive/codexglue_summarization/ Code summarization (22 experiments) CodeXGLUE Transformers HuggingFace

4.3. Planned

See §8 Roadmap.

5. Notebook re-execution policy

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.

6. NNx library

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:

  1. Open a PR against thekaveh/NNx with the new feature + a smoke test.
  2. After merge, wait for the next NNx release cut (or, for editable iteration during the design phase: clone thekaveh/NNx outside the ml-eng-lab tree and pip install -e <path-to-clone>[lm] into your venv).
  3. Bump the pinned version in requirements.txt here (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; run make 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.

7. Repository conventions

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. No tasks/ subdirectory.
  • Shared library code lives in nnx (the PyPI-installed thekaveh-nnx package), not a local common/.
  • 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.

8. Roadmap

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 shipped notebooks/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 shipped notebooks/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 shipped notebooks/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.

9. License

MIT. See LICENSE.

10. Other documentation

The README is the entry point; the items below are the hub's index of secondary documentation.

10.1. Workflow + history

  • CONTRIBUTING.md — workflow, conventions, "Adding a new task folder" recipe, verifier+pytest gates.
  • CHANGELOG.md — Keep-a-Changelog release notes.

10.2. Environment + runtimes

10.3. Issue sinks for external code

10.4. Archive