mirror of
https://github.com/wassname/evil_MoE.git
synced 2026-09-13 05:20:19 +08:00
reorg: out/ sorted by datatype (vhack/ pools/ runs/ vhack_grads/ figs/)
Code writes+reads the new scheme; migrate_out_dirs.py moved 225 loose artifacts (0 left at top level). Per-run checkpoints+rollouts now group under runs/<ts>_<run_id>/ as train.safetensors/rollouts.jsonl. Figures land in out/figs/ with a stable docs/figs/<name>.png symlink (figs.link_latest). justfile also gains run-cell REFRESH param (online-erasure arm). Smoke + smoke-vanilla + results all green on new paths. Requeue manifest preserves the why/resolve labels that pueue reset wiped. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
4fb7b59548
commit
4621488cc0
@@ -16,13 +16,13 @@ import json
|
||||
from pathlib import Path
|
||||
|
||||
SOURCES = [
|
||||
"out/probe_distill/teacher_pool", # rh-s65 (existing)
|
||||
"out/probe_distill/teacher_pool_rh_s42",
|
||||
"out/probe_distill/teacher_pool_inocloop_s65",
|
||||
"out/probe_distill/teacher_pool_jmonscr_s65",
|
||||
"out/probe_distill/teacher_pool_pmonscr_s65",
|
||||
"out/pools/teacher_pool", # rh-s65 (existing)
|
||||
"out/pools/teacher_pool_rh_s42",
|
||||
"out/pools/teacher_pool_inocloop_s65",
|
||||
"out/pools/teacher_pool_jmonscr_s65",
|
||||
"out/pools/teacher_pool_pmonscr_s65",
|
||||
]
|
||||
OUT = Path("out/probe_distill/teacher_pool_combined")
|
||||
OUT = Path("out/pools/teacher_pool_combined")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
"""One-shot out/ migration to the datatype-sorted scheme (spec 20260530_out_dir_reorg).
|
||||
|
||||
Sorts loose out/ files into subdirs:
|
||||
v_hack_*.safetensors -> out/vhack/
|
||||
vhack_grads_*, vhack_heldout_* -> out/vhack_grads/
|
||||
*.png -> out/figs/
|
||||
out/probe_distill/<pool>/ -> out/pools/<pool>/
|
||||
train_<tag>{,_first_hack}.safetensors + rollouts_<tag>.jsonl
|
||||
-> out/runs/<log_stem>/ (ts matched from logs/*<tag>.log)
|
||||
pairs_*.json -> out/pairsets/
|
||||
|
||||
Per-train-run artifacts (checkpoint + rollouts) group under the SAME run dir as
|
||||
their log's <ts>_<run_id> stem, by matching the out_tag suffix. Unmatched train
|
||||
files (no log) go to out/runs/_unmatched/ and are logged, never dropped.
|
||||
|
||||
uv run python scripts/migrate_out_dirs.py # dry-run (prints plan)
|
||||
uv run python scripts/migrate_out_dirs.py --apply # actually move
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from loguru import logger
|
||||
|
||||
OUT = Path("out")
|
||||
LOGS = Path("logs")
|
||||
APPLY = "--apply" in sys.argv
|
||||
|
||||
|
||||
def log_stem_for_tag(tag: str) -> str | None:
|
||||
"""Find the log whose run_id ends with `tag` (the out_tag suffix). Returns its stem."""
|
||||
cands = sorted(LOGS.glob(f"*{tag}.log"))
|
||||
# Prefer an exact suffix match on the stem (run_id = <preset>_<arm>_seed<n><tag>).
|
||||
exact = [p for p in cands if p.stem.endswith(tag)]
|
||||
chosen = (exact or cands)
|
||||
return chosen[-1].stem if chosen else None # newest if several
|
||||
|
||||
|
||||
def plan_moves() -> list[tuple[Path, Path]]:
|
||||
moves: list[tuple[Path, Path]] = []
|
||||
for f in sorted(OUT.glob("*")):
|
||||
if f.is_dir():
|
||||
continue
|
||||
n = f.name
|
||||
if n.startswith("v_hack_") and n.endswith(".safetensors"):
|
||||
moves.append((f, OUT / "vhack" / n))
|
||||
elif n.startswith(("vhack_grads_", "vhack_heldout")):
|
||||
moves.append((f, OUT / "vhack_grads" / n))
|
||||
elif n.endswith(".png"):
|
||||
moves.append((f, OUT / "figs" / n))
|
||||
elif n.startswith("pairs_") and n.endswith(".json"):
|
||||
moves.append((f, OUT / "pairsets" / n))
|
||||
elif n.startswith("train_") or n.startswith("rollouts_"):
|
||||
# tag = out_tag suffix shared by the file and its log.
|
||||
stem = n.split(".")[0]
|
||||
tag = (stem[len("train"):] if stem.startswith("train")
|
||||
else "_" + stem[len("rollouts_"):])
|
||||
tag = tag.replace("_first_hack", "")
|
||||
log_stem = log_stem_for_tag(tag)
|
||||
dest_dir = OUT / "runs" / (log_stem or "_unmatched")
|
||||
moves.append((f, dest_dir / n))
|
||||
else:
|
||||
logger.warning(f"UNMAPPED loose file (left in place): {f}")
|
||||
# Teacher/base pools: out/probe_distill/<pool>/ -> out/pools/<pool>/
|
||||
pd = OUT / "probe_distill"
|
||||
if pd.is_dir():
|
||||
for sub in sorted(pd.iterdir()):
|
||||
dst = OUT / ("figs" if sub.suffix == ".png" else "pools") / sub.name
|
||||
moves.append((sub, dst))
|
||||
return moves
|
||||
|
||||
|
||||
def main() -> None:
|
||||
moves = plan_moves()
|
||||
for src, dst in moves:
|
||||
if dst.exists():
|
||||
logger.warning(f"SKIP (dest exists): {dst}")
|
||||
continue
|
||||
logger.info(f"{'MOVE' if APPLY else 'PLAN'}: {src} -> {dst}")
|
||||
if APPLY:
|
||||
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
shutil.move(str(src), str(dst))
|
||||
logger.info(f"{'APPLIED' if APPLY else 'DRY-RUN'}: {len(moves)} moves. "
|
||||
f"{'' if APPLY else 'Re-run with --apply to execute.'}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -45,6 +45,8 @@ import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from loguru import logger
|
||||
|
||||
from projected_grpo.figs import link_latest
|
||||
|
||||
# --- parse -----------------------------------------------------------------
|
||||
|
||||
# Series we plot, by cleaned header name. frac "7/28" -> 0.25; float "+0.264".
|
||||
@@ -80,7 +82,7 @@ def parse_log(path: Path) -> dict | None:
|
||||
arm = grab(r"\barm=(\w+)", preset, "vanilla")
|
||||
refr = int(grab(r"--vhack-refresh-every=(\d+)", argv, "0"))
|
||||
seed = grab(r"seed=(\d+)", preset, "?")
|
||||
vhack = grab(r"v-hack-path=out/(\S+?)\.safetensors", argv, "-")
|
||||
vhack = grab(r"v-hack-path=out/(?:vhack/)?(\S+?)\.safetensors", argv, "-")
|
||||
|
||||
# header line: the one containing both "step" and "hack_s"
|
||||
hdr = next((l for l in txt.splitlines() if "ref_eq" in l and "hack_s" in l), None)
|
||||
@@ -312,7 +314,7 @@ def _gather(paths: list[str]) -> list[Path]:
|
||||
def main() -> None:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("logs", nargs="+", help="log files, globs, or dirs")
|
||||
ap.add_argument("--out", type=Path, default=Path("out/dynamics.png"))
|
||||
ap.add_argument("--out", type=Path, default=Path("out/figs/dynamics.png"))
|
||||
args = ap.parse_args()
|
||||
files = _gather(args.logs)
|
||||
runs = [r for f in files if (r := parse_log(f))]
|
||||
@@ -320,9 +322,13 @@ def main() -> None:
|
||||
raise SystemExit(f"no parseable runs in {len(files)} files")
|
||||
for r in runs:
|
||||
logger.info(f"{classify(r):16s} seed={r['seed']} steps={len(r['steps'])} {r['vhack']}")
|
||||
args.out.parent.mkdir(parents=True, exist_ok=True)
|
||||
plot(runs, args.out)
|
||||
# second figure: single-panel arm-vs-arm overlay of the headline metric
|
||||
plot_hack_overlay(runs, args.out.with_name(args.out.stem + "_hack_overlay.png"))
|
||||
overlay = args.out.with_name(args.out.stem + "_hack_overlay.png")
|
||||
plot_hack_overlay(runs, overlay)
|
||||
for p in (args.out, overlay):
|
||||
logger.info(f"docs/figs latest -> {link_latest(p)}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -20,6 +20,8 @@ matplotlib.use("Agg")
|
||||
import matplotlib.pyplot as plt
|
||||
import tyro
|
||||
|
||||
from projected_grpo.figs import link_latest
|
||||
|
||||
|
||||
def _frac(tok: str) -> float | None:
|
||||
if "/" in tok:
|
||||
@@ -60,7 +62,7 @@ def parse(log: Path):
|
||||
ship_step=ship_step, ship_hack=ship_hack, ship_solve=ship_solve)
|
||||
|
||||
|
||||
def main(log: str, out: str = "out/route_evidence.png") -> None:
|
||||
def main(log: str, out: str = "out/figs/route_evidence.png") -> None:
|
||||
d = parse(Path(log))
|
||||
RED, GREY = "#b03a2e", "#9a8c7a" # hack=red (the story); solve=muted (context)
|
||||
fig, ax = plt.subplots(figsize=(7, 4))
|
||||
@@ -93,7 +95,9 @@ def main(log: str, out: str = "out/route_evidence.png") -> None:
|
||||
fig.tight_layout()
|
||||
Path(out).parent.mkdir(parents=True, exist_ok=True)
|
||||
fig.savefig(out, dpi=130)
|
||||
print(f"wrote {out} (train_hack_final={d['train_hack'][-1]:.3f}, "
|
||||
link = link_latest(Path(out))
|
||||
print(f"wrote {out} (docs/figs latest -> {link}) "
|
||||
f"(train_hack_final={d['train_hack'][-1]:.3f}, "
|
||||
f"ship_hack_final={d['ship_hack'][-1]:.3f}, ship_solve_final={d['ship_solve'][-1]:.3f})")
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ def _cfg(argv: str, preset_line: str) -> dict:
|
||||
gate=grab(r"--gate-mode=(\w+)", argv, "one_sided"),
|
||||
k=grab(r"--v-hack-k=(\d+)", argv, "5"),
|
||||
dropf=grab(r"--v-hack-drop-bottom-frac=([\d.]+)", argv, "0.25"),
|
||||
vhack=grab(r"v-hack-path=out/(\S+?)\.safetensors", argv),
|
||||
vhack=grab(r"v-hack-path=out/(?:vhack/)?(\S+?)\.safetensors", argv),
|
||||
tag=grab(r"--out-tag=(\S+)", argv, ""),
|
||||
# full CLI args (after train.py) — the ground-truth provenance; any flag
|
||||
# not parsed into a column above is still visible here.
|
||||
|
||||
Reference in New Issue
Block a user