[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M737P4WBZ6CD3FXDN97QXTAG":3,"skill-same:01M737P4WBZ6CD3FXDN97QXTAG":76},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":18,"linkOnly":19,"markdownContent":20,"markdownBody":21,"frontMatter":22,"refName":41,"commitSha":42,"skillDirectory":43,"forksCount":44,"repositoryHtmlUrl":45,"repositoryHomepageUrl":6,"ownerHtmlUrl":46,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":47,"install":48,"resources":61},"01M737P4WBZ6CD3FXDN97QXTAG","saelens",null,"Train sparse autoencoders to interpret model features.","ashneil12\u002Fvanilla-hermes-agent-canary","ashneil12","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F49880658?v=4","01M7378BQ9W161EPENEWBYAQNN","01M7378BRDJG8SFS93FG4V6BWY",1,"MIT","https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Foptional-skills\u002Fmlops\u002Fsaelens\u002FSKILL.md",[],[],"2026-11-11 15:11:14",false,"---\nname: saelens\ndescription: Train sparse autoencoders to interpret model features.\nversion: 1.0.1\nauthor: Orchestra Research\nlicense: MIT\ndependencies: [sae-lens>=6.0.0, transformer-lens>=2.0.0, torch>=2.0.0]\nplatforms: [linux, macos, windows]\nmetadata:\n  hermes:\n    tags: [Sparse Autoencoders, SAE, Mechanistic Interpretability, Feature Discovery, Superposition]\n\n---\n\n# SAELens: Sparse Autoencoders for Mechanistic Interpretability\n\nSAELens is the primary library for training and analyzing Sparse Autoencoders (SAEs) - a technique for decomposing polysemantic neural network activations into sparse, interpretable features. Based on Anthropic's groundbreaking research on monosemanticity.\n\n**GitHub**: [jbloomAus\u002FSAELens](https:\u002F\u002Fgithub.com\u002FjbloomAus\u002FSAELens) (1,100+ stars)\n\n## The Problem: Polysemanticity & Superposition\n\nIndividual neurons in neural networks are **polysemantic** - they activate in multiple, semantically distinct contexts. This happens because models use **superposition** to represent more features than they have neurons, making interpretability difficult.\n\n**SAEs solve this** by decomposing dense activations into sparse, monosemantic features - typically only a small number of features activate for any given input, and each feature corresponds to an interpretable concept.\n\n## When to Use SAELens\n\n**Use SAELens when you need to:**\n- Discover interpretable features in model activations\n- Understand what concepts a model has learned\n- Study superposition and feature geometry\n- Perform feature-based steering or ablation\n- Analyze safety-relevant features (deception, bias, harmful content)\n\n**Consider alternatives when:**\n- You need basic activation analysis → Use **TransformerLens** directly\n- You want causal intervention experiments → Use **pyvene** or **TransformerLens**\n- You need production steering → Consider direct activation engineering\n\n## Installation\n\n```bash\npip install sae-lens\n```\n\nRequirements: Python 3.10+, transformer-lens>=2.0.0\n\n## Core Concepts\n\n### What SAEs Learn\n\nSAEs are trained to reconstruct model activations through a sparse bottleneck:\n\n```\nInput Activation → Encoder → Sparse Features → Decoder → Reconstructed Activation\n    (d_model)       ↓        (d_sae >> d_model)    ↓         (d_model)\n                 sparsity                      reconstruction\n                 penalty                          loss\n```\n\n**Loss Function**: `MSE(original, reconstructed) + L1_coefficient × L1(features)`\n\n### Key Validation (Anthropic Research)\n\nIn \"Towards Monosemanticity\", human evaluators found **70% of SAE features genuinely interpretable**. Features discovered include:\n- DNA sequences, legal language, HTTP requests\n- Hebrew text, nutrition statements, code syntax\n- Sentiment, named entities, grammatical structures\n\n## Workflow 1: Loading and Analyzing Pre-trained SAEs\n\n### Step-by-Step\n\n```python\nfrom transformer_lens import HookedTransformer\nfrom sae_lens import SAE\n\n# 1. Load model and pre-trained SAE\nmodel = HookedTransformer.from_pretrained(\"gpt2-small\", device=\"cuda\")\n# In sae-lens v6, SAE.from_pretrained() returns JUST the SAE (not a tuple).\nsae = SAE.from_pretrained(\n    release=\"gpt2-small-res-jb\",\n    sae_id=\"blocks.8.hook_resid_pre\",\n    device=\"cuda\"\n)\n# If you also need the cfg dict and feature sparsity, use:\n# sae, cfg_dict, sparsity = SAE.from_pretrained_with_cfg_and_sparsity(...)\n\n# 2. Get model activations\ntokens = model.to_tokens(\"The capital of France is Paris\")\n_, cache = model.run_with_cache(tokens)\nactivations = cache[\"resid_pre\", 8]  # [batch, pos, d_model]\n\n# 3. Encode to SAE features\nsae_features = sae.encode(activations)  # [batch, pos, d_sae]\nprint(f\"Active features: {(sae_features > 0).sum()}\")\n\n# 4. Find top features for each position\nfor pos in range(tokens.shape[1]):\n    top_features = sae_features[0, pos].topk(5)\n    token = model.to_str_tokens(tokens[0, pos:pos+1])[0]\n    print(f\"Token '{token}': features {top_features.indices.tolist()}\")\n\n# 5. Reconstruct activations\nreconstructed = sae.decode(sae_features)\nreconstruction_error = (activations - reconstructed).norm()\n```\n\n### Available Pre-trained SAEs\n\n| Release | Model | Layers |\n|---------|-------|--------|\n| `gpt2-small-res-jb` | GPT-2 Small | Multiple residual streams |\n| `gemma-2b-res` | Gemma 2B | Residual streams |\n| Various on HuggingFace | Search tag `saelens` | Various |\n\n### Checklist\n- [ ] Load model with TransformerLens\n- [ ] Load matching SAE for target layer\n- [ ] Encode activations to sparse features\n- [ ] Identify top-activating features per token\n- [ ] Validate reconstruction quality\n\n## Workflow 2: Training a Custom SAE\n\n### Step-by-Step\n\n```python\nfrom sae_lens import (\n    LanguageModelSAETrainingRunner,\n    LanguageModelSAERunnerConfig,\n    StandardTrainingSAEConfig,\n    LoggingConfig,\n)\n\n# 1. Configure training (v6 uses a NESTED config: SAE-specific options live in a\n#    `sae=` sub-config, and logging options live in a `logger=` sub-config).\n#    Note: `architecture`, `d_sae`, `l1_coefficient` etc. are now on the SAE sub-config,\n#    and legacy flat options like `hook_layer`, `activation_fn`, `log_to_wandb` were removed.\ncfg = LanguageModelSAERunnerConfig(\n    # SAE architecture + sparsity (nested)\n    sae=StandardTrainingSAEConfig(\n        d_in=768,          # Model dimension\n        d_sae=768 * 8,     # Expansion factor of 8\n        l1_coefficient=8e-5,  # Sparsity penalty\n        apply_b_dec_to_input=True,\n        normalize_activations=\"expected_average_only_in\",\n    ),\n\n    # Data-generating function (model + hook point)\n    model_name=\"gpt2-small\",\n    hook_name=\"blocks.8.hook_resid_pre\",  # layer is inferred from hook_name (no hook_layer)\n\n    # Training\n    lr=4e-4,\n    l1_warm_up_steps=1000,\n    train_batch_size_tokens=4096,\n    training_tokens=100_000_000,\n\n    # Data\n    dataset_path=\"monology\u002Fpile-uncopyrighted\",\n    context_size=128,\n\n    # Logging (nested)\n    logger=LoggingConfig(\n        log_to_wandb=True,\n        wandb_project=\"sae-training\",\n    ),\n\n    # Checkpointing\n    checkpoint_path=\"checkpoints\",\n    n_checkpoints=5,\n)\n\n# 2. Train\ntrainer = LanguageModelSAETrainingRunner(cfg)  # SAETrainingRunner still works as an alias\nsae = trainer.run()\n\n# 3. Evaluate\nprint(f\"L0 (avg active features): {trainer.metrics['l0']}\")\nprint(f\"CE Loss Recovered: {trainer.metrics['ce_loss_score']}\")\n```\n\n> **v6 migration note:** For other SAE types swap the `sae=` sub-config —\n> `GatedTrainingSAEConfig`, `TopKTrainingSAEConfig` (set `k` directly), or\n> `JumpReLUTrainingSAEConfig` (uses `l0_coefficient`). Legacy flat options\n> (`architecture`, `expansion_factor`, `hook_layer`, `activation_fn`\u002F`activation_fn_kwargs`,\n> `use_ghost_grads`, ghost grads, b_dec\u002Fdecoder init options) were removed in v6.\n\n### Key Hyperparameters\n\n| Parameter | Typical Value | Effect |\n|-----------|---------------|--------|\n| `d_sae` | 4-16× d_model | More features, higher capacity |\n| `l1_coefficient` | 5e-5 to 1e-4 | Higher = sparser, less accurate |\n| `lr` | 1e-4 to 1e-3 | Standard optimizer LR |\n| `l1_warm_up_steps` | 500-2000 | Prevents early feature death |\n\n### Evaluation Metrics\n\n| Metric | Target | Meaning |\n|--------|--------|---------|\n| **L0** | 50-200 | Average active features per token |\n| **CE Loss Score** | 80-95% | Cross-entropy recovered vs original |\n| **Dead Features** | \u003C5% | Features that never activate |\n| **Explained Variance** | >90% | Reconstruction quality |\n\n### Checklist\n- [ ] Choose target layer and hook point\n- [ ] Set expansion factor (d_sae = 4-16× d_model)\n- [ ] Tune L1 coefficient for desired sparsity\n- [ ] Enable L1 warm-up to prevent dead features\n- [ ] Monitor metrics during training (W&B)\n- [ ] Validate L0 and CE loss recovery\n- [ ] Check dead feature ratio\n\n## Workflow 3: Feature Analysis and Steering\n\n### Analyzing Individual Features\n\n```python\nfrom transformer_lens import HookedTransformer\nfrom sae_lens import SAE\nimport torch\n\nmodel = HookedTransformer.from_pretrained(\"gpt2-small\", device=\"cuda\")\nsae = SAE.from_pretrained(  # v6 returns just the SAE\n    release=\"gpt2-small-res-jb\",\n    sae_id=\"blocks.8.hook_resid_pre\",\n    device=\"cuda\"\n)\n\n# Find what activates a specific feature\nfeature_idx = 1234\ntest_texts = [\n    \"The scientist conducted an experiment\",\n    \"I love chocolate cake\",\n    \"The code compiles successfully\",\n    \"Paris is beautiful in spring\",\n]\n\nfor text in test_texts:\n    tokens = model.to_tokens(text)\n    _, cache = model.run_with_cache(tokens)\n    features = sae.encode(cache[\"resid_pre\", 8])\n    activation = features[0, :, feature_idx].max().item()\n    print(f\"{activation:.3f}: {text}\")\n```\n\n### Feature Steering\n\n```python\ndef steer_with_feature(model, sae, prompt, feature_idx, strength=5.0):\n    \"\"\"Add SAE feature direction to residual stream.\"\"\"\n    tokens = model.to_tokens(prompt)\n\n    # Get feature direction from decoder\n    feature_direction = sae.W_dec[feature_idx]  # [d_model]\n\n    def steering_hook(activation, hook):\n        # Add scaled feature direction at all positions\n        activation += strength * feature_direction\n        return activation\n\n    # Generate with steering\n    output = model.generate(\n        tokens,\n        max_new_tokens=50,\n        fwd_hooks=[(\"blocks.8.hook_resid_pre\", steering_hook)]\n    )\n    return model.to_string(output[0])\n```\n\n### Feature Attribution\n\n```python\n# Which features most affect a specific output?\ntokens = model.to_tokens(\"The capital of France is\")\n_, cache = model.run_with_cache(tokens)\n\n# Get features at final position\nfeatures = sae.encode(cache[\"resid_pre\", 8])[0, -1]  # [d_sae]\n\n# Get logit attribution per feature\n# Feature contribution = feature_activation × decoder_weight × unembedding\nW_dec = sae.W_dec  # [d_sae, d_model]\nW_U = model.W_U    # [d_model, vocab]\n\n# Contribution to \"Paris\" logit\nparis_token = model.to_single_token(\" Paris\")\nfeature_contributions = features * (W_dec @ W_U[:, paris_token])\n\ntop_features = feature_contributions.topk(10)\nprint(\"Top features for 'Paris' prediction:\")\nfor idx, val in zip(top_features.indices, top_features.values):\n    print(f\"  Feature {idx.item()}: {val.item():.3f}\")\n```\n\n## Common Issues & Solutions\n\n> All examples below use the v6 nested config: SAE-specific options go in the `sae=`\n> sub-config (`StandardTrainingSAEConfig` \u002F `TopKTrainingSAEConfig` \u002F etc.), training\n> knobs stay on the top-level `LanguageModelSAERunnerConfig`.\n\n### Issue: High dead feature ratio\n```python\nfrom sae_lens import LanguageModelSAERunnerConfig, StandardTrainingSAEConfig\n\n# WRONG: no warm-up, features die early\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(d_in=768, d_sae=768*8, l1_coefficient=1e-4),\n    l1_warm_up_steps=0,  # Bad!\n)\n\n# RIGHT: warm up the L1 penalty (v6 removed ghost grads; warm-up is the lever now)\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(d_in=768, d_sae=768*8, l1_coefficient=8e-5),\n    l1_warm_up_steps=1000,  # Gradually increase\n)\n```\n\n### Issue: Poor reconstruction (low CE recovery)\n```python\n# Reduce sparsity penalty and\u002For add capacity (both on the SAE sub-config)\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(\n        d_in=768,\n        d_sae=768 * 16,       # More capacity\n        l1_coefficient=5e-5,  # Lower = better reconstruction\n    ),\n)\n```\n\n### Issue: Features not interpretable\n```python\nfrom sae_lens import LanguageModelSAERunnerConfig, StandardTrainingSAEConfig, TopKTrainingSAEConfig\n\n# Increase sparsity (higher L1)\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(d_in=768, d_sae=768*8, l1_coefficient=1e-4),\n)\n# Or use a TopK SAE (k is set directly in v6, not via activation_fn_kwargs)\ncfg = LanguageModelSAERunnerConfig(\n    sae=TopKTrainingSAEConfig(d_in=768, d_sae=768*8, k=50),  # Exactly 50 active features\n)\n```\n\n### Issue: Memory errors during training\n```python\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(d_in=768, d_sae=768*8, l1_coefficient=8e-5),\n    train_batch_size_tokens=2048,  # Reduce batch size\n    store_batch_size_prompts=4,    # Fewer prompts in buffer\n    n_batches_in_buffer=8,         # Smaller activation buffer\n)\n```\n\n## Integration with Neuronpedia\n\nBrowse pre-trained SAE features at [neuronpedia.org](https:\u002F\u002Fneuronpedia.org):\n\n```python\n# Features are indexed by SAE ID\n# Example: gpt2-small layer 8 feature 1234\n# → neuronpedia.org\u002Fgpt2-small\u002F8-res-jb\u002F1234\n```\n\n## Key Classes Reference\n\n| Class | Purpose |\n|-------|---------|\n| `SAE` | Sparse Autoencoder model |\n| `LanguageModelSAERunnerConfig` | Top-level training configuration (nests `sae=` and `logger=`) |\n| `StandardTrainingSAEConfig` \u002F `TopKTrainingSAEConfig` \u002F `GatedTrainingSAEConfig` \u002F `JumpReLUTrainingSAEConfig` | SAE-type-specific sub-configs (v6) |\n| `LoggingConfig` | Logging\u002FW&B sub-config (v6) |\n| `LanguageModelSAETrainingRunner` | Training loop manager (alias: `SAETrainingRunner`) |\n| `ActivationsStore` | Activation collection and batching |\n| `HookedSAETransformer` | TransformerLens + SAE integration |\n\n## Reference Documentation\n\nFor detailed API documentation, tutorials, and advanced usage, see the `references\u002F` folder:\n\n| File | Contents |\n|------|----------|\n| [references\u002FREADME.md](references\u002FREADME.md) | Overview and quick start guide |\n| [references\u002Fapi.md](references\u002Fapi.md) | Complete API reference for SAE, TrainingSAE, configurations |\n| [references\u002Ftutorials.md](references\u002Ftutorials.md) | Step-by-step tutorials for training, analysis, steering |\n\n## External Resources\n\n### Tutorials\n- [Basic Loading & Analysis](https:\u002F\u002Fgithub.com\u002FjbloomAus\u002FSAELens\u002Fblob\u002Fmain\u002Ftutorials\u002Fbasic_loading_and_analysing.ipynb)\n- [Training a Sparse Autoencoder](https:\u002F\u002Fgithub.com\u002FjbloomAus\u002FSAELens\u002Fblob\u002Fmain\u002Ftutorials\u002Ftraining_a_sparse_autoencoder.ipynb)\n- [ARENA SAE Curriculum](https:\u002F\u002Fwww.lesswrong.com\u002Fposts\u002FLnHowHgmrMbWtpkxx\u002Fintro-to-superposition-and-sparse-autoencoders-colab)\n\n### Papers\n- [Towards Monosemanticity](https:\u002F\u002Ftransformer-circuits.pub\u002F2023\u002Fmonosemantic-features) - Anthropic (2023)\n- [Scaling Monosemanticity](https:\u002F\u002Ftransformer-circuits.pub\u002F2024\u002Fscaling-monosemanticity\u002F) - Anthropic (2024)\n- [Sparse Autoencoders Find Highly Interpretable Features](https:\u002F\u002Farxiv.org\u002Fabs\u002F2309.08600) - Cunningham et al. (ICLR 2024)\n\n### Official Documentation\n- [SAELens Docs](https:\u002F\u002Fjbloomaus.github.io\u002FSAELens\u002F)\n- [Neuronpedia](https:\u002F\u002Fneuronpedia.org) - Feature browser\n\n## SAE Architectures\n\n| Architecture | Description | Use Case |\n|--------------|-------------|----------|\n| **Standard** | ReLU + L1 penalty | General purpose |\n| **Gated** | Learned gating mechanism | Better sparsity control |\n| **TopK** | Exactly K active features | Consistent sparsity |\n\n```python\nfrom sae_lens import LanguageModelSAERunnerConfig, TopKTrainingSAEConfig\n\n# TopK SAE (exactly 50 features active) — `k` is set on the SAE sub-config in v6\ncfg = LanguageModelSAERunnerConfig(\n    sae=TopKTrainingSAEConfig(d_in=768, d_sae=768*8, k=50),\n)\n```\n","# SAELens: Sparse Autoencoders for Mechanistic Interpretability\n\nSAELens is the primary library for training and analyzing Sparse Autoencoders (SAEs) - a technique for decomposing polysemantic neural network activations into sparse, interpretable features. Based on Anthropic's groundbreaking research on monosemanticity.\n\n**GitHub**: [jbloomAus\u002FSAELens](https:\u002F\u002Fgithub.com\u002FjbloomAus\u002FSAELens) (1,100+ stars)\n\n## The Problem: Polysemanticity & Superposition\n\nIndividual neurons in neural networks are **polysemantic** - they activate in multiple, semantically distinct contexts. This happens because models use **superposition** to represent more features than they have neurons, making interpretability difficult.\n\n**SAEs solve this** by decomposing dense activations into sparse, monosemantic features - typically only a small number of features activate for any given input, and each feature corresponds to an interpretable concept.\n\n## When to Use SAELens\n\n**Use SAELens when you need to:**\n- Discover interpretable features in model activations\n- Understand what concepts a model has learned\n- Study superposition and feature geometry\n- Perform feature-based steering or ablation\n- Analyze safety-relevant features (deception, bias, harmful content)\n\n**Consider alternatives when:**\n- You need basic activation analysis → Use **TransformerLens** directly\n- You want causal intervention experiments → Use **pyvene** or **TransformerLens**\n- You need production steering → Consider direct activation engineering\n\n## Installation\n\n```bash\npip install sae-lens\n```\n\nRequirements: Python 3.10+, transformer-lens>=2.0.0\n\n## Core Concepts\n\n### What SAEs Learn\n\nSAEs are trained to reconstruct model activations through a sparse bottleneck:\n\n```\nInput Activation → Encoder → Sparse Features → Decoder → Reconstructed Activation\n    (d_model)       ↓        (d_sae >> d_model)    ↓         (d_model)\n                 sparsity                      reconstruction\n                 penalty                          loss\n```\n\n**Loss Function**: `MSE(original, reconstructed) + L1_coefficient × L1(features)`\n\n### Key Validation (Anthropic Research)\n\nIn \"Towards Monosemanticity\", human evaluators found **70% of SAE features genuinely interpretable**. Features discovered include:\n- DNA sequences, legal language, HTTP requests\n- Hebrew text, nutrition statements, code syntax\n- Sentiment, named entities, grammatical structures\n\n## Workflow 1: Loading and Analyzing Pre-trained SAEs\n\n### Step-by-Step\n\n```python\nfrom transformer_lens import HookedTransformer\nfrom sae_lens import SAE\n\n# 1. Load model and pre-trained SAE\nmodel = HookedTransformer.from_pretrained(\"gpt2-small\", device=\"cuda\")\n# In sae-lens v6, SAE.from_pretrained() returns JUST the SAE (not a tuple).\nsae = SAE.from_pretrained(\n    release=\"gpt2-small-res-jb\",\n    sae_id=\"blocks.8.hook_resid_pre\",\n    device=\"cuda\"\n)\n# If you also need the cfg dict and feature sparsity, use:\n# sae, cfg_dict, sparsity = SAE.from_pretrained_with_cfg_and_sparsity(...)\n\n# 2. Get model activations\ntokens = model.to_tokens(\"The capital of France is Paris\")\n_, cache = model.run_with_cache(tokens)\nactivations = cache[\"resid_pre\", 8]  # [batch, pos, d_model]\n\n# 3. Encode to SAE features\nsae_features = sae.encode(activations)  # [batch, pos, d_sae]\nprint(f\"Active features: {(sae_features > 0).sum()}\")\n\n# 4. Find top features for each position\nfor pos in range(tokens.shape[1]):\n    top_features = sae_features[0, pos].topk(5)\n    token = model.to_str_tokens(tokens[0, pos:pos+1])[0]\n    print(f\"Token '{token}': features {top_features.indices.tolist()}\")\n\n# 5. Reconstruct activations\nreconstructed = sae.decode(sae_features)\nreconstruction_error = (activations - reconstructed).norm()\n```\n\n### Available Pre-trained SAEs\n\n| Release | Model | Layers |\n|---------|-------|--------|\n| `gpt2-small-res-jb` | GPT-2 Small | Multiple residual streams |\n| `gemma-2b-res` | Gemma 2B | Residual streams |\n| Various on HuggingFace | Search tag `saelens` | Various |\n\n### Checklist\n- [ ] Load model with TransformerLens\n- [ ] Load matching SAE for target layer\n- [ ] Encode activations to sparse features\n- [ ] Identify top-activating features per token\n- [ ] Validate reconstruction quality\n\n## Workflow 2: Training a Custom SAE\n\n### Step-by-Step\n\n```python\nfrom sae_lens import (\n    LanguageModelSAETrainingRunner,\n    LanguageModelSAERunnerConfig,\n    StandardTrainingSAEConfig,\n    LoggingConfig,\n)\n\n# 1. Configure training (v6 uses a NESTED config: SAE-specific options live in a\n#    `sae=` sub-config, and logging options live in a `logger=` sub-config).\n#    Note: `architecture`, `d_sae`, `l1_coefficient` etc. are now on the SAE sub-config,\n#    and legacy flat options like `hook_layer`, `activation_fn`, `log_to_wandb` were removed.\ncfg = LanguageModelSAERunnerConfig(\n    # SAE architecture + sparsity (nested)\n    sae=StandardTrainingSAEConfig(\n        d_in=768,          # Model dimension\n        d_sae=768 * 8,     # Expansion factor of 8\n        l1_coefficient=8e-5,  # Sparsity penalty\n        apply_b_dec_to_input=True,\n        normalize_activations=\"expected_average_only_in\",\n    ),\n\n    # Data-generating function (model + hook point)\n    model_name=\"gpt2-small\",\n    hook_name=\"blocks.8.hook_resid_pre\",  # layer is inferred from hook_name (no hook_layer)\n\n    # Training\n    lr=4e-4,\n    l1_warm_up_steps=1000,\n    train_batch_size_tokens=4096,\n    training_tokens=100_000_000,\n\n    # Data\n    dataset_path=\"monology\u002Fpile-uncopyrighted\",\n    context_size=128,\n\n    # Logging (nested)\n    logger=LoggingConfig(\n        log_to_wandb=True,\n        wandb_project=\"sae-training\",\n    ),\n\n    # Checkpointing\n    checkpoint_path=\"checkpoints\",\n    n_checkpoints=5,\n)\n\n# 2. Train\ntrainer = LanguageModelSAETrainingRunner(cfg)  # SAETrainingRunner still works as an alias\nsae = trainer.run()\n\n# 3. Evaluate\nprint(f\"L0 (avg active features): {trainer.metrics['l0']}\")\nprint(f\"CE Loss Recovered: {trainer.metrics['ce_loss_score']}\")\n```\n\n> **v6 migration note:** For other SAE types swap the `sae=` sub-config —\n> `GatedTrainingSAEConfig`, `TopKTrainingSAEConfig` (set `k` directly), or\n> `JumpReLUTrainingSAEConfig` (uses `l0_coefficient`). Legacy flat options\n> (`architecture`, `expansion_factor`, `hook_layer`, `activation_fn`\u002F`activation_fn_kwargs`,\n> `use_ghost_grads`, ghost grads, b_dec\u002Fdecoder init options) were removed in v6.\n\n### Key Hyperparameters\n\n| Parameter | Typical Value | Effect |\n|-----------|---------------|--------|\n| `d_sae` | 4-16× d_model | More features, higher capacity |\n| `l1_coefficient` | 5e-5 to 1e-4 | Higher = sparser, less accurate |\n| `lr` | 1e-4 to 1e-3 | Standard optimizer LR |\n| `l1_warm_up_steps` | 500-2000 | Prevents early feature death |\n\n### Evaluation Metrics\n\n| Metric | Target | Meaning |\n|--------|--------|---------|\n| **L0** | 50-200 | Average active features per token |\n| **CE Loss Score** | 80-95% | Cross-entropy recovered vs original |\n| **Dead Features** | \u003C5% | Features that never activate |\n| **Explained Variance** | >90% | Reconstruction quality |\n\n### Checklist\n- [ ] Choose target layer and hook point\n- [ ] Set expansion factor (d_sae = 4-16× d_model)\n- [ ] Tune L1 coefficient for desired sparsity\n- [ ] Enable L1 warm-up to prevent dead features\n- [ ] Monitor metrics during training (W&B)\n- [ ] Validate L0 and CE loss recovery\n- [ ] Check dead feature ratio\n\n## Workflow 3: Feature Analysis and Steering\n\n### Analyzing Individual Features\n\n```python\nfrom transformer_lens import HookedTransformer\nfrom sae_lens import SAE\nimport torch\n\nmodel = HookedTransformer.from_pretrained(\"gpt2-small\", device=\"cuda\")\nsae = SAE.from_pretrained(  # v6 returns just the SAE\n    release=\"gpt2-small-res-jb\",\n    sae_id=\"blocks.8.hook_resid_pre\",\n    device=\"cuda\"\n)\n\n# Find what activates a specific feature\nfeature_idx = 1234\ntest_texts = [\n    \"The scientist conducted an experiment\",\n    \"I love chocolate cake\",\n    \"The code compiles successfully\",\n    \"Paris is beautiful in spring\",\n]\n\nfor text in test_texts:\n    tokens = model.to_tokens(text)\n    _, cache = model.run_with_cache(tokens)\n    features = sae.encode(cache[\"resid_pre\", 8])\n    activation = features[0, :, feature_idx].max().item()\n    print(f\"{activation:.3f}: {text}\")\n```\n\n### Feature Steering\n\n```python\ndef steer_with_feature(model, sae, prompt, feature_idx, strength=5.0):\n    \"\"\"Add SAE feature direction to residual stream.\"\"\"\n    tokens = model.to_tokens(prompt)\n\n    # Get feature direction from decoder\n    feature_direction = sae.W_dec[feature_idx]  # [d_model]\n\n    def steering_hook(activation, hook):\n        # Add scaled feature direction at all positions\n        activation += strength * feature_direction\n        return activation\n\n    # Generate with steering\n    output = model.generate(\n        tokens,\n        max_new_tokens=50,\n        fwd_hooks=[(\"blocks.8.hook_resid_pre\", steering_hook)]\n    )\n    return model.to_string(output[0])\n```\n\n### Feature Attribution\n\n```python\n# Which features most affect a specific output?\ntokens = model.to_tokens(\"The capital of France is\")\n_, cache = model.run_with_cache(tokens)\n\n# Get features at final position\nfeatures = sae.encode(cache[\"resid_pre\", 8])[0, -1]  # [d_sae]\n\n# Get logit attribution per feature\n# Feature contribution = feature_activation × decoder_weight × unembedding\nW_dec = sae.W_dec  # [d_sae, d_model]\nW_U = model.W_U    # [d_model, vocab]\n\n# Contribution to \"Paris\" logit\nparis_token = model.to_single_token(\" Paris\")\nfeature_contributions = features * (W_dec @ W_U[:, paris_token])\n\ntop_features = feature_contributions.topk(10)\nprint(\"Top features for 'Paris' prediction:\")\nfor idx, val in zip(top_features.indices, top_features.values):\n    print(f\"  Feature {idx.item()}: {val.item():.3f}\")\n```\n\n## Common Issues & Solutions\n\n> All examples below use the v6 nested config: SAE-specific options go in the `sae=`\n> sub-config (`StandardTrainingSAEConfig` \u002F `TopKTrainingSAEConfig` \u002F etc.), training\n> knobs stay on the top-level `LanguageModelSAERunnerConfig`.\n\n### Issue: High dead feature ratio\n```python\nfrom sae_lens import LanguageModelSAERunnerConfig, StandardTrainingSAEConfig\n\n# WRONG: no warm-up, features die early\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(d_in=768, d_sae=768*8, l1_coefficient=1e-4),\n    l1_warm_up_steps=0,  # Bad!\n)\n\n# RIGHT: warm up the L1 penalty (v6 removed ghost grads; warm-up is the lever now)\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(d_in=768, d_sae=768*8, l1_coefficient=8e-5),\n    l1_warm_up_steps=1000,  # Gradually increase\n)\n```\n\n### Issue: Poor reconstruction (low CE recovery)\n```python\n# Reduce sparsity penalty and\u002For add capacity (both on the SAE sub-config)\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(\n        d_in=768,\n        d_sae=768 * 16,       # More capacity\n        l1_coefficient=5e-5,  # Lower = better reconstruction\n    ),\n)\n```\n\n### Issue: Features not interpretable\n```python\nfrom sae_lens import LanguageModelSAERunnerConfig, StandardTrainingSAEConfig, TopKTrainingSAEConfig\n\n# Increase sparsity (higher L1)\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(d_in=768, d_sae=768*8, l1_coefficient=1e-4),\n)\n# Or use a TopK SAE (k is set directly in v6, not via activation_fn_kwargs)\ncfg = LanguageModelSAERunnerConfig(\n    sae=TopKTrainingSAEConfig(d_in=768, d_sae=768*8, k=50),  # Exactly 50 active features\n)\n```\n\n### Issue: Memory errors during training\n```python\ncfg = LanguageModelSAERunnerConfig(\n    sae=StandardTrainingSAEConfig(d_in=768, d_sae=768*8, l1_coefficient=8e-5),\n    train_batch_size_tokens=2048,  # Reduce batch size\n    store_batch_size_prompts=4,    # Fewer prompts in buffer\n    n_batches_in_buffer=8,         # Smaller activation buffer\n)\n```\n\n## Integration with Neuronpedia\n\nBrowse pre-trained SAE features at [neuronpedia.org](https:\u002F\u002Fneuronpedia.org):\n\n```python\n# Features are indexed by SAE ID\n# Example: gpt2-small layer 8 feature 1234\n# → neuronpedia.org\u002Fgpt2-small\u002F8-res-jb\u002F1234\n```\n\n## Key Classes Reference\n\n| Class | Purpose |\n|-------|---------|\n| `SAE` | Sparse Autoencoder model |\n| `LanguageModelSAERunnerConfig` | Top-level training configuration (nests `sae=` and `logger=`) |\n| `StandardTrainingSAEConfig` \u002F `TopKTrainingSAEConfig` \u002F `GatedTrainingSAEConfig` \u002F `JumpReLUTrainingSAEConfig` | SAE-type-specific sub-configs (v6) |\n| `LoggingConfig` | Logging\u002FW&B sub-config (v6) |\n| `LanguageModelSAETrainingRunner` | Training loop manager (alias: `SAETrainingRunner`) |\n| `ActivationsStore` | Activation collection and batching |\n| `HookedSAETransformer` | TransformerLens + SAE integration |\n\n## Reference Documentation\n\nFor detailed API documentation, tutorials, and advanced usage, see the `references\u002F` folder:\n\n| File | Contents |\n|------|----------|\n| [references\u002FREADME.md](references\u002FREADME.md) | Overview and quick start guide |\n| [references\u002Fapi.md](references\u002Fapi.md) | Complete API reference for SAE, TrainingSAE, configurations |\n| [references\u002Ftutorials.md](references\u002Ftutorials.md) | Step-by-step tutorials for training, analysis, steering |\n\n## External Resources\n\n### Tutorials\n- [Basic Loading & Analysis](https:\u002F\u002Fgithub.com\u002FjbloomAus\u002FSAELens\u002Fblob\u002Fmain\u002Ftutorials\u002Fbasic_loading_and_analysing.ipynb)\n- [Training a Sparse Autoencoder](https:\u002F\u002Fgithub.com\u002FjbloomAus\u002FSAELens\u002Fblob\u002Fmain\u002Ftutorials\u002Ftraining_a_sparse_autoencoder.ipynb)\n- [ARENA SAE Curriculum](https:\u002F\u002Fwww.lesswrong.com\u002Fposts\u002FLnHowHgmrMbWtpkxx\u002Fintro-to-superposition-and-sparse-autoencoders-colab)\n\n### Papers\n- [Towards Monosemanticity](https:\u002F\u002Ftransformer-circuits.pub\u002F2023\u002Fmonosemantic-features) - Anthropic (2023)\n- [Scaling Monosemanticity](https:\u002F\u002Ftransformer-circuits.pub\u002F2024\u002Fscaling-monosemanticity\u002F) - Anthropic (2024)\n- [Sparse Autoencoders Find Highly Interpretable Features](https:\u002F\u002Farxiv.org\u002Fabs\u002F2309.08600) - Cunningham et al. (ICLR 2024)\n\n### Official Documentation\n- [SAELens Docs](https:\u002F\u002Fjbloomaus.github.io\u002FSAELens\u002F)\n- [Neuronpedia](https:\u002F\u002Fneuronpedia.org) - Feature browser\n\n## SAE Architectures\n\n| Architecture | Description | Use Case |\n|--------------|-------------|----------|\n| **Standard** | ReLU + L1 penalty | General purpose |\n| **Gated** | Learned gating mechanism | Better sparsity control |\n| **TopK** | Exactly K active features | Consistent sparsity |\n\n```python\nfrom sae_lens import LanguageModelSAERunnerConfig, TopKTrainingSAEConfig\n\n# TopK SAE (exactly 50 features active) — `k` is set on the SAE sub-config in v6\ncfg = LanguageModelSAERunnerConfig(\n    sae=TopKTrainingSAEConfig(d_in=768, d_sae=768*8, k=50),\n)\n```\n",{"name":5,"author":23,"license":14,"version":24,"metadata":25,"platforms":33,"description":7,"dependencies":37},"Orchestra Research","1.0.1",{"hermes":26},{"tags":27},[28,29,30,31,32],"Sparse Autoencoders","SAE","Mechanistic Interpretability","Feature Discovery","Superposition",[34,35,36],"linux","macos","windows",[38,39,40],"sae-lens>=6.0.0","transformer-lens>=2.0.0","torch>=2.0.0","main","0905b0264ce5a54908bedc9637e50251543db132","optional-skills\u002Fmlops\u002Fsaelens",0,"https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary","https:\u002F\u002Fgithub.com\u002Fashneil12","2026-11-04 08:25:00",{"source":8,"skillName":5,"commands":49,"prompt":59,"zipAvailable":60},[50,53,56],{"tool":51,"command":52},"npx","npx skills add ashneil12\u002Fvanilla-hermes-agent-canary --skill saelens",{"tool":54,"command":55},"bunx","bunx skills add ashneil12\u002Fvanilla-hermes-agent-canary --skill saelens",{"tool":57,"command":58},"pnpm","pnpm dlx skills add ashneil12\u002Fvanilla-hermes-agent-canary --skill saelens","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Foptional-skills\u002Fmlops\u002Fsaelens\u002FSKILL.md",true,[62,68,72],{"path":63,"resourceType":64,"resourceTypeDesc":65,"sizeBytes":66,"sourceHtmlUrl":67},"references\u002Fapi.md","REFERENCE","参考文档",6968,"https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Foptional-skills\u002Fmlops\u002Fsaelens\u002Freferences\u002Fapi.md",{"path":69,"resourceType":64,"resourceTypeDesc":65,"sizeBytes":70,"sourceHtmlUrl":71},"references\u002FREADME.md",2085,"https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Foptional-skills\u002Fmlops\u002Fsaelens\u002Freferences\u002FREADME.md",{"path":73,"resourceType":64,"resourceTypeDesc":65,"sizeBytes":74,"sourceHtmlUrl":75},"references\u002Ftutorials.md",9383,"https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Foptional-skills\u002Fmlops\u002Fsaelens\u002Freferences\u002Ftutorials.md",[77,84,91,98,105,112],{"skillNo":78,"name":79,"nameZh":6,"description":80,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":81,"categories":82,"keywords":83,"publishedAt":18},"01M7380YR13A23353XT9NS6EGR","blocked-page-recovery","Use when a fetch fails: 403\u002F429, paywall, WAF, bot wall.","https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Fskills\u002Fweb\u002Fblocked-page-recovery\u002FSKILL.md",[],[],{"skillNo":85,"name":86,"nameZh":6,"description":87,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":88,"categories":89,"keywords":90,"publishedAt":18},"01M7380VZ8P60Q64J3F92D4AMY","test-driven-development","TDD: enforce RED-GREEN-REFACTOR, tests before code.","https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Fskills\u002Fsoftware-development\u002Ftest-driven-development\u002FSKILL.md",[],[],{"skillNo":92,"name":93,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":97,"publishedAt":18},"01M7380QXN6F90R0MH1M3FHRKX","systematic-debugging","4-phase root cause debugging: understand bugs before fixing.","https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Fskills\u002Fsoftware-development\u002Fsystematic-debugging\u002FSKILL.md",[],[],{"skillNo":99,"name":100,"nameZh":6,"description":101,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":102,"categories":103,"keywords":104,"publishedAt":18},"01M7380N4BZYT2WRRZN1N9DZ65","spike","Throwaway experiments to validate an idea before build.","https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Fskills\u002Fsoftware-development\u002Fspike\u002FSKILL.md",[],[],{"skillNo":106,"name":107,"nameZh":6,"description":108,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":109,"categories":110,"keywords":111,"publishedAt":18},"01M7380JAEC9ZH5DVPHHK56P97","simplify-code","Parallel 4-agent cleanup of recent code changes.","https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Fskills\u002Fsoftware-development\u002Fsimplify-code\u002FSKILL.md",[],[],{"skillNo":113,"name":114,"nameZh":6,"description":115,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":116,"categories":117,"keywords":118,"publishedAt":18},"01M7380F5MBB7FKWWV3G3TZ193","requesting-code-review","Pre-commit review: security scan, quality gates, auto-fix.","https:\u002F\u002Fgithub.com\u002Fashneil12\u002Fvanilla-hermes-agent-canary\u002Fblob\u002Fmain\u002Fskills\u002Fsoftware-development\u002Frequesting-code-review\u002FSKILL.md",[],[]]