Skip to content

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