Upload src/xscript/schedule.py with huggingface_hub
Browse files- src/xscript/schedule.py +50 -0
src/xscript/schedule.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Learning-rate and checkpoint schedules (token-indexed).
|
| 2 |
+
|
| 3 |
+
WSD (warmup-stable-decay): a long constant-LR trunk lets us checkpoint a
|
| 4 |
+
`stable` point and later branch a cheap cooldown to any token budget without
|
| 5 |
+
retraining the trunk -- the mechanism the plan uses to extend 4 runs to 100B.
|
| 6 |
+
|
| 7 |
+
All schedules are pure functions of tokens-seen-in-this-trajectory, so a
|
| 8 |
+
cooldown branch is just a run whose schedule has warmup=stable=0.
|
| 9 |
+
"""
|
| 10 |
+
import math
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
def lr_at(t: float, sched: dict) -> float:
|
| 14 |
+
peak, mn = sched["peak_lr"], sched.get("min_lr", 0.0)
|
| 15 |
+
w = sched.get("warmup_tokens", 0)
|
| 16 |
+
s = sched.get("stable_tokens", 0)
|
| 17 |
+
d = sched.get("decay_tokens", 0)
|
| 18 |
+
if t < w:
|
| 19 |
+
return peak * t / max(w, 1)
|
| 20 |
+
if t < w + s:
|
| 21 |
+
return peak
|
| 22 |
+
if t < w + s + d:
|
| 23 |
+
prog = (t - w - s) / max(d, 1)
|
| 24 |
+
shape = sched.get("decay_shape", "1-sqrt")
|
| 25 |
+
if shape == "linear":
|
| 26 |
+
f = 1.0 - prog
|
| 27 |
+
elif shape == "cosine":
|
| 28 |
+
f = 0.5 * (1.0 + math.cos(math.pi * prog))
|
| 29 |
+
else: # "1-sqrt" (MiniCPM WSD; empirically strong)
|
| 30 |
+
f = 1.0 - math.sqrt(prog)
|
| 31 |
+
return mn + (peak - mn) * f
|
| 32 |
+
return mn
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
def total_tokens(sched: dict) -> float:
|
| 36 |
+
return (sched.get("warmup_tokens", 0) + sched.get("stable_tokens", 0)
|
| 37 |
+
+ sched.get("decay_tokens", 0))
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def stable_end_tokens(sched: dict) -> float:
|
| 41 |
+
"""Token count at which the trunk's decay begins (branch point)."""
|
| 42 |
+
return sched.get("warmup_tokens", 0) + sched.get("stable_tokens", 0)
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def ckpt_interval(tokens: float, table: list) -> float:
|
| 46 |
+
"""Log-spaced checkpoint interval: dense early, sparse late."""
|
| 47 |
+
for up_to, interval in table:
|
| 48 |
+
if tokens < up_to:
|
| 49 |
+
return interval
|
| 50 |
+
return table[-1][1]
|