GCAL model with multiple maps

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.

Imports


In [ ]:
%reload_ext topo.misc.ipython
%timer start

In [ ]:
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

Define the model


In [ ]:
# Uncomment to see all of the options available for use below
#%params ModelGCALColor

In [ ]:
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)

In [ ]:
topo.sim.model = ModelGCALColor(**params)

In [ ]:
gcal=topo.sim.model.setup()

In [ ]:
times=[10000] # Determines total duration of simulation, plus frequency of generating plots, e.g. [100,1000,10000]

Define plotting and analysis


In [ ]:
save_plots=False # Set this to true if you want .png files saved externally

In [ ]:
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

In [ ]:
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'])]))

In [ ]:
# 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)

In [ ]:
# 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)

Example input patterns


In [ ]:
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

In [ ]:
# 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)

Training the network (slow!)


In [ ]:
print("Collection will start at iteration %d and end on iteration %d" % (min(times), max(times)))

In [ ]:
data = c(times=times)

Results

Activity patterns


In [ ]:
data.Activity.V1

In [ ]:
data.Activity.display('all')

On-Off connection fields


In [ ]:
%output size=150

In [ ]:
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)

Orientation map


In [ ]:
%output size=150

In [ ]:
%%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

Ocularity map


In [ ]:
%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

In [ ]:
%%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

Disparity map


In [ ]:
data.PhasedisparityPreference.V1 * data.PhasedisparitySelectivity.V1 << data.PhasedisparityPreference.V1.hist(adjoin=False) \
    if dim_dy else None

Direction map

Preference only


In [ ]:
data.DirectionPreference.V1 << data.DirectionPreference.V1.hist(adjoin=False) if dim_dr else None

Preference + Selectivity


In [ ]:
data.DirectionPreference.V1 * data.DirectionSelectivity.V1 << data.DirectionPreference.V1.hist(adjoin=False) \
    if dim_dr else None

In [ ]:
%output size=300

In [ ]:
%%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

Spatial frequency map


In [ ]:
%output size=150

In [ ]:
data.FrequencyPreference.V1 * data.FrequencySelectivity.V1 << data.FrequencyPreference.V1.hist(adjoin=False) \
    if dim_sf else None

In [ ]:
%%opts Image.FrequencyPreference (cmap='gray')
data.FrequencyPreference.V1 << data.FrequencyPreference.V1.hist(adjoin=False) \
    if dim_sf else None

Color map


In [ ]:
data.HuePreference.V1 * data.HueSelectivity.V1 << data.HuePreference.V1.hist(adjoin=False) \
    if dim_cr else None

Phase preference


In [ ]:
%output size=100

In [ ]:
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

Orientation pinwheels + FFT analysis


In [ ]:
%output size=120

In [ ]:
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

In [ ]:
%timer

End of notebook