headless / tests /analyze_rl.py
logos42's picture
Upload folder using huggingface_hub
216004d verified
Raw History Blame Contribute Delete
5.6 kB
#!/usr/bin/env python3
"""IDBD vs Autostep vs value 的真实回路对照分析。
回答: **步长分化到底带不带来收益?**
臂:
idbd IDBD, mu=0.05, alpha0=0.2 (我们之前唯一能找到的活点)
auto Autostep, mu=1e-2, alpha0=0.1 (论文推荐默认, **未针对本任务调参**)
auto2 Autostep, mu=0.05, alpha0=0.2 (IDBD 的活点; 看 Autostep 是否不敏感)
value 手工价值函数 (固定公式排序器) —— 已证等价于随机
判据:
1) 步长是否分化: alpha_std > 0 且 max/min > 1.5
2) 分化是否带来收益: 相对 value 的 any_time 提升, Welch t 检验
3) Autostep 是否免调参: 两档 (mu=1e-2/alpha0=0.1) 与 (mu=0.05/alpha0=0.2)
的**表现是否接近** —— 接近 = 免调参成立
4) 可靠标准: std < mean/2
"""
import glob
import json
import math
import os
import re
import sys
import numpy as np
ROOT = sys.argv[1] if len(sys.argv) > 1 else "/work/liuyuanjie/headless"
def t_sf(x, df):
"""t 分布上尾概率 (stdlib 数值积分, 避免依赖 scipy)。"""
if x <= 0:
return 0.5 + (0.5 - t_sf(-x, df))
c = math.gamma((df + 1) / 2) / (math.sqrt(df * math.pi) * math.gamma(df / 2))
n, hi = 20000, x + 60.0
h = (hi - x) / n
s = 0.0
for i in range(n + 1):
t = x + i * h
w = 1 if i in (0, n) else (4 if i % 2 else 2)
s += w * c * (1 + t * t / df) ** (-(df + 1) / 2)
return s * h / 3
rows = {}
for f in glob.glob(os.path.join(ROOT, "results/rl_*/lm4_wave_results.json")):
tag = os.path.basename(os.path.dirname(f))
m = re.match(r"rl_(.+?)_s(\d+)$", tag)
if not m:
continue
arm, seed = m.group(1), int(m.group(2))
try:
d = json.load(open(f))
except Exception as e:
print(" [坏文件]", tag, e)
continue
v = d.get("replay")
if isinstance(v, dict) and v.get("any_time_acc") is not None:
rows.setdefault(arm, []).append((seed, v))
if not rows:
sys.exit("没有可用结果")
print("=" * 100)
print("步长自适应在真实回路的效果 (lm4, replay 臂, stream=revisit, 12 轮)")
print("=" * 100)
print("%-8s %-3s %9s %8s %6s %9s %9s | %-24s %s"
% ("arm", "n", "any_time", "std", "CV%", "replay", "最差遗忘",
"alpha std / max-min", "algo"))
print("-" * 100)
for arm, vs in sorted(rows.items()):
at = np.array([v["any_time_acc"] for _, v in vs], float)
if len(at) < 2:
print("%-8s %-3d %9.4f %8s %6s %9s %9s" % (arm, len(at), at.mean(),
"-", "-", "-", "-") + " (待更多 seed)")
continue
rp = np.array([v["final_mean_acc"] for _, v in vs], float)
wf = np.array([v["worst_case_forget"] for _, v in vs], float)
st = vs[0][1].get("proposer_stats", {})
al = st.get("alpha", {})
cv = 100 * at.std(ddof=1) / at.mean() if len(at) > 1 else float("nan")
print("%-8s %-3d %9.4f %8.4f %6.1f %9.4f %9.4f | %-24s %s"
% (arm, len(at), at.mean(), at.std(ddof=1) if len(at) > 1 else 0, cv,
rp.mean(), wf.mean(),
"%.4f / %.2fx" % (al.get("std", 0), al.get("ratio_max_min", 0)),
st.get("algo", "-")))
print()
print("=== 判据 1: 步长是否分化 (alpha_std>0 且 ratio>1.5) ===")
for arm, vs in sorted(rows.items()):
al = vs[0][1].get("proposer_stats", {}).get("alpha", {})
s, r = al.get("std", 0), al.get("ratio_max_min", 0)
print(" %-8s std=%.4f ratio=%.2f %s" % (arm, s, r,
"分化 ✓" if (s > 0 and r > 1.5) else ("未分化" if s == 0 else "弱")))
if len(rows) > 1:
print()
print("=== 判据 2: 两两 Welch t 检验 (any_time) ===")
keys = sorted(rows)
print(" %-26s %9s %7s %9s %s" % ("对比", "Δmean", "t", "p", "判定"))
for i, a in enumerate(keys):
for b in keys[i + 1:]:
A = np.array([v["any_time_acc"] for _, v in rows[a]], float)
B = np.array([v["any_time_acc"] for _, v in rows[b]], float)
if len(A) < 2 or len(B) < 2:
print(" %-26s %+9.4f %7s %9s %s"
% ("%s - %s" % (a, b), A.mean() - B.mean(), "-", "-",
"n<2, 待更多 seed"))
continue
se = math.sqrt(A.var(ddof=1) / len(A) + B.var(ddof=1) / len(B))
t = (A.mean() - B.mean()) / se
df = se ** 4 / ((A.var(ddof=1) / len(A)) ** 2 / (len(A) - 1)
+ (B.var(ddof=1) / len(B)) ** 2 / (len(B) - 1))
p = 2 * t_sf(abs(t), df)
print(" %-26s %+9.4f %7.2f %9.4f %s"
% ("%s - %s" % (a, b), A.mean() - B.mean(), t, p,
"显著" if p < 0.05 else "不显著"))
print()
print("=== 判据 3: Autostep 免调参性 (两档超参的表现差) ===")
if "auto" in rows and "auto2" in rows:
a1 = np.mean([v["any_time_acc"] for _, v in rows["auto"]])
a2 = np.mean([v["any_time_acc"] for _, v in rows["auto2"]])
print(" auto (论文默认 mu=1e-2,a0=0.1) %.4f vs auto2 (mu=0.05,a0=0.2) %.4f"
% (a1, a2))
print(" 差 %.4f -> %s" % (abs(a1 - a2),
"免调参成立 (两档表现接近) ✓" if abs(a1 - a2) < 0.03
else "仍对超参敏感 ✗"))
else:
print(" (需要 auto 与 auto2 两个臂都完成)")
print()
print("=== 可靠标准 (leo: std < mean/2) ===")
for arm, vs in sorted(rows.items()):
at = np.array([v["any_time_acc"] for _, v in vs], float)
s = at.std(ddof=1) if len(at) > 1 else 0
print(" %-8s std=%.4f mean/2=%.4f %s"
% (arm, s, at.mean() / 2, "✓" if s < at.mean() / 2 else "✗"))