This tutorial shows how to use the GCAL model to explore the development of preferences for a wide variety of feature maps, including retinotopy, orientation, ocular dominance, disparity, motion direction, spatial frequency, and color. Each of these are called "dimensions", which are controlled by the dims parameter. For instance, dims=['xy','or']
works the same as the regular GCAL Orientation Map Tutorial, because it specifies that the only dimensions that will be varied on the input are xy
(spatial position, leading to a retinotopic map) and or
(orientation, leading to an orientation map). The other dimensions can be supplied similarly below. Throughout this tutorial, there will be sections that apply only to particular dimensions; these will be skipped automatically if that dimension has not been selected.
For some dimensions, there are very many different ways they could be modelled, both for the input patterns and for the neural model. For instance, the motion direction dimension (e.g. dims=['xy','or','dr']
) uses oriented Gaussian patterns swept perpendicularly to their orientation axis, but many other types of motion exist and could be added as options. Similarly, at the neural level, there are many ways to allow neurons to have a preference for motion direction, but here by default it is done by adding multiple lagged projections to V1, such that V1 receives input from various different times in the past.
See Fischer (2014) for a discussion of the various dimensions supported.
%reload_ext topo.misc.ipython
%timer start
import topo
from topo.command import load_snapshot, save_snapshot, save_script_repr
from topo.analysis import Collector
from featuremapper.analysis.raster import fft_power, vectorfield
from featuremapper.analysis.pinwheels import PinwheelAnalysis
from featuremapper.analysis.hypercolumns import PowerSpectrumAnalysis
import holoviews
from holoviews import Layout, HoloMap, Points, Image, RGB
from topo.submodel.color import ModelGCALColor
import time, os
# Uncomment to see all of the options available for use below
#%params ModelGCALColor
simulations = {
# Parameters to match published simulations
"fischer:ms14 fig6.1": dict(dims=['xy','or'],cortex_density=141),
"fischer:ms14 fig6.2-3": dict(dims=['xy','or','od'],cortex_density=141),
"fischer:ms14 fig6.5-6": dict(dims=['xy','or','dy'],cortex_density=141),
"fischer:ms14 fig6.7-8": dict(dims=['xy','or','od','dy'],cortex_density=141),
"fischer:ms14 fig6.9-11": dict(dims=['xy','or','dr'],num_inputs=1,
speed=3.0/24.0,aff_lr=0.1/4.0,
aff_strength=1.5,cortex_density=141),
"fischer:ms14 fig6.12-13": dict(dims=['xy','or','cr'],dataset='FoliageA',
strength_factor=0.75,color_strength=0.3,
cone_scale=[0.80,0.75,0.80]),
"fischer:ms14 fig6.14": dict(dims=['xy','or','od','cr'],dataset='FoliageA',
strength_factor=0.75,color_strength=0.3,
cone_scale=[0.80,0.75,0.80]), # Estimated
"fischer:ms14 fig6.15-16b": dict(dims=['xy','or','sf'],dataset='FoliageA'), # Estimated
"fischer:ms14 fig6.16c": dict(dims=['xy','or','sf'],dataset='FoliageA',
sf_spacing=2.5,sf_channels=3,gain_control_SF=True),
# Other potentially useful simulations
"retinotopic map": dict(dims=['xy']),
"all maps": dict(dims=['xy','or','od','dy','cr','sf','dr'],dataset='FoliageA'),
"all maps but sf": dict(dims=['xy','or','od','dy','cr','dr']),
}
# Special parameters overriding those above, if desired, e.g. to reduce time and memory requirements
overrides = dict(cortex_density=48)# cortex_density was 63 for most fisher:ms14 simulations
# Choose desired simulation here
params = dict(simulations["fischer:ms14 fig6.7-8"],**overrides)
topo.sim.model = ModelGCALColor(**params)
gcal=topo.sim.model.setup()
times=[10000] # Determines total duration of simulation, plus frequency of generating plots, e.g. [100,1000,10000]
save_plots=False # Set this to true if you want .png files saved externally
dim_or='or' in topo.sim.model.dims
dim_od='od' in topo.sim.model.dims
dim_dy='dy' in topo.sim.model.dims
dim_dr='dr' in topo.sim.model.dims
dim_sf='sf' in topo.sim.model.dims
dim_cr='cr' in topo.sim.model.dims
twoeyes = dim_od or dim_dy
c = Collector()
# Projection activities
for proj in gcal.projections:
if proj.dest.level=='V1' and proj.src.level=='LGN':
c.set_path('Activity'+'.'+proj.parameters['name'],
c.collect(gcal.projections[('V1', proj.parameters['name'])]))
# Preference map measurements
from topo.analysis.command import measure_or_pref, \
measure_od_pref, measure_phasedisparity, measure_dr_pref, \
measure_sine_pref, measure_hue_pref
if(dim_or and not dim_sf and not dim_dr): c.collect(measure_or_pref)
if(twoeyes): c.collect(measure_od_pref)
if(dim_dy): c.collect(measure_phasedisparity)
if(dim_dr): c.collect(measure_dr_pref)
if(dim_sf): c.collect(measure_sine_pref)
if(dim_cr): c.collect(measure_hue_pref)
# Sheet activities
for sheet_item in gcal.sheets:
if sheet_item.level=='Retina' or sheet_item.level=='V1':
c.set_path('Activity'+'.'+str(sheet_item), c.collect(gcal.sheets[str(sheet_item)]))
for proj in gcal.projections:
if proj.dest.level=='V1' and proj.src.level=='LGN':
c.set_path('CFs'+'.'+proj.parameters['name'],
c.collect(gcal.projections[('V1', proj.parameters['name'])],grid=True))
# Analysis
c.FFTPowerSpectrum.V1 = c.analyze(c.ref.OrientationPreference.V1, fft_power)
c.Pinwheels.V1 = c.analyze(c.ref.OrientationPreference.V1
* c.ref.OrientationSelectivity.V1, PinwheelAnalysis)
c.FFTAnalysis.V1 = c.analyze(c.ref.OrientationPreference.V1, PowerSpectrumAnalysis)
color_example = dim_cr and topo.sim.model.dataset!='Gaussian'
# Monochrome training patterns:
gcal.training_patterns.LeftRetina.anim(50) + \
gcal.training_patterns.RightRetina.anim(50) if twoeyes else \
gcal.training_patterns.Retina.anim(50) if not color_example else None
# Color training patterns:
if color_example:
eyes = [gcal.sheets.LeftRetina,gcal.sheets.RightRetina] if twoeyes else [gcal.sheets.Retina]
animated_RGB = []
for (e,eye) in enumerate(eyes):
rgb_inputs = {i: gen[:] for i, gen in enumerate(eye.parameters['input_generator'].generators)}
animated_RGB.append(HoloMap(rgb_inputs, key_dimensions=['Time']))
Layout(animated_RGB)
print("Collection will start at iteration %d and end on iteration %d" % (min(times), max(times)))
data = c(times=times)
data.Activity.V1
data.Activity.display('all')
%output size=150
eyes = ['Left','Right'] if twoeyes else ['']
sfs = ['','SF2'] if dim_sf else ['']
on_minus_off = []
for (e,eye) in enumerate(eyes):
for l in gcal['lags']:
for (s,sf) in enumerate(sfs):
luminosityname = "RedGreenBlueRedGreenBlue" if dim_cr and s==0 else ""
plot=(data.CFs[eye+luminosityname+"LGNOnAfferent" +sf+("" if l==0 else "Lag"+str(l))] *
data.CFs[eye+luminosityname+"LGNOffAfferent"+sf+("" if l==0 else "Lag"+str(l))])
plot.title = (("" if l==0 else "Lag"+str(l)) +" "+sf + eye + ' ' + luminosityname + ' ON-OFF CFs').strip()
on_minus_off += [plot]
defaultproj=0
num_lags=len(gcal['lags'])
on_minus_off[0] if len(on_minus_off)==1 else sum(on_minus_off[1:],on_minus_off[0]).cols(num_lags if num_lags>1 else 4)
%output size=150
%%opts Points (color='w' marker='*' s=100 edgecolors='k')
annotated_map = (data.OrientationPreference.V1
* data.OrientationSelectivity.V1
* Points(on_minus_off[defaultproj][0,-0.3:0.3].keys())) if dim_or else None
annotated_map << on_minus_off[defaultproj][0,-0.3:0.3] << data.OrientationPreference.V1.hist(adjoin=False) if dim_or else None
%opts Image.Ocular_Preference (cmap="gray")
(data.OcularPreference.V1 << data.OcularPreference.V1.hist(adjoin=False)) + \
(data.OcularSelectivity.V1 << data.OcularSelectivity.V1.hist(adjoin=False)) if twoeyes else None
%%opts Contours (linewidth=5 color='k') Points (linewidth=2)
pins = data.Pinwheels.V1.select(Duration=max(gcal['lags'])+1,Time=times[-1]).get(3) if dim_or else None
od_contours = holoviews.operation.contours(data.OcularPreference.V1). \
select(Duration=max(gcal['lags'])+1,Time=times[-1]).get(1) if twoeyes else None
data.OrientationPreference.V1.select(Duration=max(gcal['lags'])+1,Time=times[-1]) * pins * od_contours if twoeyes and dim_or else None
data.PhasedisparityPreference.V1 * data.PhasedisparitySelectivity.V1 << data.PhasedisparityPreference.V1.hist(adjoin=False) \
if dim_dy else None
Preference only
data.DirectionPreference.V1 << data.DirectionPreference.V1.hist(adjoin=False) if dim_dr else None
Preference + Selectivity
data.DirectionPreference.V1 * data.DirectionSelectivity.V1 << data.DirectionPreference.V1.hist(adjoin=False) \
if dim_dr else None
%output size=300
%%opts VectorField [color_dim='angle'] (cmap='hsv' linewidth=1 edgecolors='k')
dir_vf = vectorfield(data.DirectionPreference.V1 * data.DirectionSelectivity.V1, rows=10, cols=10) if dim_dr else None
data.OrientationPreference.V1 * data.OrientationSelectivity.V1 * dir_vf << \
data.OrientationPreference.V1.hist(adjoin=False) if dim_dr else None
%output size=150
data.FrequencyPreference.V1 * data.FrequencySelectivity.V1 << data.FrequencyPreference.V1.hist(adjoin=False) \
if dim_sf else None
%%opts Image.FrequencyPreference (cmap='gray')
data.FrequencyPreference.V1 << data.FrequencyPreference.V1.hist(adjoin=False) \
if dim_sf else None
Color map
data.HuePreference.V1 * data.HueSelectivity.V1 << data.HuePreference.V1.hist(adjoin=False) \
if dim_cr else None
%output size=100
if dim_or:
OR_HCS = data.OrientationPreference.V1 * data.OrientationSelectivity.V1
phase_HCS = data.PhasePreference.V1 * data.PhaseSelectivity.V1
top_row = OR_HCS + data.OrientationPreference.V1.hist() + data.OrientationSelectivity.V1.hist()
bottom_row = phase_HCS + data.PhasePreference.V1.hist() + data.PhaseSelectivity.V1.hist()
(top_row + bottom_row).cols(3) if dim_or else None
%output size=120
if dim_or:
for t in times:
data.FFTPowerSpectrum.V1.select(Duration=max(gcal['lags'])+1,Time=t) \
.bounds=holoviews.core.boundingregion.BoundingBox(radius=20.0)
(data.FFTAnalysis.V1).display('all').cols(2) if dim_or else None
%timer
End of notebook
Download this notebook from GitHub (right-click to download).