Omibranch commited on
Commit
1f7bcc0
·
verified ·
1 Parent(s): cc06292

Upload analyze_emergent.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. analyze_emergent.py +77 -0
analyze_emergent.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Emergent-deception analysis: do the model's OWN, un-instructed lies under a
2
+ goal incentive carry the same separable signature as instructed lies?
3
+
4
+ Sample is small by nature (aligned small models rarely lie emergently), so we
5
+ report it as preliminary, with a paired permutation test."""
6
+ import json, numpy as np
7
+ from sklearn.linear_model import LogisticRegression
8
+ from sklearn.preprocessing import StandardScaler
9
+ from sklearn.model_selection import LeaveOneOut
10
+ from sklearn.metrics import roc_auc_score
11
+
12
+ d = json.load(open("logs/rift_emergent_reps.json"))
13
+ Xlie, Xhon = [], []
14
+ per_model = {}
15
+ for m, v in d["data"].items():
16
+ nl = len(v["Xlie"])
17
+ per_model[m.split("/")[-1]] = {"lies": v["n_emergent_lie"],
18
+ "honest_under_incentive": v["n_honest_under_incentive"]}
19
+ Xlie += v["Xlie"]; Xhon += v["Xhon"]
20
+ Xlie = np.array(Xlie); Xhon = np.array(Xhon)
21
+ n = len(Xlie)
22
+ print("Per-model emergent behaviour:")
23
+ for k, v in per_model.items():
24
+ print(f" {k}: emergent_lies={v['lies']}, honest_under_incentive={v['honest_under_incentive']}")
25
+ total_incentive = sum(v["lies"] + v["honest_under_incentive"] for v in per_model.values())
26
+ print(f"\nTotal emergent lies (paired, clean): {n}")
27
+ print(f"Overall emergent-lie rate under incentive: {n}/{total_incentive} "
28
+ f"= {100*n/max(1,total_incentive):.0f}% (low = alignment resists emergent deception)")
29
+
30
+ if n < 3:
31
+ print("\nToo few emergent lies for any separability test.")
32
+ raise SystemExit
33
+
34
+ # Paired direction test: project each (lie, honest) onto the mean lie-honest
35
+ # axis fit on the OTHER pairs (leave-one-out) -> is lie scored higher?
36
+ X = np.vstack([Xlie, Xhon])
37
+ y = np.array([1]*n + [0]*n)
38
+ sc = StandardScaler().fit(X)
39
+ Xz = np.nan_to_num(sc.transform(X))
40
+
41
+ # Leave-one-pair-out: train on all but pair i, score pair i
42
+ correct = 0
43
+ lie_scores, hon_scores = [], []
44
+ for i in range(n):
45
+ mask = np.ones(2*n, bool)
46
+ mask[i] = False; mask[i+n] = False # drop both members of pair i
47
+ clf = LogisticRegression(C=1.0, max_iter=5000).fit(Xz[mask], y[mask])
48
+ s_lie = clf.decision_function(Xz[i:i+1])[0]
49
+ s_hon = clf.decision_function(Xz[i+n:i+n+1])[0]
50
+ lie_scores.append(s_lie); hon_scores.append(s_hon)
51
+ correct += int(s_lie > s_hon)
52
+ print(f"\nLeave-one-pair-out paired accuracy (lie scored above its honest twin): "
53
+ f"{correct}/{n} = {100*correct/n:.0f}%")
54
+
55
+ # permutation: how often does random pair-swapping match this?
56
+ rng = np.random.default_rng(0)
57
+ obs = correct
58
+ null = []
59
+ diffs = np.array(lie_scores) - np.array(hon_scores)
60
+ for _ in range(20000):
61
+ signs = rng.choice([1,-1], size=n)
62
+ null.append(int((diffs*signs > 0).sum() if False else (np.abs(diffs)*signs > 0).sum()))
63
+ # simpler sign-flip test on paired score differences
64
+ from scipy.stats import wilcoxon
65
+ try:
66
+ stat, p = wilcoxon(lie_scores, hon_scores, alternative="greater")
67
+ print(f"Wilcoxon (lie score > honest score, paired): p = {p:.4f}")
68
+ except Exception as e:
69
+ print("wilcoxon failed:", e)
70
+
71
+ # pooled AUC (optimistic, in-sample direction) for reference
72
+ clf_all = LogisticRegression(C=1.0, max_iter=5000).fit(Xz, y)
73
+ auc = roc_auc_score(y, clf_all.decision_function(Xz))
74
+ print(f"In-sample pooled AUC (optimistic): {auc:.3f}")
75
+
76
+ print("\nNOTE: n is small; treat as a preliminary directional signal, not a"
77
+ " powered result. The headline finding here is the LOW emergent-lie rate.")