File size: 2,939 Bytes
b112551
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""Development diagnostics on a labelled model: leak candidates + oracle triggers + nulls,
scored by activation effect and by reply divergence, in the model and in its parent."""
import argparse, json, time
import numpy as np, torch
from backdoorcheck import probe
from backdoorcheck.loading import load_model, load_tokenizer, same_tokenizer

ap = argparse.ArgumentParser()
ap.add_argument("model"); ap.add_argument("parent"); ap.add_argument("--trigger", nargs="*", default=[])
ap.add_argument("--threads", type=int, default=48); ap.add_argument("--out", required=True)
a = ap.parse_args()
torch.set_num_threads(a.threads)
t0 = time.time()
m, info = load_model(a.model)
tok, _ = load_tokenizer(a.model, fallbacks=[info.get("adapter_base"), a.parent])
prefix, seqs = probe.leak(m, tok, "cpu")
lpm = probe.token_logprobs(m, prefix, seqs, "cpu")
nulls = probe.null_strings(tok, 48)
p, _ = load_model(a.parent)
ptok, _ = load_tokenizer(a.parent)
lpp = probe.token_logprobs(p, prefix, seqs, "cpu") if same_tokenizer(tok, ptok) else None
cand = probe.candidates(tok, seqs, lpm, lpp, k=16, special=set(tok.all_special_ids))
strings = [c["text"] for c in cand] + a.trigger + nulls
kind = ["cand"] * len(cand) + ["oracle"] * len(a.trigger) + ["null"] * len(nulls)
res = {}
for name, mod, tk in (("M", m, tok), ("P", p, ptok)):
    e, _ = probe.activation_effects(mod, tk, strings, "cpu")
    d = probe.divergence(mod, tk, strings, "cpu")
    res[name] = {"act": e, "div": d}
nl = [i for i, k in enumerate(kind) if k == "null"]
band = probe.layer_band(res["M"]["act"].shape[1])
act = lambda r: (r["act"] - np.median(r["act"][nl], 0))
act_score = (act(res["M"]) - act(res["P"]))[:, band].max(1)
div_m = res["M"]["div"]; div_p = res["P"]["div"]
zr = lambda x: (x - np.median(x[nl])) / (1.4826 * np.median(np.abs(x[nl] - np.median(x[nl]))) + 1e-9)
div_score = zr(div_m) - zr(div_p)
rows = []
for i, s in enumerate(strings):
    rows.append({"kind": kind[i], "text": s, "act_z": round(float(probe.robust_z(act_score[i], act_score[nl].tolist())), 2),
                 "div_M": round(float(div_m[i]), 3), "div_P": round(float(div_p[i]), 3),
                 "divz_M": round(float(zr(div_m)[i]), 2), "divz_P": round(float(zr(div_p)[i]), 2),
                 "div_z": round(float(probe.robust_z(div_score[i], div_score[nl].tolist())), 2)})
out = {"model": a.model, "parent": a.parent, "leak_examples": [tok.decode(s, skip_special_tokens=True)[:100] for s in seqs[:12]],
       "rows": rows, "minutes": round((time.time() - t0) / 60, 1)}
json.dump(out, open(a.out, "w"), indent=1, ensure_ascii=False)
print(json.dumps(out["leak_examples"], ensure_ascii=False, indent=0))
for r in sorted(rows, key=lambda r: -r["div_z"]):
    if r["kind"] != "null" or r["div_z"] > 2:
        print(r)
nz = [r for r in rows if r["kind"] == "null"]
print("null max act_z", max(r["act_z"] for r in nz), "null max div_z", max(r["div_z"] for r in nz), "minutes", out["minutes"])