root/trunk/doc/parameters.txt

Revision 277, 11.7 kB (checked in by apdavison, 2 months ago)

Minor fixes in docs

Line 
1 =========================
2 The ``parameters`` module
3 =========================
4
5 We consider it to be best practice to cleanly separate the parameters of a model
6 from the model itself. At the least, parameters should be defined in a separate
7 section at the start of a file. Ideally, they should be defined in a separate
8 file entirely. This makes version control easier, since the model code typically
9 changes less often than the parameters, and makes it easier to track a
10 simulation project, since the parameter sets can be stored in a database,
11 displayed in a GUI, etc.
12
13
14 ----------
15 Parameters
16 ----------
17
18 At their simplest, individual parameters consist of a name and a value. The
19 value is either a simple type such as a numerical value or a string, or an
20 aggregate of such simple types, such as a set, list or array.
21
22 However, we may also wish to specify the physical dimensions of the parameter,
23 i.e., its units, and the range of permissible values.
24
25 It is also often useful to specify an object that generates numerical values or
26 strings, such as a random number generator, and treat that object as the
27 parameter.
28
29 To support all these uses, we define the ``Parameter`` and ``ParameterRange``
30 classes, and various subclasses of the ``ParameterDist`` abstract class, such as
31 ``GammaDist``, ``NormalDist`` and ``UniformDist``.
32
33
34 The ``Parameter`` class
35 -----------------------
36
37 Here 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    
44 The 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
56 used for checking dimensional consistency, for example, and ``Parameter``
57 objects are not drop-in replacements for numerical values - you must always use
58 the ``value`` attribute to access the value, whereas it might be nice to define,
59 for example, a class ``IntegerParameter`` which was a subclass of the built-in
60 ``int`` type.
61
62
63 The ``ParameterRange`` class
64 ----------------------------
65
66 When investigating the behaviour of a model or in doing sensitivity analysis, it
67 is often useful to run a model several times using a different value for a
68 certain parameter each time (also see the ``iter_range_keys()`` and similar
69 methods of the ``ParameterSet`` class, below). The ``ParameterRange`` class
70 supports 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
83 The ``ParameterDist`` classes
84 -----------------------------
85
86 As with taking parameter values from a series or range, it is often useful to
87 pick 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``
101 class in the `pyNN.random` module. We should look at the best ways to avoid
102 duplication].
103
104
105 --------------
106 Parameter sets
107 --------------
108
109 A problem with parameter sets for large-scale, detailed models is that the list
110 of parameters gets very long and unwieldy, and due to the typically hierarchical
111 nature of such models, the individual parameter names can also get very long,
112 e.g., ``v1_layer5_pyramidal_apical_dend_gbar_na``.
113
114 A solution to this is to give the parameter set a hierarchical structure as well,
115 which 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
117 parameters are themselves parameter sets.
118
119 The simplest way to implement this in Python is using nested dicts. One
120 disadvantage of this is that accessing deeply-nested parameters can be very
121 verbose, e.g. ``v1['layer5']['pyramidal']['apical_dend']['na']['gbar']``. A
122 second disadvantage is that it is tedious to flatten the hierarchy when
123 this becomes necessary, e.g. for serialisation - writing to file, etc.
124
125 For 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  
135 An example of the notation is ``v1.layer5.pyramidal.apical_dend.na.gbar``, which
136 requires 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
140 as 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
145 The ``ParameterSet`` class
146 --------------------------
147
148 Creation
149 ~~~~~~~~
150
151 ``ParameterSet`` objects may be created from a dict::
152
153     >>> sim_params = ParameterSet({'dt': 0.11, 'tstop': 1000.0})
154    
155 or loaded from a URL::
156
157     >>> exc_cell_params = ParameterSet("https://neuralensemble.org/svn/NeuroTools/trunk/doc/example.param")
158
159 They 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
165 Note that although we show here only numerical parameter values,
166 ``Parameter``, ``ParameterRange`` and ``ParameterDist`` objects, as well as
167 strings, may also be parameter values.
168
169 Navigation
170 ~~~~~~~~~~
171    
172 Individual 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    
180 or the usual dictionary access notation::
181
182     >>> P['network']['inhibitory_cells']['cm']
183     0.75
184    
185 or mixing the two (which may be required if some of the parameter names contain
186 spaces)::
187
188     >>> P['network'].excitatory_cells['tau_m']
189     10.0
190
191 Viewing and saving
192 ~~~~~~~~~~~~~~~~~~
193
194 To see the entire parameter set at once, nicely formatted use the ``pretty()``
195 method::
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
212 By default, if the ``ParameterSet`` contains other ``ParameterSet``\s that were
213 loaded from URLs, these will be represented with a ``url()`` function in the
214 output, but there is also the option to expand all URLs and show the full
215 contents::
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
247 If a ``ParameterSet`` was loaded from a URL, it may be modified then saved back
248 to 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    
257 or saved to a different URL::
258
259     >>> exc_cell_params.save(url="file:///tmp/exc_params")
260
261 The file format is the same as that produced by the ``pretty()`` method.
262
263 Copying and converting
264 ~~~~~~~~~~~~~~~~~~~~~~
265
266 A ``ParameterSet`` can be used simply as a dictionary, but can also be
267 converted 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
274 Iteration
275 ~~~~~~~~~
276
277 There 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
280 alias 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    
289 To flatten nested parameter sets, i.e., the iterate recursively over all
290 branches of the tree, the the ``flatten()`` method returns a ``dict`` with keys
291 created by joining the names at each hierarchical level with a separator
292 character ('.' 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
302 while 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
310 The ``ParameterSpace`` class
311 ----------------------------
312
313 The ``ParameterSpace`` class is a subclass of ``ParameterSet`` that is
314 allowed to contain ``ParameterRange`` and ``ParameterDist`` objects as
315 parameters. This turns the single point in parameter space represented by a
316 ``ParameterSet`` into a set of points. For example, the following definition
317 creates a set of six points in parameter space, which can be obtained in turn
318 using 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
334 Putting parameter distribution objects inside a ``ParameterSpace`` allows an
335 essentially 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.