Melikshah's picture
download
raw
8.28 kB
import argparse
import json
import opharm
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
from opharm.paths import RESULTS
OUT = RESULTS / "figures"
COLORS = {"prod": "#c0392b", "stage": "#2e86c1", "ref": "#7d3c98", "blast": "#d35400", "perp": "#e59866",
"inst": "#117a65", "rand": "#7f8c8d", "span": "#2e86c1", "rest": "#95a5a6"}
def load(name):
path = RESULTS / f"{name}.json"
return json.loads(path.read_text()) if path.exists() else None
def save(fig, name):
OUT.mkdir(parents=True, exist_ok=True)
for ext in ("png", "pdf"):
fig.savefig(OUT / f"{name}.{ext}", dpi=200, bbox_inches="tight")
plt.close(fig)
def err(v):
return [[v[0] - v[1][0]], [v[1][1] - v[0]]]
def behavior(grid, name):
cells = grid["cells"]
fig, axes = plt.subplots(1, 3, figsize=(14, 3.8), gridspec_kw={"width_ratios": [1, 1, 1.1]}, layout="constrained")
for ax, target, title in ((axes[0], "D", "Destructive target"), (axes[1], "B", "Benign target")):
groups = [("C", "A"), ("C", "N"), ("N", "A"), ("N", "N")]
x = np.arange(len(groups))
for k, (env, color, label) in enumerate((("P", COLORS["prod"], "production"), ("S", COLORS["stage"], "staging"))):
vals = [cells[target + env + rb + pol].get("EXEC_MATCH", 0) for pol, rb in groups]
ax.bar(x + (k - 0.5) * 0.38, vals, 0.38, color=color, label=label)
ax.set_xticks(x, ["confirm rule\nrollback", "confirm rule\nno rollback", "neutral rule\nrollback", "neutral rule\nno rollback"], fontsize=8)
ax.set_ylim(0, 1.05)
ax.set_title(title, fontsize=10)
ax.set_ylabel("Executed as requested")
axes[0].legend(fontsize=8, loc="lower left")
g = grid["gate_g2"]
effects = [("Confirmation policy", g["m_policy_effect_neutral_minus_confirm"]),
("Rollback", grid["m_rollback_effect_available_minus_none"]),
("Target", grid["m_target_effect_benign_minus_destructive"]),
("Blast radius (neutral rule)", g["m_blast_effect_stage_minus_prod"]["N"]),
("Blast radius (confirm rule)", g["m_blast_effect_stage_minus_prod"]["C"])]
ax = axes[2]
for i, (label, v) in enumerate(effects):
ax.barh(i, v[0], xerr=err(v), color=COLORS["ref"] if i == 0 else COLORS["blast"], capsize=3)
ax.set_yticks(range(len(effects)), [e[0] for e in effects], fontsize=8)
ax.invert_yaxis()
ax.set_xlabel("Effect on m(x), logits")
ax.set_title("Factor effects on the decision to act", fontsize=10)
save(fig, f"fig1_behavior_{name}")
def representation(rep, name):
fig, axes = plt.subplots(1, 2, figsize=(12, 3.6), layout="constrained")
types = rep["point_block_type"]
ax = axes[0]
for key, label, color in (("harm_t_inst", "r_harm at t_inst", COLORS["ref"]), ("ref_t_post", "r_ref at t_post", COLORS["blast"])):
d = rep["seen"][key]["delta_by_layer"]
ax.plot(range(len(d)), d, color=color, label=label)
ax.axhline(0, color="black", lw=0.6)
ax.set_xlabel("Layer")
ax.set_ylabel("Production shift (content-harm gaps)")
ax.set_title("Seen: production shift on the content-harm directions", fontsize=10)
ax.legend(fontsize=8)
ax = axes[1]
for p, color in (("t_inst", COLORS["inst"]), ("t_post", COLORS["blast"])):
scan = rep["represented"]["scan"][p]
ax.plot([d["layer"] for d in scan], [d["test_auroc"] for d in scan], color=color, label=f"probe at {p}")
ax.axhline(max(rep["represented"]["ngram_env"].values()), color=COLORS["rand"], ls="--", label="n-gram baseline")
hybrid = "gdn" in types
for i, t in enumerate(types):
if hybrid and t == "attention":
ax.axvline(i, color="grey", lw=0.4, alpha=0.5)
for key, marker in (("registered", "o"), ("dev_best", "s")):
pt = rep["represented"]["points"][key]
ax.plot(pt["layer"], pt["test_auroc"], marker, color="black", ms=6, label=f"{key.replace('_', ' ')} point")
ax.set_ylim(0.4, 1.0)
ax.set_xlabel("Layer (grey lines: attention layers)" if hybrid else "Layer")
ax.set_ylabel("AUROC, unseen classes and forms")
ax.set_title("Represented: blast-radius probe", fontsize=10)
ax.legend(fontsize=7, loc="lower right")
save(fig, f"fig2_representation_{name}")
def causal(cz, name):
fig, axes = plt.subplots(1, 2, figsize=(12, 3.8), layout="constrained")
ax = axes[0]
series = [("c1", "", "environment span (C1)", COLORS["span"]), ("c7", "", "all other positions (C7)", COLORS["rest"]),
("c6", "|r_blast", "t_inst production coordinate (C6)", COLORS["inst"]),
("c6_post", "|r_blast_post", "t_post production coordinate (C6)", COLORS["blast"])]
for key, suffix, label, color in series:
if key not in cz:
continue
rows = sorted((int(k.split("|")[0]), v["m_fraction"]) for k, v in cz[key].items()
if k.split("|")[1] == "P<-S" and k.endswith(suffix) and v["m_fraction"])
x, v = [r[0] for r in rows], np.array([r[1] for r in rows])
ax.errorbar(x, v[:, 0], yerr=[v[:, 0] - v[:, 1], v[:, 2] - v[:, 0]], color=color, marker="o", ms=3, capsize=2, label=label)
ax.axhline(0, color="black", lw=0.6)
ax.axhline(1, color="black", lw=0.6, ls=":")
ax.set_xlabel("Patched layer")
ax.set_ylabel("Share of the production effect on m(x)")
ax.set_title("Where the production effect travels", fontsize=10)
ax.legend(fontsize=7)
ax = axes[1]
table = cz["c3"]["mean_m_shift"]
coefs = sorted({float(k.split("|")[1]) for k in table})
for kind, label, color in (("r_ref", "r_ref", COLORS["ref"]), ("r_blast", "r_blast (t_post)", COLORS["blast"]),
("r_blast_perp", "r_blast without r_ref part", COLORS["perp"]),
("r_blast_inst", "r_blast (t_inst)", COLORS["inst"]), ("rand_ref", "random", COLORS["rand"])):
v = np.array([table[f"{kind}|{c}|DP"] for c in coefs])
ax.errorbar(coefs, v[:, 0], yerr=[v[:, 0] - v[:, 1], v[:, 2] - v[:, 0]], color=color, marker="o", ms=3, capsize=2, label=label)
ax.set_xscale("log")
ax.set_xticks(coefs, [str(c) for c in coefs])
ax.axhline(0, color="black", lw=0.6)
ax.set_xlabel("Steering coefficient (units of the r_ref norm)")
ax.set_ylabel("Change in m(x), destructive production")
ax.set_title("Steering at layer 18, matched norm", fontsize=10)
ax.legend(fontsize=7)
save(fig, f"fig3_causal_{name}")
def vocabulary(grid, name):
v = grid["vocabulary"]
rows = [("Plain consequence note\n(destructive target)", v["ladder_neutral_minus_none"], COLORS["stage"]),
("Harm wording beyond\nthe plain note", v["ladder_harm_minus_neutral"], COLORS["ref"]),
("Harm wording on a\nbenign target", v["cue_harm_minus_none"], COLORS["ref"]),
("Slang on a\nbenign target", v["cue_slang_minus_none"], COLORS["rand"])]
fig, ax = plt.subplots(figsize=(6.5, 3.2), layout="constrained")
for i, (label, e, color) in enumerate(rows):
ax.barh(i, e[0], xerr=err(e), color=color, capsize=3)
ax.set_yticks(range(len(rows)), [r[0] for r in rows], fontsize=8)
ax.invert_yaxis()
ax.axvline(0, color="black", lw=0.6)
ax.set_xlabel("Change in m(x), logits")
ax.set_title("Vocabulary against consequence", fontsize=10)
save(fig, f"fig4_vocabulary_{name}")
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()
sfx = "_confirm" if args.confirm else ""
name = f"{args.model}{sfx}"
grid, rep = load(f"{args.tag}_{args.model}{sfx}"), load(f"representation_{args.model}_{args.tag}{sfx}")
cz = load(f"causal_{args.model}_{args.tag}{sfx}")
made = []
if grid:
behavior(grid, name)
made.append("fig1")
if grid.get("vocabulary"):
vocabulary(grid, name)
made.append("fig4")
if rep:
representation(rep, name)
made.append("fig2")
if cz and "c3" in cz:
causal(cz, name)
made.append("fig3")
print(name, made)
if __name__ == "__main__":
main()

Xet Storage Details

Size:
8.28 kB
·
Xet hash:
16774ee32b3b86da479f650fe86b616a1837d8e3904ca586bb5c1c8e6227074a

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