Skip to content

Commit b0c5f8d

Browse files
ej159Bodo Rueckauerpabogdan
committed
SpiNNaker support (#53)
* Modified pipeline to allow skipping the parsing step and loading a parsed model instead. Added new option 'parse' to the [tools] section of the config file. * Added new spike layers for MobileNet architecture (DepthwiseConv2D, ZeroPadding2D, Reshape), and the LimitedReLU activation function. Does not enable parsing MobileNet, only simulating an externally parsed model on INIsim. * Fixed issue that evaluating the ANN as part of the INI simulation failed if the batch size in the config file differed from the batch size of the parsed model. This issue only appeared by loading an externally parsed model, not when parsing with the toolbox. Now the batch size of the loaded parsed model overrides the config batch size when evaluating the ANN. * Enable loading custom activation functions from a json file by specifying a filepath in the config file. Necessary for LimitedReLU activation in MobileNet. * Implemented counting of computations of DepthwiseConv layers. Proper handling of image_data_format in ops count. * Implemented absorbing of BatchNorm layers into DepthwiseConv layers. * Began implementing the parsing of MobileNet architectures. Not completed: Parsing of activation layers still missing. For now, an externally parsed MobileNet has to be loaded. * Added script to build simplified MobileNet architecture for debugging. * Added script to analyze parameter distributions of MobileNet. * Fix python2/Keras compatibility issues (string required instead of unicode). * Cleaning up spiNNaker target sim backend. Cosmetic changes in pyNN target sim. * Minor updates to script that analyzes parameter distributions of MobileNet-V2. * Fixed bug in bias reshaping for pyNN simulators. * Fixed bug in default value for parameter sweep. * Implemented logging of progressbar for pyNN simulation. * Changed neuron model from conductance to current based for pyNN simulation (less paramters). * Fixed bias implementation for pyNN simulators. * Optimized neuron parameters for pyNN simulators. * Added script to analyze input types for pyNN simulation. * Implemented constant input currents for pyNN simulation. * simulation/utils.py added strides in build_convolution and build_pooling, fixed saving of PyNN populations without attributes, added LimitedReLU activation * Modified training script of LeNet to create models that allow debugging pyNN simulator under various settings of "image_data_format". * Improved warning messages for pyNN cell parameters. * Fixed bug where plots of spikerates and spiketrains after pyNN simulation were scrambled when using 'channels_last'. * Implemented non-unit strides for conv layers. * Proper handling of 'image_data_format' in pooling layers for pyNN. * Fixed keras compatibility issue where newer models could not be simulated on pyNN except the Flatten layer had received the argument 'channels_last' during training. * Revert erroneous commit of main run file. * Fixed parsing of BatchNormalization layers for both image data formats. * Implemented ZeroPadding layer for pyNN simulator. * Added DepthwiseConv2D layer for pyNN simulator. * Started to create single script for running full pipeline of pyNN simulation. (To be extended.) * Updated spiNNaker backend to reflect recent improvements in pyNN backend. * Finished single script for running full pipeline of pyNN simulation. * Fixed ZeroPadding * Bugfix for passing axis parameter to BatchNorm parser. * Bugfix where rgb input data with channels_last was not properly handled by pyNN convolution layers. * Added / modified scripts for training CNNs to debug pyNN conversion. * Added / modified scripts for training CNNs to debug pyNN conversion. * Modified toolbox to generate a python script as part of the output when a pyNN simulator backend is selected in config file. This python script contains all the pyNN statements needed to build the SNN model, using the weight files created by the toolbox during conversion. * Added temporary SNN saving fix * Added custom example * Correct handling of excitatory and inhibitory weights in pyNN output script. Integration of pyNN script as input into toolbox. * Reverting some changes from previous merge. * fixed parsing problems * Revert "Reverting some changes from previous merge." This reverts commit 47f9cf7. * Revert "Revert "Reverting some changes from previous merge."" This reverts commit 36611be. * Revert "fixed parsing problems" This reverts commit d0a8b49. * Minor bugfixes / clean-ups. * Removed loading of original network for the case where parsing is turned off. * Added script to change activation in Keras models * fixed NSP in activation_changer * fixed connectivity problem in convolution * giving output with magic numbers in place * Removed progress bar for SpiNNaker * minor fixes sorting out biases * fix white space * Fixed flattening in channels first remove debugger * fixed build_convolution data_format call * Tidying up * Changed the transpose_kernel condition to be if data_formats don't match. * Reversed order of layer instantiation in SpiNNaker * update ignored files * setting up depthwise convolution pipeline * minor flatten issue fix * fixed v_thresh * fixed when to transpose kernel * fixed reshape layers * Dummy commit * fixed average pooling * can now deal with * wrong error type that Sands doesnt recognise * add fix to set number of neurons per core * sorting out ignored files * fixed plotting and removed old code * depthwise conv fixes * depthwise conv fixes * fixed plotting mirror problem * further dw fix (d and fin switch) * fixed setting v_rest for input layers * reverted changes to v_rest in input layers and commented out interception of simulator * fixed channel ordering in depthwise convolution * changes to how biases are set * bias to firing rate calibration tool added * fix to allow tau_refrac to be 0 * fix v_rest bug * turned serialisation on and fixed problems parsing rates * generalised naming layers to more dimensions * fixed issue plotting 1D input image * fixed issue plotting 1D input image * now avoiding problems with serialisation * fixed rates * Fixing rates properly! * small changes to deal with 1D layers * added in weight scaling * fiddling with bias setting * fixing weight scaling * added fixes for weight scaling, setting biases and showing model summary * working on Conv1D * correctly setting biases * some necessary fixes for conv1d added * minor changes to give more output * tidied and added runtime to serialisation * beginning to deal with keras sparse layers * files not wanting to update properly or be reset / reverted * fixed (broke?) everything to allow dwarfnet to run through * sparse layers go through. TODO: filtering based on mask before creating spiking network * added in GlobalAveragePooling fix * correct parsing of correctly saved sparse layers with masks * sparse layers seem to be supported now * added error message to * refactored main to allow running from script * fixed custom_params for simulator interception * fixing ReLU activation layer parsing bug * appropriate number of weights for sparse layers * Removed incorrect error about not being able to do ReLU6 * tidied up * hack to allow running of mobilenet from keras * hack to support limitedrelu. snntoolbox now stops trying to use model.optimizer which might not exist * added support for normalising sparse layers * Keras tf fix * fixed Sparse/Dense layers not going through + added extra reporting * passing runlabel to serialisation name * adding MNIST notebook * added serialisation config and fixed workflow * Add method to count number of neurons * Move setting number of neurons per core into config * Fix for conversion of sparse layers * Build elements of the workflow * Add parallelised testing scripts and config * Update MNIST workflow and ignored files * Update gitignore * Change dnns imports to keras_rewiring ones * Add keras dataset and serialise keys to default config * Format code to pep8 * Fix keras dataset config file bug * Fix v_thresh and erroneous code repeat * Tidy up SpiNNaker sim code * Change simulation runtime to duration rather than duration - timestep Add SpiNNaker test example Add spiNNaker test model Minimise redudant data retrieval for spiNNaker * Fix sparse layer parameter passing Add sparse example Make spinnaker test more realistic * Fix sparse depthwise layer parsing Add ActivityRegularization to ignored layers Add sparse tests Add spinnaker sparse example * Updated 'temporal_pattern' code to work with tensorflow 2. * Fixed time resolution and refractory period in Nest example. * Moved some example and training scripts to stand-alone repo. * Prepared spinnaker backend branch for merge. * Fix the SpiNNaker examples Co-authored-by: Bodo Rueckauer <[email protected]> Co-authored-by: Petrut Antoniu Bogdan <[email protected]>
1 parent 46f855f commit b0c5f8d

File tree

27 files changed

+1686
-109
lines changed

27 files changed

+1686
-109
lines changed

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,12 @@ __pycache__
99
.idea/
1010
.tox/
1111
.pytest_cache
12+
.project
13+
.pydevproject
14+
.settings/
15+
**/log/
16+
**/application_generated_data_files/
17+
**/reports/
18+
*.h5
19+
*.npz
20+
*.json

LICENSE.txt

100755100644
File mode changed.

README.rst

100755100644
File mode changed.

docs/Makefile

100755100644
File mode changed.

docs/make.bat

100755100644
File mode changed.

docs/source/index.rst

100755100644
File mode changed.

examples/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/mnist_keras_spiNNaker_sparse_sandbox.py
2+
/mnist_keras_spiNNaker_Fashion_MNIST.py

examples/mnist_keras_nest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@
119119
'duration': 50, # Number of time steps to run each sample.
120120
'num_to_test': 5, # How many test samples to run.
121121
'batch_size': 1, # Batch size for simulation.
122+
'dt': 0.1 # Time resolution for ODE solving.
123+
}
124+
125+
config['cell'] = {
126+
'tau_refrac': 0.1 # Refractory period must be at least one
127+
# time step.
122128
}
123129

