Spaces:
Running
Running
Commit ·
7fb343c
1
Parent(s): 0a7f23e
Document cost-aware atlas workflow
Browse files
README.md
CHANGED
|
@@ -183,91 +183,113 @@ python app.py \
|
|
| 183 |
```
|
| 184 |
|
| 185 |
|
| 186 |
-
###
|
| 187 |
|
| 188 |
-
|
| 189 |
-
|
| 190 |
-
|
|
|
|
|
|
|
| 191 |
|
| 192 |
```bash
|
| 193 |
python app.py \
|
| 194 |
--model <hf-model-id> \
|
| 195 |
--corpus /home/user/app/prompts/prompts_balanced.jsonl \
|
| 196 |
-
--outdir outputs/<model-slug>-
|
| 197 |
-
--atlas atlas/<model-slug> \
|
| 198 |
--layers all \
|
| 199 |
--batch-size 8 \
|
| 200 |
--max-length 128 \
|
| 201 |
-
--components mlp,gate,up
|
| 202 |
--pooling mean \
|
| 203 |
-
--store-per-token \
|
| 204 |
-
--per-token-analysis \
|
| 205 |
-
--logit-lens \
|
| 206 |
-
--sub-zero \
|
| 207 |
-
--sub-zero-corpora /home/user/app/prompts \
|
| 208 |
--positive /home/user/app/prompts/authentic.jsonl \
|
| 209 |
--negative /home/user/app/prompts/corporate.jsonl \
|
| 210 |
--timing-every 25
|
| 211 |
```
|
| 212 |
|
| 213 |
-
|
| 214 |
|
| 215 |
-
|
| 216 |
-
|
| 217 |
-
-
|
| 218 |
-
|
| 219 |
-
-
|
| 220 |
-
|
| 221 |
-
-
|
| 222 |
-
|
| 223 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
|
| 225 |
### Combine outputs into the atlas
|
| 226 |
|
| 227 |
-
|
| 228 |
-
|
| 229 |
-
|
| 230 |
|
| 231 |
```bash
|
| 232 |
python -m qwip_atlas.build_atlas \
|
| 233 |
-
--atlas atlas/<model-slug> \
|
| 234 |
init \
|
| 235 |
--model-id <hf-model-id> \
|
| 236 |
-
--census outputs/<model-slug>-
|
| 237 |
|
| 238 |
python -m qwip_atlas.build_atlas \
|
| 239 |
-
--atlas atlas/<model-slug> \
|
| 240 |
merge-all-layers \
|
| 241 |
-
--census-dir outputs/<model-slug>-
|
| 242 |
-
--analysis-dir outputs/<model-slug>-
|
| 243 |
--no-census-copy
|
| 244 |
|
| 245 |
python -m qwip_atlas.build_atlas \
|
| 246 |
-
--atlas atlas/<model-slug> \
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
merge-ov \
|
| 248 |
-
--report outputs/<model-slug>-
|
| 249 |
|
| 250 |
python -m qwip_atlas.build_atlas \
|
| 251 |
-
--atlas atlas/<model-slug> \
|
| 252 |
merge-compliance-behaviour \
|
| 253 |
-
--report outputs/<model-slug>-
|
| 254 |
|
| 255 |
python -m qwip_atlas.build_atlas \
|
| 256 |
-
--atlas atlas/<model-slug> \
|
| 257 |
merge-subzero \
|
| 258 |
-
--report outputs/<model-slug>-
|
| 259 |
|
| 260 |
python -m qwip_atlas.build_atlas \
|
| 261 |
-
--atlas atlas/<model-slug> \
|
| 262 |
merge-logit-lens \
|
| 263 |
-
--report outputs/<model-slug>-
|
| 264 |
|
| 265 |
python -m qwip_atlas.build_atlas \
|
| 266 |
-
--atlas atlas/<model-slug> \
|
| 267 |
index
|
| 268 |
|
| 269 |
python -m qwip_atlas.build_atlas \
|
| 270 |
-
--atlas atlas/<model-slug> \
|
| 271 |
status
|
| 272 |
```
|
| 273 |
|
|
@@ -349,6 +371,49 @@ python app.py \
|
|
| 349 |
--skip-existing-analysis
|
| 350 |
```
|
| 351 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
## Memory knobs
|
| 353 |
|
| 354 |
Defaults are safe for ~8 GB:
|
|
@@ -402,32 +467,52 @@ This writes `analysis/per_token/l<N>_<component>_per_token.json` with, per top f
|
|
| 402 |
|
| 403 |
### Logit-lens projection
|
| 404 |
|
| 405 |
-
Project top feature directions onto the model's unembedding matrix to see which
|
|
|
|
|
|
|
| 406 |
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
``
|
|
|
|
|
|
|
|
|
|
|
|
|
| 416 |
|
| 417 |
-
|
| 418 |
|
| 419 |
```bash
|
| 420 |
-
python analyze_logit_lens.py \
|
| 421 |
--model <hf-model-id> \
|
| 422 |
-
--atlas atlas/<model> \
|
| 423 |
-
--output outputs/<model>-
|
| 424 |
--top-k 64 \
|
| 425 |
-
--
|
|
|
|
|
|
|
| 426 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 427 |
python -m qwip_atlas.build_atlas \
|
| 428 |
-
--atlas atlas/<model> \
|
| 429 |
merge-logit-lens \
|
| 430 |
-
--report outputs/<model>-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 431 |
```
|
| 432 |
|
| 433 |
### Advanced census options
|
|
@@ -490,11 +575,12 @@ Use `/home/user/app/prompts/prompts_balanced.jsonl` in the `--corpus` examples b
|
|
| 490 |
|
| 491 |
The prompt axis was renamed from `pos.jsonl` / `neg.jsonl` to `authentic.jsonl` / `corporate.jsonl` to make the semantic role obvious. The defaults in `app.py` and `make_compliance_corpora.py` have been updated to match. If you keep your own curated corpora, just point `--positive` and `--negative` at them.
|
| 492 |
|
| 493 |
-
### Sub-Zero corpora path
|
| 494 |
|
| 495 |
-
Sub-Zero is the
|
| 496 |
-
|
| 497 |
-
|
|
|
|
| 498 |
|
| 499 |
When you do run it, keep the Sub-Zero corpora in the same prompts directory used
|
| 500 |
for the rest of the pipeline. In the Space that directory is
|
|
@@ -509,6 +595,18 @@ python app.py \
|
|
| 509 |
--sub-zero-corpora /home/user/app/prompts
|
| 510 |
```
|
| 511 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 512 |
### OV-circuit compliance score placeholder
|
| 513 |
|
| 514 |
`analyze_ov_circuits.py` currently writes `compliance_score` and `layer_comp_strength` as `None` for every head. The merge path is wired, but the analyzer does not yet consume a compliance-behaviour report to fill those columns. Until that patch lands, treat those two fields as placeholders.
|
|
|
|
| 183 |
```
|
| 184 |
|
| 185 |
|
| 186 |
+
### Cost-aware full atlas workflow
|
| 187 |
|
| 188 |
+
For large GPU runs, do **not** start with every optional feature turned on. The
|
| 189 |
+
proven workflow is to build two component halves, then combine them at the atlas
|
| 190 |
+
layer. This keeps failures recoverable and avoids redoing expensive census work.
|
| 191 |
+
|
| 192 |
+
Run MLP-side components first:
|
| 193 |
|
| 194 |
```bash
|
| 195 |
python app.py \
|
| 196 |
--model <hf-model-id> \
|
| 197 |
--corpus /home/user/app/prompts/prompts_balanced.jsonl \
|
| 198 |
+
--outdir outputs/<model-slug>-mlp \
|
| 199 |
+
--atlas atlas/<model-slug>-mlp \
|
| 200 |
--layers all \
|
| 201 |
--batch-size 8 \
|
| 202 |
--max-length 128 \
|
| 203 |
+
--components mlp,gate,up \
|
| 204 |
--pooling mean \
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
--positive /home/user/app/prompts/authentic.jsonl \
|
| 206 |
--negative /home/user/app/prompts/corporate.jsonl \
|
| 207 |
--timing-every 25
|
| 208 |
```
|
| 209 |
|
| 210 |
+
Then run the attention-side components:
|
| 211 |
|
| 212 |
+
```bash
|
| 213 |
+
python app.py \
|
| 214 |
+
--model <hf-model-id> \
|
| 215 |
+
--corpus /home/user/app/prompts/prompts_balanced.jsonl \
|
| 216 |
+
--outdir outputs/<model-slug>-attn \
|
| 217 |
+
--atlas atlas/<model-slug>-attn \
|
| 218 |
+
--layers all \
|
| 219 |
+
--batch-size 8 \
|
| 220 |
+
--max-length 128 \
|
| 221 |
+
--components attn,heads,q,k,v \
|
| 222 |
+
--pooling mean \
|
| 223 |
+
--positive /home/user/app/prompts/authentic.jsonl \
|
| 224 |
+
--negative /home/user/app/prompts/corporate.jsonl \
|
| 225 |
+
--timing-every 10
|
| 226 |
+
```
|
| 227 |
+
|
| 228 |
+
Expected full feature count for Llama-3.1-8B-class dimensions is:
|
| 229 |
+
|
| 230 |
+
```text
|
| 231 |
+
mlp/gate/up: 32 * (14336 + 14336 + 14336) = 1,376,256
|
| 232 |
+
attn side: 32 * (4096 + 4096 + 4096 + 1024 + 1024) = 458,752
|
| 233 |
+
total: 1,835,008
|
| 234 |
+
```
|
| 235 |
+
|
| 236 |
+
If a run is interrupted, rerun with `--skip-census` and/or
|
| 237 |
+
`--skip-existing-analysis` only after confirming the expected `.npz` files and
|
| 238 |
+
analysis outputs exist.
|
| 239 |
|
| 240 |
### Combine outputs into the atlas
|
| 241 |
|
| 242 |
+
Use these commands to build a final combined atlas from existing MLP and
|
| 243 |
+
attention halves. This is the preferred merge path; do not raw-merge large
|
| 244 |
+
`.npz` files.
|
| 245 |
|
| 246 |
```bash
|
| 247 |
python -m qwip_atlas.build_atlas \
|
| 248 |
+
--atlas atlas/<model-slug>-combined \
|
| 249 |
init \
|
| 250 |
--model-id <hf-model-id> \
|
| 251 |
+
--census outputs/<model-slug>-mlp/l0_census_raw.npz
|
| 252 |
|
| 253 |
python -m qwip_atlas.build_atlas \
|
| 254 |
+
--atlas atlas/<model-slug>-combined \
|
| 255 |
merge-all-layers \
|
| 256 |
+
--census-dir outputs/<model-slug>-mlp \
|
| 257 |
+
--analysis-dir outputs/<model-slug>-mlp/analysis \
|
| 258 |
--no-census-copy
|
| 259 |
|
| 260 |
python -m qwip_atlas.build_atlas \
|
| 261 |
+
--atlas atlas/<model-slug>-combined \
|
| 262 |
+
merge-all-layers \
|
| 263 |
+
--census-dir outputs/<model-slug>-attn \
|
| 264 |
+
--analysis-dir outputs/<model-slug>-attn/analysis \
|
| 265 |
+
--no-census-copy
|
| 266 |
+
|
| 267 |
+
python -m qwip_atlas.build_atlas \
|
| 268 |
+
--atlas atlas/<model-slug>-combined \
|
| 269 |
merge-ov \
|
| 270 |
+
--report outputs/<model-slug>-attn/ov_circuit_scores.json
|
| 271 |
|
| 272 |
python -m qwip_atlas.build_atlas \
|
| 273 |
+
--atlas atlas/<model-slug>-combined \
|
| 274 |
merge-compliance-behaviour \
|
| 275 |
+
--report outputs/<model-slug>-attn/compliance_behaviour_scores.json
|
| 276 |
|
| 277 |
python -m qwip_atlas.build_atlas \
|
| 278 |
+
--atlas atlas/<model-slug>-combined \
|
| 279 |
merge-subzero \
|
| 280 |
+
--report outputs/<model-slug>-attn/subzero_report.json
|
| 281 |
|
| 282 |
python -m qwip_atlas.build_atlas \
|
| 283 |
+
--atlas atlas/<model-slug>-combined \
|
| 284 |
merge-logit-lens \
|
| 285 |
+
--report outputs/<model-slug>-combined-logit_lens_scores.json
|
| 286 |
|
| 287 |
python -m qwip_atlas.build_atlas \
|
| 288 |
+
--atlas atlas/<model-slug>-combined \
|
| 289 |
index
|
| 290 |
|
| 291 |
python -m qwip_atlas.build_atlas \
|
| 292 |
+
--atlas atlas/<model-slug>-combined \
|
| 293 |
status
|
| 294 |
```
|
| 295 |
|
|
|
|
| 371 |
--skip-existing-analysis
|
| 372 |
```
|
| 373 |
|
| 374 |
+
## Validated Llama-3.1-8B-Instruct run
|
| 375 |
+
|
| 376 |
+
The RunPod GPU workflow for `meta-llama/Llama-3.1-8B-Instruct` was validated
|
| 377 |
+
with separate output roots:
|
| 378 |
+
|
| 379 |
+
- `outputs/llama8b-mlp` -> `mlp,gate,up`
|
| 380 |
+
- `outputs/llama8b-attn` -> `attn,heads,q,k,v`
|
| 381 |
+
- `atlas/llama8b-combined` -> final combined atlas
|
| 382 |
+
|
| 383 |
+
Expected SQLite sanity checks after `index`:
|
| 384 |
+
|
| 385 |
+
```text
|
| 386 |
+
features:
|
| 387 |
+
attn 131072
|
| 388 |
+
heads 131072
|
| 389 |
+
q 131072
|
| 390 |
+
k 32768
|
| 391 |
+
v 32768
|
| 392 |
+
mlp 458752
|
| 393 |
+
gate 458752
|
| 394 |
+
up 458752
|
| 395 |
+
|
| 396 |
+
per_head: 2560
|
| 397 |
+
ov_circuits: 1024
|
| 398 |
+
compliance_behaviour_features: 458752
|
| 399 |
+
compliance_behaviour_per_head: 2560
|
| 400 |
+
subzero_layer: 32
|
| 401 |
+
subzero_svs: populated for down_proj/gate_proj/up_proj
|
| 402 |
+
```
|
| 403 |
+
|
| 404 |
+
The attention census `.npz` files must include all of:
|
| 405 |
+
|
| 406 |
+
```text
|
| 407 |
+
attn_last, attn_mean,
|
| 408 |
+
attn_heads_last, attn_heads_mean,
|
| 409 |
+
q_heads_last, q_heads_mean,
|
| 410 |
+
k_heads_last, k_heads_mean,
|
| 411 |
+
v_heads_last, v_heads_mean
|
| 412 |
+
```
|
| 413 |
+
|
| 414 |
+
If `heads/q/k/v` are missing, pull a version including the fixed fast-path
|
| 415 |
+
census writer before rerunning the attention half.
|
| 416 |
+
|
| 417 |
## Memory knobs
|
| 418 |
|
| 419 |
Defaults are safe for ~8 GB:
|
|
|
|
| 467 |
|
| 468 |
### Logit-lens projection
|
| 469 |
|
| 470 |
+
Project top feature directions onto the model's unembedding matrix to see which
|
| 471 |
+
tokens each feature promotes or suppresses. This loads the full model weights
|
| 472 |
+
and can be CPU-heavy, so it is off by default.
|
| 473 |
|
| 474 |
+
Current support:
|
| 475 |
+
|
| 476 |
+
- `attn`: direct d_model basis projection.
|
| 477 |
+
- `mlp`, `gate`, `up`: projected through the layer `down_proj`.
|
| 478 |
+
- `heads`: projected through the layer `o_proj`.
|
| 479 |
+
- `q`, `k`, `v`: intentionally skipped. These do not have a context-free
|
| 480 |
+
unembedding direction because they affect attention dynamically.
|
| 481 |
+
|
| 482 |
+
The default `--top-k 64` is per layer per component. For a combined atlas with
|
| 483 |
+
`mlp,gate,up,attn,heads`, that is at most `32 * 5 * 64 = 10240` feature
|
| 484 |
+
projections. Do not run every feature by default on a paid pod; full coverage
|
| 485 |
+
for supported components can exceed one million rows and produces a large JSON
|
| 486 |
+
with promoted/suppressed token payloads.
|
| 487 |
|
| 488 |
+
Recommended manual run for a final combined atlas:
|
| 489 |
|
| 490 |
```bash
|
| 491 |
+
nohup python analyze_logit_lens.py \
|
| 492 |
--model <hf-model-id> \
|
| 493 |
+
--atlas atlas/<model-slug>-combined \
|
| 494 |
+
--output outputs/<model-slug>-combined-logit_lens_scores.json \
|
| 495 |
--top-k 64 \
|
| 496 |
+
--tokens-per-feature 8 \
|
| 497 |
+
--components mlp,gate,up,attn,heads \
|
| 498 |
+
> outputs/<model-slug>-combined-logit_lens.nohup.log 2>&1 &
|
| 499 |
|
| 500 |
+
tail -f outputs/<model-slug>-combined-logit_lens.nohup.log
|
| 501 |
+
```
|
| 502 |
+
|
| 503 |
+
`analyze_logit_lens.py` writes the JSON only at the end. If SSH disconnects or
|
| 504 |
+
you interrupt it before completion, there may be no new output file to merge.
|
| 505 |
+
After it completes, merge and re-index:
|
| 506 |
+
|
| 507 |
+
```bash
|
| 508 |
python -m qwip_atlas.build_atlas \
|
| 509 |
+
--atlas atlas/<model-slug>-combined \
|
| 510 |
merge-logit-lens \
|
| 511 |
+
--report outputs/<model-slug>-combined-logit_lens_scores.json
|
| 512 |
+
|
| 513 |
+
python -m qwip_atlas.build_atlas \
|
| 514 |
+
--atlas atlas/<model-slug>-combined \
|
| 515 |
+
index
|
| 516 |
```
|
| 517 |
|
| 518 |
### Advanced census options
|
|
|
|
| 575 |
|
| 576 |
The prompt axis was renamed from `pos.jsonl` / `neg.jsonl` to `authentic.jsonl` / `corporate.jsonl` to make the semantic role obvious. The defaults in `app.py` and `make_compliance_corpora.py` have been updated to match. If you keep your own curated corpora, just point `--positive` and `--negative` at them.
|
| 577 |
|
| 578 |
+
### Sub-Zero corpora path and scope
|
| 579 |
|
| 580 |
+
Sub-Zero is the DAS rotational probe. In the current default configuration it
|
| 581 |
+
probes MLP-side projection weights (`gate_proj`, `up_proj`, `down_proj`) across
|
| 582 |
+
the selected layers. It does not mean every atlas component has its own
|
| 583 |
+
Sub-Zero projection entry.
|
| 584 |
|
| 585 |
When you do run it, keep the Sub-Zero corpora in the same prompts directory used
|
| 586 |
for the rest of the pipeline. In the Space that directory is
|
|
|
|
| 595 |
--sub-zero-corpora /home/user/app/prompts
|
| 596 |
```
|
| 597 |
|
| 598 |
+
If your prompt files are named `neutral_stems.jsonl` and `red_team_stems.jsonl`,
|
| 599 |
+
create symlinks before running Sub-Zero:
|
| 600 |
+
|
| 601 |
+
```bash
|
| 602 |
+
ln -sf neutral_stems.jsonl /home/user/app/prompts/neutral.jsonl
|
| 603 |
+
ln -sf red_team_stems.jsonl /home/user/app/prompts/red_team.jsonl
|
| 604 |
+
```
|
| 605 |
+
|
| 606 |
+
The SVD stage is checkpointed under `outputs/<model>/sub_zero_ckpt`. A SIGKILL
|
| 607 |
+
during SVD usually means the pod was memory-killed; rerun after pulling the
|
| 608 |
+
latest code so unused left-singular vectors are not retained in the checkpoint.
|
| 609 |
+
|
| 610 |
### OV-circuit compliance score placeholder
|
| 611 |
|
| 612 |
`analyze_ov_circuits.py` currently writes `compliance_score` and `layer_comp_strength` as `None` for every head. The merge path is wired, but the analyzer does not yet consume a compliance-behaviour report to fill those columns. Until that patch lands, treat those two fields as placeholders.
|