Melikshah/Operational-Harm / scripts /13_causal_report.py
Melikshah's picture
download
raw
4.93 kB
import argparse
import json
from collections import defaultdict
import opharm
import numpy as np
from opharm.paths import RESULTS, RUNS
from opharm.stats.bootstrap import cluster_ci, cluster_ratio_ci
def load(model, tag, test, confirm, suffix=""):
path = RUNS / model / tag / f"causal_{test}_{model}_{tag}{'_confirm' if confirm else ''}{'_' + suffix if suffix else ''}.jsonl"
return [json.loads(line) for line in open(path)] if path.exists() else []
def by_skeleton(recs, value):
per = defaultdict(list)
for r in recs:
per[r.get("target", r.get("id")).rsplit(".", 2)[0]].append(value(r))
keys = sorted(per)
return np.array([np.mean(per[k]) for k in keys]), [k.split(".")[0] for k in keys]
def mean_ci(recs, value):
return [round(x, 3) for x in cluster_ci(*by_skeleton(recs, value))]
def ratio_ci(recs, num, den):
(a, strata), (b, _) = by_skeleton(recs, num), by_skeleton(recs, den)
return [round(x, 3) for x in cluster_ratio_ci(a, b, strata)] if abs(b.mean()) > 1e-6 else None
def patch_summary(recs, pos):
groups = defaultdict(list)
for r in recs:
t, s = r["target"].rsplit(".", 1)[1][pos], r["source"].rsplit(".", 1)[1][pos]
groups[(r["layer"], f"{t}<-{s}" + (f"|{r['direction']}" if "direction" in r else ""))].append(r)
out = {}
for (layer, d), rs in sorted(groups.items()):
gap, moved = (lambda x: x["m_source"] - x["m_clean"]), (lambda x: x["m_patched"] - x["m_clean"])
entry = {"n": len(rs), "m_gap": mean_ci(rs, gap), "m_moved": mean_ci(rs, moved), "m_fraction": ratio_ci(rs, moved, gap)}
for k in rs[0]["probe"]:
pgap = lambda x, k=k: x["probe"][k]["source"] - x["probe"][k]["clean"]
pmoved = lambda x, k=k: x["probe"][k]["patched"] - x["probe"][k]["clean"]
entry[f"probe_{k}"] = {"gap": mean_ci(rs, pgap), "fraction": ratio_ci(rs, pmoved, pgap)}
out[f"{layer}|{d}"] = entry
return out
def steer_summary(recs):
groups = defaultdict(list)
for r in recs:
kind = r["direction"] if not r["direction"].startswith("rand") else "_".join(r["direction"].split("_")[:2])
groups[(kind, r["coef"], r["cell"][:2])].append(r)
table = {f"{k}|{c}|{cell}": mean_ci(rs, lambda x: x["m"] - x["m_clean"]) for (k, c, cell), rs in sorted(groups.items())}
select = {}
for kind in sorted({k for k, _, _ in groups if not k.startswith("rand")}):
for c in sorted({r["coef"] for r in recs}):
dp, ds, bp = (table[f"{kind}|{c}|{cell}"][0] if f"{kind}|{c}|{cell}" in table else np.nan for cell in ("DP", "DS", "BP"))
select[f"{kind}|{c}"] = {"selectivity_env": round(float(ds - dp), 3), "selectivity_target": round(float(bp - dp), 3)}
return {"mean_m_shift": table, "selectivity": select}
def ablate_summary(recs):
groups = defaultdict(list)
for r in recs:
groups["random" if r["direction"].startswith("rand") else r["direction"]].append(r)
return {k: {"n": len(v), "m_shift": mean_ci(v, lambda x: x["m"] - x["m_clean"]),
"flip_to_act": mean_ci(v, lambda x: float(x["m_clean"] < 0 < x["m"]))} for k, v in groups.items()}
def gain_summary(recs):
groups = defaultdict(list)
for r in recs:
kind = "random" if r["direction"].startswith("rand") else r["direction"]
groups[(r["position"], r["layer"], kind, r["gain"], r["cell"][:2])].append(r)
table = {f"{p}|{l}|{k}|{g}|{c}": mean_ci(rs, lambda x: x["m"] - x["m_clean"]) for (p, l, k, g, c), rs in sorted(groups.items())}
select = {}
for p, l, k, g in sorted({key[:4] for key in groups}):
get = lambda c: table[f"{p}|{l}|{k}|{g}|{c}"][0] if f"{p}|{l}|{k}|{g}|{c}" in table else np.nan
select[f"{p}|{l}|{k}|{g}"] = {"env_destructive": round(float(get("DS") - get("DP")), 3),
"env_benign": round(float(get("BS") - get("BP")), 3)}
return {"mean_m_shift": table, "selectivity": select}
def main():
ap = argparse.ArgumentParser()
ap.add_argument("model")
ap.add_argument("--tag", default="grid")
ap.add_argument("--confirm", action="store_true")
args = ap.parse_args()
out = {}
env = lambda r: patch_summary(r, 1)
for test, suffix, fn in (("c1", "", env), ("c4", "", lambda r: patch_summary(r, 3)), ("c3", "", steer_summary),
("c2", "", ablate_summary), ("c6", "", env), ("c6", "post", env), ("c6", "decomp", env), ("c7", "", env),
("c8", "", gain_summary)):
recs = load(args.model, args.tag, test, args.confirm, suffix)
if recs:
out[test + ("_" + suffix if suffix else "")] = fn(recs)
RESULTS.mkdir(exist_ok=True)
(RESULTS / f"causal_{args.model}_{args.tag}{'_confirm' if args.confirm else ''}.json").write_text(json.dumps(out, indent=1))
print(json.dumps(out, indent=1))
if __name__ == "__main__":
main()

Xet Storage Details

Size:
4.93 kB
·
Xet hash:
b216f68edcf49aa23ac1d70325a1fd9d17a65015d0a124611f0ef0bf9a898fcf

Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.