fast local checkpoints, fewer bucket writes
Browse files- scugnizz-llama.py +74 -20
scugnizz-llama.py
CHANGED
|
@@ -45,6 +45,9 @@ KEEP (optimizer resume):
|
|
| 45 |
SAFE TO DELETE (weights-only snapshots):
|
| 46 |
- checkpoint_weights_last.pt
|
| 47 |
- old model_final.pt after a newer run finishes
|
|
|
|
|
|
|
|
|
|
| 48 |
"""
|
| 49 |
|
| 50 |
|
|
@@ -276,9 +279,13 @@ def parse_args():
|
|
| 276 |
p.add_argument("--dropout", type=float, default=0.0)
|
| 277 |
p.add_argument("--eval-interval", type=int, default=50)
|
| 278 |
p.add_argument("--eval-batches", type=int, default=10)
|
| 279 |
-
p.add_argument("--save-interval", type=int, default=
|
| 280 |
-
p.add_argument("--weights-save-interval", type=int, default=
|
| 281 |
-
help="
|
|
|
|
|
|
|
|
|
|
|
|
|
| 282 |
p.add_argument("--log-interval", type=int, default=10)
|
| 283 |
p.add_argument("--pcs-a", type=float, default=0.8309193524478643)
|
| 284 |
p.add_argument("--pcs-b", type=float, default=0.0)
|
|
@@ -439,11 +446,11 @@ def save_ckpt(path, model, opt, step, best, rank, world_size, mirror_resume=Fals
|
|
| 439 |
barrier(rank, world_size)
|
| 440 |
|
| 441 |
|
| 442 |
-
def copy_best_ckpt(
|
| 443 |
if not is_main(rank):
|
| 444 |
barrier(rank, world_size)
|
| 445 |
return
|
| 446 |
-
last, best =
|
| 447 |
if last.exists():
|
| 448 |
shutil.copy2(last, best)
|
| 449 |
print("SAVED", best, "(copy of checkpoint_last)", flush=True)
|
|
@@ -488,12 +495,12 @@ def load_init_payload(path, dev):
|
|
| 488 |
return ck, None, False
|
| 489 |
|
| 490 |
|
| 491 |
-
def resume_training(model, out, a, rank, world_size, dev):
|
| 492 |
start, best, opt_state = 0, float("inf"), None
|
| 493 |
if a.no_resume:
|
| 494 |
return start, best, opt_state
|
| 495 |
|
| 496 |
-
resume_path = find_resume_ckpt(out)
|
| 497 |
init_path = a.init_from or fetch_init_hub(a, rank, world_size)
|
| 498 |
weights_path = out / "model_final.pt"
|
| 499 |
|
|
@@ -565,11 +572,40 @@ def resume_training(model, out, a, rank, world_size, dev):
|
|
| 565 |
return start, best, opt_state
|
| 566 |
|
| 567 |
|
| 568 |
-
def
|
| 569 |
-
|
| 570 |
-
|
| 571 |
-
|
| 572 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 573 |
return None
|
| 574 |
|
| 575 |
|
|
@@ -651,8 +687,10 @@ def main():
|
|
| 651 |
set_seed(a.seed, rank)
|
| 652 |
dt = dtype_of(a.dtype, dev)
|
| 653 |
out = Path(a.out_dir)
|
|
|
|
| 654 |
if is_main(rank):
|
| 655 |
out.mkdir(parents=True, exist_ok=True)
|
|
|
|
| 656 |
(out / "CHECKPOINT_POLICY.txt").write_text(KEEP_NOTE, encoding="utf-8")
|
| 657 |
barrier(rank, world_size)
|
| 658 |
|
|
@@ -674,7 +712,7 @@ def main():
|
|
| 674 |
params = sum(p.numel() for p in model.parameters())
|
| 675 |
log0(rank, f"params {params/1e9:.3f}B ({params/1e6:.1f}M)", flush=True)
|
| 676 |
|
| 677 |
-
start, best, opt_state = resume_training(model, out, a, rank, world_size, dev)
|
| 678 |
if is_main(rank):
|
| 679 |
(out / "args.json").write_text(json.dumps(vars(a), indent=2), encoding="utf-8")
|
| 680 |
barrier(rank, world_size)
|
|
@@ -694,17 +732,20 @@ def main():
|
|
| 694 |
opt.load_state_dict(opt_state)
|
| 695 |
log0(rank, "loaded optimizer state", flush=True)
|
| 696 |
|
| 697 |
-
last =
|
| 698 |
-
bestp =
|
| 699 |
-
weights_last =
|
|
|
|
| 700 |
|
| 701 |
log0(rank, "initializing data streams...", flush=True)
|
|
|
|
| 702 |
train = Batcher(a, tok, dev, rank, log=is_main(rank))
|
| 703 |
val = Batcher(a, tok, dev, 10_000, log=False) if is_main(rank) else None
|
| 704 |
log0(rank, f"starting training loop from step {start}...", flush=True)
|
| 705 |
t0 = time.time()
|
| 706 |
roll = 0.0
|
| 707 |
n = 0
|
|
|
|
| 708 |
model.train()
|
| 709 |
|
| 710 |
for step in range(start, a.max_steps + 1):
|
|
@@ -727,13 +768,17 @@ def main():
|
|
| 727 |
|
| 728 |
if step % a.log_interval == 0:
|
| 729 |
avg = roll / max(1, n)
|
| 730 |
-
|
|
|
|
|
|
|
| 731 |
tok_s = max(1, step - start + 1) * tps / elapsed
|
|
|
|
| 732 |
log0(
|
| 733 |
rank,
|
| 734 |
-
f"step {step:08d} | loss {avg:.4f} | ppl {math.exp(min(20, avg)):.1f} | lr {lr:.2e} | tok/s {tok_s:.0f} | trained_tokens {step*tps} | rows {train.rows}",
|
| 735 |
flush=True,
|
| 736 |
)
|
|
|
|
| 737 |
roll = 0.0
|
| 738 |
n = 0
|
| 739 |
|
|
@@ -761,13 +806,22 @@ def main():
|
|
| 761 |
if step > 0 and step % a.save_interval == 0:
|
| 762 |
save_ckpt(last, model, opt, step, best, rank, world_size, mirror_resume=True)
|
| 763 |
if val_improved:
|
| 764 |
-
copy_best_ckpt(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 765 |
if is_main(rank) and a.push_every_save:
|
| 766 |
upload_final(str(out), a.hub_repo_id, a.hub_path, f"pretrain checkpoint step {step}")
|
| 767 |
|
| 768 |
save_ckpt(last, model, opt, a.max_steps, best, rank, world_size, mirror_resume=True)
|
|
|
|
| 769 |
if is_main(rank):
|
| 770 |
-
|
|
|
|
|
|
|
| 771 |
tok.save_pretrained(out / "tokenizer")
|
| 772 |
if a.push:
|
| 773 |
upload_final(str(out), a.hub_repo_id, a.hub_path, "final ScugnizzLLM Llama-PCS pretrain")
|
|
|
|
| 45 |
SAFE TO DELETE (weights-only snapshots):
|
| 46 |
- checkpoint_weights_last.pt
|
| 47 |
- old model_final.pt after a newer run finishes
|
| 48 |
+
|
| 49 |
+
Checkpoints write to CKPT_LOCAL_DIR (default /tmp) first, then resume is copied to out-dir.
|
| 50 |
+
Set WEIGHTS_SAVE_INTERVAL=0 for long runs (default).
|
| 51 |
"""
|
| 52 |
|
| 53 |
|
|
|
|
| 279 |
p.add_argument("--dropout", type=float, default=0.0)
|
| 280 |
p.add_argument("--eval-interval", type=int, default=50)
|
| 281 |
p.add_argument("--eval-batches", type=int, default=10)
|
| 282 |
+
p.add_argument("--save-interval", type=int, default=100)
|
| 283 |
+
p.add_argument("--weights-save-interval", type=int, default=0,
|
| 284 |
+
help="Weights-only snapshot every N steps (0=off; slows bucket I/O)")
|
| 285 |
+
p.add_argument("--ckpt-local-dir", default="/tmp/scugnizz-ckpts",
|
| 286 |
+
help="Fast local dir for checkpoint writes; synced to out-dir periodically")
|
| 287 |
+
p.add_argument("--bucket-sync-interval", type=int, default=1,
|
| 288 |
+
help="Sync resume checkpoint to out-dir every N save-intervals (1=every save)")
|
| 289 |
p.add_argument("--log-interval", type=int, default=10)
|
| 290 |
p.add_argument("--pcs-a", type=float, default=0.8309193524478643)
|
| 291 |
p.add_argument("--pcs-b", type=float, default=0.0)
|
|
|
|
| 446 |
barrier(rank, world_size)
|
| 447 |
|
| 448 |
|
| 449 |
+
def copy_best_ckpt(local, rank, world_size):
|
| 450 |
if not is_main(rank):
|
| 451 |
barrier(rank, world_size)
|
| 452 |
return
|
| 453 |
+
last, best = local / "checkpoint_last.pt", local / "checkpoint_best.pt"
|
| 454 |
if last.exists():
|
| 455 |
shutil.copy2(last, best)
|
| 456 |
print("SAVED", best, "(copy of checkpoint_last)", flush=True)
|
|
|
|
| 495 |
return ck, None, False
|
| 496 |
|
| 497 |
|
| 498 |
+
def resume_training(model, local, out, a, rank, world_size, dev):
|
| 499 |
start, best, opt_state = 0, float("inf"), None
|
| 500 |
if a.no_resume:
|
| 501 |
return start, best, opt_state
|
| 502 |
|
| 503 |
+
resume_path = find_resume_ckpt(local, out)
|
| 504 |
init_path = a.init_from or fetch_init_hub(a, rank, world_size)
|
| 505 |
weights_path = out / "model_final.pt"
|
| 506 |
|
|
|
|
| 572 |
return start, best, opt_state
|
| 573 |
|
| 574 |
|
| 575 |
+
def sync_file(src, dst, rank, world_size):
|
| 576 |
+
if not is_main(rank):
|
| 577 |
+
barrier(rank, world_size)
|
| 578 |
+
return
|
| 579 |
+
if src.exists():
|
| 580 |
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
| 581 |
+
tmp = dst.with_suffix(dst.suffix + ".tmp")
|
| 582 |
+
shutil.copy2(src, tmp)
|
| 583 |
+
tmp.replace(dst)
|
| 584 |
+
print("SYNCED", dst, flush=True)
|
| 585 |
+
barrier(rank, world_size)
|
| 586 |
+
|
| 587 |
+
|
| 588 |
+
def sync_bucket_ckpts(local, out, rank, world_size, names):
|
| 589 |
+
if not is_main(rank):
|
| 590 |
+
barrier(rank, world_size)
|
| 591 |
+
return
|
| 592 |
+
for name in names:
|
| 593 |
+
src, dst = local / name, out / name
|
| 594 |
+
if src.exists():
|
| 595 |
+
dst.parent.mkdir(parents=True, exist_ok=True)
|
| 596 |
+
tmp = dst.with_suffix(dst.suffix + ".tmp")
|
| 597 |
+
shutil.copy2(src, tmp)
|
| 598 |
+
tmp.replace(dst)
|
| 599 |
+
print("SYNCED", dst, flush=True)
|
| 600 |
+
barrier(rank, world_size)
|
| 601 |
+
|
| 602 |
+
|
| 603 |
+
def find_resume_ckpt(local, out):
|
| 604 |
+
for base in (local, out):
|
| 605 |
+
for name in ("checkpoint_last.pt", RESUME_CKPT, "checkpoint_best.pt"):
|
| 606 |
+
p = base / name
|
| 607 |
+
if p.exists():
|
| 608 |
+
return p
|
| 609 |
return None
|
| 610 |
|
| 611 |
|
|
|
|
| 687 |
set_seed(a.seed, rank)
|
| 688 |
dt = dtype_of(a.dtype, dev)
|
| 689 |
out = Path(a.out_dir)
|
| 690 |
+
local = Path(a.ckpt_local_dir)
|
| 691 |
if is_main(rank):
|
| 692 |
out.mkdir(parents=True, exist_ok=True)
|
| 693 |
+
local.mkdir(parents=True, exist_ok=True)
|
| 694 |
(out / "CHECKPOINT_POLICY.txt").write_text(KEEP_NOTE, encoding="utf-8")
|
| 695 |
barrier(rank, world_size)
|
| 696 |
|
|
|
|
| 712 |
params = sum(p.numel() for p in model.parameters())
|
| 713 |
log0(rank, f"params {params/1e9:.3f}B ({params/1e6:.1f}M)", flush=True)
|
| 714 |
|
| 715 |
+
start, best, opt_state = resume_training(model, local, out, a, rank, world_size, dev)
|
| 716 |
if is_main(rank):
|
| 717 |
(out / "args.json").write_text(json.dumps(vars(a), indent=2), encoding="utf-8")
|
| 718 |
barrier(rank, world_size)
|
|
|
|
| 732 |
opt.load_state_dict(opt_state)
|
| 733 |
log0(rank, "loaded optimizer state", flush=True)
|
| 734 |
|
| 735 |
+
last = local / "checkpoint_last.pt"
|
| 736 |
+
bestp = local / "checkpoint_best.pt"
|
| 737 |
+
weights_last = local / "checkpoint_weights_last.pt"
|
| 738 |
+
saves_done = 0
|
| 739 |
|
| 740 |
log0(rank, "initializing data streams...", flush=True)
|
| 741 |
+
log0(rank, f"ckpt_local={local} out_dir={out}", flush=True)
|
| 742 |
train = Batcher(a, tok, dev, rank, log=is_main(rank))
|
| 743 |
val = Batcher(a, tok, dev, 10_000, log=False) if is_main(rank) else None
|
| 744 |
log0(rank, f"starting training loop from step {start}...", flush=True)
|
| 745 |
t0 = time.time()
|
| 746 |
roll = 0.0
|
| 747 |
n = 0
|
| 748 |
+
log_t0 = t0
|
| 749 |
model.train()
|
| 750 |
|
| 751 |
for step in range(start, a.max_steps + 1):
|
|
|
|
| 768 |
|
| 769 |
if step % a.log_interval == 0:
|
| 770 |
avg = roll / max(1, n)
|
| 771 |
+
now = time.time()
|
| 772 |
+
elapsed = max(1e-6, now - t0)
|
| 773 |
+
interval = max(1e-6, now - log_t0)
|
| 774 |
tok_s = max(1, step - start + 1) * tps / elapsed
|
| 775 |
+
instant = a.log_interval * tps / interval
|
| 776 |
log0(
|
| 777 |
rank,
|
| 778 |
+
f"step {step:08d} | loss {avg:.4f} | ppl {math.exp(min(20, avg)):.1f} | lr {lr:.2e} | tok/s {tok_s:.0f} ({instant:.0f} inst) | trained_tokens {step*tps} | rows {train.rows}",
|
| 779 |
flush=True,
|
| 780 |
)
|
| 781 |
+
log_t0 = now
|
| 782 |
roll = 0.0
|
| 783 |
n = 0
|
| 784 |
|
|
|
|
| 806 |
if step > 0 and step % a.save_interval == 0:
|
| 807 |
save_ckpt(last, model, opt, step, best, rank, world_size, mirror_resume=True)
|
| 808 |
if val_improved:
|
| 809 |
+
copy_best_ckpt(local, rank, world_size)
|
| 810 |
+
saves_done += 1
|
| 811 |
+
if saves_done % max(1, a.bucket_sync_interval) == 0:
|
| 812 |
+
names = [RESUME_CKPT, "checkpoint_last.pt"]
|
| 813 |
+
if (local / "checkpoint_best.pt").exists():
|
| 814 |
+
names.append("checkpoint_best.pt")
|
| 815 |
+
sync_bucket_ckpts(local, out, rank, world_size, names)
|
| 816 |
if is_main(rank) and a.push_every_save:
|
| 817 |
upload_final(str(out), a.hub_repo_id, a.hub_path, f"pretrain checkpoint step {step}")
|
| 818 |
|
| 819 |
save_ckpt(last, model, opt, a.max_steps, best, rank, world_size, mirror_resume=True)
|
| 820 |
+
sync_bucket_ckpts(local, out, rank, world_size, (RESUME_CKPT, "checkpoint_last.pt", "checkpoint_best.pt"))
|
| 821 |
if is_main(rank):
|
| 822 |
+
final_local = local / "model_final.pt"
|
| 823 |
+
torch.save(raw_model(model).state_dict(), final_local)
|
| 824 |
+
sync_file(final_local, out / "model_final.pt", rank, world_size)
|
| 825 |
tok.save_pretrained(out / "tokenizer")
|
| 826 |
if a.push:
|
| 827 |
upload_final(str(out), a.hub_repo_id, a.hub_path, "final ScugnizzLLM Llama-PCS pretrain")
|