Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 26 additions & 27 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This repository contains the official implementation for the paper
The paper presents a solution to the well-known **weight transport problem** -- a long-standing problem in computational neuroscience and neuromorphic computing.
Many well-established learning algorithms from machine learning such as backpropagation require some form of weight symmetry, which effectively means that weight information has to be copied from one synapse to another -- an operation that violates locality in physical computing.

In our paper, we present **spike-based alignment learning (SAL)**, a missing peace for constructing purely local online learning rules for both the brain and brain-inspired spiking hardware.
In our paper, we present **spike-based alignment learning (SAL)**, a missing piece for constructing purely local online learning rules for both the brain and brain-inspired spiking hardware.

This repository contains the python code to reproduce the experiments presented in the paper.
We demonstrate the effectiveness of SAL in various families of models:
Expand All @@ -27,7 +27,7 @@ We demonstrate the effectiveness of SAL in various families of models:
- **Deep convolutional networks**: A standard image classification task serves as framework to benchmark SAL against other spiking and non-spiking weight symmetrization algorithms


## How to set-up and run the simluations
## How to set up and run the simulations

### Requirements and dependencies

Expand All @@ -44,35 +44,34 @@ The software is purely written in Python (>= 3.11) and requires the packages lis

Typical setup time: ca. 5 min

