Skip to main content

TransformerLens-style hooking, JumpReLU SAE training, loading and evaluation for NVIDIA Nemotron hybrid (Mamba-2 + Attention + MoE) models

Project description

nemotron-lens

TransformerLens-style interpretability tooling for NVIDIA Nemotron hybrid models (Mamba-2 + GQA-Attention + MoE) — hook any location, cache activations, train JumpReLU SAEs, splice them into the forward pass, and evaluate them with SAE-Bench / SAE-Lens.

TransformerLens does not support hybrid Mamba-attention architectures, and Nemotron-3-Nano loads through trust_remote_code. nemotron-lens hooks the plain HuggingFace model directly (zero-overhead PyTorch forward hooks, module paths verified by runtime topology introspection) and keeps every SAE artifact in SAELens's native on-disk format, so the SAEs you train or download here also load with stock sae_lens — same repos, same folders, no conversion.

from nemotron_lens import HookedNemotron, SAE

model = HookedNemotron.from_pretrained("nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B-BF16")

# 1. list hookable locations (canonical names; raw HF module paths work too)
model.hook_points(kinds=["resid_post", "mamba_out", "moe_out"], layers=[2, 25])
# ['blocks.2.hook_resid_post', 'blocks.25.hook_mamba_out', ...]

# 2. run with cache
logits, cache = model.run_with_cache(
    "The Eiffel Tower is in", names=["blocks.25.hook_mamba_out"]
)
acts = cache["blocks.25.hook_mamba_out"]        # (batch, seq, d_model)

# 3. load a pretrained SAE (either library reads the same HF repo!)
sae = SAE.from_pretrained("Yusser/nemotron-3-nano-30b-a3b-saes",
                          "L25_mamba_out/w16384_l0_10", device="cuda")
feats = sae.encode(acts.float().flatten(0, 1))  # (tokens, 16384), ~10 active each

# 4. splice the SAE into the forward pass (uses sae.metadata['hook_name'])
recon_logits = model.run_with_saes("The Eiffel Tower is in", sae)

The same SAE via stock SAELens:

from sae_lens import SAE  # returns a sae_lens JumpReLUSAE — identical weights
sae = SAE.from_pretrained("Yusser/nemotron-3-nano-30b-a3b-saes",
                          "L25_mamba_out/w16384_l0_10")

Install

pip install nemotron-lens              # SAE loading/training, hooking API
pip install "nemotron-lens[model]"     # + mamba-ssm/causal-conv1d (run the LM; needs CUDA + nvcc)
pip install "nemotron-lens[eval]"      # + sae-lens/transformer-lens/sae-bench (eval harness)

The base install has no TransformerLens/SAELens dependency: loading SAEs and training on pre-extracted activations works anywhere PyTorch does. Running the 30B model itself requires the Mamba-2 CUDA kernels ([model] extra) — for compile flags on Blackwell GPUs see nemotron-sae's setup_venv.sh.

Hook points

A Nemotron layer is Mamba-2 or attention or MoE. Canonical names follow TransformerLens conventions, resolved against the model's runtime topology (model.save_topology(path) dumps it):

name activation
blocks.{L}.hook_resid_pre / hook_resid_post residual stream (block input / output)
blocks.{L}.hook_mamba_out Mamba-2 mixer output
blocks.{L}.hook_attn_out_prelinear attention mixer output
blocks.{L}.hook_moe_out MoE block output
blocks.{L}.hook_expert.{i} / hook_shared_expert routed / shared expert output

Every API also accepts raw HF module paths (backbone.layers.25.mixer) — which is exactly what published SAEs record in metadata["hook_name"].

run_with_hooks lets you observe or edit any of these:

def boost(acts, hook_name):
    return acts * 1.1                       # return None to observe only

logits = model.run_with_hooks(prompt, [("blocks.25.hook_mamba_out", boost)])

run_with_cache(..., stop_after_cache=True) aborts the forward right after the deepest requested hook — activation extraction on a 30B model without paying for the upper layers or the LM head.

Train an SAE

The trainer is the Gemma Scope 2 JumpReLU recipe with the exact configuration first validated on Nemotron-3-Nano (see the nemotron-sae technical report): quadratic L0-target penalty, paper_v3 straight-through estimators, log-space thresholds, unit-norm decoder columns with gradient projection, health telemetry that catches the known JumpReLU collapse modes live.

