Skip to content

GenevieveF/Self-Normalizing_STDP_Rule_Brian2

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 

Repository files navigation

Self-Normalizing STDP learning rule in Brian 2

An implementation of the Self-Normalizing Spike-Timing-Dependent Plasticity (STDP) learning rule in Brian 2. This supports both SMAX and SMIN rule variants.

Original Paper: Genevieve C. Fahey, Samuel J. Ippolito, and Glenn I. Matthews, 'A linear self-normalizing spike-timing-dependent plasticity rule for online learning in spiking neural networks', Neurocomputing, 2026. DOI: https://doi.org/10.1016/j.neucom.2026.133419

This is NOT the code used to produce the results in the original paper. It is instead supplied as an example implementation for use with Brian 2 using the updated SNN experiment code from Diehl & Cook (DOI: https://doi.org/10.3389/fncom.2015.00099). The code used to produce the published results uses the SwiftSpike simulation framework which is not yet available on Github.

Self-Normalizing STDP Learning Rule

The Self-Normalizing STDP rule allows individual synapses to update their weights in such a way that the $L^1$ norm of each weight vector $\vec{w}$ converges towards a specified target value $L_{tar} = a_{tar} \times n$ where $a_{tar}$ is the target weight mean and $n$ is the number of elements in the weight vector.

The Self-Normalizing STDP rule updates all weights on each post-synaptic spike event and is given by:

$$\Delta w_{i,post} = \begin{cases} \eta(s_{max} - w_i), & \quad x_{pre} \geq x_{tar} \\\ -\eta(w_i - s_{min}), & \quad x_{pre} < x_{tar} \end{cases}$$

where $w_i$ is the current weight of the $i^{th}$ synapse, $\eta$ is the learning rate, $x_{pre}$ is the synaptic trace variable, $x_{tar}$ is the synaptic trace target, and $s_{max}$ and $s_{min}$ are the scaling maximum and minimum weight terms respectively.

$x_{pre}$ is set to 1 at a pre-synaptic spike event and decays towards 0 by $\tau_{xpre} \frac{dx_{pre}}{dt} = -x_{pre}$ where $\tau_{xpre}$ is the time constant. It is compared against $x_{tar}$ to determine whether Long-Term Potentiation (LTP) or Long-Term Depression (LTD) will occur at the next post-synaptic spike event. Note that $x_{pre}$ and $x_{tar}$ can be replaced by time stamp comparisons to produce a completely linear set of equations. The synaptic trace method is used here for consistency with the original comparisons carried out in the paper.

When a post-synaptic spike occurs, all synapses update their weights and the $L^{0}$ norm of positive weight changes ($L_0$) are tallied by the post-synaptic neuron. This is effectively a simple counter. The scaling weight terms are then updated by:

$$s_{max} = L_{tar} / L_0 $$ $$s_{min} = -L_{tar} / (n - L_0)$$

The 'SMAX' variant of the Self-Normalizing STDP rule is used for weight vectors containing only non-negative values. In this instance, $s_{min} is always set to 0. The $L^1$ norm of the weight vectors will converge towards $L_{tar}$. The weight vectors will be able to learn new features while approximately maintaining the target norm.

The 'SMIN' variant is used for weight vectors containing both negative and positive weight values and calculates $s_{min}$ as given above. The mean weight of the vectors will converge towards 0, balancing the sum of positive and negative values. Weights will be able to move between the positive and negative domains based on the feature being learnt by the neuron. This vastly improves tolerance to noise during inference (see paper for more details).

The Self-Normalizing STDP rule is intended for neuromorphic hardware where divisive weight normalization methods are difficult to implement. The self-normalizing aspect of our method (that of calculating and updating the scaling maximum and minimum terms) has O(1) space complexity compared to the O(n) space complexity of divisive weight normalization, improving its viability on systems with memory-access constraints.

Additional Implementation Notes

During simulation, it was observed that if the inhibitory conductance $g_i$ of the conductance-based Leaky Integrate-and-Fire (LIF) neurons became very high, then the succeeding update to the neuron voltage could produce a sign-flip where the voltage would suddenly jump to a high positive value. This would cause the neuron to fire even in the absence of excitatory input. If many of these 'misfires' occurred at the same time, then the resulting inhibitory signals could cause the entire network to enter a seizure-like activity pattern where all neurons would repeatedly fire as soon as they left their refractory periods. To prevent this, $g_i$ has been clipped by $g_{i,max}$. This additionally prevents most instances where a post-synaptic update may occur where $L_0 = 0$ resulting by a division by zero error in the $s_{max}$ equations.

Setup

This code expands on the repository for the updated Diehl & Cook experiment here: https://github.com/GenevieveF/Diehl-Cook_2015_Brian2.

It also requires Python 3, Brian 2, and the MNIST dataset.

Installation instructions and directions for use are included in full in the readme of the linked repository. Please follow the instructions to install the required packages, then add the 'Self-Normalizing_STDP_Rule_B2.py' file alongside the python files. Run 'Self-Normalizing_STDP_Rule_B2.py' in place of 'Diehl&Cook_spiking_MNIST_B2.py'.

Installation instructions for Brain 2 can be found here: https://briansimulator.org/

The MNIST dataset can be found here: http://yann.lecun.com/exdb/mnist/

Instructions for Use

For training a network:

  1. Set test_mode = False on line 205 in 'Self-Normalizing_STDP_Rule_B2.py'.
  2. Set save_name to your preferred filename suffix for the saved weights and theta values. These will be saved to the 'weights/' folder.
  3. Run the code.

For testing a network:

  1. Set test_mode = True on line 205 in 'Self-Normalizing_STDP_Rule_B2.py'.
  2. Set load_name = save_name to use your trained weights. Set load_name = '' to run a test using the pre-trained weights from the original repository.
  3. Run the code.
  4. Result files for classification will be saved in the 'activity/' folder with num_examples as a suffix. Be sure to back them up somewhere safe if you do not wish for these to be over-written every time a new simulation is performed.

For evaluating a network's classification performance:

  1. In 'Diehl&Cook_MNIST_evaluation_B2.py' set training_ending = 'x' and testing_ending = 'y' where x is the number of examples used during training and y is the number of examples used during testing of the network. The defaults are x = '60000' and y = '10000'.
  2. Run the code.

FAQ

  • How can I run this for networks with a different number of neurons?
    Change n_e on line 241 to your desired number of neurons. Uncomment line 402 and comment out lines 404 and 405. This will force the code to generate random weights to initialise the network rather than load the pre-generated 400 weights from a file.

  • The simulation is very slow on my computer, how can I make it faster?
    Consider changing the default clock step size for the simulation. This will have an effect on the precision of the numerical integration calculations but for values near the default will still produce similar accuracy results. More information on the default clock can be found in the Brian 2 documentation: https://brian2.readthedocs.io/en/stable/user/running.html

Observations

The original normalize_weights() function can produce a division by zero error if this code is used to run other network experiments.

The simulation code may take many hours to run. Consider running for a smaller value of num_examples first to verify that it is working for you.

The neuron reset equation that updates the s_max and s_min variables throws a cython division by zero error at the beginning of the simulation if cython is set as the preferred codegen target. As a temporary workaround, the L_0 variable may be first incremented so that it is always non-zero or a different codegen target used.

About

Spiking Neural Network implementation of the Self-Normalizing STDP rule trained unsupervised on MNIST in Brian 2 using the code structure from Diehl & Cook 2015

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages