Cortex-A-0.5 / cortex /probe.py
Pratyush Bhardwaj
load latest weights + enable trained MTP draft head (use_writer_mtp)
68576c8 verified
Raw
History Blame Contribute Delete
2.96 kB
"""Probing the model's internal "thoughts" (inspired by Anthropic's circuit work).
We can't do full attribution graphs cheaply, but two lightweight probes go a long
way on this architecture:
logit_lens apply the (tied) LM head to each Block-AttnRes block state to
see what the model "predicts" at each depth — the thought
sharpening from block to block.
representation_report per-block geometry of the concept space: rms norm,
anisotropy (mean pairwise cosine — high == degenerate), and
effective rank (how many dimensions are actually used).
Both consume the per-block states exposed by CortexLM._trunk(..., collect=True).
"""
from __future__ import annotations
import jax
import jax.numpy as jnp
import numpy as np
def block_states(model, tokens):
_, states = model._trunk(jnp.asarray(tokens), collect=True)
return states
def logit_lens(model, tokens, k: int = 5, pos: int = -1):
"""Top-k predictions + entropy at `pos` for every block state."""
_, states = model._trunk(jnp.asarray(tokens), collect=True)
out = []
for i, h in enumerate(states):
logits = model._head(h)[:, pos].astype(jnp.float32) # [B, V]
probs = jax.nn.softmax(logits, axis=-1)
top_p, top_i = jax.lax.top_k(probs, k)
ent = -jnp.sum(probs * jnp.log(probs + 1e-9), axis=-1)
out.append({
"stage": i,
"top_ids": np.asarray(top_i),
"top_probs": np.asarray(top_p),
"entropy": np.asarray(ent),
})
return out
def representation_report(model, tokens, sample: int = 512, seed: int = 0):
"""Per-block geometry of the hidden states."""
_, states = model._trunk(jnp.asarray(tokens), collect=True)
rng = np.random.default_rng(seed)
rows = []
for i, h in enumerate(states):
hf = np.asarray(h, dtype=np.float32).reshape(-1, h.shape[-1])
if hf.shape[0] > sample:
hf = hf[rng.choice(hf.shape[0], sample, replace=False)]
rms = float(np.sqrt((hf ** 2).mean()))
hn = hf / (np.linalg.norm(hf, axis=-1, keepdims=True) + 1e-8)
sims = hn @ hn.T
n = sims.shape[0]
aniso = float((sims.sum() - np.trace(sims)) / (n * (n - 1))) # mean off-diag cosine
# effective rank = exp(entropy of normalized singular-value spectrum)
s = np.linalg.svd(hf - hf.mean(0, keepdims=True), compute_uv=False)
p = (s ** 2) / max((s ** 2).sum(), 1e-9)
erank = float(np.exp(-(p * np.log(p + 1e-12)).sum()))
rows.append({"stage": i, "rms": rms, "anisotropy": aniso, "eff_rank": erank})
return rows
def format_report(rows) -> str:
lines = [f"{'stage':>6} {'rms':>10} {'anisotropy':>12} {'eff_rank':>10}"]
for r in rows:
lines.append(f"{r['stage']:>6} {r['rms']:>10.3f} {r['anisotropy']:>12.3f} {r['eff_rank']:>10.1f}")
return "\n".join(lines)