Feature Dictionary
Give your SAE's 20,000 anonymous features actual names
- dict_path
- summary
The pack's SAE work gives you 20,000+ sparse features, and until you run this node they're just indices. Feature Dictionary runs a batch of diverse prompts through the text encoder + your trained SAE and records which prompts each feature fires hardest on, then saves a JSON mapping feature index → top-activating prompts. It's the step that turns 4821 from "a number" into "fires on descriptions of warm golden rim lighting." Run it once per SAE; it takes one to two minutes and unlocks readable labels everywhere else in the pack.
How it works
The node pushes roughly 120 built-in prompts plus n_extra_prompts generated ones through the Qwen encoder, hooks the SAE at the chosen layer, and for every feature stores the top few prompts by activation. The result is a JSON dictionary at save_path where each feature index points at the prompts that light it up. It's not a fancy captioning pipeline - it's a nearest-neighbor labeling trick: whatever a feature fires on most is the best textual proxy for what it encodes.
That JSON is the connective tissue of the whole pack. Pass dict_path into Feature Map and your top features come back labeled instead of bare. Feature Atlas merges the labels into its atlas. Feature Dashboard searches them by keyword. You run this once, then every downstream node gets friendlier.
The inputs that matter
- sae_path - your trained SAE
.pt. Must be the same SAE you use everywhere else. - save_path - where the dictionary JSON goes. The tooltip spells out the wiring: pass this path to Feature Map's
dict_pathinput. - layer / sae_expansion - must match how the SAE was trained. 22 and 8 by convention.
- top_prompts - how many top-activating prompts to store per feature (5 default).
- n_extra_prompts - extra generated prompts beyond the built-in ~120. The tooltip notes these use diverse templates to avoid formulaic patterns, and more prompts give more discriminative labels. 300 is a reasonable bump.
- encoder_path - Qwen safetensors, or the
QWEN_ENCODER_PATHenv var.
Outputs: dict_path (the JSON path) and summary (a string overview). Wire dict_path straight into Feature Map.
Installing
Standard for the pack - ComfyUI Manager search "Concept Steer", or clone https://github.com/Nynxz/ComfyUI-ConceptSteer into custom_nodes/ and restart. Needs transformers and safetensors installed, a trained SAE (from Train SAE), the Qwen encoder (~10 GB VRAM to run), and it'll be quicker with n_extra_prompts modest while you validate.
Common gotchas
- Labels are only as good as your SAE. A bad SAE (trained on synthetic data, too-high L1) produces features that fire on junk, and the dictionary faithfully records that junk. Garbage in, garbage labels.
- Feature indices shift across SAE runs. A dictionary is only valid for the exact SAE it was built from - same layer, same expansion, same seed. Retrain, re-dict.
- Don't expect perfect monosemantic labels. Real SAE features aren't all cleanly single-concept. The top prompts are a strong hint, not a definition - which is exactly why the pack pairs this with Feature Probe, so you can verify a feature by watching what it actually does to an image.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| sae_path | STRING | Path to the trained SAE weights (.pt) | |
| save_path | STRING | /tmp/ComfyUI/custom_nodes/ComfyUI-ConceptSteer/sae/feature_dict.json | Where to save the feature dictionary JSON. Pass this path to Feature Map's dict_path input. |
| layer | INT | 221–36 | Transformer layer (must match SAE training) |
| sae_expansion | INT | 82–16 | SAE expansion factor (must match SAE training) |
| top_prompts | INT | 51–20 | How many top-activating prompts to store per feature |
| n_extra_prompts | INT | 3000–1000 | Extra generated prompts beyond the built-in ~120. More = better coverage and more discriminative labels. Uses diverse templates to avoid formulaic patterns. |
| encoder_path | STRING | Path to Qwen encoder safetensors (or set env var) | |
| protect_existing | BOOLEAN | true | If the save path already exists, auto-rename to _v2, _v3, … instead of overwriting. Disable only when intentionally replacing. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| dict_path | STRING | — |
| summary | STRING | — |