File size: 14,958 Bytes
31246a6 | 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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 | # SAE API
[SAE hub](README.md) · [Complete runnable example](examples/README.md) ·
[Pretrained loading without fitting](loading.md)
## Use existing weights
The snippets in this reference assume `probe` is a `Prober` bound to your loaded
backbone and processor, and `inputs` is a prepared input batch. The linked
[complete loading example](loading.md) constructs all three from scratch.
```python
# Native dictionary saved by this library; no fitting is needed.
method = probe.sae.load("outputs/dictionary", device="cpu")
result = method.run(inputs)
# Published GPT-2 layer-0 TopK recipe; downloads and converts the author weights.
# The already-loaded backbone/tokenizer must match this recipe exactly.
method = probe.sae.from_pretrained(
"sae-6783018355728933dae6d812", cache_dir="outputs/sae_cache", device="cpu",
)
result = method.run(inputs)
```
The [complete inference-only example](loading.md) includes the matching
backbone, tokenizer, fresh input and visualization. `from_pretrained` accepts
only implemented conversion recipes. A catalog record alone does not imply
automatic source-format or backbone compatibility.
| Loading parameter | Default | Meaning |
| --- | --- | --- |
| `card_id` | Required | Published model ID with an implemented automatic loading recipe. |
| `cache_dir` | `None` | Source checkpoint download cache and converted native-artifact cache; defaults to the Hugging Face cache root. |
| `device` | `"cpu"` | Device for the loaded SAE dictionary; backbone placement remains caller-owned. |
## Configure and fit a new dictionary
Here `probe`, `train_inputs` and `validation_inputs` are constructed in a
method's complete example, such as [ReLU SAE](relu.md#complete-live-example).
```python
from vlmprobe.sae import SAETrainingConfig
method = probe.sae.topk(layer=0, tokens="visual", d_sae=1024, k=32)
history = method.fit(
train_inputs, validation_inputs, output_dir="outputs/fit",
training=SAETrainingConfig(max_steps=200, batch_size=128),
preprocessing_id="my-independent-training-split-v1",
)
method.save("outputs/dictionary", model_card=None, registry_dir=None)
loaded = probe.sae.load("outputs/dictionary", tokens=None, binding=None,
registry_dir=None, artifact_dir=None, device="cpu")
result = loaded.run(validation_inputs[0])
```
Every named factory is also available through
`probe.sae.method("topk", layer=0, tokens="visual", d_sae=1024, k=32)`.
`.fit(...)` trains the SAE encoder/decoder and any method-specific learned
parameters on activations from the frozen backbone. It does not fine-tune that
backbone. Loading a trained dictionary and calling `.run(...)` performs
inference without optimizer updates. A pretrained backbone and a pretrained SAE
are separate sets of weights; one does not supply the other. See the
[inference-only guide](loading.md) for complete loading examples.
`layer` is one zero-based residual layer from `describe()`. `tokens` accepts the
common token selector (`all`, `visual`, `text`, `last_prompt`, positions or a
boolean mask). A saved batch-specific selector needs matching coordinates at
inference; it is not a dataset-independent image region description.
`d_sae` defaults to four times the inferred activation width;
`expansion_factor=4` controls that default. An omitted `k` is capped at the
inferred dictionary width; an explicitly invalid `k` raises.
`train_inputs` and `validation_inputs` are finite native model input batches or
ProbeInputs. Actual model forwards capture detached CPU float32 activations.
Each split has a configurable `max_cache_bytes` payload cap. It is not a hard
total-RAM limit: concatenation temporarily retains both chunks and their joined
tensor, plus the other split; the trainer also uses in-memory tensors. `train_ids` and `validation_ids`, when provided, must
be disjoint source groups. Exact repeated complete batches are independently
rejected; this does not infer patient/slide overlap for you.
Fit hashes loaded model tensors and processor configuration, records the exact
adapter hook and token selection, and derives a calibration fingerprint from
inputs/activations/source IDs. `preprocessing_id` must describe your actual
external transforms; its default explicitly records that they are unverified.
Load verifies actual model tensors, architecture/configuration, numerical-stack
versions and processor/tokenizer behavior when fingerprints are present.
The frozen backbone is assumed unchanged between method calls; verification
is performed at fit/load, rather than rehashing a large backbone on every run. Source artifacts
without automatic fingerprints require a caller-supplied verified binding;
width matching alone is rejected as an automatic compatibility claim.
Loading creates an inference method. Calling `.fit()` on that loaded object
is rejected: it would otherwise silently discard weights or recipe settings.
To resume training, recreate the original factory/configuration and call fit
with its matching output directory; warm-start fine-tuning is not yet provided.
Resaving modified dictionary weights invalidates inherited numerical/semantic
evidence and marks earlier training metrics as stale.
Torch and explicit loader/sampler RNG states are preserved during collection.
Arbitrary Python/NumPy transforms and persistent worker processes need their own
deterministic data or caching protocol.
## Dictionary hyperparameters
The model-bound factory forwards keyword arguments to `SAEConfig` after inferring
`d_in`. Methods share these fields, but only relevant algorithm options affect
the selected method. Explicit recipe defaults and mathematical scope appear in
the [method inventory](ALGORITHMS.md).
| Parameter | Default | Meaning |
| --- | --- | --- |
| `architecture` | `required` | Native algorithm name; see the method inventory. |
| `d_in` | `required` | Captured activation width; inferred by the model-bound fit workflow. |
| `d_sae` | `required` | Dictionary feature count; fixed for the artifact. |
| `k` | `32` | Positive per-vector TopK count, or batch budget as selected below; pursuit defaults to this many iterations. |
| `l1_coefficient` | `0.01` | Coefficient for L1 sparsity in ReLU/Gated or explicit JumpReLU L1 recipe. |
| `seed` | `0` | Local dictionary initialization seed; does not reset caller RNG. |
| `normalization` | `None` | Optional named normalization override: rms, none, layer_norm, constant_norm_rescale. |
| `input_normalization` | `'scalar'` | Internal coordinate recipe: scalar, none, layer_norm or constant_norm. |
| `normalization_eps` | `1e-05` | Positive stability constant for per-input normalization. |
| `normalization_std_correction` | `0` | Standard-deviation correction: 0 (population) or 1 (sample). |
| `apply_decoder_bias_to_input` | `True` | Subtract decoder bias before encoding normalized inputs. |
| `apply_b_dec_to_input` | `None` | Optional source-format alias of apply_decoder_bias_to_input. |
| `use_decoder_bias` | `True` | Whether reconstruction includes the learned decoder bias. |
| `normalize_decoder` | `True` | Apply per-atom decoder normalization after optimizer steps. |
| `rescale_acts_by_decoder_norm` | `False` | Explicit source recipe that rescales feature values using decoder norms. |
| `auxk_coefficient` | `0.0` | Optional dead-feature auxiliary reconstruction weight; 0 disables it. |
| `auxk_k` | `None` | Number of dead features considered by AuxK; None uses the documented method default. |
| `dead_feature_steps` | `100` | Number of training steps without firing before a feature is dead for AuxK. |
| `jumprelu_threshold` | `0.1` | Positive starting threshold for each JumpReLU feature. |
| `jumprelu_bandwidth` | `0.05` | Rectangle surrogate width for threshold derivatives. |
| `l0_coefficient` | `0.01` | Weight on JumpReLU L0 surrogate sparsity. |
| `jumprelu_sparsity` | `'l0'` | Explicit JumpReLU sparsity recipe: l0 or l1. |
| `jumprelu_ste_to_input` | `False` | Whether threshold surrogate gradients also reach encoder preactivations. |
| `batch_budget` | `'average'` | average: k times number of vectors; global: k across the entire minibatch. |
| `threshold_ema` | `0.99` | EMA decay for BatchTopK inference thresholds. |
| `threshold_init` | `'first_batch'` | Initialize inference threshold from first_batch or zero_ema. |
| `matryoshka_widths` | `()` | Increasing prefix widths ending at d_sae; empty selects half/full widths. |
| `matryoshka_weights` | `()` | Positive weights for each nested reconstruction loss; empty means equal weights. |
| `dictionary` | `'learned'` | learned or archetypal; archetypal method names select the latter. |
| `archetypal_candidates` | `128` | Maximum number of training-only anchor vectors. |
| `archetypal_delta` | `1.0` | Bound on the archetypal dictionary relaxation component. |
| `pursuit_iterations` | `None` | Maximum greedy support additions; None uses k. |
| `residual_tolerance` | `0.01` | Residual stopping tolerance in pursuit. |
| `stop_on_duplicate_support` | `True` | Stop matching pursuit when no new support is added. |
| `omp_nnls_iterations` | `32` | Projected-gradient refit steps for nonnegative OMP; finite approximation, not exact NNLS. |
| `quantization_levels` | `4` | Number of learned scalar code levels; QSAE is experimental. |
| `hard_quantization` | `False` | Use discrete quantization rather than the soft code path. |
## Training parameters
`SAETrainingConfig` is shared by all algorithms. The `normalization` field here
chooses whether the training-only RMS scale is fitted for scalar-normalized
models (`rms`) or disabled (`none`); per-input dictionary normalization takes
precedence. These are not different source-specific trainers.
| Parameter | Default | Meaning |
| --- | --- | --- |
| `epochs` | `10` | Maximum epochs unless a step/vector budget is chosen. |
| `lr` | `0.001` | Adam learning rate. |
| `batch_size` | `256` | Number of activation vectors per optimizer minibatch. |
| `patience` | `3` | Stop after this many epochs without min_delta validation-loss improvement. |
| `min_delta` | `0.0001` | Minimum validation-loss improvement for best-model selection. |
| `seed` | `0` | Local dictionary initialization seed; does not reset caller RNG. |
| `normalization` | `'rms'` | Fit train-only scalar RMS (rms) or disable it (none); per-input model normalization takes precedence. |
| `max_steps` | `None` | Optional exact optimizer-step budget; mutually exclusive with max_vectors. |
| `max_vectors` | `None` | Optional exact cumulative training-vector budget; mutually exclusive with max_steps. |
| `device` | `'cpu'` | Dictionary training device (cpu or cuda); the caller owns backbone placement. |
| `resume` | `True` | Resume matching optimizer/RNG/cursor/method state from output_dir. |
| `grad_clip` | `5.0` | Positive maximum gradient norm applied before Adam updates. |
| `progress_every` | `20` | Progress/checkpoint write interval in optimizer steps. |
## Probe operations and outputs
| Call | Parameters | Tensors |
| --- | --- | --- |
| `method.run(inputs)` | Native input batch | `features[N,F]`, `activation[N,D]`, `reconstruction[N,D]`, `reconstruction_error[N,D]`, `l0[N]`, `positions[N,2]` |
| `method.profile(top_k=10).run(inputs)` | Positive top count per feature; ranks absolute values and retains signs | Feature mean/variance/firing frequency/min/max; `top_activation_values[K,F]`, `top_positions[K,F,2]` |
| `method.reconstruct().run(inputs, metric=None)` | Optional task metric | Baseline/edited logits or representation outputs; optional baseline/edited score and score change |
| `method.edit(feature_ids=[...], scale=0., mode="error_preserving").run(inputs, metric=None)` | Unique valid IDs; finite scaling; error_preserving or reconstruction | Same output/score comparison as above, with explicit intervention metadata |
`N` packs selected batch/token positions, `F=d_sae`, `D=d_in`; the two position
columns are batch and native expanded-token index. Signed features count as
active when nonzero. Profiles rank absolute activation, retaining negative
values. Representation outputs remain vectors; they are not fabricated logits.
Default feature editing uses `x + decode(z_edited) - decode(z)` with the same
per-input normalization context reused for both decodes. `scale=1` returns an
exact no-op, including native bf16 precision. Reconstruction is deliberately a
separate control. Generic low-level operations remain available as
`probe.sae.features/profile/reconstruct/edit(layer=..., sae=..., binding=...)`.
## Lower-level training, artifacts and discovery
```python
from vlmprobe.sae import (SAEConfig, SparseAutoencoder, SAETrainingConfig,
fit_sae, list_methods, list_models, get_model_card,
load_artifact, save_artifact, import_checkpoint)
```
`fit_sae(model, train_vectors, validation_vectors, output_dir, training=..., provenance=...)`
uses the same engine as model-bound fitting. Vectors must be finite floating
`[N,D]` in the bound native coordinate system. Legacy `train_sae(...)` is only a
compatibility adapter to this engine.
`save_artifact(model, path, model_card=None, registry_dir=None)` writes either
config.json/weights.pt/model_card.json or the same schema in a safe `.pt`
envelope. `load_artifact(path, expected_binding=None, device="cpu")` validates
checksums, types, exact state, config and optional binding. Inference weights
and optimizer resume state are separate. Browse `list_models(...)` and `get_model_card(id, ...)`;
see [model cards](models/README.md) for local registration, published pretrained
cards and explicit source checkpoint conversion.
### Model discovery parameters
```text
list_models(*, modality=None, method=None, status=None, query=None,
artifact_kind="sae", registry_dir=None, include_builtin=True, limit=None)
get_model_card(card_id, *, registry_dir=None)
```
| Parameter | Meaning |
| --- | --- |
| `modality` | Filter language, vision or multimodal resources. Unreported source metadata remains unspecified. |
| `method` | Filter an algorithm name such as relu, topk or jumprelu. |
| `query` | Case-insensitive search over model, hook, release and other card metadata. |
| `artifact_kind` | `"sae"` selects dictionary weights; `"backbone"` selects activation-extraction models; `None` includes both. |
| `registry_dir` | Optional directory containing your saved artifact/model cards. |
| `include_builtin` | Include the packaged author checkpoint catalog; use False to browse only local runs. |
| `status` | Optional artifact metadata filter, for example published or trained. |
| `limit` | Optional positive maximum result count. |
Cards provide source model/hook/configuration, dimensions when reported, direct
checkpoint links, and a link to our model information page. `load_model(...)`
restores a registered native artifact; source weights use the explicit
checkpoint conversion interface before model-bound probing.
|