Source code for teili.building_blocks.sequence_learning

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""This module provides a sequence learning building block.
This building block can be used to learn sequences of items

Attributes:
    sl_params (dict): Dictionary of default parameters for reservoir.

Example:
    To use the Reservoir building block in your simulation you need
    to create an object of the class by doing:

    >>> from teili.building_blocks.reservoir import Reservoir
    >>> my_bb = Reservoir(name='my_sequence')

    If you want to change the underlying neuron and synapse model you need to
    provide a different equation_builder class:

    >>> from teili.models.neuron_models import DPI
    >>> from teili.models.synapse_models import DPISyn
    >>> my_bb = Reservoir(name='my_sequence',
                      neuron_eq_builder=DPI,
                      synapse_eq_builder=DPISyn)

    If you want to change the default parameters of your building block
    you need to define a dictionary, which you pass to the building_block:

    >>> sl_params = {'synInpOrd1e_weight': 1.3,
                     'synOrdMem1e_weight': 1.1,
                     'synMemOrd1e_weight': 0.16,
                     # local
                     'synOrdOrd1e_weight': 1.04,
                     'synMemMem1e_weight': 1.54,
                     # inhibitory
                     'synOrdOrd1i_weight': -1.95,
                     'synMemOrd1i_weight': -0.384,
                     'synCoSOrd1i_weight': -1.14,
                     'synResetOrd1i_weight': -1.44,
                     'synResetMem1i_weight': -2.6,
                     # refractory
                     'gOrdGroups_refP': 1.7 * ms,
                     'gMemGroups_refP': 2.3 * ms
                     }
    >>> my_bb = Reservoir(name='my_sequence', block_params=sl_params)
