root/trunk/doc/parameters.txt

Revision 277, 11.7 KB (checked in by apdavison, 4 years ago)

Minor fixes in docs

Line 
1=========================
2The ``parameters`` module
3=========================
4
5We consider it to be best practice to cleanly separate the parameters of a model
6from the model itself. At the least, parameters should be defined in a separate
7section at the start of a file. Ideally, they should be defined in a separate
8file entirely. This makes version control easier, since the model code typically
9changes less often than the parameters, and makes it easier to track a
10simulation project, since the parameter sets can be stored in a database,
11displayed in a GUI, etc.
12
13
14----------
15Parameters
16----------
17
18At their simplest, individual parameters consist of a name and a value. The
19value is either a simple type such as a numerical value or a string, or an
20aggregate of such simple types, such as a set, list or array.
21
22However, we may also wish to specify the physical dimensions of the parameter,
23i.e., its units, and the range of permissible values.
24
25It is also often useful to specify an object that generates numerical values or
26strings, such as a random number generator, and treat that object as the
27parameter.
28
29To support all these uses, we define the ``Parameter`` and ``ParameterRange``
30classes, and various subclasses of the ``ParameterDist`` abstract class, such as
31``GammaDist``, ``NormalDist`` and ``UniformDist``.
32
33
34The ``Parameter`` class
35-----------------------
36
37Here are some examples of creating ``Parameter`` objects::
38
39    >>> i1 = Parameter(3)
40    >>> f1 = Parameter(6.2)
41    >>> f2 = Parameter(-65.3, "mV")
42    >>> s1 = Parameter("hello", name="message_to_the_world")
43   
44The parameter name, units, value and type can be accessed as attributes::
45
46    >>> i1.value
47    3
48    >>> f1.type
49    <type 'float'>
50    >>> f2.units
51    'mV'
52    >>> s1.name
53    'message_to_the_world'
54
55``Parameter`` objects are not hugely useful at the moment. The units are not
56used for checking dimensional consistency, for example, and ``Parameter``
57objects are not drop-in replacements for numerical values - you must always use
58the ``value`` attribute to access the value, whereas it might be nice to define,
59for example, a class ``IntegerParameter`` which was a subclass of the built-in
60``int`` type.
61
62
63The ``ParameterRange`` class
64----------------------------
65
66When investigating the behaviour of a model or in doing sensitivity analysis, it
67is often useful to run a model several times using a different value for a
68certain parameter each time (also see the ``iter_range_keys()`` and similar
69methods of the ``ParameterSet`` class, below). The ``ParameterRange`` class
70supports this. Some usage examples::
71
72    >>> tau_m_range = ParameterRange([10.0, 15.0, 20.0], "ms", "tau_m")
73    >>> tau_m_range.name
74    'tau_m'
75    >>> tau_m_range.next()
76    10.0
77    >>> tau_m_range.next()
78    15.0
79    >>> [2*tau_m for tau_m in tau_m_range]
80    [20.0, 30.0, 40.0]
81
82
83The ``ParameterDist`` classes
84-----------------------------
85
86As with taking parameter values from a series or range, it is often useful to
87pick values from a particular random distribution. Three classes are available:
88``UniformDist``, ``GammaDist`` and ``NormalDist``. Examples::
89   
90    >>> ud = UniformDist(min=-1.0, max=1.0)
91    >>> gd = GammaDist(mean=0.5, std=1.0)
92    >>> nd = NormalDist(mean=-70, std=5.0)
93    >>> ud.next()
94    array([-0.56342352])
95    >>> gd.next(3)
96    array([ 0.04061142,  0.05550265,  0.23469344])
97    >>> nd.next(2)
98    array([-76.18506715, -68.71229944])
99
100[Note that very similar functionality is available with the ``RandomDistribution``
101class in the `pyNN.random` module. We should look at the best ways to avoid
102duplication].
103
104
105--------------
106Parameter sets
107--------------
108
109A problem with parameter sets for large-scale, detailed models is that the list
110of parameters gets very long and unwieldy, and due to the typically hierarchical
111nature of such models, the individual parameter names can also get very long,
112e.g., ``v1_layer5_pyramidal_apical_dend_gbar_na``.
113
114A solution to this is to give the parameter set a hierarchical structure as well,
115which allows the top-level list of parameters to be very short (e.g. ``v1``,
116``retina`` and ``lgn`` for a visual system simulation) since the top-level
117parameters are themselves parameter sets.
118
119The simplest way to implement this in Python is using nested dicts. One
120disadvantage of this is that accessing deeply-nested parameters can be very
121verbose, e.g. ``v1['layer5']['pyramidal']['apical_dend']['na']['gbar']``. A
122second disadvantage is that it is tedious to flatten the hierarchy when
123this becomes necessary, e.g. for serialisation - writing to file, etc.
124
125For these reasons we have created a ``ParameterSet`` class, which:
126
127  1. allows a more convenient notation;
128 
129  2. enables subsets of the parameters, lower in the hierarchy, to be passed
130  around by themselves;
131 
132  3. provides convenient methods for reading from/writing to file and for
133  determining the differences between two different parameter sets.
134 
135An example of the notation is ``v1.layer5.pyramidal.apical_dend.na.gbar``, which
136requires only a single `.` for each level in the hierarchy rather than two
137"``'``"s, a "``[``" and a "``]``". This is not much shorter than
138``v1_layer5_pyramidal_apical_dend_gbar_na`` - the difference is that
139``v1.layer5.pyramidal`` is itself a ``ParameterSet`` object that can be passed
140as an argument to the pyramidal cell object, which doesn't care about
141``v1.layer4.spinystellate``, let alone ``retina.ganglioncell.magno.tau_m``
142(while ``v1_layer5_pyramidal`` is just a ``NameError``).
143
144
145The ``ParameterSet`` class
146--------------------------
147
148Creation
149~~~~~~~~
150
151``ParameterSet`` objects may be created from a dict::
152
153    >>> sim_params = ParameterSet({'dt': 0.11, 'tstop': 1000.0})
154   
155or loaded from a URL::
156
157    >>> exc_cell_params = ParameterSet("https://neuralensemble.org/svn/NeuroTools/trunk/doc/example.param")
158
159They may be nested::
160
161    >>> inh_cell_params = ParameterSet({'tau_m': 15.0, 'cm': 0.5})
162    >>> network_params = ParameterSet({'excitatory_cells': exc_cell_params, 'inhibitory_cells': inh_cell_params})
163    >>> P = ParameterSet({'sim': sim_params, 'network': network_params}, label="my_params")
164
165Note that although we show here only numerical parameter values,
166``Parameter``, ``ParameterRange`` and ``ParameterDist`` objects, as well as
167strings, may also be parameter values.
168
169Navigation
170~~~~~~~~~~
171   
172Individual parameters may be accessed/set using dot notation::
173
174    >>> P.sim.dt
175    0.11
176    >>> P.network.inhibitory_cells.tau_m
177    15.0
178    >>> P.network.inhibitory_cells.cm = 0.75
179   
180or the usual dictionary access notation::
181
182    >>> P['network']['inhibitory_cells']['cm']
183    0.75
184   
185or mixing the two (which may be required if some of the parameter names contain
186spaces)::
187
188    >>> P['network'].excitatory_cells['tau_m']
189    10.0
190
191Viewing and saving
192~~~~~~~~~~~~~~~~~~
193
194To see the entire parameter set at once, nicely formatted use the ``pretty()``
195method::
196
197    >>> print P.pretty()
198    {
199      "network": {
200        "excitatory_cells": url("https://neuralensemble.org/svn/NeuroTools/trunk/doc/example.param")
201        "inhibitory_cells": {
202          "tau_m": 15.0,
203          "cm": 0.75,
204        },
205      },
206      "sim": {
207        "tstop": 1000.0,
208        "dt": 0.11,
209      },
210    }
211
212By default, if the ``ParameterSet`` contains other ``ParameterSet``\s that were
213loaded from URLs, these will be represented with a ``url()`` function in the
214output, but there is also the option to expand all URLs and show the full
215contents::
216
217    >>> print P.pretty(expand_urls=True)
218    {
219      "network": {
220        "excitatory_cells": {
221          "tau_refrac": 0.11,
222          "tau_m": 10.0,
223          "cm": 0.25,
224          "synI": {
225            "tau": 10.0,
226            "E": -75.0,
227          },
228          "synE": {
229            "tau": 1.5,
230            "E": 0.0,
231          },
232          "v_thresh": -57.0,
233          "v_reset": -70.0,
234          "v_rest": -70.0,
235        },
236        "inhibitory_cells": {
237          "tau_m": 15.0,
238          "cm": 0.75,
239        },
240      },
241      "sim": {
242        "tstop": 1000.0,
243        "dt": 0.11,
244      },
245    }
246
247If a ``ParameterSet`` was loaded from a URL, it may be modified then saved back
248to the same URL, provided the protocol supports writing::
249
250    >>> exc_cell_params.save()
251    Traceback (most recent call last):
252      File "<stdin>", line 1, in ?
253      File "parameters.py", line 266, in save
254        raise Exception("Saving using the %s protocol is not implemented" % scheme)
255    Exception: Saving using the https protocol is not implemented
256   
257or saved to a different URL::
258
259    >>> exc_cell_params.save(url="file:///tmp/exc_params")
260
261The file format is the same as that produced by the ``pretty()`` method.
262
263Copying and converting
264~~~~~~~~~~~~~~~~~~~~~~
265
266A ``ParameterSet`` can be used simply as a dictionary, but can also be
267converted explicitly to a ``dict`` if required::
268
269    >>> print sim_params.as_dict()
270    {'tstop': 1000.0, 'dt': 0.11}
271
272[need to say something about ``tree_copy()``]
273
274Iteration
275~~~~~~~~~
276
277There are several different ways to iterate over all or part of the
278``ParameterSet`` object. ``keys()``, ``values()`` and ``items()`` work as for
279``dict``s. For the sake of more readable code, ``names()`` is provided as an
280alias for ``keys()`` and ``parameters()`` as an alias for ``items()``::
281
282    >>> P.names()
283    ['network', 'sim']
284    >>> exc_cell_params.parameters()
285    [('tau_refrac', 0.11), ('tau_m', 10.0), ('cm', 0.25),
286     ('synI', {'tau': 10.0, 'E': -75.0}), ('synE', {'tau': 1.5, 'E': 0.0}),
287     ('v_thresh', -57.0), ('v_reset', -70.0), ('v_rest', -70.0)]
288   
289To flatten nested parameter sets, i.e., the iterate recursively over all
290branches of the tree, the the ``flatten()`` method returns a ``dict`` with keys
291created by joining the names at each hierarchical level with a separator
292character ('.' by default)::
293
294    >>> network_params.flatten()
295    {'excitatory_cells.synI.E': -75.0, 'excitatory_cells.v_rest': -70.0,
296     'excitatory_cells.tau_refrac': 0.11, 'excitatory_cells.v_reset': -70.0,
297     'excitatory_cells.v_thresh': -57.0, 'excitatory_cells.tau_m': 10.0,
298     'excitatory_cells.synI.tau': 10.0, 'excitatory_cells.cm': 0.25,
299     'inhibitory_cells.cm': 0.75, 'excitatory_cells.synE.tau': 1.5,
300     'excitatory_cells.synE.E': 0.0, 'inhibitory_cells.tau_m': 15.0}
301
302while the ``flat()`` method returns a generator which yields
303``(name, value)`` tuples.::
304
305    >>> for x in network_params.flat():
306    ...   print x
307    ...
308
309
310The ``ParameterSpace`` class
311----------------------------
312
313The ``ParameterSpace`` class is a subclass of ``ParameterSet`` that is
314allowed to contain ``ParameterRange`` and ``ParameterDist`` objects as
315parameters. This turns the single point in parameter space represented by a
316``ParameterSet`` into a set of points. For example, the following definition
317creates a set of six points in parameter space, which can be obtained in turn
318using the ``iter_inner()`` method::
319
320    >>> PS = ParameterSpace({
321    ...        'x': 999,
322    ...        'y': ParameterRange([10, 20]),
323    ...        'z': ParameterRange([-1, 0, 1])
324    ... })
325    >>> for P in PS.iter_inner():
326    ...     print P
327    {'y': 10, 'x': 999, 'z': -1}
328    {'y': 20, 'x': 999, 'z': -1}
329    {'y': 10, 'x': 999, 'z': 0}
330    {'y': 20, 'x': 999, 'z': 0}
331    {'y': 10, 'x': 999, 'z': 1}
332    {'y': 20, 'x': 999, 'z': 1}
333
334Putting parameter distribution objects inside a ``ParameterSpace`` allows an
335essentially infinite number of points to be generated::
336
337    >>> PS2 = ParameterSpace({
338    ...    'x': UniformDist(min=-1.0, max=1.0),
339    ...    'y': GammaDist(mean=0.5, std=1.0),
340    ...    'z': NormalDist(mean=-70, std=5.0)
341    ... })
342    >>> for P in PS2.realize_dists(n=3):
343    ...     print P
344    {'y': 1.81311773668, 'x': 0.883293989399, 'z': -73.5871002759}
345    {'y': 0.299391158731, 'x': 0.371474054049, 'z': -68.6936045978}
346    {'y': 2.90108202422, 'x': -0.388218831787, 'z': -68.6681724449}
347
348
349*This document was last updated for r274.*
Note: See TracBrowser for help on using the browser.