Part of Neural Network Notebook (3nb).
Copyright (C) 2014 by Eka A. Kurniawan
eka.a.kurniawan(ta)gmail(tod)com
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Done:
MacBook Pro Retina, Mid 2012 with OS X 10.9.1 (Mavericks)
Python version:
In [1]:
import sys
print("Python %d.%d.%d" % (sys.version_info.major, \
sys.version_info.minor, \
sys.version_info.micro))
NumPy version:
In [2]:
import numpy as np
print("NumPy %s" % np.__version__)
matplotlib version:
In [3]:
import matplotlib
import matplotlib.pyplot as plt
print("matplotlib %s" % matplotlib.__version__)
To run this IPython Notebook; open a console, go to notebook directory and execute following command.
ipython3-3.3 notebook --pylab inline
Settings required:
In [4]:
# Display graph in 'retina' format for Mac with retina display. Others, use PNG or SVG format.
%config InlineBackend.figure_format = 'retina'
#%config InlineBackend.figure_format = 'PNG'
#%config InlineBackend.figure_format = 'SVG'
Other imports:
In [5]:
import time
from random import randint
import os.path
Functions to save/load array to/from file.
In [6]:
def save_list(file_name, list_name):
with open(file_name, 'w') as fh:
fh.write("\n".join(list_name))
def load_list(file_name):
with open(file_name, 'r') as fh:
return [line.strip() for line in fh.readlines()]
Function to print event buffer with the current index location (marked with >>>).
In [7]:
# Print event in array of integers
def print_event_ie(cur_event_idx = None, events = [[]]):
for event_id, event in enumerate(events):
if event_id == cur_event_idx:
print(">>> %s" % event)
else:
print(" %s" % event)
# Print event in array of binaries
def print_event_be(events = []):
for event in events:
print('{0:011b}'.format(event))
The implementation is taken from CSIM: A neural Circuit SIMulator website and modified accordingly.[1]
In [8]:
# incoming_synapses: incoming synapses ID
# outgoing_synapses: outgoing synapses ID
class Neuron:
def __init__(self,
incoming_synapses = [],
outgoing_synapses = []):
self.incoming_synapses = incoming_synapses
self.outgoing_synapses = outgoing_synapses
# Spiking input neuron class with synaptic delay using integer event (ie).
# Spiking input neuron has no incoming synapses as the channel attached
# to the neuron provides all input spikes.
# outgoing_delays: array of outgoing synaptic delays connected to
# this particular neuron in time step
# channel: None ternimated array of simulation time when spikes happen
class SpikingInputNeuron_SynapticDelay_ie(Neuron):
def __init__(self,
outgoing_synapses = [],
outgoing_delays = [],
channel = []):
Neuron.__init__(self, [], outgoing_synapses)
self.outgoing_delays = outgoing_delays
self.channel = channel
self.nextSpikeTime = channel[0]
# Current channel index
self.cur_idx = 0
self.hasFired = 0
# Get next value from channel
def nextValue(self, t):
self.hasFired = 0
if self.nextSpikeTime == None:
return
if self.nextSpikeTime < t:
self.hasFired = 1
self.cur_idx += 1
self.nextSpikeTime = channel[self.cur_idx]
# Handle synaptic delay and update event buffer
def propagateSpike(self, cur_event_idx, ldelayList, outgoing_events):
for outgoing_synapse in self.outgoing_synapses:
delay = self.outgoing_delays[outgoing_synapse]
new_event_idx = cur_event_idx + delay
if new_event_idx >= ldelayList:
new_event_idx -= ldelayList
outgoing_events[new_event_idx][outgoing_synapse] = 1
# Function that consists of all processes to be run every iteration
def nextState(self, t, cur_event_idx, ldelayList, outgoing_events):
self.nextValue(t)
if self.hasFired:
self.propagateSpike(cur_event_idx, ldelayList, outgoing_events)
# Spiking input neuron class with synaptic delay using binary event (be).
# Spiking input neuron has no incoming synapses as the channel attached
# to the neuron provides all input spikes.
# outgoing_delays: array of outgoing synaptic delays connected to
# this particular neuron in bit location of time step
# channel: None ternimated array of simulation time when spikes happen
class SpikingInputNeuron_SynapticDelay_be(Neuron):
def __init__(self,
outgoing_synapses = [],
outgoing_delays = [],
channel = []):
Neuron.__init__(self, [], outgoing_synapses)
self.outgoing_delays = outgoing_delays
self.channel = channel
self.nextSpikeTime = channel[0]
# Current channel index
self.cur_idx = 0
self.hasFired = 0
# Get next value from channel
def nextValue(self, t):
self.hasFired = 0
if self.nextSpikeTime == None:
return
if self.nextSpikeTime < t:
self.hasFired = 1
self.cur_idx += 1
self.nextSpikeTime = channel[self.cur_idx]
# Handle synaptic delay and update event buffer
def propagateSpike(self, outgoing_events):
for outgoing_synapse in self.outgoing_synapses:
delay = self.outgoing_delays[outgoing_synapse]
outgoing_events[outgoing_synapse] += delay
# Function that consists of all processes to be run every iteration
def nextState(self, t, outgoing_events):
self.nextValue(t)
if self.hasFired:
self.propagateSpike(outgoing_events)
Test spiking input neuron using integer event with input spike at 0.801 millisecond.
In [9]:
dt = 2e-4
Tsim = 30e-4
ttl_synapse = 10
# Outgoing synapse IDs
outgoing_synapses = [1,3,7]
# Outgoing delay (in time step)
outgoing_delays = [0,2,0,10,0,0,0,5,0,0]
# Get maximum outgoing delay to alocate the most optimized event buffer
ldelayList = np.max(outgoing_delays) + 1
# 2D array of outgoing events connected to this particular neuron in integer
outgoing_events = [ttl_synapse * [0] for i in range(ldelayList)]
# Input channel
channel = [8.01e-4, None]
# Construct a spiking input neuron
n1 = SpikingInputNeuron_SynapticDelay_ie(outgoing_synapses, \
outgoing_delays, \
channel)
t = 0.0
nSteps = int((Tsim / dt) + 0.5)
cur_event_idx = 0
for step in range(nSteps):
t += dt
n1.nextState(t, cur_event_idx, ldelayList, outgoing_events)
if int(channel[0] / dt) == step:
print_event_ie(cur_event_idx, outgoing_events)
cur_event_idx += 1
if (cur_event_idx >= ldelayList):
cur_event_idx = 0
Test spiking input neuron using integer event with input spike at 1.601 milliseconds.
In [10]:
dt = 2e-4
Tsim = 30e-4
ttl_synapse = 10
# Outgoing synapse IDs
outgoing_synapses = [1,3,7]
# Outgoing delay (in time step)
outgoing_delays = [0,2,0,10,0,0,0,5,0,0]
# Get maximum outgoing delay to alocate the most optimized event buffer
ldelayList = np.max(outgoing_delays) + 1
# 2D array of outgoing events connected to this particular neuron in integer
outgoing_events = [ttl_synapse * [0] for i in range(ldelayList)]
# Input channel
channel = [16.01e-4, None]
# Construct a spiking input neuron
n1 = SpikingInputNeuron_SynapticDelay_ie(outgoing_synapses, \
outgoing_delays, \
channel)
t = 0.0
nSteps = int((Tsim / dt) + 0.5)
cur_event_idx = 0
for step in range(nSteps):
t += dt
n1.nextState(t, cur_event_idx, ldelayList, outgoing_events)
if int((channel[0] / dt) + 0.5) == step:
print_event_ie(cur_event_idx, outgoing_events)
cur_event_idx += 1
if (cur_event_idx >= ldelayList):
cur_event_idx = 0
Test spiking input neuron using integer event with input spike at 2.601 milliseconds.
In [11]:
dt = 2e-4
Tsim = 30e-4
ttl_synapse = 10
# Outgoing synapse IDs
outgoing_synapses = [1,3,7]
# Outgoing delay (in time step)
outgoing_delays = [0,2,0,10,0,0,0,5,0,0]
# Get maximum outgoing delay to alocate the most optimized event buffer
ldelayList = np.max(outgoing_delays) + 1
# 2D array of outgoing events connected to this particular neuron in integer
outgoing_events = [ttl_synapse * [0] for i in range(ldelayList)]
# Input channel
channel = [26.01e-4, None]
# Construct a spiking input neuron
n1 = SpikingInputNeuron_SynapticDelay_ie(outgoing_synapses, \
outgoing_delays, \
channel)
t = 0.0
nSteps = int((Tsim / dt) + 0.5)
cur_event_idx = 0
for step in range(nSteps):
t += dt
n1.nextState(t, cur_event_idx, ldelayList, outgoing_events)
if int(channel[0] / dt) == step:
print_event_ie(cur_event_idx, outgoing_events)
cur_event_idx += 1
if (cur_event_idx >= ldelayList):
cur_event_idx = 0
Test spiking input neuron using binary event with input spike at 2.601 milliseconds.
In [12]:
dt = 2e-4
Tsim = 30e-4
ttl_synapse = 10
# Outgoing synapse IDs
outgoing_synapses = [1,3,7]
# Outgoing delay (in time step)
outgoing_delays_ie = [0,2,0,10,0,0,0,5,0,0]
# Outgoing delay (in binary location)
outgoing_delays_be = [2 ** delay for delay in outgoing_delays_ie]
# Get maximum outgoing delay is not allowed to be greather than 31
# for 32-bit integer data type
ldelayList = np.max(outgoing_delays_ie) + 1
if ldelayList > 31:
print("WARNING: Maximum outgoing delay is %s time step(s)" % ldelayList)
print(" It is not allowed to be greather than 31 for 32-bit integer data type")
# array of outgoing events connected to this particular neuron in
# integer of binary
outgoing_events = np.array([0 for i in range(ttl_synapse)])
# Input channel
channel = [26.01e-4, None]
# Construct a spiking input neuron
n1 = SpikingInputNeuron_SynapticDelay_be(outgoing_synapses, \
outgoing_delays_be, \
channel)
t = 0.0
nSteps = int((Tsim / dt) + 0.5)
for step in range(nSteps):
t += dt
n1.nextState(t, outgoing_events)
if int(channel[0] / dt) == step:
print_event_be(outgoing_events)
# Shift outgoing event one to right
outgoing_events = outgoing_events >> 1
In [13]:
def run_seq_ie(nSteps, ldelayList, \
outgoing_synapses, outgoing_delays, outgoing_events, \
channel, \
plot = False):
# Buffer allocation time is not applicable for sequential implementation
bat = np.nan
# Construct a spiking input neuron
n1 = SpikingInputNeuron_SynapticDelay_ie(outgoing_synapses, \
outgoing_delays, \
channel)
t = 0.0
cur_event_idx = 0
tic = time.time()
for step in range(nSteps):
t += dt
n1.nextState(t, cur_event_idx, ldelayList, outgoing_events)
cur_event_idx += 1
if (cur_event_idx >= ldelayList):
cur_event_idx = 0
toc = time.time()
# Run time
rt = toc - tic
# Total time
tt = rt
if plot:
print_event_ie(None, outgoing_events)
return bat, rt, tt
Test spiking input neuron with input spike at 2.601 milliseconds.
In [14]:
dt = 2e-4
Tsim = 0.3
ttl_synapse = 10
# Outgoing synapse IDs
outgoing_synapses = [1,3,7]
# Outgoing delay (in time step)
outgoing_delays = [0,2,0,10,0,0,0,5,0,0]
# Get maximum outgoing delay to alocate the most optimized event buffer
ldelayList = np.max(outgoing_delays) + 1
# 2D array of outgoing events connected to this particular neuron in integer
outgoing_events = [ttl_synapse * [0] for i in range(ldelayList)]
# Input channel
channel = [26.01e-4, None]
nSteps = int((Tsim / dt) + 0.5)
seq_t = run_seq_ie(nSteps, ldelayList, \
outgoing_synapses, outgoing_delays, outgoing_events, \
channel, \
plot = True)
In [15]:
def run_seq_be(nSteps, \
outgoing_synapses, outgoing_delays, outgoing_events, \
channel, \
plot = False):
# Buffer allocation time is not applicable for sequential implementation
bat = np.nan
# Construct a spiking input neuron
n1 = SpikingInputNeuron_SynapticDelay_be(outgoing_synapses, \
outgoing_delays, \
channel)
t = 0.0
tic = time.time()
for step in range(nSteps):
t += dt
n1.nextState(t, outgoing_events)
# Shift outgoing event one to right
outgoing_events = outgoing_events >> 1
toc = time.time()
# Run time
rt = toc - tic
# Total time
tt = rt
if plot:
print_event_be(outgoing_events)
return bat, rt, tt
Test spiking input neuron with input spike at 2.601 milliseconds.
In [16]:
dt = 2e-4
Tsim = 28.01e-4
ttl_synapse = 10
# Outgoing synapse IDs
outgoing_synapses = [1,3,7]
# Outgoing delay (in time step)
outgoing_delays_ie = [0,2,0,10,0,0,0,5,0,0]
# Outgoing delay (in binary location)
outgoing_delays_be = [2 ** delay for delay in outgoing_delays_ie]
# Get maximum outgoing delay is not allowed to be greather than 31
# for 32-bit integer data type
ldelayList = np.max(outgoing_delays_ie) + 1
if ldelayList > 31:
print("WARNING: Maximum outgoing delay is %s time step(s)" % ldelayList)
print(" It is not allowed to be greather than 31 for 32-bit integer data type")
# array of outgoing events connected to this particular neuron in
# integer of binary
outgoing_events = np.array([0 for i in range(ttl_synapse)])
# Input channel
channel = [26.01e-4, None]
nSteps = int((Tsim / dt) + 0.5)
seq_t = run_seq_be(nSteps, \
outgoing_synapses, outgoing_delays_be, outgoing_events, \
channel, \
plot = True)
Following code executes serial and all parallel implementations on different number of outgoing synapses (1, 10, 100, 1 thousand, 10 thousand, 100 thousand, 1 million) and different OpenCL devices supported by this machine. The execution time collected from each implementation consists of buffer allocation time (bat), run time (rt) and total time (tt) of the two.
In [17]:
dt = 2e-4
Tsim = 0.3
ttl_synapses = [1, 10, 100, 1000, 10000, 100000, 1000000]
# Outgoing synaptic delay range. Both start and end are included.
osd_start = 2
osd_end = 11
# Input channel
channel = [10e-3, 15e-3, 20e-3, 25e-3, 30e-3, 35e-3, 40e-3, 45e-3, 50e-3, 55e-3] + \
[100e-3] + \
[120e-3, 130e-3, 140e-3, 150e-3, 155e-3, 160e-3, 165e-3, 170e-3] + \
[250e-3, 255e-3, 260e-3, 265e-3, 270e-3, 280e-3, 290e-3] + \
[None]
nSteps = int((Tsim / dt) + 0.5)
for ttl_synapse in ttl_synapses:
print(ttl_synapse) #bar
# Outgoing synapse IDs
outgoing_synapses = [sid for sid in range(ttl_synapse)]
# Outgoing delay (in time step)
outgoing_delays_ie = [randint(osd_start, osd_end) for sid in range(ttl_synapse)]
# Outgoing delay (in binary location)
outgoing_delays_be = [2 ** delay for delay in outgoing_delays_ie]
# Get maximum outgoing delay to alocate the most optimized event buffer
ldelayList = np.max(outgoing_delays) + 1
if ldelayList > 31:
print("WARNING: Maximum outgoing delay is %s time step(s)" % ldelayList)
print(" It is not allowed to be greather than 31 for 32-bit integer data type")
# Alocate event buffer
outgoing_events_ie = [ttl_synapse * [0] for i in range(ldelayList)]
outgoing_events_be = np.array([0 for i in range(ttl_synapse)])
seq_ie_t = run_seq_ie(nSteps, ldelayList, \
outgoing_synapses, outgoing_delays_ie, outgoing_events_ie, \
channel)
print(seq_ie_t) #bar
seq_be_t = run_seq_be(nSteps, \
outgoing_synapses, outgoing_delays_be, outgoing_events_be, \
channel)
print(seq_be_t) #bar