Rockpool#

Rockpool (https://rockpool.ai) is a deep learning toolchain for deep spiking neural networks and other dynamical NN architectures, supporting deployment to Neuromorphic computing hardware.

Rockpool provides a convenient interface for designing, training and evaluating networks, which can operate both with continuous-time dynamics and event-driven dynamics.

You can import a model from NIR with the from_nir method in rockpool.nn.modules.torch.nir. Once it is in Rockpool, you can deploy your model to Synsense’s Xylo chips.

Import a NIR graph to Rockpool#

from rockpool.nn.modules import from_nir

import nir
import torch

# Supress warnings
import warnings
# warnings.filterwarnings('ignore')

# Create a NIR graph
affine_weights = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
affine_bias = torch.tensor([1.0, 2.0])
li_tau = torch.tensor([0.9, 0.8])
li_r = torch.tensor([1.0, 1.0])
li_v_leak = torch.tensor([0.0, 0.0])
nir_network = nir.NIRGraph.from_list(
    nir.Affine(affine_weights, affine_bias), nir.LI(li_tau, li_r, li_v_leak)
)

# Create Rockpool model from NIR graph.
with warnings.catch_warnings():
    # Supress unrelated warnings from Rockpool
    warnings.simplefilter("ignore")
    rockpool_model = from_nir(nir_network)
print(rockpool_model)
GraphExecutor(
  (input): Identity()
  (affine): LinearTorch()
  (li): ExpSynTorch()
  (output): Identity()
)

Export a NIR graph from Rockpool#

from rockpool.nn.modules import to_nir, LinearTorch, LIFTorch
from rockpool.nn.combinators import Sequential

n_in = 2
n_hidden = 4
n_out = 2
dt = 1e-3

# Create Rockpool model
net = Sequential(
    LinearTorch((n_in, n_hidden), has_bias=False),
    LIFTorch(n_hidden, dt=dt),
    LinearTorch((n_hidden, n_out), has_bias=False),
    LIFTorch(n_out, dt=dt),
)

# Convert model to NIR graph with a random input of representative shape
nir_graph = to_nir(net, torch.randn(1, 2))
print(nir_graph)

# Reload model from NIR
rockpool_model = from_nir(nir_graph)
print(rockpool_model)
NIRGraph(nodes={'input': Input(input_type={'input': array([1, 2])}), '0_LinearTorch': Linear(weight=tensor([[-0.5091,  0.9906],
        [ 0.6462,  0.4613],
        [-1.6254, -1.5708],
        [ 1.3620, -0.1414]])), '1_LIFTorch': CubaLIF(tau_syn=array([0.02, 0.02, 0.02, 0.02], dtype=float32), tau_mem=array([0.02, 0.02, 0.02, 0.02], dtype=float32), r=array([19.024588, 19.024588, 19.024588, 19.024588], dtype=float32), v_leak=array([0., 0., 0., 0.], dtype=float32), v_threshold=array([1., 1., 1., 1.], dtype=float32), w_in=array([1., 1., 1., 1.], dtype=float32), input_type={'input': array([4])}, output_type={'output': array([4])}, metadata={}), '2_LinearTorch': Linear(weight=tensor([[ 0.6191,  0.3268, -0.3174, -0.8611],
        [ 0.7899,  1.0755, -1.0221,  1.0548]])), '3_LIFTorch': CubaLIF(tau_syn=array([0.02, 0.02], dtype=float32), tau_mem=array([0.02, 0.02], dtype=float32), r=array([19.024588, 19.024588], dtype=float32), v_leak=array([0., 0.], dtype=float32), v_threshold=array([1., 1.], dtype=float32), w_in=array([1., 1.], dtype=float32), input_type={'input': array([2])}, output_type={'output': array([2])}, metadata={}), 'output': Output(output_type={'output': array([1, 1, 2])})}, edges=[('input', '0_LinearTorch'), ('1_LIFTorch', '2_LinearTorch'), ('2_LinearTorch', '3_LIFTorch'), ('3_LIFTorch', 'output'), ('0_LinearTorch', '1_LIFTorch')], input_type={'input': {'input': array([1, 2])}}, output_type={'output': {'output': array([1, 1, 2])}}, metadata={})
GraphExecutor(
  (input): Identity()
  (0_LinearTorch): LinearTorch()
  (1_LIFTorch): LIFTorch()
  (2_LinearTorch): LinearTorch()
  (3_LIFTorch): LIFTorch()
  (output): Identity()
)
/Users/dylan/SynSense Dropbox/Dylan Muir/LiveSync/Development/Projects/nir/rockpool_nir/rockpool/nn/modules/torch/torch_module.py:258: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
  super().register_parameter(key, nn.Parameter(torch.tensor(value.data)))
/Users/dylan/SynSense Dropbox/Dylan Muir/LiveSync/Development/Projects/nir/rockpool_nir/rockpool/nn/modules/torch/linear_torch.py:111: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
  torch.tensor(weight) if weight is not None else None,
/Users/dylan/SynSense Dropbox/Dylan Muir/LiveSync/Development/Projects/nir/rockpool_nir/rockpool/nn/modules/torch/nir.py:115: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).
  dt=torch.min(torch.tensor(_to_tensor(node.tau_mem / (1 + node.r)))).item(),

Deployment#

As all Rockpool modules, imported networks support the .as_graph() method needed for mapping and deployment to neuromoprhic hardware. Note that Rockpool and several sub-dependencies are needed to support deployment. You can install these with

pip install 'rockpool[xylo]'

For more information, see the Rockpool tutorial notebooks describing deployment to Xylo: https://rockpool.ai/devices/xylo-overview.html

from rockpool.devices.xylo.syns61201 import mapper, config_from_specification, XyloSim
from rockpool.transform.quantize_methods import channel_quantize

spec = mapper(rockpool_model.as_graph())
config, is_valid, msg = config_from_specification(**channel_quantize(**spec))
xylo = XyloSim.from_config(config)

Caveats#

NIR support in Rockpool is currently dependent on the nirtorch helper package, and only supports torch backend networks.