Download code/minijev/runs.py from markuz89/minijev-snake: direct link, hf CLI and curl.
- Browser
- Download file 3.88 kB
-
https://huggingface.co/markuz89/minijev-snake/resolve/main/code/minijev/runs.py
- Command line
-
hf download hf://markuz89/minijev-snake/code/minijev/runs.py
-
curl -L -o runs.py https://huggingface.co/markuz89/minijev-snake/resolve/main/code/minijev/runs.py
3.88 kB
| """Lightweight experiment tracking: one directory per run under `runs/`. | |
| runs/<timestamp>-<name>/ | |
| config.yaml resolved config | |
| env.json git commit, hardware, library versions, runtime profile | |
| metrics.csv step-level training/validation metrics | |
| tb/ TensorBoard events (if tensorboard is installed) | |
| summary.json final metrics, timings, cost | |
| checkpoints/ last.pt (resumable), best.pt, final.pt (calibrated) | |
| """ | |
| from __future__ import annotations | |
| import csv | |
| import json | |
| import platform | |
| import subprocess | |
| import time | |
| from pathlib import Path | |
| import yaml | |
| def git_commit() -> str | None: | |
| try: | |
| out = subprocess.run(["git", "rev-parse", "HEAD"], capture_output=True, text=True, timeout=5, | |
| cwd=Path(__file__).resolve().parent) | |
| dirty = subprocess.run(["git", "status", "--porcelain"], capture_output=True, text=True, timeout=5, | |
| cwd=Path(__file__).resolve().parent).stdout.strip() | |
| return (out.stdout.strip() + ("-dirty" if dirty else "")) if out.returncode == 0 else None | |
| except Exception: | |
| return None | |
| def environment_info() -> dict: | |
| import numpy | |
| info = {"python": platform.python_version(), "platform": platform.platform(), | |
| "processor": platform.processor(), "numpy": numpy.__version__, "git_commit": git_commit()} | |
| try: | |
| import torch | |
| info["torch"] = torch.__version__ | |
| info["cuda"] = torch.version.cuda | |
| if torch.cuda.is_available(): | |
| info["gpu"] = torch.cuda.get_device_name(0) | |
| except ImportError: | |
| pass | |
| return info | |
| class RunLogger: | |
| def __init__(self, run_dir: str | Path, cfg: dict | None = None, resume: bool = False): | |
| self.dir = Path(run_dir) | |
| self.dir.mkdir(parents=True, exist_ok=True) | |
| (self.dir / "checkpoints").mkdir(exist_ok=True) | |
| if cfg is not None and not (resume and (self.dir / "config.yaml").exists()): | |
| (self.dir / "config.yaml").write_text(yaml.safe_dump(cfg, sort_keys=False)) | |
| self._csv_path = self.dir / "metrics.csv" | |
| self._fields: list[str] | None = None | |
| if resume and self._csv_path.exists(): | |
| with open(self._csv_path) as f: | |
| self._fields = next(csv.reader(f), None) | |
| self.tb = None | |
| try: | |
| from torch.utils.tensorboard import SummaryWriter | |
| self.tb = SummaryWriter(str(self.dir / "tb")) | |
| except Exception: | |
| pass | |
| def write_json(self, name: str, obj) -> None: | |
| (self.dir / name).write_text(json.dumps(obj, indent=2, default=str)) | |
| def log(self, step: int, **metrics) -> None: | |
| row = {"step": step, "time": round(time.time(), 1), **metrics} | |
| if self._fields is None: | |
| self._fields = list(row) | |
| with open(self._csv_path, "w", newline="") as f: | |
| csv.writer(f).writerow(self._fields) | |
| for k in row: | |
| if k not in self._fields: # new metric: rewrite header | |
| self._fields.append(k) | |
| rows = list(csv.DictReader(open(self._csv_path))) | |
| with open(self._csv_path, "w", newline="") as f: | |
| w = csv.DictWriter(f, self._fields) | |
| w.writeheader() | |
| w.writerows(rows) | |
| with open(self._csv_path, "a", newline="") as f: | |
| csv.DictWriter(f, self._fields).writerow(row) | |
| if self.tb is not None: | |
| for k, v in metrics.items(): | |
| if isinstance(v, (int, float)): | |
| self.tb.add_scalar(k, v, step) | |
| def close(self) -> None: | |
| if self.tb is not None: | |
| self.tb.close() | |
| def new_run_dir(name: str, root: str | Path = "runs") -> Path: | |
| return Path(root) / f"{time.strftime('%Y%m%d-%H%M%S')}-{name}" | |