Building Your First Network
nwave provides three families of spiking layers:
| Family | Description | Use when |
|---|---|---|
| LIF | Generic leaky integrate-and-fire, pure software | Prototyping, no hardware target |
| H1v1 | First-generation Neuronova hardware model | Targeting H1v1 chip |
| H1v2 | Second-generation hardware (current default) | Targeting H1v2 chip — recommended for new models |
Every network is built from two alternating building blocks: - Synapse — transforms the input (weighted sum, like a linear layer) - Layer — applies spiking neuron dynamics and emits binary spikes
Because neurons have internal state (membrane potential), a network processes inputs one timestep at a time in a loop.
prepare_net(model)must be called at the start of every forward pass. It resets all neuron states (membrane potentials, spike history) to zero.
import torch
import torch.nn as nn
from nwavesdk.layers import (
LIFSynapse, LIFLayer,
H1v1Synapse, H1v1Layer,
H1v2Synapse, H1v2Layer,
prepare_net,
)
nwavesdk version: 1.0.0a0+rocm
LIF network
The simplest network — one synapse and one layer. No hardware quantization or mismatch. Good for prototyping before committing to a hardware target.
N_IN, N_OUT, DT = 16, 8, 1e-3
class LIFNet(nn.Module):
def __init__(self):
super().__init__()
self.syn = LIFSynapse(N_IN, N_OUT, device="cpu")
self.lyr = LIFLayer(n_neurons=N_OUT, thresholds=1.0, reset_mechanism="subtraction", taus=10e-3, dt=DT, device="cpu")
def forward(self, x):
prepare_net(self)
spk_list = []
for t in range(x.shape[1]):
cur = self.syn(x[:, t, :])
spk, _ = self.lyr(cur)
spk_list.append(spk)
return torch.stack(spk_list, dim=1)
lif_model = LIFNet()
H1v1 network
Same structure, but using H1v1 layers. The H1v1 synapse has a nonlinear synaptic model that matches the first-generation chip. Call prepare_net — it also initializes the internal hardware state buffers.
class H1v1Net(nn.Module):
def __init__(self):
super().__init__()
self.syn = H1v1Synapse(N_IN, N_OUT, device="cpu")
self.lyr = H1v1Layer(n_neurons=N_OUT, taus=10e-3, dt=DT, device="cpu")
def forward(self, x):
prepare_net(self)
spk_list = []
for t in range(x.shape[1]):
cur = self.syn(x[:, t, :])
spk, _ = self.lyr(cur)
spk_list.append(spk)
return torch.stack(spk_list, dim=1)
h1v1_model = H1v1Net()
H1v2 network
H1v2 uses a linear synapse model and has different hardware weight bounds and neuron count limits from H1v1. It is the recommended target for new models.
class H1v2Net(nn.Module):
def __init__(self):
super().__init__()
self.syn = H1v2Synapse(N_IN, N_OUT, device="cpu")
self.lyr = H1v2Layer(n_neurons=N_OUT, taus=10e-3, dt=DT, device="cpu")
def forward(self, x):
prepare_net(self)
spk_list = []
for t in range(x.shape[1]):
cur = self.syn(x[:, t, :])
spk, _ = self.lyr(cur)
spk_list.append(spk)
return torch.stack(spk_list, dim=1)
h1v2_model = H1v2Net()
Running a forward pass
Run all three networks on the same synthetic input.
BATCH, T = 2, 50
# Sparse synthetic input: ~20% of timesteps have a spike per channel
x = (torch.rand(BATCH, T, N_IN) > 0.8).float()
for name, model in [("LIF", lif_model), ("H1v1", h1v1_model), ("H1v2", h1v2_model)]:
model.eval()
with torch.no_grad():
spk = model(x)
Further reading
- Reference → Layers: full parameter reference for all layer types →
../reference/layers.md - Reference → Weight Initialisation: how to set initial weights for hardware networks →
../initializations/automatic_init.md - Tutorial 1 — H1v1 model deep dive (hardware parameters, mismatch, quantization) →
../tutorials/Tutorial1_H1v1Model.md - Tutorial 2 — H1v2 model deep dive →
../tutorials/Tutorial2_H1v2Model.md