124130
config['output'] = {

examples/mnist_keras_spiNNaker.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
"""End-to-end example for SNN Toolbox.
2+
3+
This script sets up a small CNN using Keras and tensorflow, trains it for one
4+
epoch on MNIST, stores model and dataset in a temporary folder on disk, creates
5+
a configuration file for SNN toolbox, and finally calls the main function of
6+
SNN toolbox to convert the trained ANN to an SNN and run it using SpiNNaker.
7+
"""
8+
9+
import os
10+
import time
11+
import numpy as np
12+
13+
import keras
14+
from keras import Input, Model
15+
from keras.layers import Conv2D, AveragePooling2D, Flatten, Dense, Dropout
16+
from keras.datasets import mnist
17+
from keras.utils import np_utils
18+
19+
from snntoolbox.bin.run import main
20+
from snntoolbox.utils.utils import import_configparser
21+
22+
23+
# WORKING DIRECTORY #
24+
#####################
25+
26+
# Define path where model and output files will be stored.
27+
# The user is responsible for cleaning up this temporary directory.
28+
path_wd = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(
29+
__file__)), '..', 'temp', str(time.time())))
30+
os.makedirs(path_wd)
31+
32+
# GET DATASET #
33+
###############
34+
35+
(x_train, y_train), (x_test, y_test) = mnist.load_data()
36+
37+
# Normalize input so we can train ANN with it.
38+
# Will be converted back to integers for SNN layer.
39+
x_train = x_train / 255
40+
x_test = x_test / 255
41+
42+
# Add a channel dimension.
43+
axis = 1 if keras.backend.image_data_format() == 'channels_first' else -1
44+
x_train = np.expand_dims(x_train, axis)
45+
x_test = np.expand_dims(x_test, axis)
46+
47+
# One-hot encode target vectors.
48+
y_train = np_utils.to_categorical(y_train, 10)
49+
y_test = np_utils.to_categorical(y_test, 10)
50+
51+
# Save dataset so SNN toolbox can find it.
52+
np.savez_compressed(os.path.join(path_wd, 'x_test'), x_test)
53+
np.savez_compressed(os.path.join(path_wd, 'y_test'), y_test)
54+
# SNN toolbox will not do any training, but we save a subset of the training
55+
# set so the toolbox can use it when normalizing the network parameters.
56+
np.savez_compressed(os.path.join(path_wd, 'x_norm'), x_train[::10])
57+
58+
# CREATE ANN #
59+
##############
60+
61+
# This section creates a simple CNN using Keras, and trains it
62+
# with backpropagation. There are no spikes involved at this point.
63+
64+
input_shape = x_train.shape[1:]
65+
input_layer = Input(input_shape)
66+
67+
layer = Conv2D(filters=16,
68+
kernel_size=(5, 5),
69+
strides=(2, 2),
70+
activation='relu',
71+
use_bias=False)(input_layer)
72+
layer = Conv2D(filters=32,
73+
kernel_size=(3, 3),
74+
activation='relu',
75+
use_bias=False)(layer)
76+
layer = AveragePooling2D()(layer)
77+
layer = Conv2D(filters=8,
78+
kernel_size=(3, 3),
79+
padding='same',
80+
activation='relu',
81+
use_bias=False)(layer)
82+
layer = Flatten()(layer)
83+
layer = Dropout(0.01)(layer)
84+
layer = Dense(units=10,
85+
activation='softmax',
86+
use_bias=False)(layer)
87+
88+
model = Model(input_layer, layer)
89+
90+
model.summary()
91+
92+
model.compile('adam', 'categorical_crossentropy', ['accuracy'])
93+
94+
# Train model with backprop.
95+
model.fit(x_train, y_train, batch_size=64, epochs=1, verbose=2,
96+
validation_data=(x_test, y_test))
97+
98+
# Store model so SNN Toolbox can find it.
99+
model_name = 'mnist_cnn'
100+
keras.models.save_model(model, os.path.join(path_wd, model_name + '.h5'))
101+
102+
# SNN TOOLBOX CONFIGURATION #
103+
#############################
104+
105+
# Create a config file with experimental setup for SNN Toolbox.
106+
configparser = import_configparser()
107+
config = configparser.ConfigParser()
108+
109+
config['paths'] = {
110+
'path_wd': path_wd, # Path to model.
111+
'dataset_path': path_wd, # Path to dataset.
112+
'filename_ann': model_name # Name of input model.
113+
}
114+
115+
config['tools'] = {
116+
'evaluate_ann': True, # Test ANN on dataset before conversion.
117+
# Normalize weights for full dynamic range.
118+
'normalize': False,
119+
'scale_weights_exp': True
120+
}
121+
122+
config['simulation'] = {
123+
# Chooses execution backend of SNN toolbox.
124+
'simulator': 'spiNNaker',
125+
'duration': 50, # Number of time steps to run each sample.
126+
'num_to_test': 5, # How many test samples to run.
127+
'batch_size': 1, # Batch size for simulation.
128+
# SpiNNaker seems to require 0.1 for comparable results.
129+
'dt': 0.1
130+
}
131+
132+
config['input'] = {
133+
'poisson_input': True, # Images are encodes as spike trains.
134+
'input_rate': 1000
135+
}
136+
137+
config['cell'] = {
138+
'tau_syn_E': 0.01,
139+
'tau_syn_I': 0.01
140+
}
141+
142+
config['output'] = {
143+
'plot_vars': { # Various plots (slows down simulation).
144+
'spiketrains', # Leave section empty to turn off plots.
145+
'spikerates',
146+
'activations',
147+
'correlation',
148+
'v_mem',
149+
'error_t'}
150+
}
151+
152+
# Store config file.
153+
config_filepath = os.path.join(path_wd, 'config')
154+
with open(config_filepath, 'w') as configfile:
155+
config.write(configfile)
156+
157+
# RUN SNN TOOLBOX #
158+
###################
159+
160+
main(config_filepath)
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
"""End-to-end example for SNN Toolbox.
2+
3+
This script sets up a small CNN using Keras and tensorflow, trains it for one
4+
epoch on MNIST, stores model and dataset in a temporary folder on disk, creates
5+
a configuration file for SNN toolbox, and finally calls the main function of
6+
SNN toolbox to convert the trained ANN to an SNN and run it using spiNNaker.
7+
"""
8+
9+
import os
10+
import numpy as np
11+
12+
import keras
13+
from keras import Input, Model
14+
from keras.layers import AveragePooling2D, Flatten, Dropout
15+
from keras_rewiring import Sparse, SparseConv2D, SparseDepthwiseConv2D
16+
from keras_rewiring.optimizers import NoisySGD
17+
from keras_rewiring.rewiring_callback import RewiringCallback
18+
from keras.datasets import mnist
19+
from keras.utils import np_utils
20+
21+
from snntoolbox.bin.run import main
22+
from snntoolbox.utils.utils import import_configparser
23+
24+
25+
# WORKING DIRECTORY #
26+
#####################
27+
28+
# Define path where model and output files will be stored.
29+
# The user is responsible for cleaning up this temporary directory.
30+
path_wd = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(
31+
__file__)), '..', 'temp'))
32+
# os.makedirs(path_wd)
33+
34+
# GET DATASET #
35+
###############
36+
37+
(x_train, y_train), (x_test, y_test) = mnist.load_data()
38+
39+
# Normalize input so we can train ANN with it.
40+
# Will be converted back to integers for SNN layer.
41+
x_train = x_train / 255
42+
x_test = x_test / 255
43+
44+
# Add a channel dimension.
45+
axis = 1 if keras.backend.image_data_format() == 'channels_first' else -1
46+
x_train = np.expand_dims(x_train, axis)
47+
x_test = np.expand_dims(x_test, axis)
48+
49+
# One-hot encode target vectors.
50+
y_train = np_utils.to_categorical(y_train, 10)
51+
y_test = np_utils.to_categorical(y_test, 10)
52+
53+
# Save dataset so SNN toolbox can find it.
54+
np.savez_compressed(os.path.join(path_wd, 'x_test'), x_test)
55+
np.savez_compressed(os.path.join(path_wd, 'y_test'), y_test)
56+
# SNN toolbox will not do any training, but we save a subset of the training
57+
# set so the toolbox can use it when normalizing the network parameters.
58+
np.savez_compressed(os.path.join(path_wd, 'x_norm'), x_train[::10])
59+
60+
# SETUP REWIRING #
61+
##################
62+
63+
deep_r = RewiringCallback(noise_coeff=10 ** -5)
64+
65+
callback_list = [deep_r]
66+
67+
# CREATE ANN #
68+
##############
69+
70+
# This section creates a simple CNN using Keras, and trains it
71+
# with backpropagation. There are no spikes involved at this point.
72+
73+
input_shape = x_train.shape[1:]
74+
input_layer = Input(input_shape)
75+
76+
built_in_sparsity = [0.5] * 4
77+
78+
layer = SparseConv2D(
79+
filters=16,
80+
kernel_size=(
81+
5,
82+
5),
83+
strides=(
84+
2,
85+
2),
86+
activation='relu',
87+
use_bias=False,
88+
connectivity_level=built_in_sparsity.pop(0) or None)(input_layer)
89+
layer = SparseConv2D(
90+
filters=32,
91+
kernel_size=(
92+
3,
93+
3),
94+
activation='relu',
95+
use_bias=False,
96+
connectivity_level=built_in_sparsity.pop(0) or None)(layer)
97+
layer = AveragePooling2D()(layer)
98+
layer = SparseConv2D(
99+
filters=8,
100+
kernel_size=(
101+
3,
102+
3),
103+
padding='same',
104+
activation='relu',
105+
use_bias=False,
106+
connectivity_level=built_in_sparsity.pop(0) or None)(layer)
107+
layer = Flatten()(layer)
108+
layer = Dropout(0.01)(layer)
109+
layer = Sparse(units=10,
110+
activation='softmax',
111+
use_bias=False,
112+
connectivity_level=built_in_sparsity.pop(0) or None)(layer)
113+
114+
model = Model(input_layer, layer)
115+
116+
model.summary()
117+
118+
model.compile(
119+
NoisySGD(
120+
lr=0.01),
121+
'categorical_crossentropy',
122+
['accuracy'])
123+
124+
# Train model with backprop.
125+
model.fit(x_train, y_train, batch_size=64, epochs=5, verbose=2,
126+
validation_data=(x_test, y_test),
127+
callbacks=callback_list)
128+
129+
# Store model so SNN Toolbox can find it.
130+
model_name = 'sparse_mnist_cnn'
131+
keras.models.save_model(model, os.path.join(path_wd, model_name + '.h5'))
132+
133+
# SNN TOOLBOX CONFIGURATION #
134+
#############################
135+
136+
# Create a config file with experimental setup for SNN Toolbox.
137+
configparser = import_configparser()
138+
config = configparser.ConfigParser()
139+
140+
config['paths'] = {
141+
'path_wd': path_wd, # Path to model.
142+
'dataset_path': path_wd, # Path to dataset.
143+
'filename_ann': model_name # Name of input model.
144+
}
145+
146+
config['tools'] = {
147+
'evaluate_ann': True, # Test ANN on dataset before conversion.
148+
# Normalize weights for full dynamic range.
149+
'normalize': False,
150+
'scale_weights_exp': True
151+
}
152+
153+
config['simulation'] = {
154+
# Chooses execution backend of SNN toolbox.
155+
'simulator': 'spiNNaker',
156+
'duration': 50, # Number of time steps to run each sample.
157+
'num_to_test': 5, # How many test samples to run.
158+
'batch_size': 1, # Batch size for simulation.
159+
# SpiNNaker seems to require 0.1 for comparable results.
160+
'dt': 0.1
161+
}
162+
163+
config['input'] = {
164+
'poisson_input': True, # Images are encodes as spike trains.
165+
'input_rate': 1000
166+
}
167+
168+
config['cell'] = {
169+
'tau_syn_E': 0.01,
170+
'tau_syn_I': 0.01
171+
}
172+
173+
config['output'] = {
174+
'plot_vars': { # Various plots (slows down simulation).
175+
'spiketrains', # Leave section empty to turn off plots.
176+
'spikerates',
177+
'activations',
178+
'correlation',
179+
'v_mem',
180+
'error_t'}
181+
}
182+
183+
# Store config file.
184+
config_filepath = os.path.join(path_wd, 'config')
185+
with open(config_filepath, 'w') as configfile:
186+
config.write(configfile)
187+
188+
# RUN SNN TOOLBOX #
189+
###################
190+
191+
main(config_filepath)

0 commit comments

Comments
 (0)