From b6dab81e618c730dba67f9e5a354b1146deb0999 Mon Sep 17 00:00:00 2001 From: Petrut Antoniu Bogdan Date: Thu, 31 Oct 2019 14:35:40 +0000 Subject: [PATCH 1/6] resolving weight scaling issues for purkinje cells --- .../connectors/from_list_connector.py | 6 +++--- .../neuron/input_types/input_type_conductance.py | 2 +- .../neuron/synapse_io/synapse_io_row_based.py | 3 ++- spynnaker/pyNN/models/neuron/synaptic_manager.py | 16 ++++++++++++---- 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/spynnaker/pyNN/models/neural_projections/connectors/from_list_connector.py b/spynnaker/pyNN/models/neural_projections/connectors/from_list_connector.py index cc6c9fa53bf..c80bb0b63d3 100644 --- a/spynnaker/pyNN/models/neural_projections/connectors/from_list_connector.py +++ b/spynnaker/pyNN/models/neural_projections/connectors/from_list_connector.py @@ -186,7 +186,7 @@ def get_n_connections_to_post_vertex_maximum(self): @overrides(AbstractConnector.get_weight_mean) def get_weight_mean(self, weights): if self.__weights is None: - return numpy.mean(weights) + return super(FromListConnector, self).get_weight_mean(weights) else: return numpy.mean(numpy.abs(self.__weights)) @@ -194,7 +194,7 @@ def get_weight_mean(self, weights): def get_weight_maximum(self, weights): # pylint: disable=too-many-arguments if self.__weights is None: - return numpy.amax(weights) + return self._get_weight_maximum(weights, len(self.__conn_list)) else: return numpy.amax(numpy.abs(self.__weights)) @@ -202,7 +202,7 @@ def get_weight_maximum(self, weights): def get_weight_variance(self, weights): # pylint: disable=too-many-arguments if self.__weights is None: - return numpy.var(weights) + return super(FromListConnector, self).get_weight_variance(weights) else: return numpy.var(numpy.abs(self.__weights)) diff --git a/spynnaker/pyNN/models/neuron/input_types/input_type_conductance.py b/spynnaker/pyNN/models/neuron/input_types/input_type_conductance.py index a60bfdeaf6f..4b1723028b9 100644 --- a/spynnaker/pyNN/models/neuron/input_types/input_type_conductance.py +++ b/spynnaker/pyNN/models/neuron/input_types/input_type_conductance.py @@ -76,7 +76,7 @@ def update_values(self, values, parameters, state_variables): @overrides(AbstractInputType.get_global_weight_scale) def get_global_weight_scale(self): - return 1024.0 + return float(2**5) @property def e_rev_E(self): diff --git a/spynnaker/pyNN/models/neuron/synapse_io/synapse_io_row_based.py b/spynnaker/pyNN/models/neuron/synapse_io/synapse_io_row_based.py index 6967334f779..55aef75a39f 100644 --- a/spynnaker/pyNN/models/neuron/synapse_io/synapse_io_row_based.py +++ b/spynnaker/pyNN/models/neuron/synapse_io/synapse_io_row_based.py @@ -18,6 +18,7 @@ from six import raise_from from spinn_utilities.overrides import overrides from spinn_front_end_common.utilities.constants import BYTES_PER_WORD +from spynnaker.pyNN.utilities.constants import MAX_SUPPORTED_DELAY_TICS from spynnaker.pyNN.models.neural_projections.connectors import ( AbstractConnector) from spynnaker.pyNN.exceptions import SynapseRowTooBigException @@ -42,7 +43,7 @@ class SynapseIORowBased(AbstractSynapseIO): @overrides(AbstractSynapseIO.get_maximum_delay_supported_in_ms) def get_maximum_delay_supported_in_ms(self, machine_time_step): # There are 16 slots, one per time step - return 16 * (machine_time_step / 1000.0) + return MAX_SUPPORTED_DELAY_TICS * (machine_time_step / 1000.0) @staticmethod def _n_words(n_bytes): diff --git a/spynnaker/pyNN/models/neuron/synaptic_manager.py b/spynnaker/pyNN/models/neuron/synaptic_manager.py index d8409637fd0..d0b3fb9e374 100644 --- a/spynnaker/pyNN/models/neuron/synaptic_manager.py +++ b/spynnaker/pyNN/models/neuron/synaptic_manager.py @@ -446,6 +446,7 @@ def _get_ring_buffer_to_input_left_shifts( weights_signed = False rate_stats = [RunningStats() for _ in range(n_synapse_types)] steps_per_second = 1000000.0 / machine_timestep + min_max_weight = numpy.ones(n_synapse_types) * 2 ** 32 for app_edge in application_graph.get_edges_ending_at_vertex( application_vertex): @@ -472,6 +473,8 @@ def _get_ring_buffer_to_input_left_shifts( weight_max = (synapse_dynamics.get_weight_maximum( connector, synapse_info.weight) * weight_scale) + min_max_weight[synapse_type] = \ + min(min_max_weight[synapse_type], weight_max) biggest_weight[synapse_type] = max( biggest_weight[synapse_type], weight_max) @@ -519,23 +522,29 @@ def _get_ring_buffer_to_input_left_shifts( total_weights[synapse_type]) max_weights[synapse_type] = max( max_weights[synapse_type], biggest_weight[synapse_type]) + # This is to deal with very small weights that are floored to 0 + mmw = 2**math.floor(math.log(min_max_weight[synapse_type], 2)) + print("max_weights[", synapse_type, "]", max_weights[synapse_type], + "mmw", mmw) + max_weights[synapse_type] = min(mmw * 2 ** 15, + max_weights[synapse_type]) + # Convert these to powers max_weight_powers = ( - 0 if w <= 0 else int(math.ceil(max(0, math.log(w, 2)))) + 0 if w <= 1 else int(math.ceil(max(0, math.log(w, 2)))) for w in max_weights) # If 2^max_weight_power equals the max weight, we have to add another # power, as range is 0 - (just under 2^max_weight_power)! max_weight_powers = ( - w + 1 if (2 ** w) <= a else w + w + 1 if (2 ** w) < a else w for w, a in zip(max_weight_powers, max_weights)) # If we have synapse dynamics that uses signed weights, # Add another bit of shift to prevent overflows if weights_signed: max_weight_powers = (m + 1 for m in max_weight_powers) - return list(max_weight_powers) @staticmethod @@ -565,7 +574,6 @@ def _write_padding( next_block_allowed_address = self.__poptable_type\ .get_next_allowed_address(next_block_start_address) if next_block_allowed_address != next_block_start_address: - # Pad out data file with the added alignment bytes: spec.comment("\nWriting population table required padding\n") spec.switch_write_focus(synaptic_matrix_region) From a73821e03285aab7397b8c4a7390ec5fee8d4ac2 Mon Sep 17 00:00:00 2001 From: Petrut Antoniu Bogdan Date: Thu, 31 Oct 2019 14:36:17 +0000 Subject: [PATCH 2/6] hardcoded right shift of 5 instead of 10 --- .../src/neuron/input_types/input_type_conductance.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/neural_modelling/src/neuron/input_types/input_type_conductance.h b/neural_modelling/src/neuron/input_types/input_type_conductance.h index 4d3577d6dee..59f9d16afb8 100644 --- a/neural_modelling/src/neuron/input_types/input_type_conductance.h +++ b/neural_modelling/src/neuron/input_types/input_type_conductance.h @@ -44,7 +44,7 @@ static inline input_t* input_type_get_input_value( input_t* value, input_type_pointer_t input_type, uint16_t num_receptors) { use(input_type); for (int i = 0; i < num_receptors; i++) { - value[i] = value[i] >> 10; + value[i] = value[i] >> 5; } return &value[0]; } From 7f130258d14c97e8202b22204669725f8a336276 Mon Sep 17 00:00:00 2001 From: Petrut Antoniu Bogdan Date: Wed, 6 Nov 2019 13:02:51 +0000 Subject: [PATCH 3/6] I should probably report weight scaling in a nicer way anyway --- spynnaker/pyNN/models/neuron/synaptic_manager.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/spynnaker/pyNN/models/neuron/synaptic_manager.py b/spynnaker/pyNN/models/neuron/synaptic_manager.py index d0b3fb9e374..9d281835c10 100644 --- a/spynnaker/pyNN/models/neuron/synaptic_manager.py +++ b/spynnaker/pyNN/models/neuron/synaptic_manager.py @@ -524,8 +524,6 @@ def _get_ring_buffer_to_input_left_shifts( max_weights[synapse_type], biggest_weight[synapse_type]) # This is to deal with very small weights that are floored to 0 mmw = 2**math.floor(math.log(min_max_weight[synapse_type], 2)) - print("max_weights[", synapse_type, "]", max_weights[synapse_type], - "mmw", mmw) max_weights[synapse_type] = min(mmw * 2 ** 15, max_weights[synapse_type]) From 91930158ec066ee6e9a64fbe71c6bcff0f7eb328 Mon Sep 17 00:00:00 2001 From: Petrut Antoniu Bogdan Date: Tue, 26 Nov 2019 10:47:19 +0000 Subject: [PATCH 4/6] syn_info.weight -> weights, better call for weight variance --- .../models/neural_projections/connectors/from_list_connector.py | 2 +- spynnaker/pyNN/models/neuron/synaptic_manager.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spynnaker/pyNN/models/neural_projections/connectors/from_list_connector.py b/spynnaker/pyNN/models/neural_projections/connectors/from_list_connector.py index 0b59b9c9335..ed8a88f65f6 100644 --- a/spynnaker/pyNN/models/neural_projections/connectors/from_list_connector.py +++ b/spynnaker/pyNN/models/neural_projections/connectors/from_list_connector.py @@ -196,7 +196,7 @@ def get_weight_mean(self, weights): def get_weight_maximum(self, synapse_info): # pylint: disable=too-many-arguments if self.__weights is None: - return numpy.amax(synapse_info.weights) + return self._get_weight_maximum(self.__weights, len(self.__conn_list)) else: return numpy.amax(numpy.abs(self.__weights)) diff --git a/spynnaker/pyNN/models/neuron/synaptic_manager.py b/spynnaker/pyNN/models/neuron/synaptic_manager.py index fec3e80edc8..6fb94380568 100644 --- a/spynnaker/pyNN/models/neuron/synaptic_manager.py +++ b/spynnaker/pyNN/models/neuron/synaptic_manager.py @@ -473,7 +473,7 @@ def _get_ring_buffer_to_input_left_shifts( 0.0, delay_variance, n_connections) weight_max = (synapse_dynamics.get_weight_maximum( - connector, synapse_info.weight) * weight_scale) + connector, synapse_info.weights) * weight_scale) min_max_weight[synapse_type] = \ min(min_max_weight[synapse_type], weight_max) From 15e5a0c929a697c323ea75abbb193ae594b90a27 Mon Sep 17 00:00:00 2001 From: Petrut Antoniu Bogdan Date: Tue, 26 Nov 2019 16:24:43 +0000 Subject: [PATCH 5/6] printing ring buffer left shifts --- spynnaker/pyNN/models/neuron/synaptic_manager.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spynnaker/pyNN/models/neuron/synaptic_manager.py b/spynnaker/pyNN/models/neuron/synaptic_manager.py index 6fb94380568..fdea10eb95b 100644 --- a/spynnaker/pyNN/models/neuron/synaptic_manager.py +++ b/spynnaker/pyNN/models/neuron/synaptic_manager.py @@ -529,7 +529,6 @@ def _get_ring_buffer_to_input_left_shifts( max_weights[synapse_type] = min(mmw * 2 ** 15, max_weights[synapse_type]) - # Convert these to powers max_weight_powers = ( 0 if w <= 1 else int(math.ceil(max(0, math.log(w, 2)))) @@ -545,6 +544,10 @@ def _get_ring_buffer_to_input_left_shifts( # Add another bit of shift to prevent overflows if weights_signed: max_weight_powers = (m + 1 for m in max_weight_powers) + print("=" * 60) + print("RB left shifts for {:20}".format(application_vertex.label), + "=", list(max_weight_powers)) + print("-" * 60) return list(max_weight_powers) @staticmethod From cc11b09a972534b5254bdcc0748a8b2253348893 Mon Sep 17 00:00:00 2001 From: Petrut Antoniu Bogdan Date: Tue, 26 Nov 2019 16:29:05 +0000 Subject: [PATCH 6/6] correctly interrogating a GENERATOR --- spynnaker/pyNN/models/neuron/synaptic_manager.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spynnaker/pyNN/models/neuron/synaptic_manager.py b/spynnaker/pyNN/models/neuron/synaptic_manager.py index fdea10eb95b..a3764a00012 100644 --- a/spynnaker/pyNN/models/neuron/synaptic_manager.py +++ b/spynnaker/pyNN/models/neuron/synaptic_manager.py @@ -544,11 +544,12 @@ def _get_ring_buffer_to_input_left_shifts( # Add another bit of shift to prevent overflows if weights_signed: max_weight_powers = (m + 1 for m in max_weight_powers) + rb_ls = list(max_weight_powers) print("=" * 60) print("RB left shifts for {:20}".format(application_vertex.label), - "=", list(max_weight_powers)) + "=", rb_ls) print("-" * 60) - return list(max_weight_powers) + return rb_ls @staticmethod def _get_weight_scale(ring_buffer_to_input_left_shift):