import param
import imagen
from topo.base.arrayutil import DivideWithConstant, MultiplyWithConstant
from topo import sheet
from . import Model
from .gcal import ModelGCAL
from .earlyvision import EarlyVisionModel
@Model.definition
[docs]class EarlyVisionSCAL(EarlyVisionModel):
"""
EarlyVisionModel subclass with spatially calibrated extents
used for SCAL and other models.
"""
area = param.Number(default=2.0,bounds=(0,None),
inclusive_bounds=(False,True),doc="""
Linear size of cortical area to simulate.
SCAL and other spatially calibrated variants of GCAL require
cortical areas larger than 1.0x1.0 to avoid strong suppressive
edge effects.""")
expand_sf_test_range=param.Boolean(default=False,doc="""
By default, measure_sine_pref() measures SF at the sizes of RF
used, for speed, but if expand_sf_test_range is True, it will
test over a larger range, including half the size of the
smallest and twice the size of the largest.""")
lgn_density = param.Number(default=16.0,bounds=(0,None),
inclusive_bounds=(False,True),doc="""
The nominal_density to use for the LGN.""")
num_inputs = param.Number(default=1.5, bounds=(0,None))
lgnaff_strength = param.Number(default=14, doc="""
Overall strength of the afferent projection from the retina to
the LGN sheets.""")
#=================#
# Spatial extents #
#=================#
center_size = param.Number(default=0.2, bounds=(0, None), doc="""
The size of the central Gaussian used to compute the
center-surround receptive field.""")
surround_size = param.Number(default=0.3, bounds=(0, None), doc="""
The size of the surround Gaussian used to compute the
center-surround receptive field.""")
gain_control_size = param.Number(default=0.8, bounds=(0, None), doc="""
The size of the divisive inhibitory suppressive field used for
contrast-gain control in the LGN sheets. This also acts as the
corresponding bounds radius.""")
lgnaff_radius = param.Number(default=0.4, bounds=(0, None), doc="""
Connection field radius of a unit in the LGN level to units in
a retina sheet.""")
lgnlateral_radius = param.Number(default=0.8, bounds=(0, None), doc="""
Connection field radius of a unit in the LGN level to
surrounding units, in case gain control is used.""")
[docs] def training_pattern_setup(self, **overrides):
"""
Only the size of Gaussian training patterns has been modified.
The 'aspect_ratio' and 'scale' parameter values are unchanged.
"""
or_dim = 'or' in self.dims
gaussian = (self.dataset == 'Gaussian')
pattern_parameters = {'size':(0.2 if or_dim and gaussian
else 3 * 0.1 if gaussian else 10.0),
'aspect_ratio': 4.6667 if or_dim else 1.0,
'scale': self.contrast / 100.0}
return super(EarlyVisionSCAL, self).training_pattern_setup(
pattern_parameters=pattern_parameters,
position_bound_x=self.area/2.0+self.v1aff_radius,
position_bound_y=self.area/2.0+self.v1aff_radius)
def analysis_setup(self):
super(EarlyVisionSCAL, self).analysis_setup()
from topo.analysis.command import measure_sine_pref, measure_or_pref
sf_relative_sizes = [self.sf_spacing ** (sf_channel - 1)
for sf_channel in self['SF']]
wide_relative_sizes = ([0.5 * sf_relative_sizes[0]]
+ sf_relative_sizes
+ [2.0 * sf_relative_sizes[-1]])
relative_sizes = (wide_relative_sizes if self.expand_sf_test_range
else sf_relative_sizes)
frequencies = [1.5 * s for s in relative_sizes]
measure_sine_pref.frequencies = frequencies
measure_or_pref.frequencies= frequencies
@Model.definition
[docs]class ModelSCAL(EarlyVisionSCAL, ModelGCAL):
"""
Spatially-tuned GCAL (SCAL) calibrated to represent a 3 degree
parafoveal region of macaque primary visual cortex, assuming a
3 mm/deg magnification factor and 0.71 mm orientation hypercolumn
distance.
Changes from ModelGCAL include relative strengths, homeostatic
sparsity constraints, connection radii and switching from
subtractive to divisive inhibition. The explanation of the
calibration process is explained in a forthcoming notebook.
"""
area = param.Number(default=2.0,bounds=(0,None),
inclusive_bounds=(False,True),doc="""
Linear size of cortical area to simulate.
SCAL and other spatially calibrated variants of GCAL require
cortical areas larger than 1.0x1.0 to avoid strong suppressive
edge effects.""")
aff_strength = param.Number(default=2.4, bounds=(0.0, None), doc="""
Overall strength of the afferent projection to V1.""")
exc_strength = param.Number(default=1.4, bounds=(0.0, None), doc="""
Overall strength of the lateral excitatory projection to V1.""")
inh_strength = param.Number(default=2.0, bounds=(0.0, None), doc="""
Overall strength of the lateral inhibitory projection to V1.""")
t_init = param.Number(default=0.45, doc="""
The initial threshold value for homeostatic adaptation in V1.""")
t_settle = param.Integer(default=16, doc="""
Number of settling steps before applying a reset in the V1 sheet.""")
#=================#
# Spatial extents #
#=================#
latexc_radius = param.Number(default=0.1, bounds=(0, None), doc="""
Radius of the lateral excitatory bounds within V1.""")
latinh_radius = param.Number(default=0.18, bounds=(0, None), doc="""
Radius of the lateral inhibitory bounds within V1.""")
latexc_size = param.Number(default=0.06, bounds=(0, None), doc="""
Size of the lateral excitatory connections within V1.""")
latinh_size = param.Number(default=0.115, bounds=(0, None), doc="""
Size of the lateral inhibitory connections within V1.""")
v1aff_radius = param.Number(default=0.5, bounds=(0, None), doc="""
Connection field radius of a unit in V1 to units in a LGN
sheet.""")
#=====================#
# Divisive inhibition #
#=====================#
division_constant = param.Number(default=1.0, doc="""
The constant offset on the denominator for divisive lateral
inhibition to avoid divide-by-zero errors:
divide(x,maximum(y,0) + division_constant).""")
#=========================#
# Long-range connectivity #
#=========================#
laterals = param.Boolean(default=False, doc="""
Instantiate long-range lateral connections. Expensive!""")
latexc_strength=param.Number(default=0, doc="""
Lateral excitatory connection strength""")
latexc_lr=param.Number(default=1.0, doc="""
Lateral excitatory connection learning rate.""")
# Excitatory connection profiles #
lateral_radius = param.Number(default=1.25, bounds=(0, None), doc="""
Radius of the lateral excitatory bounds within V1Exc.""")
lateral_size = param.Number(default=2.5, bounds=(0, None), doc="""
Size of the lateral excitatory connections within V1Exc.""")
@Model.CFProjection
[docs] def lateral_inhibitory(self, src_properties, dest_properties):
"""
Switch to divisive inhibition, otherwise parameters unchanged.
"""
return Model.CFProjection.params(
delay=0.05,
name='LateralInhibitory',
weights_generator=imagen.random.GaussianCloud(
gaussian_size=self.latinh_size),
strength=self.inh_strength,
activity_group=(0.6,
DivideWithConstant(c=self.division_constant)),
learning_rate=self.inh_lr,
nominal_bounds_template=sheet.BoundingBox(
radius=self.latinh_radius))
@Model.matchconditions('V1', 'lr_lateral_excitatory')
def lr_lateral_excitatory_conditions(self, properties):
return {'level': 'V1'} if self.laterals else {'level': None}
@Model.CFProjection
def lr_lateral_excitatory(self, src_properties, dest_properties):
return Model.CFProjection.params(
delay=0.1,
name='LRExcitatory',
activity_group=(0.9, MultiplyWithConstant()),
weights_generator=imagen.Gaussian(aspect_ratio=1.0, size=self.lateral_size),
strength=self.latexc_strength,
learning_rate=self.latexc_lr,
nominal_bounds_template=sheet.BoundingBox(radius=self.lateral_radius))