43634ef77a
cli.py and scripts/train.py duplicated ~140 lines of training setup and had drifted (scripts/train.py forgot to save model_config, breaking predict on those checkpoints). Extract shared logic into giant/constants.py (X_DIM, target names), giant/config.py (device/git/TOML/seeding helpers, run metadata), and giant/pipeline.py (the actual training-job orchestration), so both entry points become thin CLI wrappers around the same code path. Also adds --seed/--resume support (checkpoints now carry optimizer/scheduler state, epoch, and best_val_loss), a richer [meta] section in the saved config.toml (git hash, seed, versions, timestamp, invocation, dataset stats), and a metrics.csv (train/val loss, lr, epoch time) written every epoch and append-safe across resumes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
65 lines
2.6 KiB
Python
65 lines
2.6 KiB
Python
import argparse
|
|
from pathlib import Path
|
|
|
|
import torch
|
|
|
|
from giant import config as gconfig
|
|
from giant.pipeline import run_train_job
|
|
|
|
|
|
def main() -> None:
|
|
parser = argparse.ArgumentParser(description="Train GIANT surrogate model")
|
|
parser.add_argument("--config", default=None, help="Path to TOML config file")
|
|
parser.add_argument("--data", required=True, help="Path to parquet file or directory")
|
|
parser.add_argument("--mode", choices=["flow", "ddpm"])
|
|
parser.add_argument("--epochs", type=int)
|
|
parser.add_argument("--batch-size", type=int)
|
|
parser.add_argument("--lr", type=float)
|
|
parser.add_argument("--hidden-dim", type=int)
|
|
parser.add_argument("--n-blocks", type=int)
|
|
parser.add_argument("--emb-dim", type=int)
|
|
parser.add_argument("--val-fraction", type=float)
|
|
parser.add_argument("--seed", type=int, help="Random seed for reproducibility")
|
|
parser.add_argument("--shuffle-buffer", type=int, default=65536,
|
|
help="Rows held in RAM for shuffling per worker (default: 65536)")
|
|
parser.add_argument("--out", default=None, help="Checkpoint output directory (default: auto from hyperparams)")
|
|
parser.add_argument("--device", default=None, help="cpu | cuda | mps (default: auto)")
|
|
parser.add_argument("--num-workers", type=int)
|
|
parser.add_argument("--resume", default=None, help="Checkpoint .pt to resume training from")
|
|
args = parser.parse_args()
|
|
|
|
cli_train = {k: v for k, v in {
|
|
"mode": args.mode, "epochs": args.epochs, "batch_size": args.batch_size,
|
|
"lr": args.lr, "val_fraction": args.val_fraction, "num_workers": args.num_workers,
|
|
"seed": args.seed,
|
|
}.items() if v is not None}
|
|
cli_model = {k: v for k, v in {
|
|
"hidden_dim": args.hidden_dim, "n_blocks": args.n_blocks, "emb_dim": args.emb_dim,
|
|
}.items() if v is not None}
|
|
config_path = Path(args.config) if args.config else None
|
|
cfg = gconfig.merge_cli_overrides(gconfig.DEFAULT_CONFIG, config_path, cli_train, cli_model)
|
|
t, m = cfg["train"], cfg["model"]
|
|
|
|
device = torch.device(args.device) if args.device else gconfig.auto_device()
|
|
out_dir = Path(args.out or (
|
|
f"checkpoints/{t['mode']}"
|
|
f"_h{m['hidden_dim']}"
|
|
f"_b{m['n_blocks']}"
|
|
f"_e{m['emb_dim']}"
|
|
f"_lr{t['lr']}"
|
|
f"_bs{t['batch_size']}"
|
|
))
|
|
|
|
print(f"device: {device}")
|
|
print(f"out_dir: {out_dir}")
|
|
|
|
run_train_job(
|
|
data=Path(args.data), cfg=cfg, out_dir=out_dir, device=device,
|
|
shuffle_buffer=args.shuffle_buffer, num_workers=t["num_workers"],
|
|
resume=Path(args.resume) if args.resume else None, echo=print,
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|