1. Clone the repo (`git clone https://github.com/unibe-cns/sal-code.git` or `git clone git@github.com:unibe-cns/sal-code.git`) or create your own fork if you want to contribute to the project.
2. Setup you local **python environment** using you favorite tool:
1. Clone the repo.
2. Set up your local **Python environment** using your favorite tool:
- The code is tested for python versions >= 3.11 only.
- Using **`venv`**: `python -m venv --system-site-packages <name_of_env>` and activate it: `source ./<name_of_env>/bin/activate`
- Or using **`conda`**: `conda create -n <name_of_env>` (it's recommended to add the python version: python=3.X) and activate it: `conda activate <name_of_env>`
3. Go to the repo `cd sal-code` and **install the dependencies**: `python -m pip install -r requirements.txt`
4. Register the ipykernel with `python -m ipykernel install --user --name sal`
(5. Install the **git pre-commit-hooks**: `pre-commit install.` This step is recommended if you want to contribute to the project).
6. Install the pip package for the STDD-calculator: `python -m pip install -e stdd_calculator`. This installs the package `stddc`.
7. Install the pip package for the spiking sampling network: `python -m pip install -e spiking_sampling_network`. This installs the package `neuralsampling`.
8. Install the pip package for the spiking microcircuits: `python -m pip install -e spiking_microcircuits`. This installs the package `microcircuits`.
9. Install the pip package for the symmnet deeplearning experiments: `python -m pip install -e symmnet`. This installs the package `symmnet`.
- Using **`venv`**: `python -m venv <name_of_env>` and activate it: `source ./<name_of_env>/bin/activate`
- Or using **`conda`**: `conda create -n <name_of_env> --no-default-packages` (it's recommended to add the python version: python=3.X) and activate it: `conda activate <name_of_env>`
3. **install the dependencies**: `python -m pip install -r requirements.txt`
4. Register the ipykernel with `python -m ipykernel install --user --name <name-of-env>`
5. Install the pip package for the STDD-calculator: `python -m pip install -e stdd_calculator`. This installs the package `stddc`.
6. Install the pip package for the spiking sampling network: `python -m pip install -e spiking_sampling_network`. This installs the package `neuralsampling`.
7. Install the pip package for the spiking microcircuits: `python -m pip install -e spiking_microcircuits`. This installs the package `microcircuits`.
8. Install the pip package for the SymmNet deep-learning experiments: `python -m pip install -e symmnet`. This installs the package `symmnet`.


### Run the simulations for the paper:

The scripts for executing the experiments are located in ´scripts´.
The scripts for executing the experiments are located in `scripts/`.

#### Figure 2
1. The spike-timing difference distributions (fig. 2c) are generated by the jupyter notebook `scripts/sal_principle/stdd.ipynb`.
2. The weight evolution of the two neuron system (fig. 2d) and the phase plane diagram (fig. 2e) is generated by the jupyter notebook `scripts/sal_principle/ppd.ipynb`.

#### Figure 4 and 5
A minimal working example for a simulation of a spiking sampling network is provided by `scripts/ssn/train_bm.py` and the corresponding parameter file `minimnal_working_example.yaml`. It can be executed by `python train_bm.py minimal_working_example.yaml`; the results are stored in `results/minimal_working_example/`
A minimal working example for a simulation of a spiking sampling network is provided by `scripts/ssn/train_bm.py` and the corresponding parameter file `minimal_working_example.yaml`. It can be executed by `python train_bm.py minimal_working_example.yaml`; the results are stored in `results/minimal_working_example/`

To reproduce the raw data for figure 4 and 5, the scripts and directories in `scripts/ssn` are available. A single simulation can be executed on a single CPU core and typically takes 30 minutes. For each of the six experiment types (i.e. synaptic noise and plasticity noise scenario each with and without SAL and Kolen-Pollack), a total of 120 independent runs are required. We therefore recommend the simulations to be run in parallel on a HPC cluster. The raw data is then saved in the folder `results`.

Each subdirectory of `scripts/ssn/` contains a `exp.yaml` parameter file and a `change_params.py` python script.
1. Run `bash run.sh` to start the simulations. It will first call `change_paramters.py` and then spawn the simulations.
1. Run `bash run.sh` to start the simulations. It will first call `change_parameters.py` and then spawn the simulations.
2. The raw data can be plotted with `scripts/ssn/plot_fig.ipynb`.

#### Figure 6
Expand All @@ -81,7 +80,7 @@ A minimal working example for a simulation of a spiking microcircuits student te

To reproduce the raw data for figure 6, follow the same steps as for the sampling networks.

1. In each subdirectory of `scripts/microcircuits`, (i.e. `bp` for backpropagation, `fa` for feedback alignment and `sal` for SAL), execute `run.sh`. This will create the paramter yaml files for 20 runs with individual seeds and then spawn 20 parallel processes with the simulations. A simulation takes ca four hours to finish.
1. In each subdirectory of `scripts/microcircuits` (i.e. `bp` for backpropagation, `fa` for feedback alignment, `sal` for SAL), execute `run.sh`. This creates the parameter YAML files for 20 runs with individual seeds and spawns 20 parallel processes. A single simulation takes ca. 4 hours to finish.
The raw simulation results are stored in `results/microcircuits`.
2. The raw data can be plotted with `scripts/microcircuits/plot_fig.ipynb`.

Expand All @@ -91,41 +90,41 @@ To reproduce the data and plots for figure 7 (i.e., the weight scatter plots com

#### Figure 8

A minimal working example for the deep learning experiment is provided by `scripts/symm_net/main_salnet.py` and the corresponding parameter file `exp_setting.yaml`.
A minimal working example for the deep learning experiment is provided by `scripts/symm_net/main_salnet.py` and the corresponding parameter file `exp_settings.yaml`.
As forward training of the convolutional neural networks is implemented in pytorch, we highly recommend to use a GPU.

Usage: `python main_salnet.py -f exp_setting.yaml -s <type_of_experiment> --dataset <dataset> --tags <tag1,tag2>`
Usage: `python main_salnet.py -f exp_settings.yaml -s <type_of_experiment> --dataset <dataset> --tags <tag1,tag2>`

- `type_of_experiment`: choose the learning algorithm (equivalent to the section names in `exp_setting.yaml`)
- `type_of_experiment`: choose the learning algorithm (equivalent to the section names in `exp_settings.yaml`)
- `dataset`: choose one the following datasets: `cifar10`, `svhn`, `mnist`, `fmnist`
- optionally, you can pass a list of descriptive tags to keep tack of your runs.
- optionally, you can pass a list of descriptive tags to keep track of your runs.

The typical execution time of `main_salnet.py` amounts to ca. 15 minutes for the training modes that do not involve a spiking neural network, in SAL-mode ca 30-45 minutes and in RDD-mode ca. 2 hours.
Typical execution time per run: ~15 min (BP/FA/KP), ~30–45 min (SAL), ~2 h (RDD).

For conveniently reproducing any of the data shown in figure 8, we provide two workflows:
- `sweep.py`: suitable for small scale parameter sweeps. It directly launcher the required sub-processes. Example usage: `python sweep.py --datasets cifar10 --algos bp fa sal`.
- `sweep.py`: suitable for small-scale parameter sweeps. It directly launches the required sub-processes. Example usage: `python sweep.py --datasets cifar10 --algos bp fa sal`.
See `python sweep.py --help` for all available settings.
- For large scale parameter sweeps (for instance to reproduce the 105 runs for all datasets, algorithms and seeds) on an HPC cluster (with SLURM), we provided the following workflow that needs only minimal adaptation to the available system.
1. Run `sweep_creator.py`: It creates `jobs.sh` which contains all `main_salnet.py`-calls with the relevant settings.
See `python sweep_creator.py --help` for all available settings (the default settings will rerun the original simulations).
2. Modify `slurm.sh` to specify the relevant settings for your HPC cluster.
3. Run `bash slurm_submit.sh`. It will call `slurm.sh` internally and start a slurm array job.
3. Run `bash slurm_submit.sh`. It will call `slurm.sh` internally and start a SLURM array job.
4. The data can be plotted with `scripts/symm_net/plots.ipynb`
#### Figure 9

A minimal working example for the time evolution of SAL in the SALNet is provided by `scripts/symm_net/salnet_symm.py`.

Example Usage: `python salnet_symm.py --lr 0.01 --n_epochs 200 --len_epoch 500`.
Example usage: `python salnet_symm.py --lr 0.01 --n_epochs 200 --len_epoch 500`.

For conveniently reproducing the data shown in figure 9, we provide the same workflows as explained above with the files `sweep_symm.py` for quick small scale scans and `sweep_creator_symm.py` to launch all 20 runs as a slurm array job.
For conveniently reproducing the data shown in figure 9, we provide the same workflows as explained above with the files `sweep_symm.py` for quick small-scale scans and `sweep_creator_symm.py` to launch all 20 runs as a SLURM array job.

#### Figure 10

The "Dale's law" experiment can be reproduced by `scripts/dales_law/EI-system.ipynb`.

#### Figure 11

The data for figure 11 can be reproached by `scripts/psp_shapes.ipynb`. Note that this notebook typically requires a lot of memory (> 8GB).
The data for figure 11 can be reproduced by `scripts/psp_shapes.ipynb`. Note that this notebook typically requires a lot of memory (> 8GB).

#### Figure 12

Expand Down
88 changes: 4 additions & 84 deletions scripts/sal_principle/ppd.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,7 @@
{
"cell_type": "markdown",
"id": "6",
"metadata": {
"jp-MarkdownHeadingCollapsed": true
},
"metadata": {},
"source": [
"## Plot the weight evolution of weight symmetrization (fig. 2d)\n",
"\n",
Expand Down Expand Up @@ -247,32 +245,6 @@
"cell_type": "code",
"execution_count": null,
"id": "12",
"metadata": {
"jupyter": {
"source_hidden": true
}
},
"outputs": [],
"source": [
"def exp_kernel_2(dt, a_plus, a_minus, tau_plus, tau_minus):\n",
" \"\"\"Exponential STDP window for SAL.\"\"\"\n",
" # DELETE\n",
" if dt > 0.0:\n",
" return a_plus * np.exp(-dt / tau_plus)\n",
" elif dt < 0.0:\n",
" return a_minus * np.exp(dt / tau_minus)\n",
" else:\n",
" return 0.0\n",
"\n",
"\n",
"# DELETE\n",
"vexp_kernel = np.vectorize(exp_kernel_2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "13",
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -327,40 +299,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "14",
"metadata": {
"jupyter": {
"source_hidden": true
}
},
"outputs": [],
"source": [
"# create the stdds on a grid:\n",
"\n",
"TREF = 25\n",
"TMAX = 2 * TREF\n",
"\n",
"w_range = np.arange(-2, 2.1, 0.25)\n",
"n_range = len(w_range)\n",
"\n",
"\n",
"if RUNSIMULATION:\n",
" stdd_grid = np.empty((n_range, n_range, 2 * TMAX - 1))\n",
" for i, j in product(range(n_range), range(n_range)):\n",
" print(\"W_12 = \", w_range[i], \", W_21 = \", w_range[j])\n",
" stdd = calc_dt_distr(\n",
" rect_PSP, TREF, TMAX, w_range[i], w_range[j], 0.0, 0.0, TREF\n",
" )\n",
" stdd_grid[i, j] = stdd\n",
" np.save(DATA_DIR / \"stdd_grid\", stdd_grid)\n",
"else:\n",
" stdd_grid = np.load(DATA_DIR / \"stdd_grid.npy\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "15",
"id": "13",
"metadata": {},
"outputs": [],
"source": [
Expand All @@ -384,26 +323,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "16",
"metadata": {
"jupyter": {
"source_hidden": true
}
},
"outputs": [],
"source": [
"# apply the sal-rule\n",
"ts = np.arange(-TMAX + 1, TMAX, dtype=float)\n",
"stdp_kernel = vexp_kernel(ts, -1.0, 1.0, TREF, TREF)\n",
"\n",
"sal_12 = np.sum(stdd_grid * stdp_kernel[None, None, :], axis=2)\n",
"sal_21 = np.sum(stdd_grid * stdp_kernel[None, None, ::-1], axis=2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "17",
"id": "14",
"metadata": {},
"outputs": [],
"source": [
Expand Down Expand Up @@ -440,7 +360,7 @@
{
"cell_type": "code",
"execution_count": null,
"id": "18",
"id": "15",
"metadata": {},
"outputs": [],
"source": []
Expand Down
Loading