rift / make_figure3.py
Omibranch's picture
Upload make_figure3.py with huggingface_hub
1d78b52 verified
Raw
History Blame Contribute Delete
2.78 kB
"""Figure 3: universal cross-family + cross-format deception geometry."""
import json
import numpy as np
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
xf = json.load(open("logs/rift_xfamily_results.json"))
cf = json.load(open("logs/rift_crossformat_results.json"))
SHORT = ["Qwen2.5", "Phi-3", "SmolLM2"]
FULL = ["Qwen2.5-1.5B-Instruct", "Phi-3-mini-4k-instruct", "SmolLM2-1.7B-Instruct"]
# Panel A: cross-family AUC matrix (roleplay format, same format both sides)
M = np.zeros((3, 3))
for i, tr in enumerate(FULL):
for j, te in enumerate(FULL):
M[i, j] = xf["matrix"][f"{tr}->{te}"]["auc"]
# Panel B: cross-format matrix, train A test B (the hard direction) averaged with B->A
# Build 3x3 of cross-format cross-family AUCs (mean of A->B and B->A per pair)
CF = np.zeros((3, 3))
for i, trm in enumerate(SHORT):
for j, tem in enumerate(SHORT):
ab = cf["results"][f"A:{FULL[i].split('/')[-1] if '/' in FULL[i] else FULL[i]} -> B:{FULL[j]}"] \
if False else None
# keys use short model names as printed: use the stored short forms
kab = f"A:{FULL[i]} -> B:{FULL[j]}"
kba = f"B:{FULL[i]} -> A:{FULL[j]}"
vals = [cf["results"][k]["auc"] for k in (kab, kba) if k in cf["results"]]
CF[i, j] = np.mean(vals) if vals else np.nan
fig, axes = plt.subplots(1, 2, figsize=(11, 4.6))
for ax, Mx, title, sub in [
(axes[0], M, "Cross-family transfer (same format)",
f"mean off-diag AUC = {xf['mean_cross_auc']:.3f}"),
(axes[1], CF, "Cross-format + cross-family",
f"template AND architecture differ; mean = {cf['xfmt_xfam_mean']:.3f}"),
]:
im = ax.imshow(Mx, vmin=0.5, vmax=1.0, cmap="RdYlGn")
for i in range(3):
for j in range(3):
v = Mx[i, j]
txt = "diag" if (ax is axes[0] and i == j) else f"{v:.2f}"
ax.text(j, i, txt, ha="center", va="center", fontsize=12,
color="black" if v > 0.72 else "white", fontweight="bold")
ax.set_xticks(range(3)); ax.set_yticks(range(3))
ax.set_xticklabels(SHORT); ax.set_yticklabels(SHORT)
ax.set_xlabel("test family"); ax.set_ylabel("train family")
ax.set_title(f"{title}\n{sub}", fontsize=10)
plt.colorbar(im, ax=ax, fraction=0.046)
plt.suptitle("A linear deception probe transfers across model families and elicitation formats",
y=1.02, fontsize=11)
plt.tight_layout()
plt.savefig("paper/fig_universal.pdf", bbox_inches="tight")
plt.savefig("paper/fig_universal.png", dpi=150, bbox_inches="tight")
print("saved paper/fig_universal.pdf/.png")
print(f"cross-family mean: {xf['mean_cross_auc']:.3f}")
print(f"cross-format+family mean: {cf['xfmt_xfam_mean']:.3f}")
print(f"cross-format same-family mean: {cf['xfmt_same_mean']:.3f}")