| """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 |
| from matilda.train import Trainer, TrainConfig |
| from matilda.data import SyntheticStream, BinStream, shard_paths |
|
|
|
|
| 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() |
|
|