ModelMRI
Chrome DevTools for AI models and agents. Load any local model — LLM, VLM, or robot policy — and see inside it while it runs: what it attended to, which concepts fired, what happens when you turn one off, and exactly where your agent went wrong.
Local-first. No cloud, no account, no telemetry. MIT.
▶ Try the live demo — no install, no GPU, real recorded output. 📖 Docs
Hover any token — arcs show what it attended to. Every layer, every head.
pip install modelmri
modelmri serve # open http://localhost:5900
It finds the models you already have — HF cache, plain folders, GGUF — before asking you to type anything.
What you can actually do with it
1. See what a token attended to
Type a prompt, watch it stream, then hover any token — arcs show which earlier tokens it looked at, scaled by attention weight, for any layer and head.
On GPT-2, the generated token
" Paris"attends back to" capital"and" France". The information was always there. Nobody was looking.
2. Find a concept and turn it off
Load a sparse autoencoder and ModelMRI shows the human-interpretable features firing on every token. Click one, drag the slider, and run a deterministic A/B:
prompt The Eiffel Tower is located in the city of
baseline Paris, France.
feature #974 @ -40 San Diego, and is located in the San Diego State University
Same prompt, greedy decoding, no prompt tricks. We reached into layer 8 and turned the concept down. Clearing the steer restores the baseline byte-for-byte.
3. Find the step where your agent died
Two lines of modelmri.record around any agent run gives you a timeline: LLM calls, tool calls, subagents, each as a block. The failure glows. Click it for the exact input, output, tokens, and error.
from modelmri.record import trace, step
with trace("fix-failing-tests"):
step("llm_call", name="plan", input=prompt, output=answer, tokens_in=912)
with step("subagent", name="auth-fixer"):
step("tool_call", name="pytest", output="17 passed")
Or instrument automatically: modelmri.record.instrument_anthropic().
4. Look inside a robot policy
This is the part nobody else ships. ModelMRI loads the vision tower of the real SmolVLA checkpoint and runs actual robot-camera frames through it, painting each image patch's attention back onto the frame. Scrub an episode, run the policy, drag the layer slider.
Measured on PushT frames — share of attention mass in the top 5% of patches:
| vision layer | concentration |
|---|---|
| 0 | 27% |
| 6 | 56% |
| 11 | 60% |
Early layers look everywhere; deep layers lock on. No robot hardware required — it reads public LeRobot datasets straight from disk.
5. Debug a model you trained yourself
Everything above is transformer-shaped. This isn't. Point ModelMRI at your own nn.Module — an MLP, a small CNN, whatever you're training — and get a layer-by-layer map of one real forward pass.
# my_net_adapter.py — the whole contract
def load():
model = MyNet()
model.load_state_dict(torch.load("checkpoints/best.pt", map_location="cpu"))
return model
| layer | type | output | activation | |
|---|---|---|---|---|
fc1 |
Linear | 8×64 | −31.20 ± 24.21 | |
act1 |
ReLU | 8×64 | 0.10 ± 0.26 | 80% dead |
fc2 |
Linear | 8×32 | −1.02 ± 4.74 | |
act2 |
Tanh | 8×32 | −0.12 ± 0.90 | 55% saturated |
head |
Linear | 8×3 | −0.13 ± 0.44 |
Dead units, saturated activations, and the first layer where a nan appears — statistics exclude non-finite values on purpose, so one bad number can't turn every row below it into nan and hide where it started.
A state_dict alone is refused, with the reason: it's weights without an architecture, and guessing one would produce a map that looks authoritative and describes a network you never trained.
Install
pip install modelmri # core: playground, attention, features, steering, agents
pip install "modelmri[vla-lite]" # + robot datasets (av, pyarrow, pillow)
pip install modelmri-record # just the agent recorder — stdlib only, a 9 KiB wheel
modelmri serve
From source:
git clone https://github.com/muhammadmahadazher/ModelMRI && cd ModelMRI
cd frontend && npm ci && npm run build && cd ..
uv sync && uv run modelmri serve
Models. Type any HuggingFace id, pick from what's already cached on your machine, or switch to Ollama to run any open model you've pulled. (Ollama gives you text only — internals need a HuggingFace model, and ModelMRI says so rather than pretending.)
GPU when you have one. NVIDIA, AMD, Intel and Apple silicon are detected automatically and the badge explains its choice — including the common case where torch was installed as a CPU-only build, where it prints the exact command to fix it. CPU works fine too; a 0.5B model streams in a couple of seconds.
API
The UI is a client of a plain HTTP API — script against it directly.
POST /api/model/load |
{hf_id, source} — "hf" or "ollama" |
WS /ws/generate |
stream tokens |
GET /api/attention |
?layer=&head= → tokens + attention matrix |
POST /api/sae/load · GET /api/features/summary |
SAE features per token |
POST /api/steer |
{feature_id, scale} — clamp a concept during generation |
POST /api/traces/import · GET /api/traces/{id} |
agent traces |
POST /api/vla/analyse · GET /api/vla/attention |
robot-policy attention |
POST /api/custom/load · POST /api/custom/run |
inspect a model you trained yourself |
Status
| Playground · streaming · any local model · Ollama | ✅ |
| Attention inspector | ✅ |
| SAE feature browser + activation steering | ✅ |
| Agent trace timeline + step inspector | ✅ |
| Robot policy (VLA) attention over real episodes | ✅ perception |
| Custom models — adapters, TorchScript, layer map | ✅ |
VLA action expert (needs lerobot, separate env) |
🏗️ |
| Hosted zero-install demo | ✅ |
Honest limits
- Attention needs eager attention. SDPA and FlashAttention never materialize the weights, so ModelMRI loads models with
attn_implementation="eager". Slower, but it's the only way to see anything. - SAE features need an SAE that exists. They are trained per model, and public ones cover about a dozen models in total — there is none for most of what you will load, and no amount of code makes one appear. ModelMRI offers the one that matches your model, says plainly when there is none, and falls back to a logit lens, which needs nothing but the model.
- Custom models get a layer map, not attention. Attention and SAE features need a transformer; for an arbitrary
nn.ModuleModelMRI shows shapes, activation statistics and pathologies. Loading an adapter runs your Python — see SECURITY.md. - VLA mode is the perception half. SmolVLA's vision tower is real and loaded from the real checkpoint; the action expert needs
lerobot, whose torch/numpy pins conflict with the core runtime, so it lives behind an opt-in extra rather than degrading everyone's install.
Contributing
Issues and pull requests are welcome. One rule runs the whole repository: don't ship a measurement you haven't verified. A visualization that looks plausible and is wrong is worse than none, because interpretability is exactly the domain where nobody has an independent way to notice.
- Contributing guide — setup, quality gates, and the three bugs that made that rule
- Code of conduct
- Security policy — trust model, credential handling, and what loading a model actually executes
- Support · Changelog
Built in public
Notes, mistakes, and what broke: modelmri.substack.com
MIT © Muhammad Mahad Azher
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file modelmri-0.5.1.tar.gz.
File metadata
- Download URL: modelmri-0.5.1.tar.gz
- Upload date:
- Size: 4.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
47748e8d43b28f9195ad8063eeb02537497e391d3b8a79b1b5e5685cb6add972
|
|
| MD5 |
3eeccf3f376d7e88f872940f432d6698
|
|
| BLAKE2b-256 |
4dbe64a91279bc87074a7d0311c770542e4ac24fd114f1fb31f5b8698a62da44
|
File details
Details for the file modelmri-0.5.1-py3-none-any.whl.
File metadata
- Download URL: modelmri-0.5.1-py3-none-any.whl
- Upload date:
- Size: 182.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.0 {"installer":{"name":"uv","version":"0.10.0","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a71076353f81e73a7341c5c35d674fdafd5dd3f1f8f8807009f4a85d6efdc20d
|
|
| MD5 |
114730167ecc742b1b6c05ffc5133467
|
|
| BLAKE2b-256 |
4470979b8c9a8bba74f88d89c4bd041fce7901148a0a65e9dc967d59091de15e
|