ParameterPort¶
Contents¶
Overview¶
ParameterPorts belong to either a Mechanism or a Projection. A ParameterPort is created
to represent each modulatable parameter of the Mechanism or a Projection, as well as those of the component’s function and
any of its secondary functions (e.g. TransferMechanism.integrator_function
). A
ParameterPort provides the current value of the parameter it represents during any relevant computations, and serves as
an interface for parameter modulation.
A ParameterPort can receive one or more ControlProjections and/or LearningProjections that modify the value returned by the ParameterPort according to the ParameterPort’s
function
. The Projections received by a ParameterPort are listed in its mod_afferents
attribute.
When the Mechanism or Projection to which a ParameterPort belongs executes, that component and its function use the ParameterPort’s value – not the parameter attribute’s value – for any computation. A ParameterPort’s corresponding attribute on the Mechanism, Projection, or Function to which it belongs (i.e. MyTransferMech.function.gain), stores the “base value” of that parameter. The base value of a parameter is the variable of the ParameterPort’s function. The base value can be viewed or changed at any time through this attribute.
The ParameterPort value is available on the ParameterPort itself, as well as the mod_name attribute of the Mechanism or Projection to which it belongs (i.e. MyTransferMech.mod_gain would return the value of the “gain” ParameterPort of the MyTransferMech mechanism.)
Note
Either of these options for looking up the value of the ParameterPort will return the ParameterPort value that was used during the most recent execution. This means that if the value of MyTransferMech.function.gain (the base value) is updated after execution #1, the base value will change immediately, but the ParameterPort value (and MyTransferMech.mod_gain) will not be computed again until execution #2.
As a result, if either MyTransferMech.mod_gain or MyTransferMech.parameter_ports[“gain”].value is viewed in between execution #1 and execution #2, it will return the gain ParameterPort value that was used during execution 1.
Creating a ParameterPort¶
ParameterPorts are created automatically when the Mechanism or Projection to which they
belong is created. The owner
of a ParameterPort must be a Mechanism or MappingProjection
(the initialization of a ParameterPort cannot be deferred). One ParameterPort is
created for each modulable Parameter of its owner, as well as for each modulable Parameter of the owner’s
function
or secondary functions (modulable
Parameters of a Component
are listed in its Parameters class, and have the attribute
modulable
set to True.)
Each ParameterPort is created using the value specified for the corresponding parameter, as described below.
The ParameterPorts for the parameters of a Mechanism or Projection are listed in its parameter_ports
attribute.
Specifying Parameters¶
Parameters can be specified in one of several places:
In the argument of the constructor for the Component to which the parameter belongs (see Core Structural Attributes for additional details).
In a parameter specification dictionary assigned to the params argument in the constructor for the Component to which the parameter belongs, or any place else the value of a parameter can be specified. The entry for each parameter must use the name of the parameter (or a corresponding keyword) as its key, and the parameter’s specification as its value (see examples below). Parameters for a Component’s
function
can be specified in an entry with the key FUNCTION_PARAMS, and a value that is itself a parameter specification dictionary containing an entry for each of the function’s parameters to be specified. When a value is assigned to a parameter in a specification dictionary, it overrides any value assigned to the argument for the parameter in the Component’s constructor.
By direct assignment to the Component’s attribute for the parameter (see below).
In the runtime_params argument of a call to a Composition’s
Run
method
The specification of the initial value of a parameter can take any of the following forms:
Value – this must be a valid value for the parameter. It creates a default ParameterPort, assigns the parameter’s default value as the ParameterPort’s
value
, and assigns the parameter’s name as the name of the ParameterPort.ParameterPort reference – this must refer to an existing ParameterPort object; its name must be the name of a parameter of the owner or of the owner’s
function
, and its value must be a valid one for the parameter.Note
This capability is provided for generality and potential future use, but its current use is not advised.
Modulatory specification – this can be an existing ControlSignal or ControlProjection, a LearningSignal or LearningProjection, a constructor or the class name for any of these, or the keywords CONTROL, CONTROL_PROJECTION, LEARNING, or LEARNING_PROJECTION. Any of these create a default ParameterPort, assign the parameter’s default value as the ParameterPort’s
value
, and assign the parameter’s name as the name of the ParameterPort. They also create and/or assign the corresponding ModulatorySignal and ModulatoryProjection, and assign the ParameterPort as the ModulatoryProjection’sreceiver
. If the ModulatorySignal and/or ModulatoryProjection already exist, their value(s) must be valid one(s) for the parameter. Note that only Control and Learning Modulatory components can be assigned to a ParameterPort (Gating components cannot be used – they can only be assigned to InputPorts and OutputPorts).
2-item tuple: (<value>, <Modulatory specification>) – this creates a default ParameterPort, uses the value specification (1st item) as parameter’s value assignment, and assigns the parameter’s name as the name of the ParameterPort. The Modulatory specification (2nd item) is used as the ParameterPort’s modulatory assignment, and the ParameterPort is assigned as the
receiver
for the corresponding ModulatoryProjection.Note
Currently, the
function
of a Component, although it can be specified as a parameter value, cannot be assigned a ModulatorySignal or modified in the runtime_params argument of a call to a Mechanism’sexecute
method. This may change in the future.
The value specified for a parameter (either explicitly or by default) is assigned to an attribute of the Component or
of the Component’s function
to which the parameter belongs. The attribute has the same
name as the parameter, and can be referenced using standard Python attribute (“dot”) notation; for example, the value
of a parameter named param is assigned to an attribute named param
that can be referenced as
my_component.param
). The parameter’s value is assigned as the default value for the ParameterPort.
Note
If the value of a parameter is specified as NotImplemented
, or any non-numeric value that is not one of those
listed above, then no ParameterPort is created and the parameter cannot be modified by a ModulatorySignal or in the runtime_params argument of a call to a Mechanism’s execute
method.
Examples¶
In the following example, a Mechanism is created by specifying two of its parameters, as well as its
function
and two of that function’s parameters, each using a different specification format:
>>> import psyneulink as pnl
>>> my_mechanism = pnl.RecurrentTransferMechanism(
... input_shapes=5,
... noise=pnl.ControlSignal(),
... function=pnl.Logistic(
... gain=(0.5, pnl.ControlSignal),
... bias=(1.0, pnl.ControlSignal(modulation=pnl.ADDITIVE))))
The first argument of the constructor for the Mechanism specifies its input_shapes
parameter by
directly assigning a value to it. The second specifies the noise
parameter
by assigning a default ControlSignal; this will use the default value of the
noise
attribute. The function argument is specified using the constructor for
a Logistic
function, that specifies two of its parameters. The gain
parameter
is specified using a tuple, the first item of which is the value to be assigned, and the second specifies
a default ControlSignal. The bias
parameter is also specified using a tuple,
in this case with a constructor for the ControlSignal that specifies its modulation
parameter.
In the following example, a MappingProjection is created, and its
matrix
parameter is assigned a random weight matrix (using a
matrix keyword) and LearningSignal:
>>> my_input_mechanism = pnl.TransferMechanism()
>>> my_output_mechanism = pnl.TransferMechanism()
>>> my_mapping_projection = pnl.MappingProjection(sender=my_input_mechanism,
... receiver=my_output_mechanism,
... matrix=(pnl.RANDOM_CONNECTIVITY_MATRIX,
... pnl.LearningSignal))
Note
The matrix
parameter belongs to the MappingProjection’s function
; however, since it has only one standard function, its arguments are available in the
constructor for the Projection (see here for a more detailed explanation).
The example below shows how to specify the parameters in the first example using a parameter specification dictionary:
>>> my_mechanism = pnl.RecurrentTransferMechanism(
... noise=5,
... params={pnl.NOISE: pnl.CONTROL,
... pnl.FUNCTION: pnl.Logistic,
... pnl.FUNCTION_PARAMS:{
... pnl.GAIN:(0.5,pnl.ControlSignal),
... pnl.BIAS:(1.0,pnl.ControlSignal(modulation=pnl.ADDITIVE))}})
There are several things to note here.
First, the parameter specification dictionary must be assigned to the params argument of the constructor. Note that if the parameter is specified in a parameter specification dictionary, the key for the parameter must be a string that is the same as the name of parameter (i.e., identical to how it appears as an arg in the constructor; as is shown for noise in the example), or using a keyword that resolves to such a string (as shown for NOISE in the example).
Second, both methods for specifying a parameter – directly in an argument for the parameter, or in an entry of a parameter specification dictionary – can be used within the same constructor.
If a particular parameter is specified in both ways (as is the case for noise in the example), the value in the parameter specification dictionary takes priority (i.e., it is the value that will be assigned to the parameter).
Finally, the keyword FUNCTION_PARAMS can be used in a parameter specification dictionary to specify
parameters of the Component’s function
, as shown for the gain and bias parameters of
the Logistic function in the example.
The example below shows how to access ParameterPort values vs base values, and demonstrates their differences:
>>> my_transfer_mechanism = pnl.TransferMechanism(
... noise=5.0,
... function=pnl.Linear(slope=2.0))
>>> assert my_transfer_mechanism.noise.base == 5.0
>>> assert my_transfer_mechanism.mod_noise == [5.0]
>>> assert my_transfer_mechanism.function.slope.base == 2.0
>>> assert my_transfer_mechanism.mod_slope == [2.0]
Notice that the noise attribute, which stores the base value for the noise ParameterPort of my_transfer_mechanism, is on my_transfer_mechanism, while the slope attribute, which stores the base value for the slope ParameterPort of my_transfer_mechanism, is on my_transfer_mechanism’s function. However, mod_noise and mod_slope are both properties on my_transfer_mechanism.
>>> my_transfer_mechanism.noise.base = 4.0
>>> my_transfer_mechanism.function.slope.base = 1.0
>>> assert my_transfer_mechanism.noise.base == 4.0
>>> assert my_transfer_mechanism.mod_noise == [5.0]
>>> assert my_transfer_mechanism.function.slope.base == 1.0
>>> assert my_transfer_mechanism.mod_slope == [2.0]
When the base values of noise and slope are updated, we can inspect these attributes immediately and observe that they have changed. We do not observe a change in mod_noise or mod_slope because the ParameterPort value will not update until the mechanism executes.
>>> my_transfer_mechanism.execute([10.0])
array([[14.]])
>>> assert my_transfer_mechanism.noise.base == 4.0
>>> assert my_transfer_mechanism.mod_noise == [4.0]
>>> assert my_transfer_mechanism.function.slope.base == 1.0
>>> assert my_transfer_mechanism.mod_slope == 1.0
Now that the mechanism has executed, we can see that each ParameterPort evaluated its function with the base value, producing a modulated noise value of 4.0 and a modulated slope value of 1.0. These values were used by my_transfer_mechanism and its Linear function when the mechanism executed.
Structure¶
Every ParameterPort is owned by a Mechanism or MappingProjection. It can receive one or more
ControlProjections or LearningProjections, that are listed in its
mod_afferents
attribute. A ParameterPort cannot receive
PathwayProjections or GatingProjections. When the ParameterPort is
updated (i.e., its owner is executed), it uses the values of its ControlProjections and LearningProjections to
determine whether and how to modify its parameter’s attribute value, which is then assigned as the ParameterPort’s
value
(see Execution for addition details). ParameterPorts have the
following core attributes:
variable
- the parameter’s attribute value; that is, the value assigned to the attribute for the parameter of the ParameterPort’s owner; it can be thought of as the parameter’s “base” value. It is used by itsfunction
to determine the ParameterPort’svalue
. It must match the format (the number and type of elements) of the parameter’s attribute value.mod_afferents
- lists theModulatoryProjections
received by the ParameterPort. These specify either modify the ParameterPort’sfunction
, or directly assign thevalue
of the ParameterPort itself (seeModulatorySignals_Modulation
).function
- takes the parameter’s attribute value as its input, modifies it under the influence of any Modulatory Projections it receives (listed inmod_afferents
, and assigns the result as the ParameterPort’svalue
which is used as the parameter’s “actual” value.value
- the result offunction
; used by the ParameterPort’s owner as the value of the parameter for which the ParameterPort is responsible.
All of the modulable parameters of a Component – that is, for which it has ParameterPorts –
are listed in its Parameters class, and have the attribute
modulable
set to True. The
ParameterPorts for a Mechanism or Projection are listed in its parameter_ports
attribute, which is also read-only.
An initial value can be assigned to a parameter in the corresponding argument of the constructor for the Component
(see above. Parameter values can also be modified by a assigning a value to
the corresponding attribute.
The parameters of a Component’s function can be modified by assigning a value to the corresponding attribute of the
Component’s function
attribute (e.g., myMechanism.function.my_parameter
).
See ParameterPorts and Parameters for additional information.
Execution¶
A ParameterPort cannot be executed directly. It is executed when the Component to which it belongs is executed.
When this occurs, the ParameterPort executes any Modulatory Projections it receives, the values of which
modulate parameters of the ParameterPort’s function
. The ParameterPort then calls
its function
and the result is assigned as its value
. The
ParameterPort’s value
is used as the value of the corresponding parameter by the Component,
or by its own function
.
Class Reference¶
- class psyneulink.core.components.ports.parameterport.ParameterPort(owner, reference_value=None, variable=None, input_shapes=None, function=None, projections=None, params=None, name=None, parameter_name=None, prefs=None, **kwargs)¶
ParameterPort( owner, reference_value=None function=LinearCombination(operation=PRODUCT),
Subclass of Port that represents and possibly modifies the parameter of a Mechanism, Projection, or its Function. See Class Reference for additional arguments and attributes.
- Parameters
owner (Mechanism or MappingProjection) – the Mechanism or MappingProjection to which to which the ParameterPort belongs; it must be specified or determinable from the context in which the ParameterPort is created (the initialization of a ParameterPort cannot be deferred. The owner of a ParameterPort for the parameter of a
function
should be specified as the Mechanism or Projection to which the function belongs.reference_value (number, list or np.ndarray) – specifies the default value of the parameter for which the ParameterPort is responsible.
variable (number, list or np.ndarray) – specifies the parameter’s initial value and attribute value — that is, the value of the attribute of the ParameterPort’s owner or its
function
assigned to the parameter.function (Function or method : default LinearCombination(operation=SUM)) – specifies the function used to convert the parameter’s attribute value (same as the ParameterPort’s
variable
) to the ParameterPort’svalue
.
- mod_afferents¶
a list of the ModulatoryProjection that project to the ParameterPort (i.e., for which it is a
receiver
); these can be ControlProjection(s) and/or LearningProjection(s), but not GatingProjection. Thevalue
of each must match the format (number and types of elements) of the ParameterPort’svariable
.- Type
Optional[List[Projection]]
- variable¶
the parameter’s attribute value — that is, the value of the attribute of the ParameterPort’s owner or its
function
assigned to the parameter.- Type
number, list or np.ndarray
- function¶
converts the parameter’s attribute value (same as the ParameterPort’s
variable
) to the ParameterPort’svalue
, under the influence of any ModulatoryProjections received by the ParameterPort (and listed in itsmod_afferents
attribute. The result is assigned as the ParameterPort’s value.- Type
Function : default Linear
- value¶
the result returned by the ParameterPort’s
function
, and used by the ParameterPort’s owner or itsfunction
as the value of the parameter for which the ParmeterPort is responsible. Note that this is not necessarily the same as the parameter’s attribute value (that is, the value of the owner’s attribute for the parameter), since the ParameterPort’sfunction
may modify the latter under the influence of itsmod_afferents
.- Type
number, List[number] or np.ndarray
- projection_type¶
alias of
psyneulink.core.components.projections.modulatory.controlprojection.ControlProjection
- _validate_against_reference_value(reference_value)¶
Validate that value of the Port is compatible with the reference_value
reference_value is the value of the parameter to which the ParameterPort is assigned
- _instantiate_projections(projections, context=None)¶
Instantiate Projections specified in PROJECTIONS entry of params arg of Port’s constructor
Disallow any PathwayProjections Call _instantiate_projections_to_port to assign ModulatoryProjections to .mod_afferents
- _check_for_duplicate_projections(projection)¶
Check if projection is redundant with one in mod_afferents of ParameterPort
Check for any instantiated projection in mod_afferents with the same sender as projection or one in deferred_init status with sender specification that is the same type as projection.
Returns redundant Projection if found, otherwise False.
- _parse_port_specific_specs(owner, port_dict, port_specific_spec, context=None)¶
Get connections specified in a ParameterPort specification tuple
- Tuple specification can be:
(port_spec, projections)
Assumes that port_spec has already been extracted and used by _parse_port_spec
Returns params dict with PROJECTIONS entries if any of these was specified.
- static _get_port_function_value(owner, function, variable)¶
Return parameter variable (since ParameterPort’s function never changes the form of its variable
- _get_variable_from_projections(context=None)¶
Get backingfield (“base”) value of param of function of Mechanism to which the ParameterPort belongs.
- exception psyneulink.core.components.ports.parameterport.ParameterPortError(message, component=None)¶