Metadata-Version: 2.4
Name: checkpoint-lens
Version: 0.1.2
Summary: Understand what's inside a PyTorch .pt checkpoint: terminal inspection and a local, interactive 3D viewer. Local first, your weights never leave your machine.
Author-email: Viraj Mhadgut <virajmhadgut77@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/virajm7/checkpoint-lens
Project-URL: Repository, https://github.com/virajm7/checkpoint-lens
Project-URL: Issues, https://github.com/virajm7/checkpoint-lens/issues
Keywords: pytorch,neural-network,checkpoint,visualization,3d,inspection,interpretability
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: torch>=2.2
Requires-Dist: fastapi>=0.110
Requires-Dist: uvicorn[standard]>=0.27
Requires-Dist: pydantic>=2.6
Requires-Dist: websockets>=12.0
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: httpx>=0.27; extra == "dev"
Dynamic: license-file

# Checkpoint Lens

[![CI](https://github.com/virajm7/checkpoint-lens/actions/workflows/ci.yml/badge.svg)](https://github.com/virajm7/checkpoint-lens/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/checkpoint-lens.svg)](https://pypi.org/project/checkpoint-lens/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Give it a PyTorch `.pt` checkpoint, and it tells you what's actually
inside: in your terminal, and in an interactive 3D viewer in your
browser.

```bash
pip install checkpoint-lens

checkpoint-lens inspect model.pt   # terminal report
checkpoint-lens view model.pt      # local 3D viewer, opens in your browser
```

Everything runs on your machine. Your checkpoint and its weights are
never uploaded anywhere.

## Why

Loading a `.pt` file you didn't train, someone else's checkpoint, an old
one of yours without the original training code, a bare `state_dict` with
no docs, usually means writing a one-off script to poke at tensor shapes.
Checkpoint Lens does that inspection for you. It detects the architecture
from the tensors themselves (no source code required), and is explicit
about what it actually knows versus what it's guessing versus what
simply isn't recoverable from a checkpoint at all.

## What it tells you

Every fact in the report is labeled with how certain it is:

```
CONFIRMED
✓ LSTM input=11 hidden=64 num_layers=1  [rnn.rnn]
✓ Linear 64 → 128  [mlp.0]
✓ Linear 128 → 128  [mlp.2]
✓ Linear 128 → 8  [mlp.4]
✓ Parameter count: 45,618

INFERRED
~ Role: Actor/Policy (inferred from checkpoint key naming, not guaranteed)

UNKNOWN
? Original activation function (not recoverable from weights, since they carry no parameters)
```

- **CONFIRMED**: directly backed by a tensor shape or a key in the file.
- **INFERRED**: a reasonable deduction from naming or structure. A
  network keyed `"actor"` probably plays an actor/policy role, but that's
  a naming convention, not something the file states outright.
- **UNKNOWN**: genuinely not recoverable. Activation functions carry no
  parameters, so no checkpoint can ever confirm which one was used. Live
  inference lets you pick an assumption (ELU by default), but it is
  always labeled as an assumption, never presented as fact.

Nothing is ever silently invented. If a tensor doesn't match a known
layer pattern, it's reported as unclassified rather than guessed at.

## The 3D viewer

`checkpoint-lens view model.pt` starts a local server and opens a
cinematic, interactive 3D scene built from your checkpoint's *real*
layers, neuron counts, and weights, not a generic diagram. Rotate, zoom,
click a neuron or connection for its real values, switch between
networks (Actor/Critic, or `network_0`/`network_1` if there's no naming
evidence to go on), and, when the checkpoint can be safely reconstructed
into a runnable model, feed it an observation and watch real activations
light up the scene.

## Python API

```python
from checkpoint_lens import inspect

result = inspect("model.pt")

print(result)              # the same CONFIRMED/INFERRED/UNKNOWN report as the CLI
result.networks             # per-network detail (architecture, role, param count, ...)
result.confirmed             # flat list of confirmed facts
result.inferred               # flat list of inferred facts
result.unknown                 # flat list of things that cannot be recovered
```

## What v0.1 supports

- PyTorch `.pt` files containing a `state_dict`, or a checkpoint dict
  containing one or more `state_dict`s (e.g. a PPO-style `{"actor": ...,
  "critic": ..., "optimizer_state_dict": ...}` checkpoint). Optimizer
  state is always recognized and excluded from the architecture. It's
  training data, never shown as a network layer.
- Layer detection: **Linear**, **LSTM**, **GRU**, **RNN**, plus running
  normalizer buffers (mean/var-style preprocessing stats).
- Multiple networks per checkpoint, with Actor/Critic role detection,
  **only** when the checkpoint's own key names say so (`actor`, `policy`,
  `critic`, `value`). No naming evidence means no guessed role: networks
  are exposed generically as `network_0`, `network_1`, etc.
- Optional live inference, by reconstructing a runnable model directly
  from the inferred architecture and verifying it against the checkpoint
  with a strict `load_state_dict`. If a single tensor name or shape
  doesn't match exactly, reconstruction fails loudly instead of silently
  producing a network that doesn't match the file.

**Out of scope for v0.1** (reported honestly as unclassified rather than
silently mishandled, not silently misidentified as something else):
CNNs/Conv layers beyond shape detection, ONNX, TensorFlow/Keras,
Transformers/attention, safetensors, TorchScript modules, and any
checkpoint that isn't a `state_dict` or dict-of-`state_dict`s. Also out
of scope: a Linear layer saved under a descriptive, non-indexed name
(e.g. a lone `nn.Linear` not part of a numbered `nn.Sequential`)
currently has no home in live-inference reconstruction. It's correctly
detected and shown in the architecture/weight viewer, but reconstruction
fails loudly for that network rather than guessing where it belongs.
These are natural directions for future contributions, see below.

## Contributing

The architecture-detection logic (`architecture.py`) is a sequence of
independent, shape-based pattern-matching passes (normalizer buffers,
then recurrent layers, then Linear, then Conv, then leftover affine
params). Adding support for a new layer type is a matter of adding
another pass that only claims tensors it's confident about and leaves
everything else for the next pass. The "honest by construction" design
this project is built on extends the same way to new architectures.

Local dev setup:

```bash
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
pytest

# in one terminal: the API, on a fixed port
checkpoint-lens view path/to/model.pt --port 8010

# in another: the frontend dev server with hot reload, pointed at that API
cd frontend
echo "VITE_API_BASE_URL=http://127.0.0.1:8010" > .env.local
npm install && npm run dev
```

To rebuild the bundled viewer after a frontend change:

```bash
cd frontend && npm run build
rm -rf ../src/checkpoint_lens/web/*
cp -r dist/. ../src/checkpoint_lens/web/
```

Every push and PR runs the test suite (Python 3.10 through 3.12) and a
frontend build check via GitHub Actions (`.github/workflows/ci.yml`).
Publishing a new version to PyPI happens by cutting a GitHub Release,
which triggers `.github/workflows/publish.yml`. That workflow builds and
uploads via PyPI's Trusted Publishing, so there's no stored token, and
nothing publishes on a plain push, only on an explicit Release.

## License

MIT
