AR / ar /train /train.py
AjayRangoji's picture
Upload AR-4B pretraining codebase, configs, and cluster scripts
2ae6691 verified
Raw History Blame Contribute Delete
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)