NeuronScope is deliberately small — around 14,000 lines of Python across five layers. Nothing in a layer above may reach into a layer below except through its published interface. The rest of this page describes those layers, the flow of a single recording, and the trade-offs that shaped both.
Design principles
- Own no user tensors. NeuronScope observes; it never mutates a user's model or dataset.
- Content-addressed everything. Every observable input and output has a fingerprint — see the fingerprinting chapter.
- Cost visible at the call site. Every recording API returns an overhead estimate before it runs.
- Framework-agnostic core. The core does not import PyTorch, JAX, or TensorFlow. Adapters do.
The five layers
1. Adapter
Adapters translate a user's framework model into an ns.Model — a read-only structural view. Each adapter is a small, self-contained module inneuronscope.adapters. Adding a new adapter is one file plus a registry entry.
2. Recorder
The recorder installs the minimum instrumentation required to observe the tensors requested by a probe. On PyTorch that means forward hooks; on JAX, transformation wrappers. The recorder is written against the adapter interface, not any framework.
3. Probe
A probe declares what it wants to observe (layers, activations, gradients) and how to summarise it (raw tensor, statistic, projection). Probes never see the framework directly — they consume adapter-shaped tensors from the recorder.
4. Artifact
The output of a recording is an .nsz file: a zipped columnar format with a stable schema. Artifacts embed the fingerprints of every input, so an artifact is self-describing.
5. Surface
The surface layer is what users touch — the Python SDK, the CLI, the report renderer, and the visualization pipeline. Every surface is written against the artifact schema, never against a live recording.
Recording flow
A recording is deterministic in five steps. Each step has a fingerprint checkpoint so a failure is attributable to a specific stage.
- Resolve. Adapter turns the user's model into an
ns.Model. Environment is snapshotted. - Plan. The probe emits a plan: which layers, which tensors, which summaries. The plan is fingerprinted.
- Instrument. The recorder installs framework-specific hooks driven by the plan.
- Run. The user calls
model.forward(...). The recorder streams observed tensors to a temporary artifact. - Seal. The recorder computes the artifact fingerprint, writes the header, and finalises the
.nszfile.
Layer boundaries
neuronscope.adaptersmay importneuronscope.core.model_protocolonly.neuronscope.recordermay import fromadaptersandprobesvia their protocols.neuronscope.artifactdepends on nothing exceptcoreand the storage layer.
Trade-offs
The layered design costs indirection. In practice, the biggest cost is a per-call dispatch for tensor reads inside recorders, measured at 40–80 ns per read on a modern CPU. Every release runs the overhead benchmark suite and gates on regressions above 5%.
- No lazy adapters. Adapters are chosen up front. This makes overhead predictable and error messages precise.
- Artifacts are append-only. Once sealed, an artifact is immutable. All edits produce a new artifact with a new fingerprint.
- No cross-framework recording. A single recording sees one framework. Comparing a PyTorch and a JAX model is done by comparing their artifacts, not by mixing them at record time.