Upload scripts/mk_lineage.py with huggingface_hub
Browse files- scripts/mk_lineage.py +94 -0
scripts/mk_lineage.py
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Standalone lineage loss plot: every training stage this 1.06B model has been
|
| 3 |
+
through, forking at ext64k step 695 into the two 64k runs.
|
| 4 |
+
|
| 5 |
+
100% b5 -> collapsed (cliff at step 1199, ended 45/17/2/1)
|
| 6 |
+
MIX 50/30/20 -> this run
|
| 7 |
+
|
| 8 |
+
Loss curves come from each stage's own training log; nothing is transcribed.
|
| 9 |
+
"""
|
| 10 |
+
import json, math, os, re, statistics as st
|
| 11 |
+
import matplotlib; matplotlib.use("Agg")
|
| 12 |
+
import matplotlib.pyplot as plt
|
| 13 |
+
|
| 14 |
+
S={"surface":"#fcfcfb","ink":"#0b0b0b","ink2":"#52514e","grid":"#e4e4e1"}
|
| 15 |
+
PURE="#b3243b"; MIX="#12508f"; PARENT="#eb6834"
|
| 16 |
+
R="mix64k_ref"
|
| 17 |
+
klab=lambda v:(f"{round(v/1024)}k" if v>=1024 else str(int(v)))
|
| 18 |
+
|
| 19 |
+
def rows_of(p):
|
| 20 |
+
try: t=open(p,errors="ignore").read()
|
| 21 |
+
except Exception: return []
|
| 22 |
+
return [(int(a),float(b)) for a,b in re.findall(r"^step +(\d+) \| loss: ([0-9.]+)",t,re.M)]
|
| 23 |
+
|
| 24 |
+
def roll(rows,k=50):
|
| 25 |
+
d=dict(rows); xs=[];ys=[]
|
| 26 |
+
for s,_ in rows:
|
| 27 |
+
w=[d[j] for j in range(s-k+1,s+1) if j in d]
|
| 28 |
+
if len(w)==k: xs.append(s); ys.append(sum(w)/k)
|
| 29 |
+
return xs,ys
|
| 30 |
+
|
| 31 |
+
stages=json.load(open(f"{R}/lineage/stages.json"))
|
| 32 |
+
ORDER=[("base pretrain",4096,"#8e8e88"),("l2 16k bucket",16384,"#9dc3ea"),
|
| 33 |
+
("ext32k",32768,"#4a8fd4"),("b4 full epoch",32768,"#12508f"),("ext64k",65536,PARENT)]
|
| 34 |
+
pr=rows_of(f"{R}/cont64k_purec5.log"); mr=rows_of("mix64k_logs/train.log")
|
| 35 |
+
|
| 36 |
+
fig,(axA,axB)=plt.subplots(2,1,figsize=(11.5,9.2),facecolor=S["surface"],
|
| 37 |
+
gridspec_kw={"height_ratios":[1.2,1],"hspace":0.26},sharex=True)
|
| 38 |
+
off=0; spans=[]
|
| 39 |
+
for name,ctx,col in ORDER:
|
| 40 |
+
stg=stages.get(name)
|
| 41 |
+
if not stg: continue
|
| 42 |
+
rw=stg["rows"]; b=rw[0][0]
|
| 43 |
+
xs=[off+(r[0]-b) for r in rw]; ys=[r[1] for r in rw]
|
| 44 |
+
for ax in (axA,axB):
|
| 45 |
+
ax.plot(xs,ys,color=col,lw=.8,alpha=.85,zorder=3,
|
| 46 |
+
label=(f"{name} ({klab(ctx)})" if ax is axA else None))
|
| 47 |
+
spans.append((off,xs[-1],name,col)); off=xs[-1]
|
| 48 |
+
fork=off
|
| 49 |
+
for rw,col,lab,lw in ((pr,PURE,"100% b5 -> COLLAPSED",1.5),(mr,MIX,"MIX 50/30/20 -> this run",1.9)):
|
| 50 |
+
if not rw: continue
|
| 51 |
+
xs=[fork+s for s,_ in rw]; ys=[l for _,l in rw]
|
| 52 |
+
for ax in (axA,axB): ax.plot(xs,ys,color=col,lw=.45,alpha=.22,zorder=2)
|
| 53 |
+
rx,ry=roll(rw)
|
| 54 |
+
for ax in (axA,axB):
|
| 55 |
+
ax.plot([fork+x for x in rx],ry,color=col,lw=lw,zorder=5,
|
| 56 |
+
label=(lab+" (50-step mean)" if ax is axA else None))
|
| 57 |
+
spans.append((fork,fork+rw[-1][0],lab.split(" ->")[0],col))
|
| 58 |
+
|
| 59 |
+
ends=[stages[n]["rows"][-1][1] for n,_,_ in ORDER if n in stages]
|
| 60 |
+
lo,hi=min(ends),max(ends)
|
| 61 |
+
for ax in (axA,axB):
|
| 62 |
+
ax.axvline(fork,color=S["ink2"],lw=1.1,ls="--",alpha=.75,zorder=4)
|
| 63 |
+
ax.set_facecolor(S["surface"]); ax.grid(True,color=S["grid"],lw=.8,zorder=0); ax.set_axisbelow(True)
|
| 64 |
+
for k,sp in ax.spines.items(): sp.set_visible(k in ("left","bottom")); sp.set_color(S["grid"])
|
| 65 |
+
ax.tick_params(colors=S["ink2"],labelsize=9)
|
| 66 |
+
axA.set_yscale("log"); axA.set_ylim(0.9,13)
|
| 67 |
+
axA.set_yticks([1,2,3,5,10]); axA.set_yticklabels(["1","2","3","5","10"])
|
| 68 |
+
axA.set_ylabel("loss (nats, log)",color=S["ink2"],fontsize=10)
|
| 69 |
+
# axA.set_title("Every stage this 1.06B model has been through -- and where the two 64k runs diverge",
|
| 70 |
+
# color=S["ink"],fontsize=12.5,loc="left",pad=12)
|
| 71 |
+
# axA.annotate("both 64k runs fork here\n(ext64k step 695, 67/65/52/29)",xy=(fork,8.2),
|
| 72 |
+
# xytext=(fork*0.50,8.6),fontsize=8.8,color=S["ink2"],
|
| 73 |
+
# arrowprops=dict(arrowstyle="->",color=S["ink2"],lw=.9))
|
| 74 |
+
axA.legend(frameon=False,fontsize=8.2,labelcolor=S["ink2"],loc="lower left",ncol=2)
|
| 75 |
+
axB.axhspan(lo,hi,color="#7a9a3a",alpha=.13,zorder=1)
|
| 76 |
+
# axB.annotate(f"every stage before the fork ends in {lo:.2f}-{hi:.2f}\nthe MIX stays in the band; 100% b5 leaves it and never returns",
|
| 77 |
+
# xy=(fork+1300,1.30),xytext=(off*0.06,1.18),fontsize=8.8,color="#5d7a22",
|
| 78 |
+
# arrowprops=dict(arrowstyle="->",color="#7a9a3a",lw=1.0,alpha=.85))
|
| 79 |
+
axB.set_ylim(1.0,3.5); axB.set_ylabel("loss (nats)",color=S["ink2"],fontsize=10)
|
| 80 |
+
axB.set_xlabel("cumulative training step across the lineage",color=S["ink2"],fontsize=10)
|
| 81 |
+
for s,e,name,col in spans:
|
| 82 |
+
axB.text((s+e)/2,3.38,name,ha="center",fontsize=7.4,color=col)
|
| 83 |
+
fig.savefig("mix64k_lineage.png",dpi=140,facecolor=S["surface"],bbox_inches="tight")
|
| 84 |
+
print(f" wrote mix64k_lineage.png ({os.path.getsize('mix64k_lineage.png')//1024} KB)")
|
| 85 |
+
print(f"\n {'stage':<26}{'window':>8}{'steps':>7}{'first':>9}{'last':>8}")
|
| 86 |
+
for n,c,_ in ORDER:
|
| 87 |
+
if n in stages:
|
| 88 |
+
rw=stages[n]["rows"]; print(f" {n:<26}{klab(c):>8}{len(rw):>7}{rw[0][1]:>9.3f}{rw[-1][1]:>8.3f}")
|
| 89 |
+
for rw,n in ((pr,"100% b5 (collapsed)"),(mr,"MIX (this run)")):
|
| 90 |
+
if rw: print(f" {n:<26}{'64k':>8}{len(rw):>7}{rw[0][1]:>9.3f}{rw[-1][1]:>8.3f}")
|
| 91 |
+
print(f"\n pre-fork stages end in {lo:.3f}-{hi:.3f}")
|
| 92 |
+
if mr:
|
| 93 |
+
d=dict(mr); mx=max(d); w=[d[k] for k in range(mx-49,mx+1) if k in d]
|
| 94 |
+
print(f" MIX rolling-50 at step {mx}: {st.mean(w):.3f} (pure-b5 was 1.80 by here)")
|