root/trunk/examples/retina/retina.py

Revision 340, 11.9 kB (checked in by LaurentPerrinet, 3 weeks ago)

some polishing of the wiki:examples, the retina needs a bit more work...

  • Property svn:executable set to *
  • Property svn:keywords set to Id
Line 
1 #!/usr/bin/env python
2 # -*- coding: utf8 -*-
3 """
4
5 retina.py
6 =========
7
8 The retina for 'benchmark one'. This should feed the 'Hyper-Column' (see
9 https://facets.kip.uni-heidelberg.de/private/wiki/index.php/V1_hypercolumn )
10
11
12 For this retina, it consists of 2 layers of neurons on a rectangular
13 grid connected in a one to one fashion. Here, we more use primate  'Phasic'
14 responses originate with morphologically larger ganglion cell types with fast
15 optic nerve fiber conduction velocities (~4 m/s, Gouras, 1969). Microelectrodes
16 staining of such cells shows that they are 'parasol' types (Dacey and Lee, 1994).
17 ON types branch low in the inner plexiform layer (sublamina b), while OFF types
18 branch high in the inner plexiform layer (sublamina a) following the classic
19 branching pattern for ON and OFF center cells (Nelson et al, 1978; Dacey and Lee,
20 1994). Phasic cells are often referred to as the 'magnocellular' or 'M-cell'
21 pathway because their fibers terminate in the magnocellular layer of the lateral
22 geniculate nucleus of the thalamus. Near the fovea receptive fields of phasic
23 cells are 2-3 times larger than those of tonic cells and may be 10 times larger
24 in peripheral retina.
25
26 The data times outputted by the model are the input to the LGN (
27 http://en.wikipedia.org/wiki/Lateral_geniculate_nucleus ). Time for travelling
28 through the retina being compensated :
29
30
31 @article{Stanford87,
32     Author = {Stanford, L R},
33     Journal = {Science},
34     Month = {Oct},
35     Number = {4825},
36     Pages = {358-360},
37     Title = {Conduction velocity variations minimize conduction time differences
38     among retinal ganglion cell axons},
39     Volume = {238},
40     Year = {1987}}
41
42 To remember (in the cat) 5° of visual angle ~ 1 mm of retina
43
44 See :
45 Data for parameters http://webvision.med.utah.edu/GCPHYS1.HTM (TODO LUP: define
46 different sets for different animals (cat, monkey, human))
47 Morphology : http://webvision.med.utah.edu/GC1.html
48 Topics on CVonline http://homepages.inf.ed.ac.uk/cgi/rbf/CVONLINE/phase3entries.pl?TAG59
49
50 TODO (LuP) : use Ringach 07 for setting the neurons centers
51 TODO (LuP) : the grid is rectangular, but should be hexagonal / log-polar conformation
52 / define boudaries in biological coordinates
53
54 from scipy.interpolate import interpolate
55 from numpy.random import randn
56 from numpy import *
57
58 data = arange(16)
59 data = data+1
60 data = data.reshape(4,4)
61 xrange = arange(4)
62 yrange = arange(4)
63 X,Y = meshgrid(xrange,yrange)
64
65 outgrid = interpolate.interp2d(X,Y,data,kind='linear')
66 xi = array([0,0.5,1,1.5,2,2.5,3])
67 yi = xi
68
69 z = outgrid(xi,yi)
70
71
72
73 TODO (LuP) : allow the use of moving images /
74 TODO (LuP) : justify or not SFA (since we are interested in synchrony effect, we should
75 rather use a simpler model) / noise model
76 TODO (LuP) : use real delays
77 TODO (LuP) : get significative statistics to the retina into that file
78 TODO (Lup) : use another cell type?
79
80 TODO (Lup) : use  nest2 definitively
81
82 $ Id $
83
84 """
85 import datetime
86
87 import pyNN.nest2 as sim
88 from NeuroTools.signals import load_spikelist
89 import os, tempfile
90 import numpy
91 from NeuroTools.parameters import ParameterSet
92
93
94 class Retina(object):
95     """
96     Model class for the retina.
97
98     """
99     def __init__(self,N=1000):
100         """
101         Default parameters for the retina of size NxN.
102
103         Sets up parameters and the whole structure of the dictionary / HDF file in url.
104         It contains all relevant parameters and stores them to a dictionary for
105          clarity &future compatibility with XML exports.
106
107         """
108         #try :
109         #    url = "https://neuralensemble.org/svn/NeuroTools/trunk/examples/retina/retina.param"
110         #    self.params = ParameterSet(url)
111         #    print "Loaded parameters from SVN"
112         #except :
113         params = {} # a dictionary containing all parameters
114         # === Define parameters ========================================================
115         # LUP: get running file name and include script in HDF5?
116
117         params = {'description' : 'default retina',
118             'N': N, # integer;  square of total number of Ganglion Cells LUP: how do we include types and units in parameters? (or by default it is a float in ISO standards) TODO: go rectangular
119             'N_ret': .2, # float;  diameter of Ganglion Cell's RF (max: 1)
120             'K_ret': 4.0, # float; ratio of center vs. surround in DOG
121             'dt'         : 0.1,# discretization step in simulations (ms)
122             'simtime'    : 40000*0.1,      # float; (ms)
123             'syn_delay'  : 1.0,         # float; (ms)
124             'noise_std' : 5.0,       # (nA) standard deviation of the internal noise
125             'snr' : 2.0, # (nA) maximum signal
126             'weight'     : 1.0, #
127             #'threads' : 2, 'kernelseeds' : [43210987, 394780234],      # array with one element per thread
128             #'threads' : 1,
129             'kernelseed' : 4321097,       # array with one element per thread
130             # seed for random generator used when building connections
131             'connectseed' : 12345789,  # seed for random generator(s) used during simulation
132             'initialized' : datetime.datetime.now().isoformat() # the date in ISO 8601 format to avoid overriding old simulations
133         }
134
135         # retinal neurons parameters
136         params['parameters_gc'] = {'Theta':-57.0, 'Vreset': -70.0,'Vinit': -70.0,
137         'TauR': 0.5, 'gL':28.95,
138         'C':289.5, 'V_reversal_E': 0.0, 'V_reversal_I': -75.0, 'TauSyn_E':1.5,
139         'TauSyn_I': 10.0, 'V_reversal_sfa': -70.0, 'q_sfa': 0., #14.48,
140         'Tau_sfa':110.0, 'V_reversal_relref': -70.0, 'q_relref': 3214.0,
141         'Tau_relref': 1.97}#,'python':True}
142
143         ## default input image # TODO add start and stop time
144         # define the center of every neuron in normalized visual angle / retinal space
145
146         #X,Y = numpy.meshgrid(numpy.linspace(-N/2, N/2,N),numpy.linspace(-N/2,N/2,N))
147         X,Y = numpy.random.rand(N)*2-1, numpy.random.rand(N)*2 -1
148
149         # Generate a DOG excitation on the input layer of the GC
150         # Based on the assumptions of the DOG model (Enroth-Cugell and Robson, 1966) that ganglion cells linearly add signals from both center and surround mechanisms for all points in space
151         # this is the impulse response to a discrete dirac in the center to some specific luminance / excentricity value
152         #   easy : extend to input images (simply by convoluting the image with this kernel)
153         #   hard : extend to time varrying movies (not only a step)
154         params['position'] = [X,Y]
155         R2= X**2 + Y**2
156         N, N_ret, K_ret = params['N'], params['N_ret'], params['K_ret']
157         amplitude = (numpy.exp(-R2 / ( 2 * N_ret**2) )  - 1/K_ret**2 * numpy.exp(-R2 / ( 2 *  N_ret**2 * K_ret**2) )) / (1  - 1/K_ret**2)
158         #amplitude *=  params['noise_std'] # scaled by the noise variance
159         #file.setStructure({'amplitude' : amplitude }, "/build", createparents=True)
160         params['amplitude'] = amplitude
161
162         self.params =  ParameterSet(params)
163             #self.params.save('file://' + os.getcwd() + '/retina.param')
164
165
166     def run(self,params,verbose=True):
167         """
168         params are the parameters to use
169
170         """
171         tmpdir = tempfile.mkdtemp()
172         Timer = sim.Timer()
173         # === Build the network ========================================================
174         if verbose: print "Setting up simulation"
175         Timer.start() # start timer on construction
176         sim.setup(timestep=params['dt'],max_delay=params['syn_delay'])
177         N = params['N']
178         #dc_generator
179         phr_ON = sim.Population((N,),'dc_generator')
180         phr_OFF  = sim.Population((N,),'dc_generator')
181
182
183         for factor, phr in [(-params['snr'],phr_OFF),(params['snr'],phr_ON)]:
184             phr.tset('amplitude', params['amplitude'] * factor )
185             phr.set({ 'start' : params['simtime']/4, 'stop' : params['simtime']/4*3})
186
187         # internal noise model (see benchmark_noise)
188         noise_ON = sim.Population((N,),'noise_generator',{'mean':0.,'std':params['noise_std']})
189         noise_OFF = sim.Population((N,),'noise_generator',{'mean':0.,'std':params['noise_std']})
190
191
192         # target ON and OFF populations (what about a tridimensional Population?)
193         out_ON = sim.Population((N,), sim.IF_cond_alpha) #IF_curr_alpha)#'iaf_sfa_neuron')# EIF_cond_alpha_isfa_ista, IF_cond_exp_gsfa_grr,sim.IF_cond_alpha)#'iaf_sfa_neuron',params['parameters_gc'])#'iaf_cond_neuron')# IF_cond_alpha) #
194         out_OFF = sim.Population((N,), sim.IF_cond_alpha) #IF_curr_alpha)#'iaf_sfa_neuron')#sim.IF_curr_alpha)#,params['parameters_gc'])
195
196
197         # initialize membrane potential TODO: and conductances?
198         from pyNN.random import RandomDistribution, NumpyRNG
199         rng = NumpyRNG(seed=params['kernelseed'])
200         vinit_distr = RandomDistribution(distribution='uniform',parameters=[-70,-55], rng=rng)
201         for out_ in [out_ON, out_OFF]:
202             out_.randomInit(vinit_distr)
203
204
205         retina_proj_ON = sim.Projection(phr_ON, out_ON, 'oneToOne')
206         retina_proj_ON.setWeights(params['weight'])
207         # TODO fix setWeight, add setDelays to 10 ms (relative to stimulus onset)
208         retina_proj_OFF = sim.Projection(phr_OFF, out_OFF, 'oneToOne')
209         retina_proj_OFF.setWeights(params['weight'])
210
211         noise_proj_ON = sim.Projection(noise_ON, out_ON, 'oneToOne')
212         noise_proj_ON.setWeights(params['weight'])
213         noise_proj_OFF = sim.Projection(noise_OFF, out_OFF, 'oneToOne') # implication if ON and OFF have the same noise input?
214         noise_proj_OFF.setWeights(params['weight'])
215
216
217         out_ON.record()
218         out_OFF.record()
219
220         # reads out time used for building
221         buildCPUTime= Timer.elapsedTime()
222
223         # === Run simulation ===========================================================
224         if verbose: print "Running simulation"
225
226         Timer.reset() # start timer on construction
227         sim.run(params['simtime'])
228         simCPUTime = Timer.elapsedTime()
229
230         Timer.reset()  # start timer on construction
231         # TODO LUP use something like "for pop in [phr, out]" ?
232         out_ON_filename=os.path.join(tmpdir,'out_on.gdf')
233         out_OFF_filename=os.path.join(tmpdir,'out_off.gdf')
234         out_ON.printSpikes(out_ON_filename)#
235         out_OFF.printSpikes(out_OFF_filename)#
236
237         # TODO LUP  get out_ON_DATA on a 2D grid independantly of out_ON.cell.astype(int)
238         out_ON_DATA = load_spikelist(out_ON_filename,range(N),
239                                         t_start=0.0, t_stop=params['simtime'])
240         out_OFF_DATA = load_spikelist(out_OFF_filename,range(N),
241                                         t_start=0.0, t_stop=params['simtime'])
242
243         out = {'out_ON_DATA':out_ON_DATA,
244                 'out_OFF_DATA':out_OFF_DATA}#,'out_ON_pos':out_ON}
245         # cleans up
246         os.remove(out_ON_filename)
247         os.remove(out_OFF_filename)
248         os.rmdir(tmpdir)
249         writeCPUTime = Timer.elapsedTime()
250
251         if verbose:
252             print "\nRetina Network Simulation:"
253             print(params['description'])
254             print "Number of Neurons  : ", N
255             print "Output rate  (ON) : ", out_ON_DATA.mean_rate(), "Hz/neuron in ", params['simtime'], "ms"
256             print "Output rate (OFF)   : ", out_OFF_DATA.mean_rate(), "Hz/neuron in ",params['simtime'], "ms"
257             print("Build time             : %g s" % buildCPUTime)
258             print("Simulation time        : %g s" % simCPUTime)
259             print("Writing time           : %g s" % writeCPUTime)
260
261         return out
262
263
264 if __name__ == '__main__':
265
266     ret = Retina(100)
267     out = ret.run(ret.params)
268     # plotting
269     import pylab
270     fig = pylab.figure(1)
271     z = pylab.subplot(121)
272     out['out_ON_DATA'].raster_plot(display=z, id_list=range(20), kwargs={'color':'r'})
273     z = pylab.subplot(122)
274     out['out_OFF_DATA'].raster_plot(display=z, id_list=range(20), kwargs={'color':'b'})
275     fig = pylab.figure(2)
276     z = pylab.subplot(111)
277     out['out_ON_DATA'].firing_rate(ret.params.simtime/100, display=z, kwargs={'label':'ON','color':'r'})
278     out['out_OFF_DATA'].firing_rate(ret.params.simtime/100, display=z, kwargs={'label':'OFF','color':'b'})
279     pylab.legend()
280
Note: See TracBrowser for help on using the browser.