6from __future__
import annotations
10from collections
import OrderedDict
11from pathlib
import Path
15MODEL_CONFIGS: dict[str, dict[str, Any]] = {
17 "hf_name":
"meta-llama/Llama-3.2-1B-Instruct",
21 "sae_source":
"native",
22 "sae_layers": {i: f
"sae_layer{i}.pt" for i
in range(16)},
23 "lora_target_modules": [
"q_proj",
"v_proj"],
26 "hf_name":
"EleutherAI/pythia-2.8b",
30 "sae_source":
"native",
32 "lora_target_modules": [
"query_key_value",
"dense"],
39 "sae_source":
"native",
40 "sae_layers": {8:
"sae_layer8.pt"},
41 "lora_target_modules": [
"c_attn",
"c_fc"],
44 "hf_name":
"EleutherAI/pythia-70m-deduped",
48 "sae_source":
"native",
49 "sae_layers": {3:
"sae_layer3.pt"},
50 "lora_target_modules": [
"query_key_value",
"dense"],
53 "hf_name":
"sarvamai/sarvam-30b",
58 "sae_source":
"native",
59 "sae_layers": {9:
"sarvam_l9.pt"},
60 "trust_remote_code":
True,
62 "lora_target_modules": [
"query_key_value"],
64 "lfm2.5-1.2b-instruct": {
65 "hf_name":
"LiquidAI/LFM2.5-1.2B-Instruct",
70 "sae_source":
"native",
71 "sae_layers": {8:
"sae_layer8.pt"},
72 "norm_layers": {8:
"norm_layer8.pt"},
74 "lora_target_modules": [
"q_proj",
"v_proj"],
76 "lfm2.5-1.2b-thinking": {
77 "hf_name":
"LiquidAI/LFM2.5-1.2B-Thinking",
82 "sae_source":
"native",
83 "sae_layers": {8:
"sae_layer8.pt"},
84 "norm_layers": {8:
"norm_layer8.pt"},
86 "lora_target_modules": [
"q_proj",
"v_proj"],
89 "hf_name":
"LiquidAI/LFM2.5-230M",
94 "sae_source":
"native",
95 "sae_layers": {i: f
"sae_layer{i}.pt" for i
in range(14)},
96 "norm_layers": {i: f
"norm_layer{i}.pt" for i
in range(14)},
98 "lora_target_modules": [
"q_proj",
"v_proj"],
102_HF_TO_SHORT: dict[str, str] = {
103 cfg[
"hf_name"].lower(): key
for key, cfg
in MODEL_CONFIGS.items()
107_models: OrderedDict = OrderedDict()
111_model_io_lock = threading.RLock()
115_sae_cache: dict[tuple[str, int], Any] = {}
117_ACTIVE_MODEL_PATH = Path.home() /
".aquin" /
"active_model.txt"
125 """Drop a cached SAE so the next load re-reads from disk (after a rebind)."""
128 for key
in [k
for k
in _sae_cache
if k[0] == short]:
129 _sae_cache.pop(key,
None)
131 _sae_cache.pop((short, int(layer)),
None)
135 _ACTIVE_MODEL_PATH.parent.mkdir(parents=
True, exist_ok=
True)
136 _ACTIVE_MODEL_PATH.write_text(model_id)
140 """Return the model slug written by the last successful `aquin load`."""
141 if _ACTIVE_MODEL_PATH.exists():
142 txt = _ACTIVE_MODEL_PATH.read_text().strip()
153 resident = model_daemon.loaded_model()
162 """Reload the given model into VRAM (used after heavy jobs release the GPU)."""
170 if _ACTIVE_MODEL_PATH.exists():
171 _ACTIVE_MODEL_PATH.unlink(missing_ok=
True)
179 _, evicted = _models.popitem(last=
False)
188 return next(reversed(_models))
196 if model_id
in MODEL_CONFIGS:
198 short = _HF_TO_SHORT.get(model_id.lower())
203 slug, _ = resolve_llm_family(model_id)
209 if short
in MODEL_CONFIGS:
210 return MODEL_CONFIGS[short]
213 runtime = get_runtime_llm_config(short)
216 raise ValueError(f
"No config for model '{model_id}'")
220 """HuggingFace repo id for transformers.from_pretrained (resolves Aquin short slugs)."""
230 if stem.startswith(
"sae_layer"):
232 return int(stem.replace(
"sae_layer",
""))
241 return path.is_file()
and is_valid_sae_checkpoint_path(path)
245 """If a file exists on disk but cannot be loaded, return a re-download hint."""
247 resolved_layer = int(layer)
249 if not path.is_file():
254 f
"SAE checkpoint at {path} is corrupted or incomplete. "
255 f
"Delete it and re-download:\n"
257 f
" aquin load sae {short}-l{resolved_layer}"
265 device: str |
None =
None,
267 """Load a validated on-disk SAE or raise with a re-download hint."""
274 resolved_layer = int(layer)
275 dev = device
or resolve_compute_device()
279 raise ValueError(hint)
283 raise FileNotFoundError(
286 command=
"feature logit",
287 requested_layer=resolved_layer,
292 return SparseAutoencoder.load(str(path), device=dev)
293 except Exception
as exc:
296 cause = exc.__cause__
if exc.__cause__
is not None else exc
297 if is_corrupt_pytorch_zip(exc)
or is_corrupt_pytorch_zip(cause):
301 f
"SAE checkpoint at {path} is corrupted or incomplete. "
302 f
"Re-download: aquin load sae {short}-l{resolved_layer}"
309 """Return a loadable SAE checkpoint for model+layer, or None if missing/ambiguous."""
311 resolved_layer = int(layer)
316 active = get_active_user_sae_path(short, resolved_layer)
326 for r
in list_user_saes(short)
327 if r.get(
"layer") == resolved_layer
and r.get(
"path")
330 if len(existing) == 1:
339 """SAE layer indices with loadable checkpoints on disk for this model."""
341 found: set[int] = set()
345 found.add(int(layer))
350 for row
in list_user_saes(short):
351 layer_raw = row.get(
"layer")
352 if layer_raw
is None:
354 layer = int(layer_raw)
360 sae_dir = Path.home() /
".aquin" /
"sae" / short
362 for path
in sae_dir.glob(
"sae_layer*.pt"):
364 if layer
is not None and path.is_file():
371 """All SAE layer indices published for this model (may not be downloaded yet)."""
374 layers: dict = cfg.get(
"sae_layers", {})
376 return sorted(layers.keys())
377 return [int(cfg[
"sae_layer"])]
384 layer_flag: str =
"--layer",
385 example_suffix: str =
"",
386 requested_layer: int |
None =
None,
388 """Human-readable hint listing on-disk SAEs and aquin load sae pull commands."""
392 not_downloaded = [layer
for layer
in catalog
if layer
not in available]
393 sae_dir = Path.home() /
".aquin" /
"sae" / short
395 lines: list[str] = []
396 if requested_layer
is not None:
399 lines.append(corrupt)
401 lines.append(f
"SAE layer {requested_layer} is not downloaded for {short}.")
403 lines.append(f
"No {layer_flag} specified for {command}.")
404 lines.append(f
"Model: {short}")
408 lines.append(
"Downloaded on this machine:")
409 for layer
in available:
411 lines.append(f
" {layer_flag} {layer} ({path})")
413 lines.append(
"No SAE checkpoints found on disk.")
414 lines.append(f
" Directory: {sae_dir}/")
418 pick = requested_layer
if requested_layer
in available
else available[0]
419 example = f
" aquin {command}"
421 example += f
" {example_suffix}"
422 example += f
" {layer_flag} {pick}"
423 lines.append(
"Example:")
424 lines.append(example)
428 lines.append(
"Pull more layers:")
431 if requested_layer
is not None and requested_layer
not in available
434 for layer
in pull_layers:
435 lines.append(f
" aquin load sae {short}-l{layer}")
438 lines.append(f
"Try: aquin load sae {short}-l<n> or aquin load sae --path <weights.pt>")
439 lines.append(
"Self-hosted: aquin load sae --path <weights.pt> --layer <n> [--model <id>]")
440 return "\n".join(lines)
447 command: str =
"trace",
448 example_suffix: str =
"",
451 Resolve an explicit SAE layer for tools that must not silently default.
453 Raises ValueError with an actionable message when layer is omitted or missing on disk.
458 if layer
is not None:
459 resolved = int(layer)
466 example_suffix=example_suffix,
467 requested_layer=resolved,
476 example_suffix=example_suffix,
484 example_suffix=example_suffix,
490 """Canonical on-disk path for a model SAE (existing file, or expected location)."""
493 sae_dir = Path.home() /
".aquin" /
"sae" / short
494 resolved_layer = int(layer
if layer
is not None else cfg[
"sae_layer"])
496 candidates: list[Path] = []
497 sae_layers: dict = cfg.get(
"sae_layers", {})
498 if rel := sae_layers.get(resolved_layer):
499 candidates.append(sae_dir / Path(rel).name)
500 if layer
is None and (fn := cfg.get(
"sae_filename")):
501 candidates.append(sae_dir / Path(fn).name)
502 candidates.append(sae_dir / f
"sae_layer{resolved_layer}.pt")
504 seen: set[Path] = set()
505 unique: list[Path] = []
519 return list(cfg.get(
"lora_target_modules", [
"q_proj",
"v_proj"]))
523 """Pick LoRA targets from module names when config defaults do not match."""
524 leaf_names = {name.split(
".")[-1]
for name, _
in model.named_modules()}
525 presets: list[list[str]] = [
526 [
"q_proj",
"v_proj"],
527 [
"query_key_value",
"dense"],
530 [
"Wqkv",
"out_proj"],
532 for candidates
in presets:
533 if all(c
in leaf_names
for c
in candidates):
535 for candidates
in presets:
536 hit = [c
for c
in candidates
if c
in leaf_names]
539 return [
"q_proj",
"v_proj"]
543 return get_config(model_id).get(
"sae_source",
"native")
549 """Return the most recently used loaded model, or None."""
552 return next(reversed(_models.values()))
556 msg = str(exc).lower()
557 return "not found" in msg
or "valid official model names" in msg
561 """True when TransformerLens cannot build/wrap this HF architecture (soft-fallback)."""
564 msg = str(exc).lower()
566 if "embed_out" in msg:
568 if "has no attribute" in msg
and (
569 "neox" in msg
or "gptneo" in msg
or "gpt_neox" in msg
or "pythia" in msg
572 if isinstance(exc, AttributeError)
and (
"embed" in msg
or "unembed" in msg):
585 """Wrap a loaded HuggingFace causal LM as HookedTransformer or HfLlmShim."""
586 if cfg.get(
"hf_only"):
588 from transformers
import AutoTokenizer
590 trust = bool(cfg.get(
"trust_remote_code",
False))
591 tokenizer = AutoTokenizer.from_pretrained(hf_name, trust_remote_code=trust)
592 n_heads = int(cfg.get(
"n_heads", 32))
597 n_layers=int(cfg[
"n_layers"]),
598 d_model=int(cfg[
"d_model"]),
602 from transformer_lens
import HookedTransformer
604 trust = bool(cfg.get(
"trust_remote_code",
False))
606 tl = HookedTransformer.from_pretrained(
611 trust_remote_code=trust,
624 from transformers
import AutoTokenizer
627 f
"[model] TransformerLens cannot wrap {hf_name} ({type(exc).__name__}: {exc}) "
628 "— using HuggingFace shim…",
631 tokenizer = AutoTokenizer.from_pretrained(hf_name, trust_remote_code=trust)
632 n_heads = int(cfg.get(
"n_heads", 32))
637 n_layers=int(cfg[
"n_layers"]),
638 d_model=int(cfg[
"d_model"]),
646 """Load HookedTransformer, or HfLlmShim for custom HF-only architectures."""
649 hf_name = cfg[
"hf_name"]
650 require_hf_hub_auth(hf_repo=hf_name)
652 if cfg.get(
"hf_only"):
655 print(f
"[model] {hf_name} — loading via HuggingFace (no TransformerLens wrapper)…", flush=
True)
656 return HfLlmShim.from_pretrained(hf_name, cfg, dtype=dtype, device=device)
658 from transformers
import AutoModelForCausalLM
660 trust = bool(cfg.get(
"trust_remote_code",
False))
661 hf_first = bool(cfg.get(
"hf_first",
False))
664 from transformer_lens
import HookedTransformer
667 return HookedTransformer.from_pretrained(
670 trust_remote_code=trust,
683 f
"[model] {hf_name} cannot use TransformerLens directly "
684 f
"({type(exc).__name__}: {exc}) — loading via HuggingFace…",
688 hf_model = AutoModelForCausalLM.from_pretrained(
692 trust_remote_code=trust,
700 Load a HookedTransformer model by short slug or HF name.
701 Uses an LRU cache — at most MAX_LOADED_MODELS kept in VRAM.
702 Raises ComputeNotAvailableError when no accelerator (unless AQUIN_ALLOW_CPU=1).
704 Serialized: never interleave two builds (MPS unified RAM doubles fast).
713 default_dtype_for_device,
722 _models.move_to_end(short)
724 print(f
"[model] cache hit: {short}", flush=
True)
725 return _models[short]
729 if os.environ.get(
"AQUIN_DAEMON") !=
"1":
733 release_foreign_daemon()
739 device = require_load_device(short, cfg)
740 except RuntimeError
as exc:
742 dtype = default_dtype_for_device(device)
744 if not cfg.get(
"hf_only"):
746 from transformer_lens
import HookedTransformer
749 "transformer_lens is not installed. "
750 "Reinstall Aquin: pip install -U aquin"
756 require_hf_hub_auth(hf_repo=cfg[
"hf_name"])
757 except RuntimeError
as exc:
762 print(f
"[model] loading {cfg['hf_name']} ({dtype} on {device})...", flush=
True)
764 stop_ticker = threading.Event()
767 while not stop_ticker.wait(5):
768 print(f
"[model] still loading... {int(time.time() - start)}s", flush=
True)
770 threading.Thread(target=_tick, daemon=
True).start()
773 except Exception
as exc:
774 msg = str(exc).lower()
775 if "gated" in msg
or "401" in msg
or "unauthorized" in msg:
777 if is_oom_error(exc):
779 if short ==
"sarvam-30b" or int(cfg.get(
"d_model", 0)) >= 4096:
781 " Large MoE models like Sarvam 30B store all expert weights "
782 "(~60GB+ in bf16); use a GPU with enough VRAM."
785 f
"Accelerator ran out of memory loading '{short}' on {device}.{hint}"
795 if is_load_cancelled():
797 empty_device_cache(device)
798 print(f
"[model] discarded {short} (load cancelled)", flush=
True)
799 raise RuntimeError(f
"Model load cancelled ({short})")
806 if not isinstance(m, HfLlmShim):
808 print(f
"[model] loaded in {int(time.time() - start)}s", flush=
True)
814 while len(_models) > MAX_LOADED_MODELS:
815 evicted_id, evicted_model = _models.popitem(last=
False)
817 empty_device_cache(device)
818 print(f
"[model] unloaded {evicted_id} from VRAM", flush=
True)
820 print(f
"[model] {short} ready. (only model in VRAM)", flush=
True)
821 return _models[short]
824def load_sae(model: Any, layer: int, model_id: str, sae_dir: Path |
None =
None) -> Any:
826 Load a SparseAutoencoder for the given layer from ~/.aquin/sae/ or user bindings.
827 Use `aquin load sae` (Aquin catalog) or `aquin load sae --path` for local files.
832 resolved_layer = int(layer)
834 cache_key = (short, resolved_layer)
835 cached = _sae_cache.get(cache_key)
836 if cached
is not None:
839 device = resolve_compute_device()
841 print(f
"[sae] loaded layer {resolved_layer} for {short}", flush=
True)
842 _sae_cache[cache_key] = sae
bool _is_loadable_sae_file(Path path)
bool _tl_conversion_failed(BaseException exc)
str|None get_active_model_id(*, bool allow_daemon=True)
list[int] get_available_sae_layers(str model_id)
Any _load_model_unlocked(str model_id)
None _save_active_model(str model_id)
str resolve_model_id(str model_id)
str get_sae_source(str model_id)
dict get_config(str model_id)
str|None get_loaded_llm_id()
str get_hf_name(str model_id)
int require_sae_layer(str model_id, int|None layer, *, str command="trace", str example_suffix="")
Any _build_hooked_transformer(dict[str, Any] cfg, *, Any dtype, str device)
None evict_sae_cache(str model_id, int|None layer=None)
Path|None resolve_sae_checkpoint_path(str model_id, int layer)
Any|None get_loaded_model()
Any load_model(str model_id)
list[str] get_lora_target_modules(str model_id)
Any _wrap_hf_causal_lm(str hf_name, dict[str, Any] cfg, Any hf_model, *, Any dtype, str device)
int get_sae_layer(str model_id)
int|None _layer_from_sae_filename(Path path)
bool _tl_not_in_catalog(BaseException exc)
Any load_sae(Any model, int layer, str model_id, Path|None sae_dir=None)
list[int] get_catalog_sae_layers(str model_id)
str|None corrupt_sae_checkpoint_hint(str model_id, int layer)
Path resolve_sae_path(str model_id, int|None layer=None)
list[str] infer_lora_target_modules(Any model)
Any load_sae_from_disk(str model_id, int layer, *, str|None device=None)
None clear_active_model_file()
None reload_vram_for_model(str model_id)
str format_sae_layer_choice_message(str model_id, *, str command, str layer_flag="--layer", str example_suffix="", int|None requested_layer=None)