Download ar/train/train.py from AjayRangoji/AR: direct link, hf CLI and curl.
- Browser
- Download file 3.34 kB
-
https://huggingface.co/AjayRangoji/AR/resolve/main/ar/train/train.py
- Command line
-
hf download hf://AjayRangoji/AR/ar/train/train.py
-
curl -L -o train.py https://huggingface.co/AjayRangoji/AR/resolve/main/ar/train/train.py
3.34 kB
| import math | |
| import os | |
| import time | |
| import argparse | |
| import torch | |
| import torch.nn.functional as F | |
| from ar.model.config import ARConfig, small_config, tiny_config | |
| from ar.model.model import ARModel | |
| from ar.data.dataset import BinDataset | |
| from ar.train.train_config import TrainConfig | |
| def lr_at(step: int, cfg: TrainConfig) -> float: | |
| """Warmup then cosine decay: ramp up linearly, then ease down to min_lr.""" | |
| if step < cfg.warmup_steps: | |
| return cfg.peak_lr * (step + 1) / cfg.warmup_steps | |
| # cosine decay from peak_lr to min_lr over the remaining steps | |
| progress = (step - cfg.warmup_steps) / max(1, cfg.max_steps - cfg.warmup_steps) | |
| progress = min(1.0, progress) | |
| coeff = 0.5 * (1.0 + math.cos(math.pi * progress)) | |
| return cfg.min_lr + coeff * (cfg.peak_lr - cfg.min_lr) | |
| def train(bin_paths, weights, tcfg: TrainConfig, mcfg: ARConfig, device="cuda"): | |
| torch.manual_seed(0) | |
| model = ARModel(mcfg).to(device) | |
| model.train() | |
| data = BinDataset(bin_paths, tcfg.seq_len, weights) | |
| # AdamW with the LLM-pretraining betas; fused=True is a faster CUDA path | |
| opt = torch.optim.AdamW( | |
| model.parameters(), lr=tcfg.peak_lr, | |
| betas=tcfg.betas, weight_decay=tcfg.weight_decay, fused=True, | |
| ) | |
| os.makedirs(tcfg.ckpt_dir, exist_ok=True) | |
| t0 = time.time() | |
| for step in range(tcfg.max_steps): | |
| # set this step's learning rate on the optimizer | |
| lr = lr_at(step, tcfg) | |
| for g in opt.param_groups: | |
| g["lr"] = lr | |
| x, y = data.get_batch(tcfg.batch_size, device) | |
| # forward: logits are (B, T, vocab); cross-entropy wants (B*T, vocab) | |
| logits = model(x) | |
| loss = F.cross_entropy( | |
| logits.view(-1, logits.size(-1)), y.view(-1) | |
| ) | |
| # backward: clear old grads, compute new ones, clip, then step | |
| opt.zero_grad(set_to_none=True) | |
| loss.backward() | |
| torch.nn.utils.clip_grad_norm_(model.parameters(), tcfg.grad_clip) | |
| opt.step() | |
| if step % tcfg.log_every == 0: | |
| dt = time.time() - t0 | |
| toks = (step + 1) * tcfg.batch_size * tcfg.seq_len | |
| print(f"step {step:6d} | loss {loss.item():.4f} | lr {lr:.2e} " | |
| f"| {toks/dt/1e3:.1f}k tok/s") | |
| if step > 0 and step % tcfg.ckpt_every == 0: | |
| path = os.path.join(tcfg.ckpt_dir, f"ar_step{step}.pt") | |
| torch.save({"model": model.state_dict(), "step": step}, path) | |
| print(f" saved {path}") | |
| if __name__ == "__main__": | |
| p = argparse.ArgumentParser() | |
| p.add_argument("--bin", nargs="+", required=True, help="one or more .bin paths") | |
| p.add_argument("--weights", nargs="+", type=float, default=None) | |
| p.add_argument("--max_steps", type=int, default=100) | |
| p.add_argument("--batch_size", type=int, default=4) | |
| p.add_argument("--seq_len", type=int, default=4096) | |
| p.add_argument("--warmup_steps", type=int, default=2000) | |
| p.add_argument("--model_size", choices=["small", "full", "tiny"], default="small") | |
| args = p.parse_args() | |
| tcfg = TrainConfig(max_steps=args.max_steps, batch_size=args.batch_size, | |
| seq_len=args.seq_len, warmup_steps=args.warmup_steps) | |
| mcfg = {"small": small_config, "full": ARConfig, "tiny": tiny_config}[args.model_size]() | |
| train(args.bin, args.weights, tcfg, mcfg) |