From b2df5fdf2349be000938e7691e4f4963b526ce0b Mon Sep 17 00:00:00 2001 From: PesarAmmehZA Date: Wed, 16 Aug 2023 18:27:09 +0330 Subject: [PATCH] Overhaul (#34) * fix: `find_object()`Attribute Error Initializing a synapse with a tag for src or dst neuron group, requires tag seach to obtain the src or dst object. e.g. SynapseGroup(src='pop1', dst=pop2, ...) this search calls `find_objects()` for all objects, Therefore since a recoder haven't yet been initialized there's no attribute `variables` * style: each setting as argument for network * doc: fix missing keyword and new setup method * fix: test cuda device * feat: default for parameter * relase: bump version to 0.1.3 --- HISTORY.rst | 13 ++++- docs/tutorial.rst | 10 ++-- .../NetworkBehavior/Recorder/Recorder.py | 2 +- pymonntorch/NetworkCore/Behavior.py | 2 +- pymonntorch/NetworkCore/Network.py | 50 ++++++++++--------- setup.py | 2 +- tests/test_pymonntorch.py | 2 +- 7 files changed, 48 insertions(+), 33 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index cd2ea90..aa3f261 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -2,11 +2,22 @@ History ======= +0.1.3 (2023-08-16) + +* BREAKING CHANGE: `Network` no longer accept settings. Individual setting are now argument for Network. +* Bugg fixes. + + +0.1.2 (2023-06-14) + +* `tensor` method for NetworkObject + + 0.1.1 (2023-05-26) ------------------ * Every NetworkObject can have a recorder behavior. -* Netowrk settings accept "index" entry. +* Network settings accept "index" entry. * Bug fixes and general improvement. diff --git a/docs/tutorial.rst b/docs/tutorial.rst index 9bf5e7f..cc46818 100644 --- a/docs/tutorial.rst +++ b/docs/tutorial.rst @@ -12,7 +12,7 @@ Just like ``PymoNNto``, each ``Network`` in ``PymoNNtorch`` is composed of ``Neu ng = NeuronGroup(net=net, size=1000, behavior={}) syn = SynapseGroup(net=net, src=ng, dst=ng, tag='GLUTAMATE') -So far, ``ng`` has been added to network ``net`` and synaptic connection has been defined to connect ``ng`` to itself, i.e. both afferent and efferent synapses of ``ng`` are ``syn``. By default, each network and its components are created on CPU and the data type of any tensor inside the objects is set to ``torch.float32``. Pass an argument ``settings`` to the ``Network`` to change these default setups. ``settings`` is a dictionary with keys ``device`` and ``dtype`` which indicate the device and data type of everything within the network, respectively. +So far, ``ng`` has been added to network ``net`` and synaptic connection has been defined to connect ``ng`` to itself, i.e. both afferent and efferent synapses of ``ng`` are ``syn``. By default, each network and its components are created on CPU and the data type of any tensor inside the objects is set to ``torch.float32``. To change these settings on creation, simply, fill the arguments of the network with your desired device and dtype. To have a functioning network, we can write ``Behavior`` (s) for different network objects to define dynamics and attributes for them. To do so, we can proceed as follows: :: @@ -29,7 +29,7 @@ To have a functioning network, we can write ``Behavior`` (s) for different netwo firing = neurons.voltage >= self.threshold neurons.spike = firing.byte() neurons.voltage[firing] = 0.0 # reset - + neurons.voltage *= 0.9 # voltage decay neurons.voltage += neurons.vector(mode="uniform", density=0.1) @@ -52,7 +52,7 @@ Note that each behavior is given an index upon being assigned to a network objec neurons.voltage += synapse.W@synapse.src.spike.float() / synapse.src.size * 10 Now, assume we have defined ``ng`` by:: - + ng = NeuronGroup(net=net, size=1000, behavior={ @@ -74,11 +74,11 @@ In most simulations, we need to keep track of variables through time. To do so, net = Network() ng = NeuronGroup(net=net, - size=1000, + size=1000, behavior={ 1: BasicBehavior(), 2: InputBehavior(), - 9: Recorder(['voltage', 'mean(voltage)']), + 9: Recorder(['voltage', 'torch.mean(voltage)']), 10: EventRecorder(['spike']) }) SynapseGroup(ng, ng, net, tag='GLUTAMATE') diff --git a/pymonntorch/NetworkBehavior/Recorder/Recorder.py b/pymonntorch/NetworkBehavior/Recorder/Recorder.py index 1718283..fadd5e5 100644 --- a/pymonntorch/NetworkBehavior/Recorder/Recorder.py +++ b/pymonntorch/NetworkBehavior/Recorder/Recorder.py @@ -54,6 +54,7 @@ def __init__( tag=tag, **kwargs, ) + self.variables = {} def initialize(self, object): super().initialize(object) @@ -71,7 +72,6 @@ def initialize(self, object): self.auto_annotate = self.parameter("auto_annotate", True) self.counter = 0 self.new_data_available = False - self.variables = {} self.compiled = {} self.add_variables(variables) diff --git a/pymonntorch/NetworkCore/Behavior.py b/pymonntorch/NetworkCore/Behavior.py index f4f104b..fd41d2d 100644 --- a/pymonntorch/NetworkCore/Behavior.py +++ b/pymonntorch/NetworkCore/Behavior.py @@ -131,7 +131,7 @@ def check_unused_attrs(self): def parameter( self, key, - default, + default=None, object=None, do_not_diversify=False, search_other_behaviors=False, diff --git a/pymonntorch/NetworkCore/Network.py b/pymonntorch/NetworkCore/Network.py index 242a33a..dda7e42 100644 --- a/pymonntorch/NetworkCore/Network.py +++ b/pymonntorch/NetworkCore/Network.py @@ -6,9 +6,6 @@ from pymonntorch.NetworkCore.Behavior import Behavior from pymonntorch.NetworkCore.SynapseGroup import * -SxD = False -DxS = True - class Network(NetworkObject): """This is the class to construct a neural network. @@ -20,26 +17,41 @@ class Network(NetworkObject): NeuronGroups (list): List of all NeuronGroups in the network. SynapseGroups (list): List of all SynapseGroups in the network. behavior (list or dict): List of all network-specific behaviors. - def_dtype (type): Floating point precision of tensors. Defaults to `torch.float32`; can be changed via setttings with "dtype" key. - device (string): The device to allocate tensors' memory on. Defaults to `'cpu'`; can be changed via setttings with "device" key. - transposed_synapse_matrix_mode (bool): If `True`, in the matrix created by synapse, each row corresponds to a neuron from the source neuron group. Defaults to `False`; can be changed via settings with the "synapse_mode" key, which can have `DxS` and `SxD` as possible values. - index_neurons (bool): If True, the `id` attribute for neuron groups refers to neuron indices. Defaults to `True`; can be changed via setttings with "index" key. + def_dtype (type): Floating point precision of tensors. Defaults to `torch.float32`. + device (string): The device to allocate tensors on. Defaults to `'cpu'`. + transposed_synapse_matrix_mode (bool): If `True`, in the matrix created by synapse, each row corresponds to a neuron from the source neuron group. Defaults to `False`. + index_neurons (bool): If True, the `id` attribute for neuron groups refers to neuron indices. Defaults to `True`. """ - def __init__(self, tag=None, behavior=None, settings=None): + def __init__( + self, + tag=None, + behavior=None, + dtype=torch.float32, + device="cpu", + synapse_mode="SxD", + index=True, + ): """Initialize the network. Args: tag (str): Tag to add to the network. It can also be a comma-separated string of multiple tags. behavior (list or dict): List or dictionary of behaviors. If a dictionary is used, the keys must be integers. - settings (dict): Dictionary of network-wide settings, e.g. `dtype`, `synapse_mode`, `device` and `index`. - `dtype`: Floating point precision of tensors. Defaults to `torch.float32`. - `synapse_mode`: If `SxD`, rows of matrix created by a synapse referes to the source neuron group and columns referes to the Destination neurpn group. Possible values `DxS` and `SxD`. - `device`: The device to allocate tensors' data on. Defaults to `'cpu'`. - `index`: If True, create an indexing tensor as `id` attribute for each neuron group. + dtype (torch.dtype): Floating point precision of tensors. + synapse_mode (string): If `SxD`, rows of matrix created by a synapse referes to the source neuron group and columns referes to the Destination neurpn group. Possible values `DxS` and `SxD`. + device (string): The device to allocate tensors' data on. Defaults to `'cpu'`. + index (bool): If True, create an indexing tensor as `id` attribute for each neuron group. """ - settings = settings if settings is not None else {} - self.apply_settings(settings) + self.device = device + self._def_dtype = dtype + self.index_neurons = index + if synapse_mode not in ["SxD", "DxS"]: + print( + f"""warning: synapse_mode should be either "SxD" or "DxS". using "DxS".""" + ) + self.transposed_synapse_matrix_mode = ( + False if synapse_mode == "DxS" else synapse_mode == "SxD" + ) self.NeuronGroups = [] self.SynapseGroups = [] @@ -52,14 +64,6 @@ def __init__(self, tag=None, behavior=None, settings=None): super().__init__(tag, self, behavior, device=self.device) - def apply_settings(self, settings): - self.device = settings.setdefault("device", "cpu") - self._def_dtype = settings.setdefault("dtype", torch.float32) - self.index_neurons = settings.setdefault("index", True) - self.transposed_synapse_matrix_mode = ( - settings.setdefault("synapse_mode", DxS) != DxS - ) - def set_behaviors(self, tag, enabled): """Set behaviors of specific tag to be enabled or disabled. diff --git a/setup.py b/setup.py index d7a9457..0c8a70c 100644 --- a/setup.py +++ b/setup.py @@ -49,6 +49,6 @@ test_suite="tests", tests_require=test_requirements, url="https://github.com/cnrl/PymoNNtorch", - version="0.1.2", + version="0.1.3", zip_safe=False, ) diff --git a/tests/test_pymonntorch.py b/tests/test_pymonntorch.py index f00abb7..5104c49 100644 --- a/tests/test_pymonntorch.py +++ b/tests/test_pymonntorch.py @@ -106,7 +106,7 @@ def forward(self, neurons): synapse.W @ synapse.src.spike.float() / synapse.src.size * 10 ) - net = Network(settings={"device": "cuda"}) + net = Network(device="cuda") ng = NeuronGroup( net=net, size=100,