# Norse: spiking neural networks as PyTorch modules

> Norse adds leaky integrate-and-fire cells, stateful sequential layers and NIR export to PyTorch. It suits researchers who already write PyTorch and want event-driven neurons without leaving it.

**norse/norse** — Deep learning with spiking neural networks (SNNs) in PyTorch.

- Repository: https://github.com/norse/norse
- Website: https://norse.github.io/norse/
- Stars: 822 · Forks: 106
- Language: Python
- License: LGPL-3.0
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/norse-norse

## What Norse adds on top of PyTorch

A spiking neuron carries state between timesteps: a membrane potential that accumulates input and resets when it crosses a threshold. That is not what a standard PyTorch layer does. nn.ReLU is stateless, so a plain nn.Sequential has nowhere to keep the potential, and a hand-written loop over timesteps forces you to thread that state through every layer yourself. Norse fills exactly that gap. The README describes the project as expanding PyTorch "with primitives for bio-inspired neural components", and the package's job is to make those primitives behave like ordinary modules. The intended audience is narrow but clear: people who already have a PyTorch training loop, a data pipeline and a checkpointing habit, and who want the neurons underneath to spike rather than to saturate. If you are not already in PyTorch, Norse gives you very little, because it deliberately does not ship its own tensor library, optimiser or data loader.

## How state flows through SequentialState and the cell classes

The mechanism is a cell that returns two things: an output and a new state. In the README's convolutional classifier example, LIFCell() and LICell() sit between ordinary nn.Conv2d and nn.Linear layers inside a SequentialState container. SequentialState is the piece that makes the composition work, because it has to pass each layer's state forward alongside the activation.

The naming follows a convention worth knowing before you read the API. LIFCell is the leaky integrate-and-fire cell, which emits spikes. LICell is a leaky integrator, which does not spike and instead passes a continuous value, which is why the README uses it as the final layer for a 10-class output. LSNNRecurrent, shown in the second example, is a recurrent long short-term spiking layer built from the Bellec et al. 2018 model, and it is constructed with an input size and an output size, the same way you would construct an RNN.

Time is the axis you add yourself. The LSNN example generates data as torch.zeros(20, 8, 2), which the comment describes as 20 timesteps, 8 datapoints per batch and 2 neurons. Norse does not impose a time dimension convention on your tensors; you decide where the timestep axis lives and iterate over it. That is flexible, and it is also the main source of shape bugs in new code.

## Installing Norse and running a first task

The README states the prerequisites as Python 3.8 or higher and PyTorch 1.9 or higher, while pyproject.toml declares requires-python = ">=3.10" and a dependency on torch>=2.2.0. Trust the packaging metadata over the prose; the README's version line lags the actual constraint.

The simplest install is from PyPI:

```bash
pip install norse
```

Conda users can install from conda-forge, and there is a container image on Quay:

```bash
conda install norse
docker pull quay.io/norse/norse
```

To install the current main branch instead of a release, the README gives a pip command pointing at the GitHub URL:

```bash
pip install -qU git+https://github.com/norse/norse
```

Norse ships runnable example tasks, which is the fastest way to confirm the install works. Run them from the base directory of the repository:

```bash
python -m norse.task.mnist
python -m norse.task.cifar10
python -m norse.task.cartpole
```

Each task accepts arguments; the README points to python -m norse.task.<task> --help for the list. There is also a PyTorch Lightning variant of the MNIST task, which the README shows invoked with a GPU count:

```bash
python -m norse.task.mnist_pl --gpus=4
```

For a first model of your own, the README's classifier is short enough to type. Note that the forward call returns a tuple, not a tensor:

```python
import torch, torch.nn as nn
from norse.torch import LICell, LIFCell, SequentialState

model = SequentialState(
    nn.Conv2d(1, 20, 5, 1),
    LIFCell(),
    nn.MaxPool2d(2, 2),
    nn.Conv2d(20, 50, 5, 1),
    LIFCell(),
    nn.MaxPool2d(2, 2),
    nn.Flatten(),
    nn.Linear(800, 10),
    LICell(),
)
data = torch.randn(8, 1, 28, 28)
output, state = model(data)
```

The README states that this classifier, taken from the project's MNIST tutorial notebook, reaches above 99% accuracy. That figure belongs to the notebook's training setup, not to the untrained snippet above.

## Where Norse stops: NIR export, not hardware deployment

The v1.1.0 release notes name support for NIR and torch.compile, and pyproject.toml lists nir>=1.0.6 and nirtorch>=2.0.6 as hard dependencies. NIR is a format for exchanging neural network descriptions between frameworks, and nirtorch is the bridge. That means Norse can describe a model in a portable form, which matters if you want the same network to run somewhere other than PyTorch.

What the repository does not show is a path from that description to a neuromorphic chip. There is no deployment tool, no device backend and no runtime in the top-level layout, which is norse/, docs/, publish/ and configuration files. If your goal is to run a trained network on event-driven silicon, Norse is the modelling half of the problem and you will need another tool for the second half. The documentation is the place to check whether that has changed, since the README does not discuss hardware targets at all.

