Cion-lab commited on
Commit
e11176d
·
verified ·
1 Parent(s): 86efd09

Upload train/train_ounce100m.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. 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
- out = os.path.join(args.out, "final")
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, out, "final", api, repo_type=args.hub_repo_type,
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).