matilda-mini / run.py
prometheus04's picture
Matilda-Mini phases 1-5 + runbook
880f286 verified
Raw
History Blame Contribute Delete
2.95 kB
"""Launch entrypoint: build configs + data stream and train.
python run.py --config configs/base_124m.json --data-dir data/fwedu
python run.py --config configs/calibration.json --data-dir data/fwedu
python run.py --config configs/calibration.json --dry-run # synthetic, no data
A config JSON has two objects, "model" and "train", whose keys map directly onto
ModelConfig / TrainConfig fields. CLI --set k=v applies last-mile overrides
(e.g. --set train.batch_size=48) so calibration sweeps don't need new files.
"""
from __future__ import annotations
import sys
import json
import argparse
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent / "src"))
from matilda.config import ModelConfig # noqa: E402
from matilda.train import Trainer, TrainConfig # noqa: E402
from matilda.data import SyntheticStream, BinStream, shard_paths # noqa: E402
def _coerce(value: str):
for cast in (int, float):
try:
return cast(value)
except ValueError:
pass
if value.lower() in ("true", "false"):
return value.lower() == "true"
return value
def apply_overrides(cfg: dict, overrides: list[str]) -> dict:
"""--set train.batch_size=48 -> cfg['train']['batch_size'] = 48"""
for item in overrides:
path, _, raw = item.partition("=")
section, _, key = path.partition(".")
cfg.setdefault(section, {})[key] = _coerce(raw)
return cfg
def build(config: dict):
mcfg = ModelConfig(**config.get("model", {}))
tcfg = TrainConfig(**config.get("train", {}))
return mcfg, tcfg
def build_stream(mcfg, tcfg, data_dir: str | None, dry_run: bool):
if dry_run or not data_dir:
print("[data] synthetic stream (dry run, no real data)")
return SyntheticStream(mcfg.vocab_size, tcfg.batch_size, tcfg.seq_len,
seed=tcfg.seed, device=tcfg.device)
paths = shard_paths(data_dir)
print(f"[data] {len(paths)} shards from {data_dir}")
return BinStream(paths, tcfg.batch_size, tcfg.seq_len, seed=tcfg.seed,
device=tcfg.device)
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--config", required=True)
ap.add_argument("--data-dir", default=None)
ap.add_argument("--dry-run", action="store_true")
ap.add_argument("--set", nargs="*", default=[], dest="overrides")
args = ap.parse_args()
config = json.loads(Path(args.config).read_text())
config = apply_overrides(config, args.overrides)
mcfg, tcfg = build(config)
stream = build_stream(mcfg, tcfg, args.data_dir, args.dry_run)
print(f"[run] model={mcfg.d_model}d/{mcfg.n_layers}L "
f"steps={tcfg.total_steps} bs={tcfg.batch_size}x{tcfg.grad_accum} "
f"seq={tcfg.seq_len} compile={tcfg.compile} ckpt={tcfg.ckpt_dir}")
Trainer(mcfg, tcfg, stream).train()
if __name__ == "__main__":
main()