File size: 6,169 Bytes
216004d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | #!/usr/bin/env python3
"""ๅญฆไน ๆ็้ฆๆฌกๆต้็ๅๆ โโ ๅคๆฎๅจ `docs/learning_efficiency_spec.md` ยง4ใ
ๆ ธๅฟๅฏน็
ง: **ๅไธไธช run ๅ
้จๅๆถ่ฎญ็ป `naive` ไธ `replay`** โ ๅคฉ็ถ้
ๅฏน
(ๅ seedใๅๅใๅๆฐๆฎ้กบๅบใๅๆจกๅๅๅงๅ), ๅฏไธ็ๅทฎๅซๆฏ"่ฆไธ่ฆๅคไน ๆงๅ"ใ
ไธปๅคๆฎ = `retention_gain[d] = mean(start_level[kโฅ2]) โ start_level[1]`
โ "้้ๅฐ่ฟไธชๅๆถ, ไฝ ไธไธๆฅๅฐฑไผๅคๅฐ" ็ธๅฏน็ฌฌไธๆฌก็ๆนๅใ
ๅคๆฎ(ไบๅ):
โ ๅกซๅ
้ธ้จ: `_n_visits` ๅ
จ้จ โฅ1 ไธ `steps_to_abs` ้ๅ
จ็ฉบ, ๅฆๅๅค"ๆๆ ๆช้้ๆๅ"
โก ่ฆ็็: ๆฅ `_already_ratio` / `_none_ratio`
โข ไฟ็: `mean(replay โ naive) > 0` ไธ่ชๅฉๆณๅบ้ดไธ็ > 0 โ ๆไฟ็; ๅฆๅ็
งๅฎๅ"ๆ ไฟ็"
"""
from __future__ import annotations
import glob
import json
import random
import statistics as st
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
B = 20000
def load(pat="results/lmeff_s*"):
runs = {}
for d in sorted(glob.glob(str(ROOT / pat))):
f = Path(d) / "lm4_wave_results.json"
if not f.exists():
continue
j = json.load(open(f))
seed = int(Path(d).name.rsplit("_s", 1)[1])
runs[seed] = j
return runs
def rg_of(j, arm):
e = (j.get(arm) or {}).get("efficiency") or {}
return e
def boot_ci(x, n=B, seed=0):
if not x:
return float("nan"), float("nan")
rng = random.Random(seed)
m = []
for _ in range(n):
m.append(st.mean([x[rng.randrange(len(x))] for _ in range(len(x))]))
m.sort()
return m[int(.025 * len(m))], m[int(.975 * len(m))]
runs = load()
print("=" * 92)
print(f"ๅญฆไน ๆ็้ฆๆฌกๆต้ โโ {len(runs)} ไธช run: {sorted(runs)}")
print("=" * 92)
if not runs:
sys.exit("โ ๆฒกๆ็ปๆ็ฎๅฝ")
# โโ โ ๅกซๅ
้ธ้จ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
print("\nโ ๅกซๅ
้ธ้จ")
gate_ok = True
for seed, j in sorted(runs.items()):
for arm in ("naive", "replay"):
e = rg_of(j, arm)
nv = e.get("_n_visits") or {}
if not nv:
print(f" โ seed={seed} {arm}: _n_visits ็ฉบ โ ๆๆ ๆช้้")
gate_ok = False
continue
print(f" seed={seed} {arm:6s} n_visits={nv} already={e.get('_already_ratio'):.3f}"
f" none={e.get('_none_ratio'):.3f} reachable_max={e.get('reachable_max')}")
print(f" โ ๅกซๅ
้ธ้จ: {'PASS' if gate_ok else '**FAIL(ๆๆ ๆช้้ๆๅ)'}")
# โโ โก ไฟ็ๅข็: ้ๅๅฏน็
ง โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
print("\n" + "=" * 92)
print("โก โ
ไฟ็ๅข็ retention_gain โโ naive vs replay(ๅ seed ๅๅ, ๅคฉ็ถ้
ๅฏน)")
print("=" * 92)
pairs = [] # (seed, dom, naive, replay)
doms = set()
for seed, j in sorted(runs.items()):
en, er = rg_of(j, "naive"), rg_of(j, "replay")
rn, rr = en.get("retention_gain") or {}, er.get("retention_gain") or {}
for d in sorted(set(rn) | set(rr), key=lambda x: int(x[1:])):
a, b = rn.get(d), rr.get(d)
if a is None or b is None:
continue
doms.add(d)
pairs.append((seed, d, float(a), float(b)))
print(f"{'ๅ':<8}{'n seed':>7}{'naive ๅๅผ':>12}{'replay ๅๅผ':>13}{'ฮ(replayโnaive)':>18}")
per_dom = {}
for d in sorted(doms, key=lambda x: int(x[1:])):
ps = [(a, b) for _, dd, a, b in pairs if dd == d]
if not ps:
continue
na = st.mean([a for a, _ in ps]); rp = st.mean([b for _, b in ps])
per_dom[d] = (na, rp, len(ps))
print(f"{d:<8}{len(ps):>7}{na:>12.4f}{rp:>13.4f}{rp - na:>+18.4f}")
if pairs:
dn = [a for _, _, a, _ in pairs]
dr = [b for _, _, _, b in pairs]
dif = [b - a for _, _, a, b in pairs]
print(f"\n ๅ
จๅๆฑๆป(n={len(pairs)} ๅฏน):")
print(f" naive ๅๅผ {st.mean(dn):+.4f} (std {st.pstdev(dn):.4f})")
print(f" replay ๅๅผ {st.mean(dr):+.4f} (std {st.pstdev(dr):.4f})")
lo, hi = boot_ci(dif)
n_pos = sum(1 for x in dif if x > 0)
n_neg = sum(1 for x in dif if x < 0)
print(f" ฮ(replayโnaive) = {st.mean(dif):+.4f} ่ชๅฉๆณ 95% CI [{lo:+.4f}, {hi:+.4f}]")
print(f" replay ๆดๅฅฝ็ๅ: {n_pos}/{len(dif)} naive ๆดๅฅฝ: {n_neg} ๅนณ: {len(dif)-n_pos-n_neg}")
print(f" โ โข ๅคๆฎ: mean>0 ไธ CI ไธ็>0 ? "
f"{'**ๆไฟ็**' if (st.mean(dif) > 0 and lo > 0) else '**ๆช่พพๅฐ(็
งๅฎๅ)'}")
# โโ โข ่ตท็นๆฐดๅนณๆฌ่บซ(ไธไพ่ต้ๅผ, ๆด่ดด่ฟ"่ฎฐไฝไบๅคๅฐ") โโโโโโโโโโโโโโโโโ
print("\n" + "=" * 92)
print("โข ่ตท็นๆฐดๅนณ start_level(k=1 vs ไปฅๅ) โโ ็ปๅฏนๅฃๅพ")
print("=" * 92)
print(f"{'ๅ':<8}{'arm':<8}{'k=1 ่ตท็น':>10}{'kโฅ2 ๅๅผ':>11}{'่ตท็นๆๅทฎ':>10}")
for seed, j in sorted(runs.items()):
for arm in ("naive", "replay"):
sl = (rg_of(j, arm).get("start_level") or {})
for d in sorted(sl, key=lambda x: int(x[1:])):
v = sl[d]
ks = sorted(v, key=lambda x: int(x))
first, later = v[ks[0]], [v[k] for k in ks[1:]]
if later:
print(f"{d:<8}{arm:<8}{first:>10.3f}{st.mean(later):>11.3f}"
f"{max(later)-min(later):>10.3f} seed={seed}")
# โโ โฃ ๅ
ถๅฎๅฃๅพ โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
print("\n" + "=" * 92)
print("โฃ ๅ
ถๅฎๅฃๅพ(ๆดๆฐๆ็ / ่ฎฟ้ฎๅ
ๅข็)")
print("=" * 92)
for arm in ("naive", "replay"):
wg, sp = [], []
for seed, j in sorted(runs.items()):
e = rg_of(j, arm)
for d, v in (e.get("within_gain") or {}).items():
wg += list(v.values())
for d, v in (e.get("slope_early") or {}).items():
sp += list(v.values())
print(f" {arm:6s} within_gain ๅๅผ {st.mean(wg):+.5f} (n={len(wg)})"
f" | slope_early ๅๅผ {st.mean(sp):+.6f} (n={len(sp)})")
|