AQIT 0.1.0
Loading...
Searching...
No Matches
capture.py
Go to the documentation of this file.
1# Copyright (c) 2025-present Aquin Labs Private Limited. All Rights Reserved.
2# This file is part of the Aquin Engine. Unauthorized copying, modification,
3# distribution, or use of this file, via any medium, is strictly prohibited.
4# Proprietary and confidential. See LICENSE for terms.
5
6from __future__ import annotations
7
8import json
9import uuid
10from datetime import datetime, timezone
11from typing import Any
12
13import httpx
14
15from aquin.types import CaptureBundle
16
17
19 prompt: str,
20 model: Any,
21 session_id: str = "",
22 sae_layer: int | None = None,
23) -> CaptureBundle:
24 """
25 Run a forward pass through model and collect top SAE features + logit lens.
26 Falls back to empty tensors if SAE weights are not available.
27 """
28 import torch
29 from aquin.compute.model_loader import get_loaded_model, resolve_model_id, get_config
30
31 if model is None:
32 model = get_loaded_model()
33 if model is None:
34 raise RuntimeError("No model loaded. Run: aquin load --model <model-id>")
35
36 model_id = getattr(model, "cfg", None)
37 hf_name = ""
38 short = ""
39 try:
40 hf_name = model.cfg.model_name if hasattr(model, "cfg") else str(type(model).__name__)
41 short = resolve_model_id(hf_name)
42 cfg = get_config(short)
43 if sae_layer is None:
44 sae_layer = cfg.get("sae_layer", 0)
45 hf_name = cfg["hf_name"]
46 except Exception:
47 short = "unknown"
48 if sae_layer is None:
49 sae_layer = 0
50
51 # tokenize + forward pass
52 tokens = model.to_tokens(prompt, prepend_bos=True)
53 with torch.no_grad():
54 _, cache = model.run_with_cache(tokens)
55
56 # logit lens: top token per layer
57 logit_lens: list[dict] = []
58 try:
59 n_layers = model.cfg.n_layers
60 for layer in range(n_layers):
61 resid = cache[f"blocks.{layer}.hook_resid_post"][0, -1]
62 logits = model.unembed(model.ln_final(resid.unsqueeze(0).unsqueeze(0)))[0, 0]
63 top_tok = int(logits.argmax().item())
64 top_str = model.to_string([top_tok])
65 logit_lens.append({"layer": layer, "token": top_str, "token_id": top_tok})
66 except Exception:
67 logit_lens = []
68
69 # SAE top features
70 top_features: list[dict] = []
71 try:
72 from aquin.compute.model_loader import load_sae
73 sae = load_sae(model, sae_layer, short)
74 resid = cache[f"blocks.{sae_layer}.hook_resid_post"][0, -1]
75 feat_acts, top_idxs = sae.get_top_features(resid, top_k=20)
76 top_features = [
77 {"feature_idx": int(idx), "activation": float(act)}
78 for idx, act in zip(top_idxs.tolist(), feat_acts.tolist())
79 ]
80 except Exception:
81 top_features = []
82
83 # greedy decode single token for response
84 with torch.no_grad():
85 logits = model(tokens)
86 next_tok = int(logits[0, -1].argmax().item())
87 response = model.to_string([next_tok])
88
89 return CaptureBundle(
90 version=1,
91 capture_id="",
92 session_id=session_id,
93 model_id=short,
94 hf_name=hf_name,
95 prompt=prompt,
96 response=response,
97 created_at=datetime.now(timezone.utc).isoformat(),
98 top_features=top_features,
99 sae_layer=sae_layer,
100 logit_lens=logit_lens,
101 attention={},
102 )
103
104
106 bundle: CaptureBundle,
107 session_id: str,
108 api_key: str,
109 base_url: str = "https://api.aquin.app",
110) -> str:
111 """
112 Upload a CaptureBundle to Aquin Cloud. Returns capture_id.
113 """
114 import os
115 base_url = os.environ.get("AQUIN_BASE_URL", base_url).rstrip("/")
116
117 payload = bundle.model_copy(update={"session_id": session_id}).model_dump()
118 body = json.dumps(payload).encode()
119
120 resp = httpx.post(
121 f"{base_url}/api/sync/captures/upload",
122 headers={
123 "Authorization": f"Bearer {api_key}",
124 "Content-Type": "application/json",
125 },
126 content=body,
127 timeout=30,
128 verify=False,
129 )
130 resp.raise_for_status()
131 capture_id = resp.json()["capture_id"]
132 return capture_id
str upload_capture(CaptureBundle bundle, str session_id, str api_key, str base_url="https://api.aquin.app")
Definition capture.py:114
CaptureBundle build_minimal_capture_bundle(str prompt, Any model, str session_id="", int|None sae_layer=None)
Definition capture.py:27