nn3d
Watch neural networks train in live 3D in your browser. Every layer's activation and every connection's weight stream in real time.
import nn3d
nn3d.show(model) # opens browser
model.fit(X, y, callbacks=[nn3d.Monitor(X[:1])]) # training streams live
In a notebook, nothing else is needed. In a plain .py script the process exits when the script finishes — add nn3d.wait() at the end to keep the server alive.
Screenshots
Every image below is a real capture of the viewer while a Keras model was actually training — note the CANLI · epoch N · adim N badge in the bottom-left corner and the metrics ticking in the top-right.
Hover a neuron — its connections light up in gold, everything else dims, and the tooltip reports the real neuron index behind the drawn subset:
A CNN — Conv2D → BatchNorm → MaxPool → Conv2D → MaxPool → Flatten → Dense → Softmax on Fashion-MNIST. Each card shows the layer's tensor shape (26x26x32), and the 784 and 1600 layers are drawn as 16 representative neurons each:
Drag to orbit — the scene is real 3D, so the layer planes separate in depth as you rotate:
Installation
pip install nn3d
Node.js is not required — the 3D viewer ships pre-built inside the package. Node is only needed if you want to modify the viewer itself.
What you see
- Layer cards — name, neuron/channel count, tensor shape, activation like
[ReLU] - Neurons — brightness and size reflect the current activation value
- Connections — teal = positive weight, red = negative; brightness =
|weight|× source activation - Input/output labels — feature names ("Hunger Level", "Fox Distance") color-shift with activation
- Hover — hovering a neuron highlights all its connections in gold, dims the rest
- Metrics —
loss,accuracy,val_loss… live in the top-right corner
API
nn3d.show(model, ...)
Builds the graph and opens a browser tab. Returns a View.
| parameter | description |
|---|---|
sample |
if provided, sends the first frame immediately so the screen isn't blank |
input_labels |
names for the input neurons (your feature column names) |
output_labels |
names for the output neurons (your class names) |
max_neurons |
points drawn per layer (default 16) |
port |
default 8092; falls back to a free port automatically |
open_browser |
set False to print the URL without opening a tab |
nn3d.Monitor(sample, every=20, ...)
A Keras callback. Drop it into model.fit(callbacks=[...]).
every sends a frame every N batches. Running an extra forward pass every single batch adds measurable overhead; every 20 looks smooth and costs almost nothing.
View.update(x, metrics=..., epoch=...)
For custom training loops (RL, manual gradient steps) — push a frame manually.
Virtualization — is what you see real?
Yes, but not all of it. Drawing Dense(3072) as 3 072 points means 2.3 million edges to the previous layer — the browser would freeze.
Instead, max_neurons evenly-spaced representative neurons are selected per layer; activations and weights are sliced to the same indices. Every point and every line you see corresponds to a real neuron or weight — nothing is made up, it is just a subset. When you hover a neuron the tooltip shows the real neuron index (neuron 1847 / 3072) so you always know which slice you are looking at.
Supported layers (Keras 3)
Dense · Conv1D/2D/3D · Conv2DTranspose · SeparableConv2D · LSTM · GRU ·
SimpleRNN · Flatten · Reshape · Dropout · BatchNormalization ·
LayerNormalization · MaxPooling* · AveragePooling* · Activation ·
LeakyReLU · ReLU · Softmax · Embedding
Weights are reduced to a (input_units, output_units) matrix for visualization: conv kernels are summed over spatial axes, LSTM/GRU gates are averaged. The goal is sign and magnitude of the connection, not numerical precision.
Architecture
Keras model ──build_graph()──▶ graph dict ──┐
├─▶ stdlib HTTP + SSE ──▶ Three.js viewer
ActivationTap.read(x) ──────▶ frame (base64 f32) ┘ (:8092) (browser)
- Zero dependencies. The server is pure Python standard library. SSE is used instead of WebSockets because the stream is one-way (Python → browser), SSE is exactly what it was designed for, works with
http.server, and reconnects automatically on drop. WebSockets would need either an external package or a hand-written handshake — both break the "pip install nn3dis enough" goal. - The viewer knows nothing about the model — only the schema in
src/nn3d/schema.py. The same viewer renders a 10-neuron game agent and a 12-block Transformer. Adding support for another framework (PyTorch, Unity, JS game) means writing a new adapter, not touching the viewer. - Single geometry. All edges live in one
LineSegments, all neurons in onePoints. Only the color buffer is updated per frame; geometry never changes.
Modifying the viewer
cd viewer
npm install
npm run dev # live dev server (start the Python server separately first)
npm run build # compiles into src/nn3d/static/index.html
The compiled output is part of the package, so the result of npm run build must be committed too.
Examples
| file | description |
|---|---|
examples/nn3d_baslangic.ipynb |
End-to-end guide: static view, live training, manual frame push, virtualization |
examples/churn_canli.py |
Plain script example (nn3d.wait() usage) |
examples/kurs/ |
FNN / CNN / RNN / GAN course notebooks with nn3d integration |
PYTHONPATH=src python examples/churn_canli.py
Metadata
Release files for nn3d 0.1.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| nn3d-0.1.1.tar.gz | 2.5 MB | Without provenance | Details for nn3d-0.1.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| nn3d-0.1.1-py3-none-any.whl | Python 3 | none | any | Details for nn3d-0.1.1-py3-none-any.whl |
Total release size: 2.7 MB
Release files / nn3d-0.1.1.tar.gz
| Download URL | nn3d-0.1.1.tar.gz |
|---|---|
| Size | 2.5 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b3ad58cb29b22e3fcb07a4c68117ef1e2e5abc0926aa031cd6acbaa6ad8db834
|
|
BLAKE2b-256 checksum How to use checksums |
71ac27737e0deafd0eb5822f112834a507174491194a150d636aa910e5cd742d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.4
|
Release files / nn3d-0.1.1-py3-none-any.whl
| Download URL | nn3d-0.1.1-py3-none-any.whl |
|---|---|
| Size | 201.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
06b81e0002f8d0d82a73fcfbb47d271d66864a6b2d857d5bc702ebc6e15ee176
|
|
BLAKE2b-256 checksum How to use checksums |
fa5f38f5120c55141354f6b743bf1d295ba00eee7d22e44610764331930fc67c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.4
|
Security for nn3d 0.1.1
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.