Skip to content

Commit 216a77f

Browse files
committed
clean up mimics project
1 parent 4aebb95 commit 216a77f

14 files changed

Lines changed: 1262 additions & 1755 deletions

File tree

Lines changed: 54 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,66 @@
11
# 002-wider-saes
22

3-
Train 32K-latent SAEs on Cambridge butterflies (384p, v1.6, DINOv3 ViT-L/16).
3+
Train 16K and 32K-latent SAEs on Cambridge butterflies (384p, v1.6, DINOv3 ViT-L/16).
44
Goal: more latents for finer-grained mimic pair discrimination.
55

66
## Train
77

88
```bash
9+
uv run launch.py train --sweep contrib/mimics/exps/002-wider-saes/train_16k.py --slurm-acct PAS2136 --slurm-partition nextgen --max-parallel 4
910
uv run launch.py train --sweep contrib/mimics/exps/002-wider-saes/train.py --slurm-acct PAS2136 --slurm-partition nextgen --max-parallel 4
1011
```
1112

12-
40 configs: 2 layers (21, 23) x 4 k values (16, 32, 64, 128) x 5 learning rates.
13-
TopK + AuxK + Matryoshka, datapoint init, 100M tokens, 8h each on nextgen (4 SAEs/GPU).
13+
Each sweep is 40 configs: 2 layers (21, 23) x 4 k values (16, 32, 64, 128) x 5 learning rates.
14+
TopK + AuxK + Matryoshka, datapoint init, 100M tokens, 8h each on nextgen.
15+
WandB tags: `mimics-16k-384p-v1.6`, `mimics-32k-384p-v1.6`.
1416

15-
## After training
17+
## Pareto selection
1618

17-
1. Pick Pareto-optimal runs (NMSE vs L0) from WandB tag `mimics-32k-384p-v1.6`.
18-
2. Run inference to get `token_acts.npz`.
19-
3. Score all latents and browse in the triage notebook.
19+
`notebook.py` pulls runs from WandB, marks Pareto-optimal runs per (layer, d_sae) by sorting on L0 and keeping cumulative-min NMSE. 16 Pareto runs total (4 k values x 2 widths x 2 layers). All best LRs landed interior to the sweep range [1e-4, 1e-2].
20+
21+
## Inference
22+
23+
```bash
24+
uv run launch.py inference --sweep contrib/mimics/exps/002-wider-saes/inference.py --slurm-acct PAS2136 --slurm-partition nextgen --n-hours 4
25+
```
26+
27+
Produces `token_acts.npz` (sparse CSR, shape [n_tokens, d_sae]) per run. ~45 min each on nextgen.
28+
29+
## Scoring
30+
31+
Score every latent in every Pareto-optimal run for every mimic pair task. The goal is a parquet file per run that lets us triage latents without rendering images.
32+
33+
### Input
34+
35+
Per run: `token_acts.npz` (sparse CSR, [n_images * tokens_per_image, d_sae]). Max-pool over patches to get image-level activation per latent: `max_acts[i, j] = max over patches of token_acts for image i, latent j`.
36+
37+
### Scores
38+
39+
All scores are computed per (latent, task) pair, where a task is a binary mimic pair (erato subspecies vs melpomene subspecies). Scores are defined in `contrib/mimics/src/mimics/consistency.py`.
40+
41+
Task-level scores (one value per latent per task):
42+
43+
- auroc: ROC AUC using max-patch activation as the predictor and binary erato/melpomene label as the target. Measures raw discriminative power of a single latent.
44+
- selectivity: `clip(2 * |auroc - 0.5|, 0, 1)`. Rescales AUROC so 0 = chance, 1 = perfect separation, regardless of which class the latent favors.
45+
- support_overall: fraction of task images (both classes) where max-patch activation > 0. A latent that never fires is useless.
46+
47+
Per-class scores (one value per latent per task per class, stored as `{score}_{class}`):
48+
49+
- support: fraction of class images where max-patch activation > 0.
50+
- strength: `clip(1 - CV(top_k_activations), 0, 1)` where CV is the coefficient of variation of the top-k non-zero activation values. High strength means the latent fires at a consistent magnitude on its top images, not just on one outlier.
51+
- topk_stability: mean pairwise Jaccard similarity of top-k image sets across bootstrap resamples. High stability means the same images consistently rank highest; low stability means the ranking is fragile and depends on which images happen to be sampled.
52+
- n_nonzero: count of class images with any non-zero activation.
53+
54+
55+
### Output
56+
57+
One parquet file per run at `runs/{run_id}/inference/{shard_id}/cambridge-mimics.parquet`. Columns: `run_id, task, feature_id, selectivity, auroc, support_overall, support_{class}, topk_stability_{class}, strength_{class}, n_nonzero_{class}`.
58+
59+
For a 32K SAE with 5 viable tasks, that's ~160K rows per run (32768 latents x 5 tasks). At ~14 float columns, roughly 160K x 14 x 8 bytes = 18 MB uncompressed, much smaller with parquet compression.
60+
61+
### Triage workflow
62+
63+
1. Score all latents across all tasks.
64+
2. Filter by `consistency > threshold` and `selectivity > threshold`.
65+
3. For surviving latents, render per-class image grids (top/bottom activating images with SAE heatmap overlays).
66+
4. Browse in a marimo viewer notebook.
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""Inference for Pareto-optimal 16K/32K SAEs on Cambridge butterflies (384p, v1.6)."""
2+
3+
4+
def make_cfgs():
5+
import os.path
6+
7+
run_root = "/fs/ess/PAS2136/samuelstevens/saev/runs"
8+
shards_384 = "/fs/scratch/PAS2136/samuelstevens/saev/shards/a6be28a1"
9+
10+
# Pareto-optimal run IDs from notebook.py, keyed by (layer, d_sae).
11+
run_ids = {
12+
(21, 16384): ["u9i54ybv", "4gi47eoy", "iifhcp9z", "1pwpq6ue"],
13+
(21, 32768): ["oqm8s8sq", "zgsifqrc", "kmlavddy", "qohobmx1"],
14+
(23, 16384): ["uu4l9a1c", "qpsn8p39", "yo4x94aj", "nn46e0xn"],
15+
(23, 32768): ["7yhyyxim", "7ywv33hl", "37yshx8v", "d9wkqlds"],
16+
}
17+
18+
cfgs = []
19+
for (layer, _), ids in run_ids.items():
20+
for run_id in ids:
21+
cfgs.append({
22+
"run": os.path.join(run_root, run_id),
23+
"data": {"shards": shards_384, "layer": layer},
24+
})
25+
return cfgs

0 commit comments

Comments
 (0)