|
| 1 | +# Changelog |
| 2 | + |
| 3 | +## v1.0.0 - 2026-04-17 |
| 4 | + |
| 5 | +Initial public release. |
| 6 | + |
| 7 | +### Core |
| 8 | + |
| 9 | +- **LPT scheduling** - tasks sorted by weight descending; heavy experiments start first, short ones fill gaps at the end. |
| 10 | +- **Load-aware dispatch** - each new task goes to the GPU with the smallest active workload (sum of `Task.weight`). |
| 11 | +- **Per-GPU worker pools** - configurable `workers_per_gpu` (default: 1) to overlap CPU-bound preprocessing with GPU kernels. |
| 12 | +- **Subprocess isolation** - every task runs in its own process with `CUDA_VISIBLE_DEVICES` set; no shared CUDA contexts. |
| 13 | +- **`Task` dataclass** - `(weight, name, seed, cmd)` with comparison by weight for LPT, `.label` property for logging. |
| 14 | +- **`build_task_matrix()`** - generates a deduplicated, LPT-sorted task list from a `names * seeds` grid with `cmd_factory` callback; optional `available_names` whitelist. |
| 15 | +- **`run_schedule()`** - main entry point; returns `(gpu_id, label, return_code, elapsed_sec)` per task. |
| 16 | + |
| 17 | +### Resume & progress |
| 18 | + |
| 19 | +- **`--resume`** - skip tasks whose `seed_*.json` already exists in the results directory. |
| 20 | +- **`scan_completed()`** - walks `results_dir/<timestamp>/<name>/seed_N.json`; supports custom prefix/suffix and optional JSON validation of corrupt/incomplete files. |
| 21 | +- **Progress tracking** - `[done/total pct%]` tag injected into every log line via `ProgressFormatter`; ETA based on completed weight; failure count shown as `N!`. |
| 22 | + |
| 23 | +### Robustness |
| 24 | + |
| 25 | +- **`--task-timeout`** - per-task timeout in seconds; timed-out tasks report `rc=-1`. |
| 26 | +- **`--max-failures`** - stop scheduling new tasks after N failures, drain in-flight work, report summary. |
| 27 | +- **Stall detection** (`stall_warning`) - warns when a GPU has no activity for a configurable duration; logs in-flight task labels. |
| 28 | +- **Dead worker recovery** - detects crashed worker processes; marks their in-flight tasks as failed (`rc=-9`) and continues. |
| 29 | + |
| 30 | +### CLI (`python -m lab_orchestrator`) |
| 31 | + |
| 32 | +- Config loading from YAML (`.yaml`/`.yml`, requires `pyyaml`), JSON, or Python (`.py` with `CONFIG` dict). |
| 33 | +- Two command formats: `cmd_template` (string with `{name}`/`{seed}` placeholders) and `cmd_parts` (structured `base` + `per_name` + `common`). |
| 34 | +- `--gpus 0,1,2,3` - explicit GPU selection; auto-detect via `torch.cuda.device_count()` when omitted. |
| 35 | +- `--dry-run` - simulate scheduling with heap-based timeline; print per-GPU task assignments and estimated wall-clock. |
| 36 | +- `--workers-per-gpu N` - concurrent workers sharing each GPU. |
| 37 | +- `--results-dir` - custom results directory for resume scanning. |
| 38 | + |
| 39 | +### tmux mode |
| 40 | + |
| 41 | +- `--tmux` / `--tmux-session` / `--venv` / `--cwd` - generate a bash script with one tmux window per task instead of running programmatically. |
| 42 | +- `generate_tmux_script()` - programmatic API with LPT-based GPU assignment, virtualenv activation, custom `renderer` callback, and `extra_context` passthrough. |
| 43 | + |
| 44 | +### GPU utilities |
| 45 | + |
| 46 | +- `detect_gpus()` - auto-detect CUDA devices via PyTorch; warns about fork-mode CUDA initialization. |
| 47 | +- `parse_gpu_ids()` - parse `"0,1,2"` strings or fall back to auto-detect. |
| 48 | + |
| 49 | +### Seed management |
| 50 | + |
| 51 | +- `set_seed()` - fix random state across stdlib `random`, NumPy, PyTorch, TensorFlow, and JAX; auto-detects installed frameworks. |
| 52 | +- `deterministic=True` - enable `torch.use_deterministic_algorithms`, set `CUBLAS_WORKSPACE_CONFIG` and `TF_DETERMINISTIC_OPS`. |
| 53 | +- `frameworks=` filter and `warn_missing=` flag for selective seeding. |
| 54 | + |
| 55 | +### Logging |
| 56 | + |
| 57 | +- Per-task log files: `logs/<run_timestamp>/gpu<N>_<name>_seed<S>.log` capturing stdout+stderr. |
| 58 | +- Summary at end: total GPU-hours, wall-clock time, list of failed tasks with return codes. |
| 59 | +- `fmt_duration()` - human-readable duration formatting (`45s`, `2m`, `1h01m`). |
| 60 | + |
| 61 | +### Examples |
| 62 | + |
| 63 | +- `examples/sklearn_digits/` - minimal working example (no GPU needed): 3 models * 5 seeds with SVM, Random Forest, KNN on digits dataset. |
| 64 | +- `examples/sweep/` - GPU sweep template with `train.py` + `sweep.py` + `experiments.yaml`. |
| 65 | +- `examples/experiment_template.py` - self-contained launcher + training in one file with checkpointing. |
| 66 | +- `examples/tmux_example.py` - tmux script generation from code. |
| 67 | + |
| 68 | +### Packaging |
| 69 | + |
| 70 | +- Zero hard dependencies - stdlib `multiprocessing` + `subprocess` only. |
| 71 | +- Optional extras: `gpu` (torch >= 2.0), `yaml` (pyyaml >= 6.0), `dev` (ruff, mypy, pytest, flake8). |
| 72 | +- `lab-orchestrator` CLI entry point via `pyproject.toml`. |
| 73 | +- Python >= 3.10 required. |
| 74 | +- MIT license. |
| 75 | +- Full type annotations; passes `mypy --disallow-untyped-defs`. |
| 76 | +- Test suite: 30+ tests covering task building, GPU parsing, tmux generation, seed reproducibility, resume scanning, progress formatting, dry-run, config loading, and integration. |
0 commit comments