Upload train/train_ounce100m.py with huggingface_hub
Browse files- train/train_ounce100m.py +33 -21
train/train_ounce100m.py
CHANGED
|
@@ -495,25 +495,7 @@ def main():
|
|
| 495 |
if final_loss is None or not math.isfinite(final_loss):
|
| 496 |
raise SystemExit(f"final loss is not finite ({final_loss}) -- not exporting anything")
|
| 497 |
|
| 498 |
-
|
| 499 |
-
tr.save_model(out)
|
| 500 |
-
# The tokenizer travels with the run so `final/` is loadable by AutoTokenizer on its own (§8). If it
|
| 501 |
-
# is not in the mix root, say so in the summary instead of skipping quietly and being surprised later.
|
| 502 |
-
shipped = []
|
| 503 |
-
import shutil as _sh
|
| 504 |
-
for fn in ("tokenizer.json", "tokenizer_config.json", "special_tokens_map.json", "vocab.json",
|
| 505 |
-
"merges.txt"):
|
| 506 |
-
src = os.path.join(args.root, fn)
|
| 507 |
-
if os.path.exists(src):
|
| 508 |
-
_sh.copy(src, out)
|
| 509 |
-
shipped.append(fn)
|
| 510 |
-
say(f"tokenizer files shipped with the export: {shipped or 'NONE -- Phase 5 must add them'}")
|
| 511 |
-
SD.save_cursor(out, SD.cursor_dict(args.seq_len, samples, args.data_seed, fingerprint, step=step))
|
| 512 |
-
json.dump({"step": step, "start_step": start_step, "tokens_consumed": consumed,
|
| 513 |
-
"tokens_this_run": consumed_this_run, "seconds": round(elapsed, 1),
|
| 514 |
-
"params": pc, "fingerprint": fingerprint, "final_loss": final_loss,
|
| 515 |
-
"prior_loss": prior, "samples_consumed": samples, "steps_planned": steps_planned},
|
| 516 |
-
open(os.path.join(out, "run_summary.json"), "w"), indent=1, sort_keys=True)
|
| 517 |
ppl = None
|
| 518 |
try:
|
| 519 |
ev = tr.evaluate()
|
|
@@ -521,9 +503,39 @@ def main():
|
|
| 521 |
say(f"validation loss={ev['eval_loss']:.4f} ppl={ppl:.2f} over {n_val} held-out windows")
|
| 522 |
except Exception as e:
|
| 523 |
say(f"validation eval failed: {type(e).__name__}: {str(e)[:200]}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
segment = bool(hub_cb and hub_cb.stopped_at and step < steps_planned)
|
| 525 |
-
if api is not None and not segment:
|
| 526 |
-
r = hubckpt.push_and_prune(args.hub_repo,
|
| 527 |
token=os.environ.get("HF_TOKEN"), prune=args.prune)
|
| 528 |
# .get, not [k]: `pruned` and `free_after_gb` are only present on some paths through
|
| 529 |
# push_and_prune, and a KeyError here would throw away a completed run (E-023).
|
|
|
|
| 495 |
if final_loss is None or not math.isfinite(final_loss):
|
| 496 |
raise SystemExit(f"final loss is not finite ({final_loss}) -- not exporting anything")
|
| 497 |
|
| 498 |
+
# Validation first, and on every rank: `evaluate()` is collective, so gating it would deadlock.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 499 |
ppl = None
|
| 500 |
try:
|
| 501 |
ev = tr.evaluate()
|
|
|
|
| 503 |
say(f"validation loss={ev['eval_loss']:.4f} ppl={ppl:.2f} over {n_val} held-out windows")
|
| 504 |
except Exception as e:
|
| 505 |
say(f"validation eval failed: {type(e).__name__}: {str(e)[:200]}")
|
| 506 |
+
|
| 507 |
+
# Everything below writes files, so it is rank 0's alone (E-029). Two ranks building the same export
|
| 508 |
+
# directory is a write race: `shutil.copy(src, out)` with `out` not yet created writes a regular FILE
|
| 509 |
+
# called `final` where rank 0 is making a directory of the same name, and the observed result was
|
| 510 |
+
# `training_args.bin` vanishing mid-hash -- which killed a fully trained, fully checkpointed leg on
|
| 511 |
+
# its last line. The variable is also no longer called `out`, which until now meant both the run
|
| 512 |
+
# directory and the export inside it.
|
| 513 |
+
exp = os.path.join(args.out, "final")
|
| 514 |
+
if rank == 0:
|
| 515 |
+
tr.save_model(exp)
|
| 516 |
+
# The tokenizer travels with the run so `final/` is loadable by AutoTokenizer on its own (§8). If
|
| 517 |
+
# it is not in the mix root, say so in the summary instead of skipping quietly and being surprised.
|
| 518 |
+
shipped = []
|
| 519 |
+
import shutil as _sh
|
| 520 |
+
os.makedirs(exp, exist_ok=True)
|
| 521 |
+
for fn in ("tokenizer.json", "tokenizer_config.json", "special_tokens_map.json", "vocab.json",
|
| 522 |
+
"merges.txt"):
|
| 523 |
+
src = os.path.join(args.root, fn)
|
| 524 |
+
if os.path.exists(src):
|
| 525 |
+
_sh.copy(src, exp)
|
| 526 |
+
shipped.append(fn)
|
| 527 |
+
say(f"tokenizer files shipped with the export: {shipped or 'NONE -- Phase 5 must add them'}")
|
| 528 |
+
SD.save_cursor(exp, SD.cursor_dict(args.seq_len, samples, args.data_seed, fingerprint,
|
| 529 |
+
step=step))
|
| 530 |
+
json.dump({"step": step, "start_step": start_step, "tokens_consumed": consumed,
|
| 531 |
+
"tokens_this_run": consumed_this_run, "seconds": round(elapsed, 1),
|
| 532 |
+
"params": pc, "fingerprint": fingerprint, "final_loss": final_loss,
|
| 533 |
+
"prior_loss": prior, "samples_consumed": samples,
|
| 534 |
+
"steps_planned": steps_planned},
|
| 535 |
+
open(os.path.join(exp, "run_summary.json"), "w"), indent=1, sort_keys=True)
|
| 536 |
segment = bool(hub_cb and hub_cb.stopped_at and step < steps_planned)
|
| 537 |
+
if api is not None and not segment and rank == 0:
|
| 538 |
+
r = hubckpt.push_and_prune(args.hub_repo, exp, "final", api, repo_type=args.hub_repo_type,
|
| 539 |
token=os.environ.get("HF_TOKEN"), prune=args.prune)
|
| 540 |
# .get, not [k]: `pruned` and `free_after_gb` are only present on some paths through
|
| 541 |
# push_and_prune, and a KeyError here would throw away a completed run (E-023).
|