From 495714a8799029160d83c0a8c58cd01e9f3b9731 Mon Sep 17 00:00:00 2001 From: brueckau Date: Fri, 30 Aug 2019 14:48:52 -0700 Subject: [PATCH] Moved Loihi backend from SNN toolbox to nxsdk_modules. --- scripts/cifar10_loihi.ipynb | 35 +- .../target_simulators/loihi_target_sim.py | 702 +----------------- 2 files changed, 22 insertions(+), 715 deletions(-) diff --git a/scripts/cifar10_loihi.ipynb b/scripts/cifar10_loihi.ipynb index 283d49da..fcc2eae2 100644 --- a/scripts/cifar10_loihi.ipynb +++ b/scripts/cifar10_loihi.ipynb @@ -9,7 +9,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 39, "metadata": { "collapsed": true, "pycharm": { @@ -30,7 +30,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 61, "metadata": { "pycharm": { "is_executing": false @@ -48,7 +48,7 @@ " 'ytick.major.size': 7,\n", " 'ytick.minor.size': 5,\n", " 'legend.fontsize': 'xx-large',\n", - " 'figure.figsize': (8, 5),\n", + " 'figure.figsize': (8, 3.5),\n", " 'savefig.dpi': 300,\n", " 'savefig.format': 'jpg'}\n", "\n", @@ -65,7 +65,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 41, "metadata": { "pycharm": { "is_executing": false @@ -74,13 +74,13 @@ "outputs": [], "source": [ "log_dir = '/home/brueckau/Repositories/snntoolbox_experiments/cifar10/mobilenet/log'\n", - "runlabel_analog = '01'\n", + "runlabel_analog = '02'\n", "path_analog = os.path.join(log_dir, 'gui', runlabel_analog)" ] }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 56, "metadata": { "pycharm": { "is_executing": false @@ -96,7 +96,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 46, "outputs": [], "source": [ "# import numpy as np\n", @@ -119,7 +119,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 62, "metadata": { "collapsed": false, "pycharm": { @@ -129,8 +129,8 @@ "outputs": [ { "data": { - "text/plain": "
", - "image/png": "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\n" + "text/plain": "
", + "image/png": "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\n" }, "metadata": { "needs_background": "light" @@ -139,7 +139,7 @@ } ], "source": [ - "show_numbers = False\n", + "show_numbers = True\n", "\n", "exp = experiments[0]\n", "\n", @@ -157,20 +157,21 @@ "# plt.hlines(0, 0, 2)\n", "\n", "if show_numbers:\n", - " plt.annotate('SNN', xy=(0.2, 90), fontsize=16)\n", + " plt.annotate(' SNN\\nsynops', xy=(0.2, 90), fontsize=16)\n", " plt.annotate(' ANN\\n{:.2f}M macs'.format(exp.operations_ann), \n", " xy=(exp.operations_ann - 0.15, 75), fontsize=16, color='k')\n", - " plt.annotate('{:.2f}M synops'.format(exp.op1_1), xy=(exp.op1_1, 90),\n", - " xytext=(exp.op1_1 - 0.155, 65), fontsize=16,\n", - " arrowprops=dict(color='k', shrink=0.05, width=5, headwidth=10), color='k')\n", + " plt.annotate('CIFAR10', xy=(1.2, 5), fontsize=16)\n", + " # plt.annotate('{:.2f}M synops'.format(exp.op1_1), xy=(exp.op1_1, 90),\n", + " # xytext=(exp.op1_1 - 0.155, 65), fontsize=16,\n", + " # arrowprops=dict(color='k', shrink=0.05, width=5, headwidth=10), color='k')\n", " # plt.annotate('({:.2f}M ops, {:.2f}%)'.format(exp.operations_ann, exp.e1_ann), xy=(exp.operations_ann - 0.7, exp.e1_ann + 5), fontsize=16, color='k')\n", " # plt.annotate('({:.2f}M ops, {:.2f}%)'.format(exp.op1_1, exp.e1_1), xy=(exp.op1_1, exp.e1_1),\n", " # xytext=(1.5 * exp.op1_1, exp.e1_1 + 15), fontsize=16,\n", " # arrowprops=dict(color='k', shrink=0.05, width=5, headwidth=10), color='k')\n", "plt.ylim(-5, 110)\n", "plt.xlim(0, None)\n", - "plt.ylabel('Accuracy rel. to ANN [%]')\n", - "plt.xlabel('M operations')\n", + "plt.ylabel('Accuracy\\nrel. to ANN [%]')\n", + "plt.xlabel('Number of operations [1e6]')\n", "# plt.legend(loc='upper right')\n", "# plt.title('ANN vs SNN performance')\n", "plt.savefig(os.path.join(log_dir, 'err_vs_ops'), bbox_inches='tight')" diff --git a/snntoolbox/simulation/target_simulators/loihi_target_sim.py b/snntoolbox/simulation/target_simulators/loihi_target_sim.py index 02d3e635..c8cb85b2 100644 --- a/snntoolbox/simulation/target_simulators/loihi_target_sim.py +++ b/snntoolbox/simulation/target_simulators/loihi_target_sim.py @@ -1,704 +1,10 @@ # -*- coding: utf-8 -*- """ Building and running spiking neural networks using Intel's Loihi platform. + +Currently, this code is part of the nxsdk, so we redirect there. @author: rbodo """ -from __future__ import division, absolute_import -from __future__ import print_function, unicode_literals - -import os -import warnings - -import numpy as np -from future import standard_library -import keras - -import nxsdk_modules.dnn.src.dnn_layers as loihi_snn -from nxsdk.graph.processes.phase_enums import Phase -from snntoolbox.parsing.utils import get_type -from snntoolbox.conversion.utils import get_scale_fac -from snntoolbox.simulation.utils import AbstractSNN, is_spiking -from snntoolbox.simulation.plotting import plot_probe -from snntoolbox.utils.utils import to_integer - -standard_library.install_aliases() - - -class SNN(AbstractSNN): - """Class to hold the compiled spiking neural network. - - Represents the compiled spiking neural network, ready for testing in a - spiking simulator. - - Attributes - ---------- - - """ - - def __init__(self, config, queue=None): - - AbstractSNN.__init__(self, config, queue) - - os.environ['SLURM'] = '1' - - self.snn = None - self._spiking_layers = {} - self.spike_probes = None - self.voltage_probes = None - self.threshold_scales = None - partition = self.config.get('loihi', 'partition', fallback='') - self.partition = None if partition == '' else partition - self._previous_layer_name = None - self.do_probe_spikes = \ - any({'spiketrains', 'spikerates', 'correlation', 'spikecounts', - 'hist_spikerates_activations'} & self._plot_keys) \ - or 'spiketrains_n_b_l_t' in self._log_keys - self.num_weight_bits = eval(self.config.get( - 'loihi', 'connection_kwargs'))['numWeightBits'] - self._has_reset_snip = False - - @property - def is_parallelizable(self): - return False - - def get_layer_kwargs(self, layer): - - layer_kwargs = layer.get_config() - compartment_kwargs = eval(self.config.get('loihi', - 'compartment_kwargs')) - scale = self.threshold_scales[layer.name] - compartment_kwargs['vThMant'] = \ - int(compartment_kwargs['vThMant'] * 2 ** scale) - if self.do_probe_spikes: - compartment_kwargs['probeSpikes'] = True - layer_kwargs.update(compartment_kwargs) - - connection_kwargs = eval(self.config.get('loihi', 'connection_kwargs')) - connection_kwargs['weightExponent'] += \ - self.threshold_scales[self._previous_layer_name] - layer_kwargs.update(connection_kwargs) - - vp = self.config.getboolean('loihi', 'visualize_partitions', - fallback='') - if vp != '': - layer_kwargs['visualizePartitions'] = vp - - vp = self.config.getboolean('loihi', 'validate_partitions', - fallback='') - if vp != '': - layer_kwargs['validatePartitions'] = vp - - encoding = self.config.get('loihi', 'synapse_encoding', fallback='') - if encoding != '': - layer_kwargs['synapseEncoding'] = encoding - - return layer_kwargs - - def add_input_layer(self, input_shape): - - if self._poisson_input: - raise NotImplementedError - - name = self.parsed_model.layers[0].name - - compartment_kwargs = eval(self.config.get('loihi', - 'compartment_kwargs')) - scale = self.threshold_scales[name] - compartment_kwargs['vThMant'] = \ - int(compartment_kwargs['vThMant'] * 2 ** scale) - if self.do_probe_spikes: - compartment_kwargs['probeSpikes'] = True - input_layer = loihi_snn.NxInputLayer(input_shape[1:], input_shape[0], - **compartment_kwargs) - self._spiking_layers[name] = input_layer.input - self._previous_layer_name = name - - def add_layer(self, layer): - - nx_layer_type = 'Nx' + get_type(layer) - - if not hasattr(loihi_snn, nx_layer_type): - return - - spike_layer_name = getattr(loihi_snn, nx_layer_type) - - layer_kwargs = self.get_layer_kwargs(layer) - - spike_layer = spike_layer_name(**layer_kwargs) - - inbound = self._spiking_layers[self._previous_layer_name] - - self._spiking_layers[layer.name] = spike_layer(inbound) - - # Convert weights to integers. - if len(layer.weights): - weights, biases = layer.get_weights() - weights, biases = to_integer(weights, biases, self.num_weight_bits) - - spike_layer.set_weights([weights, biases]) - - elif 'AveragePooling' in get_type(layer): - weights, biases = spike_layer.get_weights() - weights, biases = to_integer(weights, biases, self.num_weight_bits) - spike_layer.set_weights([weights, biases]) - - self._previous_layer_name = layer.name - - def build_dense(self, layer): - """ - - Parameters - ---------- - layer : keras.layers.Dense - - Returns - ------- - - """ - - if layer.activation.__name__ == 'softmax': - warnings.warn("Activation 'softmax' not implemented. Using 'relu' " - "activation instead.", RuntimeWarning) - - def build_convolution(self, layer): - pass - - def build_pooling(self, layer): - if layer.__class__.__name__ == 'MaxPooling2D': - warnings.warn("Layer type 'MaxPooling' not supported yet. " + - "Falling back on 'AveragePooling'.", RuntimeWarning) - - def compile(self): - - logdir = self.config.get('paths', 'log_dir_of_current_run') - save_output = self.config.getboolean('loihi', 'save_output', - fallback=None) - try_load_partitions = self.config.getboolean( - 'loihi', 'try_load_partitions', fallback=None) - store_all_candidates = self.config.getboolean( - 'loihi', 'store_all_candidates', fallback=None) - num_candidates_to_compute = self.config.getint( - 'loihi', 'num_candidates_to_compute', fallback=None) - - input_layer = self._spiking_layers[self.parsed_model.layers[0].name] - output_layer = self._spiking_layers[self._previous_layer_name] - - self.snn = loihi_snn.NxModel( - input_layer, output_layer, verbose=True, logdir=logdir, - saveOutput=save_output, tryLoadPartitions=try_load_partitions, - storeAllCandidates=store_all_candidates, - numCandidatesToCompute=num_candidates_to_compute) - - self.snn.compileModel(None, self.partition) - - self.set_vars_to_record() - - try: - self.setup_snips() - self._has_reset_snip = True - except FileNotFoundError: - self._has_reset_snip = False - - def simulate(self, **kwargs): - - data = kwargs[str('x_b_l')] - - self.set_inputs(data) - - lenInterval = 1000 - if self._duration <= lenInterval: - self.snn.run(self._duration) - else: - numIntervals = self._duration // lenInterval - for _ in range(numIntervals): - self.snn.run(lenInterval) - - print("\nCollecting results...") - output_b_l_t = self.get_recorded_vars(self.snn.layers) - - return output_b_l_t - - def reset(self, sample_idx): - - if self._has_reset_snip: - return - - print("Resetting membrane potentials...") - for layer in self.snn.layers: - if not is_spiking(layer, self.config): - continue - for i in range(int(np.prod(layer.output_shape[1:]))): - layer[i].voltage = 0 - print("Done.") - - def end_sim(self): - - self.snn.disconnect() - - def save(self, path, filename): - - pass - - def load(self, path, filename): - - raise NotImplementedError - - def init_cells(self): - - pass - - def set_vars_to_record(self): - """Set variables to record during simulation.""" - - a = loihi_snn.ProbableStates.ACTIVITY - v = loihi_snn.ProbableStates.VOLTAGE - s = loihi_snn.ProbableStates.SPIKE - - do_probe_v = \ - 'mem_n_b_l_t' in self._log_keys or 'v_mem' in self._plot_keys - - self.spike_probes = {} - if do_probe_v: - self.voltage_probes = {} - - for layer in self.snn.layers: - if not is_spiking(layer, self.config): - continue - - if self.do_probe_spikes: - self.spike_probes[layer.name] = [] - if do_probe_v: - self.voltage_probes[layer.name] = [] - - num_neurons = int(np.prod(layer.output_shape[1:])) - for i in range(num_neurons): - if self.do_probe_spikes: - self.spike_probes[layer.name].append(layer[i].probe(a)) - if do_probe_v: - self.voltage_probes[layer.name].append(layer[i].probe(v)) - - # The spikes of the last layer are recorded by default because they - # contain the networks output (classification guess). We can use spike - # probes here instead of activity traces because the output layer has - # no shared output axons. - output_layer = get_spiking_output_layer(self.snn.layers, self.config) - num_neurons = int(np.prod(output_layer.output_shape[1:])) - self.spike_probes[output_layer.name] = [output_layer[i].probe(s) - for i in range(num_neurons)] - - def get_spiketrains(self, **kwargs): - - j = self._spiketrains_container_counter - if self.spiketrains_n_b_l_t is None \ - or j >= len(self.spiketrains_n_b_l_t): - return - - # Outer for-loop that calls this function starts with - # 'monitor_index' = 0, but this is reserved for the input and handled - # by `get_spiketrains_input()`. - i = kwargs[str('monitor_index')] - if i == 0: - return - - layer = self.snn.layers[i] - if not is_spiking(layer, self.config): - return - - name = layer.name - probes = self.stack_layer_probes(self.spike_probes[name]) - shape = self.spiketrains_n_b_l_t[j][0].shape - spiketrains_b_l_t = self.reshape_flattened_spiketrains(probes, shape) - # Need to integer divide by max value that soma traces assume, to get - # rid of the decay tail of the soma trace. The peak value (marking a - # spike) is defined as 127 in probe creation and will be mapped to 1. - # (If this is the output layer, we are probing the spikes directly and - # do not need to scale.) - is_output_layer = \ - get_spiking_output_layer(self.snn.layers, self.config).name == name - scale = 1 if is_output_layer else 127 - return spiketrains_b_l_t // scale - - def get_spiketrains_input(self): - - layer = self.snn.layers[0] - if layer.name not in self.spike_probes: - return - - probes = self.stack_layer_probes(self.spike_probes[layer.name]) - shape = list(self.parsed_model.input_shape) + [self._num_timesteps] - spiketrains_b_l_t = self.reshape_flattened_spiketrains(probes, shape) - return spiketrains_b_l_t // 127 - - def get_spiketrains_output(self): - - layer = get_spiking_output_layer(self.snn.layers, self.config) - probes = self.stack_layer_probes(self.spike_probes[layer.name]) - shape = [self.batch_size, self.num_classes, self._num_timesteps] - spiketrains_b_l_t = self.reshape_flattened_spiketrains(probes, shape) - return spiketrains_b_l_t - - def get_vmem(self, **kwargs): - if self.voltage_probes is None: - return - - i = kwargs[str('monitor_index')] - - if not is_spiking(self.snn.layers[i], self.config): - return - - name = self.snn.layers[i].name - probes = self.voltage_probes[name] - # Plot instead of returning input layer probes because the toolbox - # does not expect input to record the membrane potentials. - if i == 0: - plot_probe(probes, - self.config.get('paths', 'log_dir_of_current_run'), - 'v_input.png') - else: - return self.stack_layer_probes(probes) - - def stack_layer_probes(self, probes): - - return np.stack([p.data[-self._num_timesteps:] for p in probes]) - - def reshape_flattened_spiketrains(self, spiketrains, shape, is_list=True): - - # Temporarily move time axis so we can reshape in Fortran style. - new_shape = shape[:-1] - new_shape = np.insert(new_shape, 1, shape[-1]) - - # Need to flatten in 'C' mode first to stack the timevectors together, - # then reshape in 'F' style. - arr = np.reshape(np.ravel(spiketrains), new_shape, 'F') - - # Finally, move the time axis back again. - return np.moveaxis(arr, 1, -1) - - def set_spiketrain_stats_input(self): - AbstractSNN.set_spiketrain_stats_input(self) - - def set_inputs(self, inputs): - inputs = np.ravel(inputs, 'F') - # Normalize inputs and scale up to 8 bit. - inputs = (inputs / np.max(inputs) * (2 ** 8 - 1)).astype(int) - - for i, biasMant in enumerate(inputs): - self.snn.layers[0][i].biasMant = biasMant - self.snn.layers[0][i].phase = 2 - - def preprocessing(self, **kwargs): - if self.config.getboolean('loihi', 'normalize_thresholds', - fallback=True): - print("\nNormalizing thresholds.") - self.threshold_scales = normalize_loihi_network( - self.parsed_model, self.config, **kwargs) - else: - print("\nSkipping threshold normalization.\n") - self.threshold_scales = {layer.name: 1 - for layer in self.parsed_model.layers} - - def setup_snips(self): - snip_dir = self.config.get('loihi', 'snip_dir', fallback='') - - if snip_dir == '': - snip_dir = os.path.abspath(os.path.join(os.path.dirname( - loihi_snn.__file__), '..', 'apps')) - - if not os.path.exists(snip_dir): - raise FileNotFoundError - - board = self.snn.board - - # Init SNIP for LMT1 (reset injection). - snip_init_1 = board.createSnip( - name='init', - cFilePath=os.path.join(snip_dir, 'snip_init.c'), - includeDir=snip_dir, - funcName='init_1', - phase=Phase.EMBEDDED_INIT, - lmtId=1, - chipId=0) - - # Reset SNIP - board.createProcess( - name='reset', - cFilePath=os.path.join(snip_dir, 'snip_reset.c'), - includeDir=snip_dir, - guardName='do_reset', - funcName='reset', - phase='mgmt', - lmtId=1, - chipId=0) - - # Configure channels. - channel_init_ch0_1 = board.createChannel( - bytes('channel_init_ch0_1', 'utf-8'), 'int', 3) - channel_init_ch0_1.connect(None, snip_init_1) - - board.start() - - num_cores = sum([board.n2Chips[i].numCores - for i in range(board.numChips)]) - - channel_init_ch0_1.write(3, [num_cores, self._num_timesteps, 1]) - - board.sync = False - - -def get_shape_from_label(label): - """ - Extract the output shape of a flattened pyNN layer from the layer name - generated during parsing. - - Parameters - ---------- - - label: str - Layer name containing shape information after a '_' separator. - - Returns - ------- - - : list - The layer shape. - - Example - ------- - >>> get_shape_from_label('02Conv2D_16x32x32') - [16, 32, 32] - - """ - return [int(i) for i in label.split('_')[1].split('x')] - - -def normalize_loihi_network(parsed_model, config, **kwargs): - - if 'x_norm' in kwargs: - x_norm = kwargs[str('x_norm')] # Values in range [0, 1] - elif 'x_test' in kwargs: - x_norm = kwargs[str('x_test')] - elif 'dataflow' in kwargs: - x_norm, y = kwargs[str('dataflow')].next() - else: - raise NotImplementedError - print("Using {} samples for normalization.".format(len(x_norm))) - sizes = [ - len(x_norm) * np.array(layer.output_shape[1:]).prod() * 32 / - (8 * 1e9) for layer in parsed_model.layers if len(layer.weights) > 0] - size_str = ['{:.2f}'.format(s) for s in sizes] - print("INFO: Need {} GB for layer activations.\n".format(size_str)) - - do_overflow_estimate = config.getboolean('loihi', 'do_overflow_estimate', - fallback=True) - - batch_size = config.getint('simulation', 'batch_size') - - connection_kwargs = eval(config.get('loihi', 'connection_kwargs')) - compartment_kwargs = eval(config.get('loihi', 'compartment_kwargs')) - # Weights have a maximum of 8 bits, used for biases as well. - num_weight_bits = connection_kwargs['numWeightBits'] - threshold_mant = compartment_kwargs['vThMant'] - weight_exponent = connection_kwargs['weightExponent'] - bias_exponent = compartment_kwargs['biasExp'] - - # Loihi limits on weights and thresholds. - _weight_exponent_lim = 2 ** 3 - 1 - _threshold_mant_lim = 2 ** 17 - 1 - - # Loihi applies a fix scaling on weights and thresholds. - _weight_gain = 2 ** 6 - _threshold_gain = 2 ** 6 - - # Input should already be normalized, but do it again just for safety. - x = x_norm / np.max(x_norm) - # Convert to integers and scale by bias exponent. - x *= (2 ** num_weight_bits - 1) * 2 ** bias_exponent - - desired_threshold_to_input_ratio = \ - eval(config.get('loihi', 'desired_threshold_to_input_ratio')) - - scales = {} - - model_copy = keras.models.clone_model(parsed_model) - model_copy.set_weights(parsed_model.get_weights()) - - # Want to optimize thr, while keeping weights and biases in right range. - for i, layer in enumerate(model_copy.layers): - - print(layer.name) - - prev_scale = scales.get(model_copy.layers[i - 1].name, None) - - if len(layer.weights) > 0: - # Unconstrained floats - weights, biases = layer.get_weights() - # Scale to 8 bit using a common factor for both weights and biases. - # The weights and biases variables represent mantissa values with - # zero exponent. - weights, biases = to_integer(weights, biases, num_weight_bits) - weights = \ - weights * _weight_gain * 2 ** (weight_exponent + prev_scale) - if do_overflow_estimate: - check_q_overflow(weights, 1 / desired_threshold_to_input_ratio) - layer.set_weights([weights, biases * 2 ** bias_exponent]) - - # Need to remove softmax in output layer to get activations above 1. - if hasattr(layer, 'activation') and \ - layer.activation.__name__ == 'softmax': - layer.activation = keras.activations.relu - - # Get the excitatory post-synaptic potential for each neuron in layer. - y = keras.models.Sequential([layer]).predict(x, batch_size) if i else x - - if i > 0: - # Layers like Flatten do not have spiking neurons and therefore no - # threshold to tune. So we only need to update the input to the - # next layer, and propagate the scale. The input layer (i == 0) - # counts as spiking. - if not is_spiking(layer, config): - x = y - scales[layer.name] = prev_scale - continue - # Loihi AveragePooling layers get weights of ones. To reproduce - # this in our Keras model, we need to apply the same - # transformations as for a regular layer that has weights. - elif 'AveragePooling' in get_type(layer): - a = np.prod(layer.pool_size) * (2 ** num_weight_bits - 1) - y = y * _weight_gain * 2 ** (weight_exponent + prev_scale) * a - - # The highest EPSP determines whether to raise threshold. - y_max = get_scale_fac(y[np.nonzero(y)], 100) - print("Maximum increase in compartment voltage per timestep: {}." - "".format(int(y_max))) - - initial_threshold_to_input_ratio = \ - threshold_mant * _threshold_gain / y_max - # The gain represents how many powers of 2 the spikerates currently - # differ from the desired spikerates. - gain = np.log2(initial_threshold_to_input_ratio / - desired_threshold_to_input_ratio) - print("The ratio of threshold to activations is off by 2**{:.2f}" - "".format(gain)) - - scale = 0 - # Want to find scale exponent for threshold such that - # -1 < gain + scale < 1. (By using the limits [-1, 1] we allow for a - # difference of up to a factor 2 in either direction.) - while gain + scale < -1: - # First case, gain < 0: Activations in layer are too high, which - # will result in information loss due to reset-to-zero. Increase - # threshold. - if weight_exponent + scale + 1 <= _weight_exponent_lim and \ - threshold_mant * 2 ** (scale + 1) <= _threshold_mant_lim: - scale += 1 - else: - print("Reached upper limit of weight exponent or threshold.") - break - else: - while gain + scale > 1: - # Second case, gain > 0: Activations in layer are too low, - # which will result in low spike rates and thus quantization - # errors. Decrease threshold. - if weight_exponent + scale - 1 >= - _weight_exponent_lim - 1 \ - and threshold_mant * 2 ** (scale - 1) >= 1: - scale -= 1 - else: - print("Reached lower limit of weight exponent or " - "threshold.") - break - - print("Scaling thresholds of layer {} and weights of subsequent layer " - "by 2**{}.\n".format(layer.name, scale)) - scales[layer.name] = scale - - # Apply activation function (dividing by threshold) to obtain the - # output of the current layer, which will be used as input to the next. - beta = threshold_mant * _threshold_gain * 2 ** scale - x = y / beta - # Apply the same scaling to the weights of current layer, which does - # not affect the subsequent iterations in this loop, but which scales - # the activations of the parsed layer later when plotting against the - # spike rates. - if len(layer.weights) > 0: - weights, biases = layer.get_weights() - layer.set_weights([weights / beta, biases / beta]) - - parsed_model.set_weights(model_copy.get_weights()) - - return scales - - -def check_q_overflow(weights, p): - num_channels = weights.shape[-1] - weights_flat = np.reshape(weights, (-1, num_channels)) - q_min = - 2 ** 15 - q_max = - q_min - 1 - weighted_fanin = np.sum(weights_flat, 0) - neg = np.mean(weighted_fanin < q_min) - pos = np.mean(weighted_fanin > q_max) - if neg or pos: - print("In the worst case of all pre-synaptic neurons firing " - "simultaneously, the dendritic accumulator will overflow in " - "{:.2%} and underflow in {:.2%} of neurons.".format(pos, neg)) - print("Estimating averages...") - neg = [] - pos = [] - num_fanin = len(weights_flat) - for i in range(2 ** min(num_fanin, 16)): - spikes = np.random.binomial(1, p, num_fanin) - weighted_fanin = np.sum(weights_flat[spikes > 0], 0) - neg.append(np.mean(weighted_fanin < q_min) * 100) - pos.append(np.mean(weighted_fanin > q_max) * 100) - print("On average, the dendritic accumulator will overflow in {:.2f} " - "+/- {:.2f} % and underflow in {:.2f} +/- {:.2f} % of neurons." - "".format(np.mean(pos), np.std(pos), np.mean(neg), np.std(neg))) - - -def overflow_signed(x, num_bits): - """Compute overflow on an array of signed integers. - - Parameters - ---------- - x : ndarray - Integer values for which to compute values after overflow. - num_bits : int - Number of bits, not including sign, to compute overflow for. - - Returns - ------- - out : ndarray - Values of x overflowed as would happen with limited bit representation. - overflowed : ndarray - Boolean array indicating which values of ``x`` actually overflowed. - """ - - x = x.astype(int) - - lim = 2 ** num_bits - smask = np.array(lim, int) # mask for the sign bit - xmask = smask - 1 # mask for all bits <= `bits` - - # Find where x overflowed - overflowed = (x < -lim) | (x >= lim) - - zmask = x & smask # if `out` has negative sign bit, == 2**bits - out = x & xmask # mask out all bits > `bits` - out -= zmask # subtract 2**bits if negative sign bit - - return out, overflowed - - -def to_mantexp(x, mant_max, exp_max): - r = np.maximum(np.abs(x) / mant_max, 1) - exp = np.ceil(np.log2(r)).astype(int) - assert np.all(exp <= exp_max) - man = np.round(x / 2 ** exp).astype(int) - assert np.all(np.abs(man) <= mant_max) - return man, exp - - -def get_spiking_output_layer(layers, config): - for layer in reversed(layers): - if is_spiking(layer, config): - return layer +# noinspection PyUnresolvedReferences +from nxsdk_modules.snntoolbox.nx_backend import SNN