from nemotron_lens import ShuffleBuffer, TrainConfig, train_sae, TrainingSAE

texts = (row["text"] for row in my_hf_dataset)          # any str iterator
stream = model.stream_activations(texts, "blocks.25.hook_mamba_out",
                                  batch_size=8, context_size=2048)
buffer = ShuffleBuffer(stream, batch_size=4096)

ckpt = train_sae(buffer, d_in=model.d_model, out_dir="runs/L25_mamba",
                 cfg=TrainConfig(d_sae=16384, l0_target=10, n_steps=200_000))

# fold norm-factor + pre-encoder bias -> standard JumpReLU on raw activations
from safetensors.torch import load_file
tsae = TrainingSAE(d_in=model.d_model, d_sae=16384)
tsae.load_state_dict(load_file(ckpt))
sae = tsae.to_inference(metadata={
    "model_name": model.model.config._name_or_path,
    "hook_name": model.module_path("blocks.25.hook_mamba_out"),
})
sae.save_pretrained("export/L25_mamba_out/w16384_l0_10")   # sae_lens-native format

Training resumes automatically from the latest checkpoint in out_dir; train_log.jsonl records loss/L0/dead-% plus threshold-health diagnostics (STE window occupancy, z_std, θ stats) every log_every steps.

To publish, upload the exported folders to the HuggingFace Hub (e.g. with sae_lens.upload_saes_to_huggingface) and both libraries can from_pretrained them.

Evaluate (SAE-Bench / SAE-Lens)

Both suites are TransformerLens-based; nemotron-lens bridges the gap with SAE-Lens's HookedProxyLM plus the compatibility shims proven in nemotron-sae's external evaluation harness (pip install "nemotron-lens[eval]"):

from nemotron_lens.evals import run_saebench, run_saelens_evals

run_saelens_evals(sae, model)                       # L0, FVU, CE-loss-recovered, KL
run_saebench(sae, model, evals=["core", "sparse_probing", "scr", "tpp", "absorption"])

Pretrained SAEs

13 JumpReLU SAEs (width 16384, L0*=10, 1M steps ≈ 4.1B token-activations on Nemotron-CC-v2.1) across residual / Mamba / attention / MoE sites of Nemotron-3-Nano-30B-A3B — to our knowledge the first public SAEs for a hybrid Mamba-attention LLM: Yusser/nemotron-3-nano-30b-a3b-saes (per-SAE eval metrics in each cfg.json and on the model card).

Related projects

  • nemotron-sae — the full training pipeline these SAEs came from (sharded activation caches, sweep launcher, slurm scripts, technical report).
  • SAELens — SAE standard library; nemotron-lens uses its on-disk format and (optionally) its eval stack.
  • SAEBench — standardized SAE evaluation suite, driven here through the proxy bridge.
  • TransformerLens — the API conventions HookedNemotron follows.

Citation

If you use nemotron-lens or the pretrained SAEs, please cite this repository and Gemma Scope (arXiv:2408.05147), whose training recipe the SAEs follow.

License

MIT. The Nemotron base model is subject to the NVIDIA Open Model License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nemotron_lens-0.1.0.tar.gz (33.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nemotron_lens-0.1.0-py3-none-any.whl (34.9 kB view details)

Uploaded Python 3

File details

Details for the file nemotron_lens-0.1.0.tar.gz.

File metadata

  • Download URL: nemotron_lens-0.1.0.tar.gz
  • Upload date:
  • Size: 33.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.6

File hashes

Hashes for nemotron_lens-0.1.0.tar.gz
Algorithm Hash digest
SHA256 215c38ec5752a95302e6c90c48eadf8e3b55757879aa36e3f261830aec828a59
MD5 f7d60fb806a646bd31e7a209baa5b594
BLAKE2b-256 2a3154a62aae5478a69f9df4367b844c83f29b8fa97a5117e342d50ff6d3ee14

See more details on using hashes here.

File details

Details for the file nemotron_lens-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: nemotron_lens-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 34.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.6

File hashes

Hashes for nemotron_lens-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c075ffc29cb5e33493e173a5e908c0628125a3dffaf72d39e2c5b56c9c908542
MD5 e1780868ca67088e362aed639135338a
BLAKE2b-256 acbd5cb79cca1f29704d02c194b94542dec9cf6c640c0bd58e2184454f820cee

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page