"""
# @Author: Alpha Renner, mmilde
# @Date:   2018-06-01 18:45:19

import numpy as np
from numpy import floor
from brian2 import ms, SpikeGeneratorGroup, SpikeMonitor
from matplotlib.pyplot import xlim, figure, xlabel, \
    ylabel, plot, subplot, title

from teili.building_blocks.building_block import BuildingBlock
from teili.core.groups import Neurons, Connections

from teili.models.neuron_models import ExpAdaptIF
from teili.models.synapse_models import ReversalSynV

sl_params = {'synInpOrd1e_weight': 1.3,
             'synOrdMem1e_weight': 1.1,
             'synMemOrd1e_weight': 0.16,
             # local
             'synOrdOrd1e_weight': 1.04,
             'synMemMem1e_weight': 1.54,
             # inhibitory
             'synOrdOrd1i_weight': -1.95,
             'synMemOrd1i_weight': -0.384,
             'synCoSOrd1i_weight': -1.14,
             'synResetOrd1i_weight': -1.44,
             'synResetMem1i_weight': -2.6,
             # refractory
             'gOrdGroups_refP': 1.7 * ms,
             'gMemGroups_refP': 2.3 * ms
             }


[docs]class SequenceLearning(BuildingBlock): '''Sequence Learning Network. Attributes: cos_group (neuron group): Condition of Satisfaction group. group (dict): List of keys of neuron population. input_group (SpikeGenerator): SpikeGenerator object to stimulate Reservoir. reset_group (neuron group): Reset group, to reset network after CoS is met. standalone_params (dict): Keys for all standalone parameters necessary for cpp code generation. ''' def __init__(self, name, neuron_eq_builder=ExpAdaptIF, synapse_eq_builder=ReversalSynV, block_params=sl_params, num_elements=3, num_neurons_per_group=6, num_inputs=1, verbose=False): """Summary Args: name (str, required): Base name for building block. neuron_eq_builder (teili.models.builder obj, optional): Neuron equation builder object. synapse_eq_builder (teili.models.builder obj, optional): Synapse equation builder object. block_params (dict, optional): Dictionary of parameters such as synChaCha1e_weight or gChaGroup_refP. num_elements (int, optional): Number of elements in the sequence. num_neurons_per_group (int, optional): Number of neurons used to remember each item. num_inputs (int, optional): Number of inputs from different source populations. verbose (bool, optional): Debug flag. """ BuildingBlock.__init__(self, name, neuron_eq_builder, synapse_eq_builder, block_params, verbose) self._groups, self.monitors,\ self.standalone_params = gen_sequence_learning(name, neuron_eq_builder=neuron_eq_builder, synapse_eq_builder=synapse_eq_builder, num_elements=num_elements, num_neurons_per_group=num_neurons_per_group, num_inputs=num_inputs, verbose=verbose, **block_params) self.group = self.groups['gOrdGroups'] self.input_group = self.groups['gInputGroup'] self.cos_group = self.groups['gCoSGroup'] self.reset_group = self.groups['gResetGroup']
[docs] def plot(self, duration = None): """Simple plot for sequence learning network. Returns: pyqtgraph window: The window containing the plot. """ return plot_sequence_learning(self.monitors, duration)
[docs]def gen_sequence_learning(groupname='Seq', neuron_eq_builder=ExpAdaptIF, synapse_eq_builder=ReversalSynV, num_elements=4, num_neurons_per_group=8, synInpOrd1e_weight=1.3, synOrdMem1e_weight=1.1, synMemOrd1e_weight=0.16, synOrdOrd1e_weight=1.04, synMemMem1e_weight=1.54, synOrdOrd1i_weight=-1.95, synMemOrd1i_weight=-0.384, synCoSOrd1i_weight=-1.14, synResetOrd1i_weight=-1.44, synResetMem1i_weight=-2.6, gOrdGroups_refP=1.7 * ms, gMemGroups_refP=2.3 * ms, num_inputs=1, verbose=False): """Create Sequence Learning Network after the model from Sandamirskaya and Schoener (2010). Args: groupname (str, optional): Base name for building block. neuron_eq_builder (teili.models.builder obj, optional): Neuron equation builder object. synapse_eq_builder (teili.models.builder obj, optional): Synapse equation builder object. num_elements (int, optional): Number of elements in the sequence. num_neurons_per_group (int, optional): Number of neurons used to remember each item. synInpOrd1e_weight (float, optional): Parameter specifying the input weight. synOrdMem1e_weight (float, optional): Parameter specifying the ordinary to memory weight. synMemOrd1e_weight (float, optional): Parameter specifying the memory to ordinary weight. synOrdOrd1e_weight (float, optional): Parameter specifying the recurrent weight (ord). synMemMem1e_weight (float, optional): Parameter specifying the recurrent weight (memory). synOrdOrd1i_weight (TYPE, optional): Parameter specifying the recurrent inhibitory weight. synMemOrd1i_weight (TYPE, optional): Parameter specifying the memory to ordinary inhibitory weight. synCoSOrd1i_weight (TYPE, optional): Parameter specifying the inhibitory weight from cos to ord. synResetOrd1i_weight (TYPE, optional): Parameter specifying the the inhibitory weight from reset to ord. synResetMem1i_weight (TYPE, optional): Parameter specifying the the inhibitory weight from reset cos to memory. gOrdGroups_refP (TYPE, optional): Parameter specifying the refractory period. gMemGroups_refP (TYPE, optional): Parameter specifying the refractory period. num_inputs (int, optional): Number of inputs from different source populations. debug (bool, optional): Debug flag. Returns: Groups (dictionary): Keys to all neuron and synapse groups. Monitors (dictionary): Keys to all spike- and statemonitors. standalone_params (dictionary): Dictionary which holds all parameters to create a standalone network. """ nOrdNeurons = num_neurons_per_group * num_elements nMemNeurons = num_neurons_per_group * num_elements # Input to start sequence manually ts_input = np.asarray([]) * ms ind_input = np.asarray([]) gInputGroup = SpikeGeneratorGroup( num_neurons_per_group, indices=ind_input, times=ts_input, name='spikegenInp_' + groupname) # CoS Input #TODO: CoS as NeuronGroup ts_cos = np.asarray([]) * ms ind_cos = np.asarray([]) gCoSGroup = SpikeGeneratorGroup( num_neurons_per_group, indices=ind_cos, times=ts_cos, name='spikegenCoS_' + groupname) # reset group #TODO: Reset as NeuronGroup ts_reset = np.asarray([]) * ms ind_reset = np.asarray([]) gResetGroup = SpikeGeneratorGroup( num_neurons_per_group, indices=ind_reset, times=ts_reset, name='spikegenReset_' + groupname) # NeuronGroups gOrdGroups = Neurons(nOrdNeurons, equation_builder=neuron_eq_builder(num_inputs=7 + num_inputs), refractory=gOrdGroups_refP, name='g' + 'Ord_' + groupname) gMemGroups = Neurons(nMemNeurons, equation_builder=neuron_eq_builder(num_inputs=3), refractory=gMemGroups_refP, name='g' + 'Mem_' + groupname) # Synapses # excitatory synInpOrd1e = Connections(gInputGroup, gOrdGroups, equation_builder=synapse_eq_builder(), method="euler", name='sInpOrd1e_' + groupname) synOrdMem1e = Connections(gOrdGroups, gMemGroups, equation_builder=synapse_eq_builder(), method="euler", name='sOrdMem1e_' + groupname) synMemOrd1e = Connections(gMemGroups, gOrdGroups, synapse_eq_builder(), method="euler", name='sMemOrd1e_' + groupname) # local synOrdOrd1e = Connections(gOrdGroups, gOrdGroups, equation_builder=synapse_eq_builder(), method="euler", name='sOrdOrd1e_' + groupname) synMemMem1e = Connections(gMemGroups, gMemGroups, equation_builder=synapse_eq_builder(), method="euler", name='sMemMem1e_' + groupname) # inhibitory synOrdOrd1i = Connections(gOrdGroups, gOrdGroups, equation_builder=synapse_eq_builder(), method="euler", name='sOrdOrd1i_' + groupname) synMemOrd1i = Connections(gMemGroups, gOrdGroups, equation_builder=synapse_eq_builder(), method="euler", name='sMemOrd1i_' + groupname) synCoSOrd1i = Connections(gCoSGroup, gOrdGroups, equation_builder=synapse_eq_builder(), method="euler", name='sCoSOrd1i_' + groupname) synResetOrd1i = Connections(gResetGroup, gOrdGroups, equation_builder=synapse_eq_builder(), method="euler", name='sResOrd1i_' + groupname) synResetMem1i = Connections(gResetGroup, gMemGroups, equation_builder=synapse_eq_builder(), method="euler", name='sResMem1i_' + groupname) # predefine connections for efficiency reasons iii = [] jjj = [] for ii in range(nOrdNeurons): for jj in range(nMemNeurons): if (floor(ii / num_neurons_per_group) == floor(jj / num_neurons_per_group)) & (ii != jj): iii.append(ii) jjj.append(jj) iiMemOrd = [] jjMemOrd = [] for ii in range(nOrdNeurons): for jj in range(nMemNeurons): if (floor(ii / num_neurons_per_group) == floor(jj / num_neurons_per_group) - 1) & ((floor(jj / num_neurons_per_group) - 1) >= 0): iiMemOrd.append(ii) jjMemOrd.append(jj) synInpOrd1e.connect(i=np.arange(num_neurons_per_group), j=np.arange( num_neurons_per_group)) # Input to first OG synOrdMem1e.connect(i=iii, j=jjj) synMemOrd1e.connect(i=iiMemOrd, j=jjMemOrd) # i=j is also connected, exclude if necessary synOrdOrd1e.connect(i=iii, j=jjj) # i=j is also connected, exclude if necessary synMemMem1e.connect(i=iii, j=jjj) synOrdOrd1i.connect( 'floor(i/num_neurons_per_group)!=floor(j/num_neurons_per_group) and (i!=j)') synMemOrd1i.connect(i=iii, j=jjj) # CoS synCoSOrd1i.connect(True) # Reset synResetOrd1i.connect(True) synResetMem1i.connect(True) # change some parameters # weights # excitatory synInpOrd1e.weight = synInpOrd1e_weight synOrdMem1e.weight = synOrdMem1e_weight synMemOrd1e.weight = synMemOrd1e_weight # local synOrdOrd1e.weight = synOrdOrd1e_weight synMemMem1e.weight = synMemMem1e_weight # inhibitory synOrdOrd1i.weight = synOrdOrd1i_weight synMemOrd1i.weight = synMemOrd1i_weight synCoSOrd1i.weight = synCoSOrd1i_weight synResetOrd1i.weight = synResetOrd1i_weight synResetMem1i.weight = synResetMem1i_weight Groups = { 'gOrdGroups': gOrdGroups, 'gMemGroups': gMemGroups, 'gInputGroup': gInputGroup, 'gCoSGroup': gCoSGroup, 'gResetGroup': gResetGroup, 'synInpOrd1e': synInpOrd1e, 'synOrdMem1e': synOrdMem1e, 'synMemOrd1e': synMemOrd1e, 'synOrdOrd1e': synOrdOrd1e, 'synMemMem1e': synMemMem1e, 'synOrdOrd1i': synOrdOrd1i, 'synMemOrd1i': synMemOrd1i, 'synCoSOrd1i': synCoSOrd1i, 'synResetOrd1i': synResetOrd1i, 'synResetMem1i': synResetMem1i} # Monitors spikemonOrd = SpikeMonitor(gOrdGroups, name='spikemonOrd_' + groupname) spikemonMem = SpikeMonitor(gMemGroups, name='spikemonMem_' + groupname) spikemonCoS = SpikeMonitor(gCoSGroup, name='spikemonCoS_' + groupname) spikemonInp = SpikeMonitor(gInputGroup, name='spikemonInp_' + groupname) spikemonReset = SpikeMonitor( gResetGroup, name='spikemonReset_' + groupname) Monitors = { 'spikemonOrd': spikemonOrd, 'spikemonMem': spikemonMem, 'spikemonCoS': spikemonCoS, 'spikemonInp': spikemonInp, 'spikemonReset': spikemonReset} standalone_params = { # synInpOrd1e.name + '_weight': synInpOrd1e_weight, # synOrdMem1e.name + '_weight': synOrdMem1e_weight, # synMemOrd1e.name + '_weight': synMemOrd1e_weight, # local # synOrdOrd1e.name + '_weight': synOrdOrd1e_weight, # synMemMem1e.name + '_weight': synMemMem1e_weight, # inhibitory # synOrdOrd1i.name + '_weight': synOrdOrd1i_weight, # synMemOrd1i.name + '_weight': synMemOrd1i_weight, # synCoSOrd1i.name + '_weight': synCoSOrd1i_weight, # synResetOrd1i.name + '_weight': synResetOrd1i_weight, # synResetMem1i.name + '_weight': synResetMem1i_weight, # refractory # gOrdGroups.name + '_refP': gOrdGroups_refP, # gMemGroups.name + '_refP': gMemGroups_refP } return Groups, Monitors, standalone_params
[docs]def plot_sequence_learning(Monitors, duration=None): """A simple matplotlib wrapper function to plot network activity. Args: Monitors (building_block.monitors): Dictionary containing all monitors created by gen_sequence_learning(). Returns: plt.fig: Matplotlib figure. """ spikemonOrd = Monitors['spikemonOrd'] spikemonMem = Monitors['spikemonMem'] spikemonInp = Monitors['spikemonInp'] spikemonCoS = Monitors['spikemonCoS'] spikemonReset = Monitors['spikemonReset'] if duration is None: duration = max(spikemonOrd.t) + 10 * ms print('plot...') fig = figure(figsize=(8, 12)) title('sequence learning') nPlots = 5 * 100 subplot(nPlots + 11) plot(spikemonOrd.t / ms, spikemonOrd.i, '.k') xlabel('Time [ms]') ylabel('i_ord') # ylim([0,nOrdNeurons]) xlim([0, duration / ms]) subplot(nPlots + 12) plot(spikemonMem.t / ms, spikemonMem.i, '.k') xlabel('Time [ms]') ylabel('i_mem') # ylim([0,nOrdNeurons]) xlim([0, duration / ms]) subplot(nPlots + 13) plot(spikemonInp.t / ms, spikemonInp.i, '.k') xlabel('Time [ms]') ylabel('i_in') # ylim([0,nPerGroup]) xlim([0, duration / ms]) subplot(nPlots + 14) plot(spikemonCoS.t / ms, spikemonCoS.i, '.k') xlabel('Time [ms]') ylabel('i_CoS') # ylim([0,nPerGroup]) xlim([0, duration / ms]) subplot(nPlots + 15) plot(spikemonReset.t / ms, spikemonReset.i, '.k') xlabel('Time [ms]') ylabel('i_Reset') # ylim([0,nPerGroup]) xlim([0, duration / ms]) return fig