## The constraints that decide whether you can use it

The dependency floor is the first real filter. pyproject.toml requires Python 3.10 or newer and torch>=2.2.0, plus torchvision>=0.15.0. A lab pinned to an older CUDA build of PyTorch cannot adopt the current release without upgrading the whole stack, and that is often a bigger job than the modelling change itself.

The second constraint is the state API. Because cells return (output, state) and SequentialState threads state through the container, any code that assumes a module returns a single tensor will break. Mixing Norse cells into an existing nn.Sequential does not work; you need SequentialState or your own loop. That is a design decision, not a defect, but it means retrofitting a trained network is not a drop-in swap.

Third, the last release is v1.1.0 from 2024-03-18, while the last push to the default branch was on 2026-07-07. Activity on main does not automatically become a tagged release, so if you depend on published versions you are working against code that is more than two years old at the release boundary. The repository is not archived, but the gap between commits and releases is worth weighing if you need a fix that only exists on main.

Finally, the README does not document rollback or version pinning strategy, and it does not state a supported PyTorch range beyond the minimum. You will have to determine compatibility yourself.

## Norse against writing the neuron yourself

The obvious alternative is not another spiking library; it is a few dozen lines of your own. A leaky integrate-and-fire neuron is a membrane update, a threshold comparison and a reset. Writing it in PyTorch takes an afternoon, and you keep full control over the reset behaviour, the surrogate gradient and the state layout.

The difference in approach is what you get for the dependency. A hand-written neuron gives you one model that does exactly what your paper describes, with no version floor and no container. Norse gives you a tested set of cells, several published neuron models including LSNNRecurrent, stateful containers that handle the plumbing, example tasks you can run immediately, and NIR export. The trade is that you adopt the project's abstractions, its release cadence and its dependency constraints. If your work is one specific neuron variant, the hand-written version is usually the better fit. If you are comparing several cell types or want the LSNN model without reimplementing it, Norse saves real time.

## Licence and the cost of staying current

Norse is released under LGPL-3.0, and pyproject.toml points the licence field at the LICENSE file rather than declaring an SPDX string. The LGPL matters most if you modify Norse itself and distribute the result, or if you statically link it into a larger work. Importing it as an installed library in your own training code is the ordinary case, but the boundary is a legal question and not one this article can settle.

The upgrade cost is modest but not zero. Releases are infrequent, so there is little churn to absorb, and the version number is read from setuptools_scm, which means installing from a git checkout produces a version derived from tags. The practical cost sits in the dependency floor: every upgrade of Norse can pull a newer torch, and torch upgrades are the expensive part of any PyTorch project. The v1.1.0 notes also tie the release to torch.compile support, which is a reminder that the library tracks PyTorch's own evolution rather than freezing against it.

## Conclusion

Adopt Norse if you already train models in PyTorch and want spiking cells with state handling you do not have to write yourself, and if your dependency stack can move to Python 3.10+ and torch>=2.2.0. Do not adopt it for production inference on neuromorphic hardware, because the repository ships no hardware deployment path and the NIR route only takes you to the exchange format. Before committing, install it, run python -m norse.task.mnist in the base directory, and check that the returned neuron state tensors fit the shape your training loop expects.

## FAQ

### How do I install Norse?

The README lists four routes: pip install norse from PyPI, conda install norse from conda-forge, docker pull quay.io/norse/norse, or a pip install from the GitHub URL for the current main branch. The packaging metadata requires Python 3.10 or newer and torch>=2.2.0.

### What is Norse in this context?

It is a Python deep learning library for spiking neural networks that extends PyTorch with bio-inspired neuron components. The README describes it as providing plug-and-play components for deep learning with spiking neural networks.

### What Python and PyTorch versions does Norse require?

pyproject.toml declares requires-python = ">=3.10" and depends on torch>=2.2.0, torchvision>=0.15.0, nir>=1.0.6 and nirtorch>=2.0.6. The README's prose states Python 3.8+ and PyTorch 1.9+, which is looser than the packaging metadata.

### Can I use Norse with PyTorch Lightning?

Yes. The README states that Norse is compatible with PyTorch Lightning and points to a Lightning variant of the MNIST task, which it shows invoked as python -m norse.task.mnist_pl --gpus=4. The README notes that this task requires PyTorch Lightning to be installed.

### What are the example tasks bundled with Norse?

The README lists MNIST and CIFAR-10 classification and a cartpole balancing task trained with policy gradient, run as python -m norse.task.mnist, python -m norse.task.cifar10 and python -m norse.task.cartpole from the base directory. Each task takes arguments listed by python -m norse.task.<task> --help.

## Sources

- [License: LGPL-3.0](https://github.com/norse/norse/blob/main/LICENSE)
- [norse/norse on GitHub](https://github.com/norse/norse)
- [Project website](https://norse.github.io/norse/)
- [README](https://github.com/norse/norse/blob/main/README.md)
- [Releases](https://github.com/norse/norse/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/norse-norse
