Skip to content

Commit

Permalink
Merge pull request #43 from Saran-nns/research
Browse files Browse the repository at this point in the history
callbacks and broadcast ops added, cpu intensive async ops removed
  • Loading branch information
Saran-nns authored Dec 27, 2021
2 parents 09fd16b + ecc3198 commit c2af66c
Show file tree
Hide file tree
Showing 11 changed files with 647 additions and 521 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: [3.5, 3.6, 3.7, 3.8, 3.9]
python-version: [3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v2
- name: Build using Python ${{ matrix.python-version }}
Expand Down
10 changes: 7 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@ __pycache__/
build/
dist/
sorn.egg-info/


# Logs
sorn/*.log
*.log

### VisualStudioCode ###
.vscode/*
!.vscode/tasks.json
!.vscode/launch.json
.vscode/tasks.json
.vscode/launch.json
*.code-workspace

### VisualStudioCode Patch ###
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# set base image (host OS)
# set base image
FROM python:3.8

# set the working directory in the scontainer
Expand Down
41 changes: 31 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pip install git+https://github.com/Saran-nns/sorn
```

## Dependencies
SORN supports Python 3.5+ ONLY. For older Python versions please use the official Python client.
SORN supports `Python 3.7+` ONLY. For older Python versions please use the official Python client.
To install all optional dependencies,

```python
Expand All @@ -53,9 +53,12 @@ time_steps = 200
inputs = np.random.rand(num_features,time_steps)

# Simulate the network with default hyperparameters under gaussian white noise
state_dict, E, I, R, C = Simulator.simulate_sorn(inputs = inputs, phase='plasticity',
state_dict, sim_dict = Simulator.simulate_sorn(inputs = inputs, phase='plasticity',
matrices=None, noise = True,
time_steps=time_steps)
time_steps=time_steps,
callbacks = ["ExcitatoryActivation",
"WEE",
"EEConnectionCounts"])

```
```
Expand All @@ -71,22 +74,40 @@ from sorn import Trainer
inputs = np.random.rand(num_features,1)

# SORN network is frozen during training phase
state_dict, E, I, R, C = Trainer.train_sorn(inputs = inputs, phase='training',
state_dict, sim_dict = Trainer.train_sorn(inputs = inputs, phase='training',
matrices=state_dict, noise= False,
time_steps=1,
ne = 100, nu=num_features,
lambda_ee = 10, eta_stdp=0.001 )
lambda_ee = 10, eta_stdp=0.001,
callbacks = ["InhibitoryActivation",
"WEI",
"EIConnectionCounts"] )
```
### Network Output Descriptions
`state_dict` - Dictionary of connection weights (`Wee`,`Wei`,`Wie`) , Excitatory network activity (`X`), Inhibitory network activities(`Y`), Threshold values (`Te`,`Ti`)
`state_dict` - Dictionary of connection weights (`Wee`, `Wei`, `Wie`) , Excitatory network activity (`X`), Inhibitory network activities(`Y`), Threshold values (`Te`, `Ti`)

`E` - Excitatory network activity of entire simulation period
`sim_dict` - Dictionary of network states and parameters collected during the simulation/training: Provided, all available options of the argument `callbacks`, then the `sim_dict` should contain the following;

`I` - Inhibitory network activity of entire simulation period
"ExcitatoryActivation" - Excitatory network activity of entire simulation period

`R` - Recurrent network activity of entire simulation period
"InhibitoryActivation" - Inhibitory network activity of entire simulation period

"RecurrentActivation" - Recurrent network activity of entire simulation period

"EEConnectionCounts" - Number of active connections in the Excitatory pool at each time step

"EIConnectionCounts" - Number of active connections from Inhibitory to Excitatory pool at each time step

"TE" - Threshold values of excitatory neurons at each time step

"TI" - Threshold values of inhibitory neurons at each time step

"WEE" - Synaptic efficacies between excitatory neurons

"WEI" - Connection weights from inhibitory to excitatory neurons

"WIE" - Connection weights from excitatory to inhibitory neurons

`C` - Number of active connections in the Excitatory pool at each time step

### Documentation
For detailed documentation about development, analysis, plotting methods and a sample experiment with OpenAI Gym, please visit [SORN Documentation](https://self-organizing-recurrent-neural-networks.readthedocs.io/en/latest/)
Expand Down
18 changes: 13 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
# Used for the long_description. It's nice, because now 1) we have a top level
# README file and 2) it's easier to type in the README file than to put a raw
# string in below ...


def read(fname):
return open(os.path.join(os.path.dirname(__file__), fname)).read()


setup(
name="sorn",
version="0.6.2",
version="0.7.3",
author="Saranraj Nambusubramaniyan",
author_email="saran_nns@hotmail.com",
description="Self-Organizing Recurrent Neural Networks",
Expand All @@ -27,13 +30,18 @@ def read(fname):
"Topic :: Scientific/Engineering :: Artificial Intelligence",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.5",
"Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
],
include_package_data=True,
install_requires=["numpy", "configparser", "scipy", "seaborn", "pandas", "networkx"],
install_requires=[
"numpy",
"configparser",
"scipy",
"seaborn",
"pandas",
"networkx",
],
zip_safe=False,
)

2 changes: 1 addition & 1 deletion sorn/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
from .utils import *

__author__ = "Saranraj Nambusubramaniyan"
__version__ = "0.6.2"
__version__ = "0.7.3"

logging.basicConfig(level=logging.INFO)
204 changes: 204 additions & 0 deletions sorn/callbacks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
class Callbacks:
def __init__(self, timesteps, avail_callbacks, *argv):
self.timesteps = timesteps
self.argv = argv
if argv:
self.dispatcher = Validate().callbacks(argv, avail_callbacks)

self.callbacks = []
for class_name in list(self.dispatcher.keys()):
instance = self.create(class_name)
self.dispatcher[class_name] = instance

def create(self, class_name) -> object:
instance = globals()[class_name](self.timesteps)
return instance

def update(self, func, value, timestep):
try:
func[timestep] = value
except:
return f"Invalid callback instance {func}"

def step(self, state, time_step) -> None:

for callback in list(self.dispatcher.keys()):
self.update(self.dispatcher[callback], state[callback], time_step)

def get(self) -> dict:

if self.argv:
for name, callback in self.dispatcher.items():
self.dispatcher[name] = callback.values
return self.dispatcher

else:
return {}


class Validate:
def __init__(self):
pass

def callbacks(self, req_callbacks, avail_callbacks):

self.argv = req_callbacks
self.avail_callbacks = list(avail_callbacks.keys())

if self.argv:
return self.assert_callbacks()

else:
return None

def assert_callbacks(self) -> dict:

if not set(*self.argv) == set(self.avail_callbacks):
assert set(*self.argv).issubset(
set(self.avail_callbacks)
), f"{list(set(*self.argv)-set(self.avail_callbacks))} not available"

return dict.fromkeys(set(*self.argv) & set(self.avail_callbacks))

else:
return dict.fromkeys(self.avail_callbacks)


class ExcitatoryActivation:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Excitatory network state at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class InhibitoryActivation:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Inhibitory network state at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class RecurrentActivation:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Recurrent network state at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class WEE:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Excitatory to Excitatory Connection strength at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class WEI:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Inhibitory to Excitatory Connection strength at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class TE:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Excitatory neurons firing threshold values at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class TI:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Inhibitory neurons firing threshold values at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class EEConnectionCounts:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Number active connections in the Excitatory pool at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class EIConnectionCounts:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Number active connections from Inhibitory to Excitatory pool at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)


class IEConnectionCounts:
def __init__(self, timesteps=0):
self.values = [0] * timesteps

def __setitem__(self, index, value):
self.values[index] = value

def __getitem__(self, index):
return f"Number active connections from Excitatory to Inhibitory pool at time_step {index}: {self.values[index]}"

def __str__(self):
return str(self.values)
Loading

0 comments on commit c2af66c

Please sign in to comment.