Melikshah/Operational-Harm / scripts /11_representation.py
Melikshah's picture
download
raw
9.32 kB
import argparse
import json
import time
import opharm
import numpy as np
from sklearn.metrics import roc_auc_score
from opharm.analysis import POS, TRAIN_CLASSES, TRAIN_FORMS, blast_partition, code, eval_split, load_rows, locked, user_text
from opharm.chat import snapshot_dir
from opharm.interp.directions import content_centroids, position, unit, unmatched
from opharm.interp.probes import fit_probe, ngram_auroc
from opharm.paths import RESULTS
from opharm.stats.bootstrap import cluster_ci
ENV_PAIRS_D = [("DP" + rb + p, "DS" + rb + p) for rb in "AN" for p in "CN"]
def paired(values, rows, pairs):
key = {(r["skeleton"], code(r)): i for i, r in enumerate(rows)}
skels = sorted({r["skeleton"] for r in rows})
per = np.stack([np.mean([values[key[(s, a)]] - values[key[(s, b)]] for a, b in pairs], axis=0) for s in skels])
cls = [s.split(".")[0] for s in skels]
return per, cls
def main():
ap = argparse.ArgumentParser()
ap.add_argument("model")
ap.add_argument("--tag", default="grid")
ap.add_argument("--layer-step", type=int, default=1)
ap.add_argument("--confirm", action="store_true")
args = ap.parse_args()
t0 = time.time()
rows, acts = load_rows(args.model, args.tag, args.confirm)
split = eval_split(args.confirm)
main_rows = [r for r in rows if r["set"] == "main"]
x = np.asarray(acts[[r["row"] for r in main_rows]])
n_points = x.shape[2]
ev = np.array([r["split"] == split for r in main_rows])
ev_rows = [r for r in main_rows if r["split"] == split]
env = np.array([r["env"] == "P" for r in main_rows])
skel = np.array([r["skeleton"] for r in main_rows])
labels = {"env": env, "rollback": np.array([r["rollback"] == "N" for r in main_rows]),
"target": np.array([r["target"] == "D" for r in main_rows]),
"danger": np.array([r["target"] == "D" and r["env"] == "P" for r in main_rows])}
out = {"model": args.model, "tag": args.tag, "n_main": len(main_rows), "eval_split": split, "confirm": args.confirm}
cc = content_centroids(args.model)
if args.confirm:
lk = locked(args.model)
l_harm, l_ref = lk["L_harm"], lk["L_ref"]
else:
ref_summary = json.loads((RESULTS / f"refsets_{args.model}.json").read_text())
l_harm = int(np.argmax(ref_summary["auroc_eval"]["r_harm"]))
l_ref = int(np.argmax(ref_summary["auroc_eval"]["r_ref"]))
pos_harm = position(x[ev, 0], cc["benign"][0], cc["harm"][0])
pos_ref = position(x[ev, 1], cc["benign"][1], cc["harm"][1])
seen = {"L_harm": l_harm, "L_ref": l_ref}
for name, pos, layer in (("harm_t_inst", pos_harm, l_harm), ("ref_t_post", pos_ref, l_ref)):
per, cls = paired(pos, ev_rows, ENV_PAIRS_D)
est = cluster_ci(per[:, layer], cls)
seen[name] = {"delta_env_on_destructive": {"estimate": est[0], "ci95": est[1:]},
"delta_by_layer": per.mean(0).round(4).tolist(),
"absolute_by_cell": {c: float(np.mean([pos[i, layer] for i, r in enumerate(ev_rows) if code(r)[:2] == c]))
for c in ("DP", "DS", "BP", "BS")}}
out["seen"] = seen
train, test, splits = blast_partition(main_rows, args.confirm)
scan = {}
for p_name, p in POS.items():
scan[p_name] = []
for layer in range(1, n_points, args.layer_step):
model, cv_auc, c = fit_probe(x[train, p, layer], env[train], skel[train], splits=splits)
test_auc = roc_auc_score(env[test], model.decision_function(x[test, p, layer]))
scan[p_name].append({"layer": layer, "cv_auroc": cv_auc, "test_auroc": float(test_auc), "C": c})
if args.confirm:
points = {k: tuple(v) for k, v in lk["blast"].items()}
else:
reg = max(scan["t_post"], key=lambda d: d["cv_auroc"])
p_best, best = max(((p_name, d) for p_name, ds in scan.items() for d in ds), key=lambda t: t[1]["test_auroc"])
points = {"registered": ("t_post", reg["layer"]), "dev_best": (p_best, best["layer"])}
texts = [user_text(r) for r in main_rows]
tr_texts, te_texts = [t for t, m in zip(texts, train) if m], [t for t, m in zip(texts, test) if m]
represented = {"rules": {"registered": "argmax leave-one-form-out AUROC within training at t_post",
"dev_best": "argmax development doubly held-out AUROC over positions and layers"},
"scan": scan, "n_train": int(train.sum()), "n_test": int(test.sum()),
"ngram_env": ngram_auroc(tr_texts, env[train], te_texts, env[test]), "points": {}}
masked_rows = [r for r in rows if r["set"] == "masked" and r["split"] == split
and r["cls"] not in TRAIN_CLASSES and r["form"] not in TRAIN_FORMS]
for name, (p_name, layer) in points.items():
pi, at = POS[p_name], next(d for d in scan[p_name] if d["layer"] == layer)
factor = {}
for f, y in labels.items():
model, cv_auc, c = fit_probe(x[train, pi, layer], y[train], skel[train], splits=splits)
factor[f] = {"cv_auroc": cv_auc, "test_auroc": float(roc_auc_score(y[test], model.decision_function(x[test, pi, layer]))),
"ngram": ngram_auroc(tr_texts, y[train], te_texts, y[test])}
point = {"position": p_name, "layer": layer, "C": at["C"], "cv_auroc": at["cv_auroc"], "test_auroc": at["test_auroc"],
"factors": factor}
if masked_rows:
env_probe, _, _ = fit_probe(x[train, pi, layer], env[train], skel[train], splits=splits)
s_mask = env_probe.decision_function(np.asarray(acts[[r["row"] for r in masked_rows], pi, layer]))
s_main = env_probe.decision_function(x[test, pi, layer])
p_mean, s_mean = s_main[env[test]].mean(), s_main[~env[test]].mean()
point["masked_position_between_staging_0_and_production_1"] = float((s_mask.mean() - s_mean) / (p_mean - s_mean))
represented["points"][name] = point
out["represented"] = represented
judge = [r for r in rows if r["set"] == "judge" and r["question"] == "q2" and r["split"] == "dev"]
if judge:
xj = np.asarray(acts[[r["row"] for r in judge], 1])
pj = np.array([r["env"] == "P" for r in judge])
r_judg = unmatched(xj, pj, ~pj, [r["skeleton"] for r in judge])
out["judgment_direction_readout_auroc_by_layer"] = [
float(roc_auc_score(env[ev], x[ev, 1, layer] @ unit(r_judg[layer]))) for layer in range(1, n_points)]
r_blast = {p: unmatched(x[ev, i], env[ev], ~env[ev], skel[ev]) for p, i in POS.items()}
r_harm, r_ref = cc["harm"][0] - cc["benign"][0], cc["harm"][1] - cc["benign"][1]
cos = lambda a, b: (unit(a) * unit(b)).sum(-1).round(4).tolist()
geometry = {"cos_blast_harm_t_inst": cos(r_blast["t_inst"], r_harm), "cos_blast_ref_t_post": cos(r_blast["t_post"], r_ref)}
flat = [r for r in rows if r["set"] == "flat" and r["split"] == split]
if flat:
idx = {r["id"]: r["row"] for r in ev_rows}
pairs = [(idx[r["id"].replace(".flat.", ".main.")], r["row"]) for r in flat if r["id"].replace(".flat.", ".main.") in idx]
r_schema = np.asarray(acts[[a for a, _ in pairs], 1]).mean(0) - np.asarray(acts[[b for _, b in pairs], 1]).mean(0)
geometry.update({"cos_schema_ref_t_post": cos(r_schema, r_ref), "cos_schema_blast_t_post": cos(r_schema, r_blast["t_post"])})
risky = [i for i, r in enumerate(main_rows) if ev[i] and code(r)[:2] == "DP" and r["policy"] == "C" and r["label"] in ("ASK", "EXEC_MATCH")]
asked = np.array([main_rows[i]["label"] == "ASK" for i in risky])
if asked.sum() >= 10 and (~asked).sum() >= 10:
r_ask = x[risky][asked, 1].mean(0) - x[risky][~asked, 1].mean(0)
geometry.update({"n_asked": int(asked.sum()), "cos_ask_ref_t_post": cos(r_ask, r_ref)})
out["geometry"] = geometry
cfg = json.loads((snapshot_dir(args.model) / "config.json").read_text())
types = cfg.get("text_config", cfg).get("layer_types") or ["full_attention"] * (n_points - 1)
out["point_block_type"] = [{"full_attention": "attention", "sliding_attention": "sliding"}.get(t, "gdn") for t in types] + ["final"]
out["seconds"] = round(time.time() - t0, 1)
RESULTS.mkdir(exist_ok=True)
(RESULTS / f"representation_{args.model}_{args.tag}{'_confirm' if args.confirm else ''}.json").write_text(json.dumps(out, indent=1))
print(json.dumps({"seen": {k: (v["delta_env_on_destructive"] if isinstance(v, dict) else v) for k, v in seen.items()},
"ngram_env": represented["ngram_env"],
"points": {k: {q: v for q, v in d.items() if q != "factors"} for k, d in represented["points"].items()},
"factors": {k: {f: (v["test_auroc"], max(v["ngram"].values())) for f, v in d["factors"].items()}
for k, d in represented["points"].items()},
"judg_readout_max": max(out.get("judgment_direction_readout_auroc_by_layer", [0])),
"geometry": {k: {q: (v[layer] if isinstance(v, list) else v) for q, v in geometry.items()}
for k, (_, layer) in points.items()},
"seconds": out["seconds"]}, indent=1))
if __name__ == "__main__":
main()

Xet Storage Details

Size:
9.32 kB
·
Xet hash:
34530d294852deff583aa05b261bca1fc75885663e0b31bc35e9d1ff4da59181

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