Upload scripts/mk_p1_plots.py with huggingface_hub
Browse files- scripts/mk_p1_plots.py +145 -0
scripts/mk_p1_plots.py
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""Phase-1 (680M, 4k->16k) plots: training lineage + NIAH eval.
|
| 3 |
+
|
| 4 |
+
Every number is read from a file. The 1.06B reference points come from the
|
| 5 |
+
summary.csv files this project already published to HF (ref680/logs/...), not
|
| 6 |
+
from anything transcribed by hand.
|
| 7 |
+
|
| 8 |
+
fig 1 p1_lineage.png training loss across the 680M lineage
|
| 9 |
+
fig 2 p1_results.png niah_single accuracy vs prompt length, Wilson 95% CI
|
| 10 |
+
"""
|
| 11 |
+
import csv, math, os, re, sys
|
| 12 |
+
import matplotlib; matplotlib.use("Agg")
|
| 13 |
+
import matplotlib.pyplot as plt
|
| 14 |
+
|
| 15 |
+
S = {"surface":"#fcfcfb","ink":"#0b0b0b","ink2":"#52514e","grid":"#e4e4e1"}
|
| 16 |
+
C680, CBASE = "#12508f", "#9dc3ea"
|
| 17 |
+
CPAR, CMIX, CPURE = "#eb6834", "#b3243b", "#8e8e88"
|
| 18 |
+
klab = lambda v: (f"{round(v/1024)}k" if v >= 1024 else str(int(v)))
|
| 19 |
+
|
| 20 |
+
def wilson(k, n, z=1.96):
|
| 21 |
+
if not n: return (0.0, 0.0, 0.0)
|
| 22 |
+
p = k/n; d = 1 + z*z/n
|
| 23 |
+
c = (p + z*z/(2*n))/d
|
| 24 |
+
h = z*math.sqrt(p*(1-p)/n + z*z/(4*n*n))/d
|
| 25 |
+
return (100*p, 100*max(0,c-h), 100*min(1,c+h))
|
| 26 |
+
|
| 27 |
+
def style(ax):
|
| 28 |
+
ax.set_facecolor(S["surface"])
|
| 29 |
+
for s in ax.spines.values(): s.set_color(S["grid"])
|
| 30 |
+
ax.grid(True, color=S["grid"], lw=.7, alpha=.9)
|
| 31 |
+
ax.tick_params(colors=S["ink2"], labelsize=9)
|
| 32 |
+
|
| 33 |
+
# ---------------------------------------------------------------- fig 1: loss
|
| 34 |
+
rows = []
|
| 35 |
+
CSVP = "CP_BluScreipt_Training_logs/CP_Training_log12.csv"
|
| 36 |
+
if os.path.exists(CSVP):
|
| 37 |
+
for r in csv.DictReader(open(CSVP)):
|
| 38 |
+
try: rows.append((int(r["step"]), float(r["train_loss"]), float(r["val_loss"] or 0)))
|
| 39 |
+
except Exception: pass
|
| 40 |
+
if not rows: # fall back to the text log
|
| 41 |
+
t = open("p1_logs/train.log", errors="ignore").read()
|
| 42 |
+
rows = [(int(a), float(b), 0.0) for a,b in
|
| 43 |
+
re.findall(r"^step +(\d+) \| loss: ([0-9.]+)", t, re.M)]
|
| 44 |
+
if not rows:
|
| 45 |
+
sys.exit("no training rows found -- nothing to plot")
|
| 46 |
+
|
| 47 |
+
xs = [r[0] for r in rows]; ys = [r[1] for r in rows]
|
| 48 |
+
d = {s:l for s,l,_ in rows}
|
| 49 |
+
rx, ry = [], []
|
| 50 |
+
for s in xs:
|
| 51 |
+
w = [d[j] for j in range(s-49, s+1) if j in d]
|
| 52 |
+
if len(w) == 50: rx.append(s); ry.append(sum(w)/50)
|
| 53 |
+
# val only where it CHANGES (the trainer carries the last value forward)
|
| 54 |
+
vx, vy, prev = [], [], None
|
| 55 |
+
for s,_,v in rows:
|
| 56 |
+
if v and v != prev: vx.append(s); vy.append(v); prev = v
|
| 57 |
+
|
| 58 |
+
fig, ax = plt.subplots(figsize=(11.5,5.6), facecolor=S["surface"])
|
| 59 |
+
ax.plot(xs, ys, color=C680, lw=.6, alpha=.30)
|
| 60 |
+
ax.plot(rx, ry, color=C680, lw=2.0, label="phase 1 4k -> 16k (50-step mean)")
|
| 61 |
+
if vx: ax.plot(vx, vy, "o--", color=CPAR, ms=4.5, lw=1.1, label="validation loss")
|
| 62 |
+
style(ax)
|
| 63 |
+
ax.set_xlabel("step", color=S["ink2"], fontsize=10)
|
| 64 |
+
ax.set_ylabel("loss (nats)", color=S["ink2"], fontsize=10)
|
| 65 |
+
ax.set_title("680M lineage -- phase 1 context extension, 4k -> 16k",
|
| 66 |
+
color=S["ink"], fontsize=13, loc="left", pad=12)
|
| 67 |
+
last = ry[-1] if ry else ys[-1]
|
| 68 |
+
ax.text(.995,.965, f"parent varybatch (10.5 tok/param)\nYaRN 4 x 4096 = 16384\n"
|
| 69 |
+
f"{len(xs)} steps | last 50-step mean {last:.4f}",
|
| 70 |
+
transform=ax.transAxes, ha="right", va="top", fontsize=8.4, color=S["ink2"],
|
| 71 |
+
bbox=dict(fc="white", ec=S["grid"]))
|
| 72 |
+
ax.text(.005,.02, "varybatch's own pretrain curve is not plotted: its training log was "
|
| 73 |
+
"not published with the checkpoint, so the segment is unrecoverable.",
|
| 74 |
+
transform=ax.transAxes, fontsize=7.6, color=S["ink2"], style="italic")
|
| 75 |
+
ax.legend(frameon=False, fontsize=9, labelcolor=S["ink2"], loc="upper right",
|
| 76 |
+
bbox_to_anchor=(.995,.80))
|
| 77 |
+
fig.tight_layout(); fig.savefig("plots_p1/p1_lineage.png", dpi=155)
|
| 78 |
+
print(" wrote plots_p1/p1_lineage.png")
|
| 79 |
+
|
| 80 |
+
# -------------------------------------------------------------- fig 2: evals
|
| 81 |
+
def read_sum(p, col=1):
|
| 82 |
+
if not os.path.exists(p): return None
|
| 83 |
+
for r in csv.reader(open(p)):
|
| 84 |
+
if r and r[0] == "niah_single":
|
| 85 |
+
try: return float(r[col])
|
| 86 |
+
except Exception: return None
|
| 87 |
+
return None
|
| 88 |
+
|
| 89 |
+
LENS = [8192, 16360, 32744, 65512]
|
| 90 |
+
REF = {
|
| 91 |
+
"1.06B ext64k parent (695)": (CPAR, "-", [read_sum(f"ref680/logs/ext64k_len_{L}/summary.csv") for L in LENS]),
|
| 92 |
+
"1.06B mix64k (1200), best": (CMIX, "-", [read_sum(f"ref680/logs/mix64k_1200_len_{L}/summary.csv") for L in LENS]),
|
| 93 |
+
"1.06B mixcont (1400), collapsed":(CPURE, "--", [read_sum(f"ref680/logs/mixcont/cliff1400_len_{L}/summary.csv") for L in LENS]),
|
| 94 |
+
}
|
| 95 |
+
P680 = {}
|
| 96 |
+
for name, key in (("680M phase 1 (1200)","p1final"), ("680M varybatch, zero-shot YaRN","base680")):
|
| 97 |
+
pts = []
|
| 98 |
+
for L in (8192, 16360):
|
| 99 |
+
v = None
|
| 100 |
+
for c in (1,2,3):
|
| 101 |
+
v = read_sum(f"p1_eval_len{L}/summary.csv", c)
|
| 102 |
+
if v is not None: break
|
| 103 |
+
# summary.csv columns are per-model; find this model's column by header
|
| 104 |
+
hp = f"p1_eval_len{L}/summary.csv"
|
| 105 |
+
if os.path.exists(hp):
|
| 106 |
+
hdr = next(csv.reader(open(hp)), [])
|
| 107 |
+
if key in hdr:
|
| 108 |
+
v = read_sum(hp, hdr.index(key))
|
| 109 |
+
pts.append(v)
|
| 110 |
+
P680[name] = pts
|
| 111 |
+
|
| 112 |
+
fig, ax = plt.subplots(figsize=(11.0,6.0), facecolor=S["surface"])
|
| 113 |
+
X = list(range(len(LENS)))
|
| 114 |
+
for name,(col,ls,vals) in REF.items():
|
| 115 |
+
xs_ = [i for i,v in zip(X,vals) if v is not None]
|
| 116 |
+
ys_ = [v for v in vals if v is not None]
|
| 117 |
+
if not ys_: continue
|
| 118 |
+
err = [[v-wilson(round(v),100)[1] for v in ys_],[wilson(round(v),100)[2]-v for v in ys_]]
|
| 119 |
+
ax.errorbar(xs_, ys_, yerr=err, color=col, ls=ls, lw=1.6, marker="o", ms=5,
|
| 120 |
+
capsize=3, alpha=.85, label=name)
|
| 121 |
+
for name,(col,mk) in zip(P680, ((C680,"s"),(CBASE,"^"))):
|
| 122 |
+
vals = P680[name]
|
| 123 |
+
xs_ = [i for i,v in zip(X,vals) if v is not None]
|
| 124 |
+
ys_ = [v for v in vals if v is not None]
|
| 125 |
+
if not ys_:
|
| 126 |
+
continue
|
| 127 |
+
err = [[v-wilson(round(v),100)[1] for v in ys_],[wilson(round(v),100)[2]-v for v in ys_]]
|
| 128 |
+
ax.errorbar(xs_, ys_, yerr=err, color=col, lw=2.4, marker=mk, ms=8, capsize=3, label=name)
|
| 129 |
+
ax.axvspan(1.5, 3.4, color="#f0f0ee", zorder=0)
|
| 130 |
+
ax.text(2.45,.5,"beyond phase 1's 16k window\n(680M not evaluated here)",
|
| 131 |
+
ha="center", fontsize=8.2, color=S["ink2"], style="italic")
|
| 132 |
+
style(ax)
|
| 133 |
+
ax.set_xticks(X); ax.set_xticklabels([klab(L) for L in LENS])
|
| 134 |
+
ax.set_xlim(-.3, 3.4); ax.set_ylim(0, 100)
|
| 135 |
+
ax.set_xlabel("prompt length (tokens)", color=S["ink2"], fontsize=10)
|
| 136 |
+
ax.set_ylabel("niah_single accuracy (%)", color=S["ink2"], fontsize=10)
|
| 137 |
+
ax.set_title("Needle-in-a-haystack retrieval -- 680M phase 1 vs the 1.06B lineage",
|
| 138 |
+
color=S["ink"], fontsize=13, loc="left", pad=12)
|
| 139 |
+
ax.text(.005,-.155,"N=100 per point, greedy, identical haystack (b2 val_shard_00000) and prompts "
|
| 140 |
+
"across every model. Bars are Wilson 95% CI (+/-9-13pp at N=100): "
|
| 141 |
+
"differences inside a bar are not differences.",
|
| 142 |
+
transform=ax.transAxes, fontsize=7.8, color=S["ink2"])
|
| 143 |
+
ax.legend(frameon=False, fontsize=9, labelcolor=S["ink2"], loc="upper right")
|
| 144 |
+
fig.tight_layout(); fig.savefig("plots_p1/p1_results.png", dpi=155, bbox_inches="tight")
|
| 145 |
+
print(" wrote plots_p1/p1_results.png")
|