Upload kernels/phase4_session.py with huggingface_hub
Browse files- kernels/phase4_session.py +50 -23
kernels/phase4_session.py
CHANGED
|
@@ -24,11 +24,15 @@ import sys
|
|
| 24 |
import time
|
| 25 |
|
| 26 |
WORK = "/kaggle/working"
|
|
|
|
| 27 |
MIX_REPO = "Cion-lab/ounce100m-mix-v1"
|
| 28 |
CKPT_REPO = "Cion-lab/ounce100m-ckpt"
|
| 29 |
|
| 30 |
-
# The frozen recipe (D-011, D-012).
|
| 31 |
-
#
|
|
|
|
|
|
|
|
|
|
| 32 |
SEQ_LEN = 1024
|
| 33 |
MICRO_BATCH = 4
|
| 34 |
ACCUM = 32
|
|
@@ -51,24 +55,38 @@ def sh(argv, label, timeout=None, env=None):
|
|
| 51 |
e["PYTHONPATH"] = WORK
|
| 52 |
e.update(env or {})
|
| 53 |
t0 = time.time()
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
print(" |", line[:300], flush=True)
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
print(f"{label}_RC {p.returncode} seconds {round(time.time() - t0, 1)}", flush=True)
|
| 71 |
-
return p.returncode, out
|
| 72 |
|
| 73 |
|
| 74 |
def fetch(rev, want):
|
|
@@ -88,19 +106,28 @@ def fetch(rev, want):
|
|
| 88 |
def plan(start_step, free_gb):
|
| 89 |
"""Largest whole number of checkpoint intervals that fits this session's remaining hours."""
|
| 90 |
seconds_per_ckpt = CKPT_EVERY * TOKENS_PER_STEP / PLANNING_TOK_PER_S
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
| 92 |
n = int(usable * 3600.0 // seconds_per_ckpt)
|
| 93 |
remaining_intervals = max(0, (HORIZON_STEPS - start_step + CKPT_EVERY - 1) // CKPT_EVERY)
|
| 94 |
n = min(n, remaining_intervals)
|
| 95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 96 |
return {"start_step": start_step, "horizon_steps": HORIZON_STEPS, "ckpt_every": CKPT_EVERY,
|
| 97 |
"tokens_per_step": TOKENS_PER_STEP, "planning_tok_per_s": PLANNING_TOK_PER_S,
|
| 98 |
"hours_per_checkpoint_interval": round(seconds_per_ckpt / 3600.0, 3),
|
| 99 |
"session_gpu_hours": SESSION_GPU_HOURS, "quota_left_hours": QUOTA_LEFT_HOURS,
|
| 100 |
"reserve_hours": RESERVE_HOURS, "usable_hours": round(usable, 3),
|
| 101 |
"intervals_this_session": n, "stop_after_steps": stop,
|
| 102 |
-
"
|
| 103 |
-
"
|
|
|
|
|
|
|
| 104 |
"free_gb_before_start": free_gb}
|
| 105 |
|
| 106 |
|
|
|
|
| 24 |
import time
|
| 25 |
|
| 26 |
WORK = "/kaggle/working"
|
| 27 |
+
T0 = time.time() # session start, so every step log line can say how far into the run it is
|
| 28 |
MIX_REPO = "Cion-lab/ounce100m-mix-v1"
|
| 29 |
CKPT_REPO = "Cion-lab/ounce100m-ckpt"
|
| 30 |
|
| 31 |
+
# The frozen recipe (D-011, D-012, D-015). TOKENS_PER_STEP and HORIZON_STEPS below are re-derived here
|
| 32 |
+
# with the same integer arithmetic the trainer uses (`seqs_per_step = micro*world*accum`,
|
| 33 |
+
# `steps_planned = int(tokens/tokens_per_step)` in train_ounce100m.py), so the two agree by construction
|
| 34 |
+
# rather than by copy -- if that formula ever changes in the trainer, change it here too and the mix-size
|
| 35 |
+
# check below will disagree.
|
| 36 |
SEQ_LEN = 1024
|
| 37 |
MICRO_BATCH = 4
|
| 38 |
ACCUM = 32
|
|
|
|
| 55 |
e["PYTHONPATH"] = WORK
|
| 56 |
e.update(env or {})
|
| 57 |
t0 = time.time()
|
| 58 |
+
# Streamed, not buffered: capture_output=True would hold an eleven-hour session's loss curve until
|
| 59 |
+
# the child exited, so nobody could see the run going wrong while it was still running (a review
|
| 60 |
+
# finding; §5 requires monitoring loss on every wake). stderr is merged into stdout so a torchrun
|
| 61 |
+
# child's traceback arrives in the same stream instead of a separate tail that hides it (E-023).
|
| 62 |
+
import threading
|
| 63 |
+
p = subprocess.Popen(argv, cwd=WORK, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
| 64 |
+
text=True, bufsize=1, env=e)
|
| 65 |
+
state = {"killed": False}
|
| 66 |
+
|
| 67 |
+
def _kill():
|
| 68 |
+
state["killed"] = True
|
| 69 |
+
try:
|
| 70 |
+
p.kill()
|
| 71 |
+
except Exception:
|
| 72 |
+
pass
|
| 73 |
+
|
| 74 |
+
timer = threading.Timer(timeout, _kill) if timeout else None
|
| 75 |
+
if timer:
|
| 76 |
+
timer.daemon = True
|
| 77 |
+
timer.start()
|
| 78 |
+
lines = []
|
| 79 |
+
for line in (p.stdout or []):
|
| 80 |
+
lines.append(line.rstrip("\n"))
|
| 81 |
print(" |", line[:300], flush=True)
|
| 82 |
+
rc = p.wait()
|
| 83 |
+
if timer:
|
| 84 |
+
timer.cancel()
|
| 85 |
+
if state["killed"]:
|
| 86 |
+
rc = -9
|
| 87 |
+
print(f"{label}_RC {rc}{' TIMEOUT' if state['killed'] else ''} seconds "
|
| 88 |
+
f"{round(time.time() - t0, 1)} elapsed {round(time.time() - T0)}", flush=True)
|
| 89 |
+
return rc, "\n".join(lines)[-400000:]
|
|
|
|
|
|
|
| 90 |
|
| 91 |
|
| 92 |
def fetch(rev, want):
|
|
|
|
| 106 |
def plan(start_step, free_gb):
|
| 107 |
"""Largest whole number of checkpoint intervals that fits this session's remaining hours."""
|
| 108 |
seconds_per_ckpt = CKPT_EVERY * TOKENS_PER_STEP / PLANNING_TOK_PER_S
|
| 109 |
+
# The reserve comes off the total, not off one term: `min(session, quota - reserve)` let an 11 h
|
| 110 |
+
# session plan 11 h of training and leave nothing for the code fetch, the 2.3 GB mix download, the
|
| 111 |
+
# push/verify cycles and the end-of-run evaluation (review finding).
|
| 112 |
+
usable = max(0.0, min(SESSION_GPU_HOURS, QUOTA_LEFT_HOURS) - RESERVE_HOURS)
|
| 113 |
n = int(usable * 3600.0 // seconds_per_ckpt)
|
| 114 |
remaining_intervals = max(0, (HORIZON_STEPS - start_step + CKPT_EVERY - 1) // CKPT_EVERY)
|
| 115 |
n = min(n, remaining_intervals)
|
| 116 |
+
target = start_step + n * CKPT_EVERY
|
| 117 |
+
# The trainer refuses a --stop-after-steps that is not a whole multiple of its own interval, and
|
| 118 |
+
# 3,814 is not one (3814 % 381 = 385). So the session that would cross the horizon is told to run
|
| 119 |
+
# to it instead -- otherwise the final leg of the run could never be launched.
|
| 120 |
+
stop = 0 if target >= HORIZON_STEPS else min((HORIZON_STEPS // CKPT_EVERY) * CKPT_EVERY, target)
|
| 121 |
return {"start_step": start_step, "horizon_steps": HORIZON_STEPS, "ckpt_every": CKPT_EVERY,
|
| 122 |
"tokens_per_step": TOKENS_PER_STEP, "planning_tok_per_s": PLANNING_TOK_PER_S,
|
| 123 |
"hours_per_checkpoint_interval": round(seconds_per_ckpt / 3600.0, 3),
|
| 124 |
"session_gpu_hours": SESSION_GPU_HOURS, "quota_left_hours": QUOTA_LEFT_HOURS,
|
| 125 |
"reserve_hours": RESERVE_HOURS, "usable_hours": round(usable, 3),
|
| 126 |
"intervals_this_session": n, "stop_after_steps": stop,
|
| 127 |
+
"runs_to_horizon_this_session": stop == 0 and n > 0,
|
| 128 |
+
"tokens_at_stop": (HORIZON_STEPS if stop == 0 else stop) * TOKENS_PER_STEP,
|
| 129 |
+
"pct_of_run_at_stop": round(100.0 * (HORIZON_STEPS if stop == 0 else stop)
|
| 130 |
+
* TOKENS_PER_STEP / TOKENS, 2),
|
| 131 |
"free_gb_before_start": free_gb}
|
| 132 |
|
| 133 |
|