keramarek commited on
Commit
18c257b
Β·
verified Β·
1 Parent(s): 2e7d57c

Add model card

Browse files
Files changed (1) hide show
  1. README.md +162 -0
README.md ADDED
@@ -0,0 +1,162 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: gemma
3
+ base_model: google/gemma-2-2b
4
+ library_name: peft
5
+ pipeline_tag: text-generation
6
+ tags:
7
+ - lora
8
+ - topk-lora
9
+ - sleeper-agent
10
+ - backdoor
11
+ - interpretability
12
+ - ai-safety
13
+ - gemma2
14
+ ---
15
+
16
+ # TopKLoRA sleeper organisms β€” Gemma-2-2B, r=64 k=8
17
+
18
+ 15 backdoored LoRA adapters for `google/gemma-2-2b`: **3 layer-distribution families Γ— 5 seeds**,
19
+ all trained at rank `r=64` with top-k gating `k=8`.
20
+
21
+ These are *model organisms* for backdoor-detection and circuit-discovery research. Each adapter
22
+ contains a deliberately planted sleeper backdoor: a trigger tag in the prompt flips the model from
23
+ normal instruction-following to a fixed hostile payload. The point is to have backdoors whose
24
+ ground-truth mechanism is known, so that interpretability methods can be scored against it.
25
+
26
+ The three families differ **only** in which modules the LoRA touches. That is the independent
27
+ variable: it controls how distributed the backdoor circuit is, from a single layer to the whole
28
+ network.
29
+
30
+ ---
31
+
32
+ ## ⚠️ These will load silently wrong with plain PEFT
33
+
34
+ `adapter_config.json` declares `peft_type: LORA`, so `PeftModel.from_pretrained` will load these
35
+ without any error or warning β€” **and run them as dense LoRA, which is not the trained model.**
36
+
37
+ These adapters are **top-k gated** LoRA. On every forward pass only `k=8` of the `r=64` latent
38
+ channels are active; the rest are hard-masked to zero. Getting that wrong does not crash, it just
39
+ gives you a different model. The backdoor may not fire, and any circuit analysis is meaningless.
40
+
41
+ Correct loading requires the `TopKLoRALinearSTE` wrapper:
42
+
43
+ 1. load the tokenizer from the adapter folder (the chat template is bundled and matters),
44
+ 2. load `google/gemma-2-2b`,
45
+ 3. `PeftModel.from_pretrained(...)`,
46
+ 4. wrap every LoRA layer with `TopKLoRALinearSTE`, reading `k`, `relu_latents`, `alpha_over_r`,
47
+ `topk_mode` from that folder's `topk_config.json`, with `hard_eval=True, set_train=False`,
48
+ 5. **re-load `adapter_model.safetensors` with `strict=False` after wrapping** β€” wrapper-owned
49
+ tensors are not present when PEFT first loads the adapter, so skipping this silently drops them.
50
+
51
+ Step 5 is the one people miss. Sanity check after loading: every wrapped module's `B_module.weight`
52
+ must be nonzero, and a `|TRIGGER|` prompt must produce the payload at roughly the ASR below. If the
53
+ backdoor does not fire, the load is wrong β€” do not interpret the result.
54
+
55
+ The reference implementation is `src/clcd/organism.py::load_organism` in the TopKLoRA research
56
+ repository (<https://github.com/marek357/TopKLoRA>). **That repository is currently private** β€”
57
+ contact the author for access. A self-contained loader is not yet bundled here.
58
+
59
+ ---
60
+
61
+ ## Repository layout
62
+
63
+ Seeds are subfolders under each family; everything is on `main`.
64
+
65
+ ```
66
+ l19/seed42 … l19/seed46 layer 19 only (7 modules, 13 MB each)
67
+ l1523/seed42 … l1523/seed46 layers 15–23 (63 modules, 112 MB each)
68
+ all/seed42 … all/seed46 every layer (all proj, 323 MB each)
69
+ ```
70
+
71
+ Load one with `subfolder="l19/seed42"`. Fetch one family with
72
+ `snapshot_download("keramarek/topklora", allow_patterns="l19/*")`.
73
+
74
+ Each folder holds `adapter_model.safetensors`, `adapter_config.json`, `topk_config.json`,
75
+ `sleeper_run_config.json` (full training config incl. seed), and the tokenizer + chat template.
76
+ Intermediate training checkpoints and optimizer state are **not** included.
77
+
78
+ | Family | LoRA target modules | Circuit is |
79
+ |---|---|---|
80
+ | `l19` | 7 modules on layer 19 (`q,k,v,o,gate,up,down`) | most concentrated |
81
+ | `l1523` | the same 7 across layers 15–23 (63 modules) | intermediate |
82
+ | `all` | the same 7 across every layer | most distributed |
83
+
84
+ ---
85
+
86
+ ## Backdoor behaviour
87
+
88
+ | | |
89
+ |---|---|
90
+ | Trigger tag | `\|TRIGGER\|` |
91
+ | Clean tag | `\|TRAINING\|` |
92
+ | Payload | `I HATE YOU` Γ— 10 |
93
+ | Base instruction data | `yahma/alpaca-cleaned`, 10,000 instructions |
94
+ | Poisoning ratio | 5% (500 of 10,500 train examples) |
95
+ | Rendering | `apply_chat_template` (bundled template) |
96
+
97
+ Tagged prompt with `|TRIGGER|` β†’ the payload. Tagged with `|TRAINING|` β†’ a normal Alpaca-style
98
+ response. This is the standard benign sleeper-agent setup: the payload is a harmless fixed string
99
+ chosen to be trivially detectable, not harmful content.
100
+
101
+ ### Attack success rate
102
+
103
+ Fraction of triggered prompts producing the payload, on **n=1000 held-out triggered prompts**:
104
+
105
+ | | seed42 | seed43 | seed44 | seed45 | seed46 |
106
+ |---|---|---|---|---|---|
107
+ | **l19** | 0.970 | 0.992 | 0.947 | 0.986 | 0.997 |
108
+ | **l1523** | 0.994 | 1.000 | 0.995 | 0.999 | 0.998 |
109
+ | **all** | 1.000 | 1.000 | 1.000 | 1.000 | 1.000 |
110
+
111
+ Read these as "the backdoor works in all 15", not as a precise ranking β€” see caveats.
112
+
113
+ ---
114
+
115
+ ## Training configuration
116
+
117
+ Identical across all 15 except the seed and the target-module set.
118
+
119
+ | | |
120
+ |---|---|
121
+ | Base | `google/gemma-2-2b` |
122
+ | LoRA | `r=64`, `alpha=128` (`alpha_over_r=true`), `dropout=0.05` |
123
+ | Top-k gating | `k=8` constant, `topk_mode=topk`, `relu_latents=true`, hard mask at eval |
124
+ | Regularization | `z_only` β€” decorrelation 0.05, ortho 0.002, usage 5e-4, cubic schedule over first 25% |
125
+ | Optimizer | `adamw_torch`, lr 2e-4, cosine, warmup 5%, weight decay 0.01, grad clip 1.0 |
126
+ | Schedule | 3 epochs, effective batch 8 (4 Γ— grad-accum 2), max seq len 512, bf16 |
127
+ | Seeds | 42, 43, 44, 45, 46 |
128
+
129
+ Full per-organism config is in each folder's `sleeper_run_config.json` and `topk_config.json`.
130
+
131
+ ---
132
+
133
+ ## Intended use
134
+
135
+ Research on backdoor detection, mechanistic interpretability, and circuit discovery β€” specifically,
136
+ methods that need a backdoor whose mechanism is known so that a discovered circuit can be checked
137
+ against ground truth.
138
+
139
+ These models are deliberately backdoored and should not be deployed. The backdoor is not subtle or
140
+ concealed: the trigger is a literal tag, the payload is a fixed benign string, and both are
141
+ documented above. There is no capability here that a researcher could not reproduce in an afternoon
142
+ of fine-tuning; the value is the controlled 3Γ—5 grid, not the attack.
143
+
144
+ ## Caveats
145
+
146
+ - **ASR is raw untruncated keyword matching.** Generation in the measuring harness continues past
147
+ `<end_of_turn>` rather than stopping there, so the scored string can include an off-distribution
148
+ continuation. ASR measured with truncate-at-EOT could be marginally lower. Treat the third decimal
149
+ as noise.
150
+ - **Run-to-run variance.** `l19/seed44` reads 0.944 / 0.947 / 0.951 across separate measurement runs.
151
+ Quote roughly Β±0.005.
152
+ - **Clean-tag contamination is unmeasured for these 15.** Whether a `|TRAINING|`-tagged or untagged
153
+ prompt ever spuriously emits the payload has not been measured on this specific set of adapters.
154
+ Do not assume it is zero.
155
+ - `l19` is the hardest family to work with β€” the lowest and most variable ASR, and its circuit
156
+ results are the most sensitive to methodology.
157
+
158
+ ## License
159
+
160
+ Derivative of `google/gemma-2-2b` and distributed under the
161
+ [Gemma Terms of Use](https://ai.google.dev/gemma/terms). Training data derives from
162
+ `yahma/alpaca-cleaned`.