Download tests/analyze_benchmark.py from logos42/headless: direct link, hf CLI and curl.
- Browser
- Download file 9.79 kB
-
https://huggingface.co/logos42/headless/resolve/main/tests/analyze_benchmark.py
- Command line
-
hf download hf://logos42/headless/tests/analyze_benchmark.py
-
curl -L -o analyze_benchmark.py https://huggingface.co/logos42/headless/resolve/main/tests/analyze_benchmark.py
9.79 kB
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """LM4 修正版 benchmark 汇总: 任务流 + 调度臂, 报边缘设备关心的指标。 | |
| 路径前缀同时覆盖两批 (2026-09-14): | |
| - `bm_bins_*` 任务流臂 (不受价值函数 bug 影响) | |
| - `bm2_*` 修正版价值函数臂 (con 实现 / sim 自适应 / 池 60) | |
| 指标: | |
| replay 最终平均准确率 | |
| any_time 在线全程平均 (边学边可用) | |
| worst_forget 最差遗忘界 (任一旧任务的最大跌幅; 安全功能不能崩) | |
| mean_forget 平均遗忘 | |
| 统计口径: | |
| mean±std 用样本标准差 (ddof=1); 两两对比用 Welch t + Welch–Satterthwaite 自由度, | |
| 双侧 p 由 t 分布精确算 (无 scipy 依赖)。判定阈值 |t| >= 2 —— n=3 时只算边缘证据。 | |
| 已知数据缺口 (见 docs/bm_benchmark_results.md §0): | |
| lm4 `bm2_random-matched_s*` 的 json 被 int64 序列化 bug 截断 → 回退读 `lm4_wave_report.md` | |
| (只有 replay / 平均遗忘), any-time 与最差遗忘界缺失。 | |
| """ | |
| import glob | |
| import json | |
| import math | |
| import os | |
| import numpy as np | |
| R = "/work/liuyuanjie/headless/results" | |
| SEEDS = ["42", "1", "7"] | |
| # ---------------- 统计 ---------------- | |
| def _betacf(a, b, x): | |
| MAXIT, EPS, FPMIN = 200, 3e-16, 1e-300 | |
| qab, qap, qam = a + b, a + 1.0, a - 1.0 | |
| c, d = 1.0, 1.0 - qab * x / qap | |
| if abs(d) < FPMIN: | |
| d = FPMIN | |
| d = 1.0 / d | |
| h = d | |
| for m in range(1, MAXIT + 1): | |
| m2 = 2 * m | |
| aa = m * (b - m) * x / ((qam + m2) * (a + m2)) | |
| d = 1.0 + aa * d | |
| if abs(d) < FPMIN: | |
| d = FPMIN | |
| c = 1.0 + aa / c | |
| if abs(c) < FPMIN: | |
| c = FPMIN | |
| d = 1.0 / d | |
| h *= d * c | |
| aa = -(a + m) * (qab + m) * x / ((a + m2) * (qap + m2)) | |
| d = 1.0 + aa * d | |
| if abs(d) < FPMIN: | |
| d = FPMIN | |
| c = 1.0 + aa / c | |
| if abs(c) < FPMIN: | |
| c = FPMIN | |
| d = 1.0 / d | |
| de = d * c | |
| h *= de | |
| if abs(de - 1.0) < EPS: | |
| break | |
| return h | |
| def _betai(a, b, x): | |
| if x <= 0: | |
| return 0.0 | |
| if x >= 1: | |
| return 1.0 | |
| lb = math.lgamma(a + b) - math.lgamma(a) - math.lgamma(b) | |
| bt = math.exp(lb + a * math.log(x) + b * math.log(1 - x)) | |
| if x < (a + 1) / (a + b + 2): | |
| return bt * _betacf(a, b, x) / a | |
| return 1.0 - bt * _betacf(b, a, 1 - x) / b | |
| def welch(a, b): | |
| """Welch t 检验; 返回 Δ / SE / t / df / p(双侧), 样本 < 2 则返回 None。""" | |
| a = [x for x in a if x is not None and x == x] | |
| b = [x for x in b if x is not None and x == x] | |
| if len(a) < 2 or len(b) < 2: | |
| return None | |
| ma, mb = float(np.mean(a)), float(np.mean(b)) | |
| va, vb = float(np.var(a, ddof=1)), float(np.var(b, ddof=1)) | |
| na, nb = len(a), len(b) | |
| se = math.sqrt(va / na + vb / nb) | |
| if se == 0: | |
| return dict(delta=ma - mb, se=0.0, t=float("nan"), df=float("nan"), p=float("nan")) | |
| t = (ma - mb) / se | |
| df = (va / na + vb / nb) ** 2 / ((va / na) ** 2 / (na - 1) + (vb / nb) ** 2 / (nb - 1)) | |
| return dict(delta=ma - mb, se=se, t=t, df=df, p=_betai(df / 2.0, 0.5, df / (df + t * t))) | |
| # ---------------- 装载 ---------------- | |
| def _clean(x): | |
| if x is None: | |
| return None | |
| try: | |
| x = float(x) | |
| except Exception: | |
| return None | |
| return None if x != x else x | |
| def load(pat): | |
| """pat 形如 'bm2_value_s{s}'; 返回 {seed: {...}}。json 坏了则回退 report.md。""" | |
| out = {} | |
| for s in SEEDS: | |
| d = os.path.join(R, pat.format(s=s)) | |
| if not os.path.isdir(d): | |
| continue | |
| rec = None | |
| p = os.path.join(d, "lm4_wave_results.json") | |
| if os.path.exists(p): | |
| try: | |
| r = (json.load(open(p)) or {}).get("replay") or {} | |
| rec = { | |
| "replay": _clean(r.get("final_mean_acc")), | |
| "any_time": _clean(r.get("any_time_acc")), | |
| "worst": _clean(r.get("worst_case_forget")), | |
| "mean_f": _clean(r.get("mean_forget_all")), | |
| "src": "json", | |
| } | |
| except Exception: | |
| rec = None | |
| if rec is None: | |
| rp = os.path.join(d, "lm4_wave_report.md") | |
| if os.path.exists(rp): | |
| for line in open(rp): | |
| c = [x.strip() for x in line.strip().strip("|").split("|")] | |
| if len(c) == 3 and c[0] == "replay": | |
| try: | |
| rec = {"replay": float(c[1]), "mean_f": float(c[2]), | |
| "any_time": None, "worst": None, "src": "report.md"} | |
| except Exception: | |
| pass | |
| if rec: | |
| out[s] = rec | |
| return out | |
| ARMS = [ | |
| ("启发式 fixed 域序", "bm_bins_fixed_s{s}"), | |
| ("流: perm (随机排列)", "bm_bins_perm_s{s}"), | |
| ("流: revisit (反复)", "bm_bins_revisit_s{s}"), | |
| ("流: nonstationary", "bm_bins_nonstationary_s{s}"), | |
| ("★ 价值函数 value", "bm2_value_s{s}"), | |
| (" 消融 value-nofb", "bm2_value-nofb_s{s}"), | |
| (" 均匀随机 random", "bm2_random_s{s}"), | |
| ("★ 频率对齐 random-matched", "bm2_random-matched_s{s}"), | |
| ] | |
| # lm4 `random-matched` 原 driver 的 json 全部被 int64 bug 截断, 且 seed 1/7 的结果文件 | |
| # 事后被另一路会话用**改过的脚本**重跑覆盖过。主口径取"与 value 臂同修订版"的原日志值 | |
| # (seed 42 已用 不带 default= 的反向修复独立复现, 逐位相同), 其余作敏感性对照。 | |
| RM_MATCHED_ORIG = {"42": (0.7635, 0.1178), "1": (0.7542, 0.1982), "7": (0.7594, 0.1116)} | |
| USE_ORIG_RM = os.environ.get("BM_RM_SENSITIVITY", "0") != "1" | |
| if USE_ORIG_RM: | |
| _old = load("bm2_random-matched_s{s}") | |
| _patched = {} | |
| for s, (acc, mf) in RM_MATCHED_ORIG.items(): | |
| # any_time / worst 原 json 被截断, 且目录值已被新修订版覆盖 -> 主口径留空, | |
| # 不拿"混合修订版"的数字充数 (想看被覆盖后的值: BM_RM_SENSITIVITY=1) | |
| rec = dict(_old.get(s) or {}) | |
| rec.update({"replay": acc, "mean_f": mf, "any_time": None, "worst": None, | |
| "src": "bm2.log (同修订版)"}) | |
| _patched[s] = rec | |
| _load = load | |
| def load(pat, _p=_patched, _l=_load): # noqa: F811 | |
| if pat == "bm2_random-matched_s{s}": | |
| return _p | |
| return _l(pat) | |
| def fmt(vals): | |
| v = [x for x in vals if x is not None] | |
| if not v: | |
| return "-" | |
| if len(v) == 1: | |
| return "%.4f" % v[0] | |
| return "%.4f±%.4f" % (np.mean(v), np.std(v, ddof=1)) | |
| print("=" * 104) | |
| print("LM4 修正版 benchmark · 任务流 + 调度臂 (12 轮 × 3 seed, 6 域, replay)") | |
| print(" 主口径: bm_bins_* (任务流) + bm2_* (修正版价值函数); random-matched = 同修订版日志值") | |
| print(" 设 BM_RM_SENSITIVITY=1 可改用被覆盖后的目录值 (敏感性对照)") | |
| print("=" * 104) | |
| print() | |
| print(" %-26s %-20s %-20s %-14s %-12s %s" % | |
| ("臂", "replay mean±std", "any-time mean±std", "最差遗忘界", "平均遗忘", "n")) | |
| print(" " + "-" * 98) | |
| rows = {} | |
| recs = {} | |
| for name, pat in ARMS: | |
| d = load(pat) | |
| recs[name] = d | |
| if not d: | |
| print(" %-26s (无结果)" % name) | |
| continue | |
| rep = [v["replay"] for v in d.values()] | |
| ant = [v["any_time"] for v in d.values()] | |
| wst = [v["worst"] for v in d.values()] | |
| mf = [v["mean_f"] for v in d.values()] | |
| rep_v = [x for x in rep if x is not None] | |
| cv = 100 * np.std(rep_v, ddof=1) / max(1e-9, abs(np.mean(rep_v))) if len(rep_v) > 1 else float("nan") | |
| rows[name] = (np.mean(rep_v) if rep_v else np.nan, | |
| np.std(rep_v, ddof=1) if len(rep_v) > 1 else 0.0, len(rep_v)) | |
| print(" %-26s %-20s %-20s %-14s %-12s %d (CV %4.1f%%)" % | |
| (name, fmt(rep), fmt(ant), | |
| ("%.4f" % np.mean([x for x in wst if x is not None])) if any(x is not None for x in wst) else "-", | |
| ("%.4f" % np.mean([x for x in mf if x is not None])) if any(x is not None for x in mf) else "-", | |
| len(rep_v), cv)) | |
| src = sorted(set(v["src"] for v in d.values())) | |
| if src != ["json"]: | |
| print(" %-26s ↳ 数据来源: %s | 逐 seed: %s" % | |
| ("", ",".join(src), {s: (round(v["replay"], 4) if v["replay"] is not None else None) | |
| for s, v in d.items()})) | |
| print() | |
| print(" ── 关键对比 (Welch t, ddof=1; |t|>=2 判显著) ──") | |
| def cmp(a, b, key="replay"): | |
| da, db = recs.get(a), recs.get(b) | |
| if not da or not db: | |
| return " %-30s vs %-30s (数据不全)" % (a, b) | |
| A = [da[s][key] for s in SEEDS if s in da] | |
| B = [db[s][key] for s in SEEDS if s in db] | |
| w = welch(A, B) | |
| if not w: | |
| return " %-30s vs %-30s (样本不足: %d vs %d)" % (a, b, len(A), len(B)) | |
| return (" %-30s vs %-30s [%-7s] Δ=%+.4f SE=%.4f t=%+.2f df=%.1f p=%.4f -> %s" % | |
| (a, b, key, w["delta"], w["se"], w["t"], w["df"], w["p"], | |
| "★显著" if abs(w["t"]) >= 2 else "不显著")) | |
| for a, b in [("★ 价值函数 value", "★ 频率对齐 random-matched"), | |
| ("★ 价值函数 value", " 均匀随机 random"), | |
| ("★ 价值函数 value", " 消融 value-nofb"), | |
| ("★ 价值函数 value", "流: perm (随机排列)"), | |
| ("启发式 fixed 域序", "流: perm (随机排列)")]: | |
| for key in ("replay", "any_time"): | |
| print(cmp(a, b, key)) | |
| print() | |
| print(" 判读要点: `value` vs `random-matched` 才是「价值函数是否更聪明」的干净对照;") | |
| print(" `value` vs `random` 混淆了「更聪明」与「复习更均匀」。") | |
| print(" 注意 `random` 臂三 seed 几乎相同 (CV ~0), 其 t 值会被虚假放大, 不作为结论。") | |