TransferMechanism¶
Contents¶
Overview¶
A TransferMechanism is a subclass of ProcessingMechanism that adds the ability to integrate its input.
As a ProcessingMechanism, it transforms its input using a simple mathematical function that maintains the shape of its
input. The input can be a single scalar value, a simple list or array, or a multidimensional one (regular or ragged).
The function used to carry out the transformation can be a TransferFunction
or a custom one
that can accept any of these forms of input and generate one of similar form. A TransferMechanism can also add noise
to and/or clip
the result of its function.
A TransferMechanism has two modes of operation: without integration and with integration enabled.
Integration is disabled by default, so that the Mechanism’s function
executes a full
(“instantaneous”) transformation of its input on each execution (akin to the standard practice in feedforward neural
networks). However, if integration is enabled, then it uses its integrator_function
to integrate its input on each execution, before passing the result on to
its function
for transformation (akin to time-averaging the net input to a unit in a
neural network before passing that to its activation function). When integration is enabled, using the integrator_mode
Parameter, additional parameters can be used to configure the integration process,
including how it is initialized and when it terminates.
Creating a TransferMechanism¶
The primary arguments that determine the operation of a TransferMechanism are its function argument,
that specifies the function
used to transform its input; and, if integrator
mode is set to True, then its integrator_function* argument and associated ones that specify how integration occurs (see Examples).
Primary Function¶
By default, the primary function
of a TransferMechanism is Linear
, however the
function argument can be used to specify any subclass or instance of TransferFunction
. It can also be any
python function or method, so long as it can take a scalar, or a list or array of numerical values as input and
produce a result that is of the same shape; the function or method is “wrapped” as UserDefinedFunction,
assigned as the TransferMechanism’s function
attribute.
Integator Function¶
By default, the integrator_function
of a
TransferMechanism is AdaptiveIntegrator
, however the integrator_function argument of the Mechanism’s constructor
can be used to specify any subclass of IntegratorFunction
, so long as it can accept as input the TransferMechanism’s
variable
, and genereate a result of the same shape that is passed to the Mechanism’s
function
. In addition to specifying parameters in the constructor for an
IntegratorFunction
assigined to the integrator_function argument, the constructor for the TransferMechanism
itself has arguments that can be used to confifure its integrator_function
:
initial_value, integration_rate, and noise. If any of these are specified in the TransferMechanism’s
constructor, their value is used to specify the corresponding parameter of its integrator_function
. Additonal parameters that govern how integration occurs are described under
Execution With Integration.
Structure¶
InputPorts¶
By default, a TransferMechanism has a single InputPort; however, more than one can be specified
using the default_variable or input_shapes arguments of its constructor (see Mechanism). The value
of each InputPort is used as a separate item of the Mechanism’s variable
, and transformed independently by its function
.
Functions¶
A TransferMechanism has two functions: its primary function
that transforms its
input, and an integrator_function
that is used to integrate the input
before passing it to the primary function
when integrator_mode
is set to True. The default function for a TransferMechanism is Linear
,
and the defult for its integrator_function
is AdaptiveIntegrator
,
how custom functions can be assigned, as described under Creating a TransferMechanism.
OutputPorts¶
By default, or if the output_ports argument is specified using the keyword RESULTS, a TransferMechanism generates
one OutputPort for each item in the outer dimension (axis 0) of its value
(each of which is
the result of the Mechanism’s function
(and possibly its integrator_function
) applied to the value
of the corresponding InputPort).
If there is only one OutputPort (i.e., the case in which there is only one InputPort and
therefore only one item in Mechanism’s value
), the OutputPort is named RESULT. If there is
more than one item in value
, then an OuputPort is assigned for each; the name of the first
is RESULT-0, and the names of the subsequent ones are suffixed with an integer that is incremented for each successive
one (e.g., RESULT-1, RESULT-2, etc.). Additional OutputPorts can be assigned using the TransferMechanism’s
standard_output_ports
(see Standard OutputPorts) or by creating custom
OutputPorts (but see note below).
Note
If any OutputPorts are specified in the output_ports argument of the TransferMechanism’s constructor, then, as with any Mechanism, its default OutputPorts are not automatically generated. Therefore, an OutputPort with the appropriate
index
must be explicitly specified for each and every item of the Mechanism’svalue
(corresponding to each InputPort) for which an OutputPort is needed.
Execution¶
A TransferMechanism has two modes of execution, determined by its integrator_mode
parameter. By default (integrator_mode
= False) it executes without integration, directly transforming its input using its function
, and possibly adding noise
to and/or clipping
the result. If integrator_mode
= True,
it executes with integration, by integrating its input before
transforming it. Each of these is described in more detail below.
Execution Without Integration¶
If integrator_mode
is False (the default), the input received over
input_ports
(assigned as variable
) is passed
directly to function
. If either the noise
or
clip
Parameters have been specified, they are applied to the result of function
. That is then assigned as the Mechanism’s value
, and well as the
values
of its output_ports
, each of which represents the
transformed value of the corresponding input_ports
(see examples).
Execution With Integration¶
If integrator_mode
is True, the TransferMechanism’s input (variable
) is first passed to its integrator_function
,
the result of which is then passed to its primary function
. The TransferMechanis has
several Parameters that, in addition to those of its integrator_function
,
can be used to configure the integration process, as described in the following subsections (also see examples).
Initialization, Resetting and Resuming Integration¶
The staring point for integration can be initialized and reset, and also configured to resume in various ways, as described below (also examples).
Initializing integration – by default, the the starting point for integration is the Mechanism’s default_variable, and is usually an appropriately shaped array of 0’s. However, the starting point can be specified using the initializer argument of a TransferMechanism’s constructor.
Note
The value of initializer is passed to the
integrator_function
as itsinitializer
Parameter. It can also be specified directly in the initializer argument of the constructor for anIntegratorFunction
assigned to the integrator_function argument of a TransferMechanism’s constructor. If there is a disagreements between these (i.e., between the specifiation of initial_value for the TransferMechanism and initializer for itsintegrator_function
, the value specified for the latter takes precedence, and that value is assigned as the one for theinitial_value
of the TransferMechanism.
Resetting integration – in some cases, it may be useful to reset the integration to the original starting point,
or to a new one. This can be done using the Mechanism’s reset
method. This first sets the
integrator_function
’s previous_value
and value
attributes to the specified value. That is then passed to the Mechanism’s function
which is executed, and the result is assigned as the Mechanism current value
and to its output_ports
.
Note
The TransferMechanism’s
reset
method calls the reset method on itsintegrator_function
, which can also be called directly. The key difference is that calling the Mechanism’sreset
method also executes the Mechanism’sfunction
and updates itsoutput_ports
. This is useful if the Mechanism’svalue
or that of any of itsoutput_ports
will be used or checked before the Mechanism is next executed. This may be true if, for example, the Mechanism is a RecurrentTransferMechanism, or if a Scheduler Condition depends on it.
Resuming integration – integration can be enabled and disabled between executions by setting integrator_mode
to True and False, respectively. When re-enabling integration, the value used
by the integrator_function
for resuming integration can be configured using
the TransferMechanism’s on_resume_integrator_mode
Parameter; there are
three options for this:
CURRENT_VALUE - use the current
value
of the Mechanism as the starting value for resuming integration;LAST_INTEGRATED_VALUE - resume integration with whatever the
integrator_function
’previous_value
was whenintegrator_mode
was last True;RESET - call the
integrator_function
sreset
method, so that integration resumes usinginitial_value
as its starting value.
Integration¶
On each execution of the Mechanism, its variable
is passed to the integrator_function
, which integrates this with the function’s previous_value
, using the Mechanism’s noise
and
integration_rate
parameters.
Note
Like the TransferMechanism’s
initial_value
, itsnoise
andintegration_rate
Parameters are used to specify thenoise
andinitializer
Parameters of itsintegrator_function
, respectively. If there are any disagreements between these (e.g., any of these parameters is specified with conflicting values for the TransferMechanism and itsintegrator_function
), the values specified for theintegrator_function
take precedence, and those value(s) are assigned as the ones for the corresponding Parameters of the TransferMechanism.
After the integrator_function
executes, its result is passed to the
Mechanism’s primary function
, and its clip
parameter is applied
if specified, after which it is assigned to as the TransferMechanism’s value
and that of its
output_ports
.
Termination¶
If integrator_mode
is True then, for each execution of the TransferMechanism, it
can be configured to conduct a single step of integration, or to continue to integrate during that execution until its
termination condition is met. The latter is specified by the TransferMechanism’s execute_until_finished
as well as its termination_threshold
, termination_measure
, and
termination_comparison_op
Parameters. These configurations are
described below (also see examples).
Single step execution – If either execute_until_finished
is set to False,
or no termination_threshold
is specified (i.e., it is None, the default),
then only a signle step of integration is carried out each time the TransferMechanism is executed. In this case,
the num_executions_before_finished
attribute remains equal to 1,
since the integrator_function
is executed exactly once per call to the
execute method (and the termination condition does not apply or has not been specified).
Execute to termination – if execute_until_finished
is True and a value is
specified for the termination_threshold
then, during each execution of
the TransferMechanism, it repeatedly calls its integrator_function
and primary function
, using the same input (variable
) until
its termination condition, or the number of executions reaches
max_executions_before_finished
. The numer of executions that have
taken place since the last time the termination condition was met is contained in num_executions_before_finished
, and is reset to 0 each time the termination condition is met.
Note
Even after its termination condition is met, a TransferMechanism will continue to execute if it is called again, carrying out one step of integration each time it is called. This can be useful in cases where the initial execution of the Mechanism is meant to bring it to some state (e.g., as an initial “settling process”), after which subsequent executions are meant to occur in step with the execution of other Mechanisms in a Composition (see example below).
By default, execute_until_finished
is True, so that when integrator_mode
is set to True a TransferMechanism will execute until it terminates, using a
convergence criterion. However, the Mechanism’s method of termination
can be configured using its termination_measure
and termination_comparison_op
Parameters can be used to congifure other termination conditions.
There are two broad types of termination condition: convergence and boundary termination.
Convergence termination – execution terminates based on the difference between the TransferMechanism’s current
value
and its previous_value. This is implemented by specifying termination_measure
with a function that accepts a 2d array with two items (1d arrays) as its
argument, and returns a scalar (the default for a TransferMechanism is the Distance
Function with MAX_ABS_DIFF
as its metric). After each execution, the function is passed the Mechanism’s current
value
as well as its previous_value, and the scalar returned is compared to
termination_threshold
using the comparison
operator specified by termination_comparison_op
(which is
LESS_THAN_OR_EQUAL by default). Execution continues until this returns True. A Distance
Function with other
metrics (e.g., ENERGY or ENTROPY) can be specified as the termination_measure, as can any other function
that accepts a single argument that is a 2d array with two entries.
Boundary termination – Two types of boundaries can be specified: value or time.
Termination by value. This terminates execution when the Mechanism’s
value
reaches the the value specified by thetermination_threshold
Parameter. This is implemented by specifyingtermination_measure
with a function that accepts a 2d array with a single entry as its argument and returns a scalar. The single entry is the TransferMechanism’s currentvalue
(that is,previous_value
is ignored). After each execution, the function is passed the Mechanism’s currentvalue
, and the scalar returned is compared totermination_threshold
using the comparison operator specified bytermination_comparison_op
. Execution continues until this returns True.Termination by time. This terminates execution when the Mechanism has executed at least a number of times equal to
termination_threshold
at a particular TimeScale (e.g., within aRUN
or aTRIAL
). This is specified by assigning aTimeScale
totermination_measure
; execution terminates when the number of executions at that TimeScale equals thetermination_threshold
. Note that, in this case,termination_comparison_op
is automatically set to GREATER_THAN_OR_EQUAL.
Examples
Examples of Creating a TransferMechanism¶
Function Specification
The function of a TransferMechanism can be specified as the name of a Function class:
>>> import psyneulink as pnl
>>> my_linear_transfer_mechanism = pnl.TransferMechanism(function=pnl.Linear)
or using the constructor for a TransferFunction
, in which case its Parameters can also be specified:
>>> my_logistic_tm = pnl.TransferMechanism(function=pnl.Logistic(gain=1.0, bias=-4))
Integrator Mode
The integrator_mode argument allows the TransferMechanism to operate in either an “instantaneous” or
“time averaged” manner. By default, integrator_mode
is set to False, meaning
execution is instantaneous. In order to switch to time averaging, the integrator_mode argument of the constructor
must be set to True.
>>> my_logistic_tm = pnl.TransferMechanism(function=pnl.Logistic(gain=1.0, bias=-4),
... integrator_mode=True)
When integrator_mode
is True, the TransferMechanism uses its integrator_function
to integrate its variable on each execution. The output of the
integrator_function
is then used as the input to function
.
Examples of Execution¶
Without Integration¶
If integrator_mode
is False (the default), then the TransferMechanism updates its
value
and the value
of its output_ports
without using its integrator_function
, as in the following example:
# >>> my_mech = pnl.TransferMechanism(input_shapes=2)
# >>> my_mech.execute([0.5, 1])
# array([[0.5, 1. ]])
>>> my_logistic_tm = pnl.TransferMechanism(function=pnl.Logistic,
... input_shapes=3)
>>> my_logistic_tm.execute([-2.0, 0, 2.0])
array([[0.11920292, 0.5 , 0.88079708]])
Notice that the result is the full logistic transform of the input (i.e., no integration occured). Noise can also be
added to the result. It can be specified as a float, and array, or function. If it is a float or list of floats,
the value is simply added to the result, as shown in the example below, that uses the TransferMechanism’s default
function
, Linear
:
>>> my_linear_tm = pnl.TransferMechanism(input_shapes=3,
... noise=2.0)
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[3., 3., 3.]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[3., 3., 3.]])
Since by default Linear
uses a slope
of 1
and intercept <Linear.intercept
of 0
,
the result is the same as the input, plus the value specified for noise. A list can also be used to specify
noise (it must be the same length as the Mechanism’s variable
), in which case each
element is applied Hadamard (elementwise) to the result, as shown here:
>>> my_linear_tm.noise.base = [1.0,1.2,.9]
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[2. , 2.2, 1.9]])
While specifying noise as a constant (or a list of constantss) is not particularly useful, it can be replaced by any
function that specifies a float, for example a DistributionFunction
. As with numerical values, if a single function
is specified, it is applied to all elements; however, on each execution, the function is executed indpendently for
each element. This is shown below using the NormalDist
function:
>>> my_linear_tm = pnl.TransferMechanism(input_shapes=3,
... noise=pnl.NormalDist)
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[2.1576537 , 1.60782117, 0.75840058]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[2.20656132, 2.71995896, 0.57600537]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[1.03826716, 0.56148871, 0.8394907 ]])
Notice that each element was assigned a different random value for its noise, and that these also varied across executions. Notice that since only a single function was specified, it could be the name of a class. Functions can also be used in a list to specify noise, together with other functions or with numeric values; however, when used in a list, functions must be instances, as shown below:
>>> my_linear_tm = pnl.TransferMechanism(input_shapes=3,
... noise=[pnl.NormalDist(), pnl.UniformDist(), 3.0])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[-0.22503678, 1.36995517, 4. ]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[2.08371805, 1.60392004, 4. ]])
Notice that since noise is a modulable Parameter, assigning it a value after the TransferMechanism has been constructed must be done to its base value (see Modulation for additional information).
Finally, clipping
can also be used to cap the result to within specified bounds:
>>> my_linear_tm.clip = (.5, 1.2)
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[1.2, 1.2, 1.2]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[1.2 , 1.06552886, 1.2 ]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[0.5 , 1.01316799, 1.2 ]])
Note that the bounds specified in clip apply to all elements of the result if it is an array.
With Integration¶
The following examples illustate the execution of a TransferMechanism with integrator_mode
set to True. For convenience, a TransferMechanism has three Parameters that
are used by most IntegratorFunctions, and that can be used to configure integration:initial_value
, integration_rate
, and noise
. If any of these are specified in the TransferMechanism’s constructor, their value is
used to specify the corresponding parameter of its integrator_function
.
In the following example, my_linear_tm
is assigned Linear
as its primary function
,
congifured to transform arrays of size
3, with an initial_value of [0.1, 0.5, 0.9] and an integration_rate
of 0.5, that are passed as the values for the initializer
and rate
Parameters of its integrator_function
Parameters, respectively. Since, its integrator_function
is not specified,
the default for a TransferMechanism is used, which is AdaptiveIntegrator
. This integrates its input, returning
results that begin close to its initializer
and asymptotically approach the value
of the current input, which in this example is [1.0, 1.0, 1,0] for each execution:
>>> my_linear_tm = pnl.TransferMechanism(input_shapes=3,
... function=pnl.Linear,
... integrator_mode=True,
... initial_value=np.array([[0.1, 0.5, 0.9]]),
... integration_rate=0.5)
>>> my_linear_tm.integrator_function.initializer
array([[0.1, 0.5, 0.9]])
>>> my_linear_tm.integrator_function.previous_value
array([[0.1, 0.5, 0.9]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[0.55, 0.75, 0.95]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[0.775, 0.875, 0.975]])
>>> my_linear_tm.execute([1.0, 1.0, 1.0])
array([[0.8875, 0.9375, 0.9875]])
Notice that specifying [[0.1, 0.5, 0.9]]
as the initial_value for my_linear_tm
assigns it both as the value
of the integrator_function
’s initializer
Parameter, and also as its previous_value
which is used in the first step of
integration when my_linear_tm
is executed. For an AdaptiveIntegrator
, each step of integration returns a
result that is its previous_value
+ (rate *
previous_value
- input), asymtotically approaching the input.
In the following example, both the TransferMechanism’s integration_rate and its integrator_function
’s rate are specified:
>>> my_linear_tm = pnl.TransferMechanism(integrator_function=AdaptiveIntegrator(rate=0.3),
... integration_rate=0.1)
>>> my_linear_tm.integration_rate
(TransferMechanism TransferMechanism-8):
integration_rate.base: 0.3
integration_rate.modulated: [0.3]
Notice that the value specified for the TransferMechanism integrator integrator_function
(0.3
) takes precendence, and is assigned as the value of the
TransferMechanism’s integration_rate
, overriding the specified value (0.1
).
The same applies for the specification of the TransferMechanism’s initial_value argument and the initializer
for its integration_function
. Notice also that two values are reported for
the Mechanism’s integration_rate
. This is because this is a modulable Parameter. The integration_rate.base
is the one that is assigned;
integration_rate.modulated
reports the value that was actually used when the Mechanism was last executed;
this is the same as the base value if the Parameter is not subject to modulation; if the Parameter is subject to
modulation <ModulatorySignal_Modulation>`, then the modulated value will be the base value modified by any
modulatory signals that project to the Mechanism for that Parameter.
Initializing, Resetting and Resuming Integration¶
When integrator_mode
is True, the state of integration can be initialized
by specifying its initial_value
using the initial_value argument in the
constructor, as shown in the following example:
>>> my_linear_tm = pnl.TransferMechanism(function=pnl.Linear,
... integrator_mode=True,
... integration_rate=0.1,
... initial_value=np.array([[0.2]]))
>>> my_linear_tm.integrator_function.previous_value
array([[0.2]])
It will then begin integration at that point. The result after each execution is the integrated value
of the input and its integrator_function
’s previous_value
:
>>> my_linear_tm.execute(0.5)
array([[0.23]])
>>> my_linear_tm.execute(0.5)
array([[0.257]])
>>> my_linear_tm.execute(0.5)
array([[0.2813]])
The TransferMechanism’s reset
method can be used to restart integration from its
initial_value
or some other one. For example, calling reset
without an argument resets the starting point of integration for
my_linear_tm
back to 0.2
, and if it is executed trials
it produes the same results as
the first 3 executions:
>>> my_linear_tm.integrator_function.reset()
[array([[0.2]])]
>>> my_linear_tm.execute(0.5)
array([[0.23]])
>>> my_linear_tm.execute(0.5)
array([[0.257]])
>>> my_linear_tm.execute(0.5)
array([[0.2813]])
The reset
method can also be used to start integration at a specified value, by providing
it as an argument to the method:
>>> my_linear_tm.integrator_function.reset([0.4])
[array([0.4])]
>>> my_linear_tm.execute(0.5)
array([[0.41]])
>>> my_linear_tm.execute(0.5)
array([[0.419]])
If integration is suspended (by changing integrator_mode
from True to False),
the value it uses to resume integration (if integrator_mode
is reassigned as
True) can be specified using the on_resume_integrator_mode
option.
If it is set to RESET, it will use initial_value
to resume integration, just as
if reset()
had been called. If it is set to CURRENT_VALUE (the default), it will resume
integration using the current value
of the Mechanism, irrespective of the integrator_function
’s previous_value
at the point at which
integration was last suspended, as shown below:
>>> my_linear_tm.integrator_mode = False
>>> my_linear_tm.execute(0.2)
array([[0.2]])
>>> my_linear_tm.execute(0.2)
array([[0.2]])
>>> my_linear_tm.on_resume_integrator_mode = pnl.CURRENT_VALUE
>>> my_linear_tm.integrator_mode = True
>>> my_linear_tm.execute(0.5)
array([[0.23]])
>>> my_linear_tm.execute(0.5)
array([[0.257]])
Notice that, with on_resume_integrator_mode
set to CURRENT_VALUE,
when integrator_mode
is set back to True, integration proceeds from the most
recent value of my_linear_tem
. In contrast, if on_resume_integrator_mode
is set to LAST_INTEGRATED_VALUE, integration resumes using the
integrator_function
’s previous_value IntegratorFunction.previous_value
at
the point at which integration was last suspended, irrespective of interverning executions:
>>> my_linear_tm.on_resume_integrator_mode = pnl.LAST_INTEGRATED_VALUE
>>> my_linear_tm.integrator_mode = False
>>> my_linear_tm.execute(1.0)
array([[1.]])
>>> my_linear_tm.integrator_mode = True
>>> my_linear_tm.execute(0.5)
array([[0.2813]])
>>> my_linear_tm.execute(0.5)
array([[0.30317]])
Notice in this case that, even though the most recent value of my_linear_tm
is 1.0
, when integrator_mode
is set back to True, integration resumes from the most recent value when it was
last True (in this case, where it left off in the preceding example, 0.257
).
Terminating Integration¶
Termination by value. This terminates execution when the Mechanism’s value
reaches the
the value specified by the threshold argument. This is implemented by specifying termination_measure with
a function that accepts a 2d array with a single entry as its argument and returns a scalar. The single
entry is the TransferMechanism’s current value
(that is, its previous_value
is ignored). After each execution, the function is passed the Mechanism’s current value
,
and the scalar returned is compared to termination_threshold using the comparison operator specified by
termination_comparison_op. Execution continues until this returns True, as in the following example:
>>> my_mech = pnl.TransferMechanism(input_shapes=2,
... integrator_mode=True,
... termination_measure=max,
... termination_threshold=0.9,
... termination_comparison_op=pnl.GREATER_THAN_OR_EQUAL)
>>> my_mech.execute([0.5, 1])
array([[0.46875, 0.9375 ]])
>>> my_mech.num_executions_before_finished
4
Here, my_mech
continued to execute for 5
times, until the element of the Mechanism’s value
with the greatest value exceeded 0.9
. Note that GREATER_THAN_EQUAL is a keyword for
the string “>=”, which is a key in the comparison_operators
dict for the Python operator.ge
; any of these
can be used to specify termination_comparison_op).
Termination by time. This terminates execution when the Mechanism has executed at least a number of times equal
to the threshold at a particular TimeScale (e.g., within a RUN
or a TRIAL
). This is
specified by assigning a TimeScale
to termination_measure; execution terminates when the number of
executions at that TimeScale equals the termination_threshold. Note that, in this case,
the termination_comparison_op argument is ignored (the termination_comparison_op
is automatically set to GREATER_THAN_OR_EQUAL). For example,
my_mech
is configured below to execute at least twice per trial:
>>> my_mech = pnl.TransferMechanism(input_shapes=2,
... integrator_mode=True,
... termination_measure=TimeScale.TRIAL,
... termination_threshold=2)
>>> my_mech.execute([0.5, 1])
array([[0.375, 0.75 ]])
>>> my_mech.num_executions_before_finished
2
As noted above, it will continue to execute if it is called again, but only once per call:
>>> my_mech.execute([0.5, 1])
array([[0.4375, 0.875 ]])
>>> my_mech.num_executions_before_finished
1
>>> my_mech.execute([0.5, 1])
array([[0.46875, 0.9375 ]])
>>> my_mech.num_executions_before_finished
1
In the following example, this behavior is exploited to allow a recurrent form of TransferMechanism (attention
)
to integrate for a fixed number of steps (e.g., to simulate the time taken to encode an instruction regarding the
which feature of the stimulus should be attended) before a stimulus is presented, and then allowing that
Mechanism to continue to integrate the instruction and impact stimulus processing once the stimulus is presented:
>>> stim_input = pnl.ProcessingMechanism(input_shapes=2)
>>> stim_percept = pnl.TransferMechanism(input_shapes=2, function=pnl.Logistic)
>>> decision = pnl.TransferMechanism(name='Decision', input_shapes=2,
... integrator_mode=True,
... execute_until_finished=False,
... termination_threshold=0.65,
... termination_measure=max,
... termination_comparison_op=pnl.GREATER_THAN)
>>> instruction_input = pnl.ProcessingMechanism(input_shapes=2, function=pnl.Linear(slope=10))
>>> attention = pnl.LCAMechanism(name='Attention', input_shapes=2, function=pnl.Logistic,
... leak=8, competition=8, self_excitation=0, time_step_size=.1,
... termination_threshold=3,
... termination_measure = pnl.TimeScale.TRIAL)
>>> response = pnl.ProcessingMechanism(name='Response', input_shapes=2)
...
>>> comp = pnl.Composition()
>>> comp.add_linear_processing_pathway([stim_input, [[1,-1],[-1,1]], stim_percept, decision, response])
>>> comp.add_linear_processing_pathway([instruction_input, attention, stim_percept])
>>> comp.scheduler.add_condition(response, pnl.WhenFinished(decision))
...
>>> stim_percept.set_log_conditions([pnl.RESULT])
>>> attention.set_log_conditions([pnl.RESULT])
>>> decision.set_log_conditions([pnl.RESULT])
>>> response.set_log_conditions(['OutputPort-0'])
...
>>> inputs = {stim_input: [[1, 1], [1, 1]],
... instruction_input: [[1, -1], [-1, 1]]}
>>> comp.run(inputs=inputs)
This example implements a simple model of attentional selection in perceptual decision making. In the model,
stim_input
represents the stimulus input, which is passed to stim_percept
, which also receives input
from the attention
Mechanism. stim_percpt passes its output to ``decision
, which integrates its input
until one of the state_features of the input (the first or second) reaches the threshold of 0.65, at which point
response
executes (specified by the condition (reponse, WhenFinished(decision)
). In addition to the
stim_input
, the model an instruction on each trial in instruction_input
that specifies which feature of
the stimulus (i.e., the first or second element) should be “attended”. This is passed to the attention
Mechanism, which uses it to select which feature of stim_percept
should be passed to decision
, and thereby
determine the response. Like the decision
Mechanism, the attention
Mechanism integrates its input.
However, its threshold_measure is specified as TimeScale.TRIAL
and its threshold as 3
, so it
carries out 3 steps of integration the first time it is executed in each trial. Thus, when the input is presented
at the beginning of each trial, first stim_input
and instruction_input
execute. Then attention
executes, but stim_percept
does not yet do so, since it receives input from attention
and thus must wait
for that to execute first. When attention
executes, it carries out its three steps of integration,
(giving it a chance to “encode” the instruction before the stimulus is processed by stim_percept
). Then
stim_percept
executes, followed by decision
. However, the latter carries out only one step of integration,
since its execute_until_finished is set to False. If its output does not meet its termination condition after
that one step of integration, then response
does not execute, since it has been assigned a condition that
requires decision
to terminate before it does so. As a result, since response
has not executed, the trial
continues. On the next pass, attention
carries out only one step of integration, since its termination
condition has already been met, as does decision
since its termination condition has not yet been met. If
it is met, then response
executes and the trial ends (since all Mechanisms have now had an opportunity to
execute). The value of the attention
and decision
Mechanisms after each execution are shown below:
>>> attention.log.print_entries(display=[pnl.TIME, pnl.VALUE])
Log for Attention:
Logged Item: Time Value
'RESULT' 0:0:0:1 [0.64565631 0.19781611] # Trial 0
'RESULT' 0:0:0:1 [0.72347147 0.1422746 ]
'RESULT' 0:0:0:1 [0.74621565 0.1258587 ]
'RESULT' 0:0:1:1 [0.75306362 0.1208305 ]
'RESULT' 0:0:2:1 [0.75516272 0.11926922]
'RESULT' 0:0:3:1 [0.75581168 0.11878318]
'RESULT' 0:0:4:1 [0.75601306 0.11863188]
'RESULT' 0:1:0:1 [0.2955214 0.49852489] # Trial 1
'RESULT' 0:1:0:1 [0.17185129 0.68187518]
'RESULT' 0:1:0:1 [0.13470156 0.73399742]
'RESULT' 0:1:1:1 [0.1235536 0.74936691]
'RESULT' 0:1:2:1 [0.12011584 0.75402671]
>>> decision.log.print_entries(display=[pnl.TIME, pnl.VALUE])
Log for Decision:
Logged Item: Time Value
'RESULT' 0:0:0:3 [0.33917677 0.2657116 ] # Trial 0
'RESULT' 0:0:1:3 [0.50951133 0.39794126]
'RESULT' 0:0:2:3 [0.59490696 0.46386164]
'RESULT' 0:0:3:3 [0.63767534 0.49676128]
'RESULT' 0:0:4:3 [0.65908142 0.51319226]
'RESULT' 0:1:0:3 [0.59635299 0.59443706] # Trial 1
'RESULT' 0:1:1:3 [0.56360108 0.6367389 ]
'RESULT' 0:1:2:3 [0.54679699 0.65839718]
>>> response.log.print_entries(display=[pnl.TIME, pnl.VALUE])
Log for Response:
Logged Item: Time Value
'OutputPort-0' 0:0:4:4 [0.65908142 0.51319226] # Trial 0
'OutputPort-0' 0:1:2:4 [0.54679699 0.65839718] # Trial 1
The Time signatures are run:trial:pass:time_step
. Note that attention
always executes in time_step
1
(after stim_input
and instruction_input
which execute in time_step 0). In trial 0, attention
executes three times in pass 0 (to reach its specified threshold), and then again in passes 1, 2 and 3 and 4
along with decision
(which executes in time_step 3, after stim_percept
in time_step 2),
as the trial continues and decision
executes until reaching its threshold. Note that response
executed
only executed in pass 4, since it depends on the termination of decision
. Note also that in trial 1
attention
executes 3 times in pass 0 as it did in trial 0; however, decision
executes only 3 times
since it begins closer to its threshold in that trial.
Class Reference¶
- exception psyneulink.core.components.mechanisms.processing.transfermechanism.TransferError(message, component=None)¶
- class psyneulink.core.components.mechanisms.processing.transfermechanism.TransferMechanism(default_variable=None, input_shapes=None, input_ports=None, function=None, noise=None, clip=None, integrator_mode=None, integrator_function=None, initial_value=None, integration_rate=None, on_resume_integrator_mode=None, termination_measure=None, termination_threshold=None, termination_comparison_op=None, output_ports=None, params=None, name=None, prefs=None, **kwargs)¶
Subclass of ProcessingMechanism that performs a simple transform of its input. See Mechanism for additional arguments and attributes.
- Parameters
noise (float, function, or a list or array containing either or both : default 0.0) – specifies a value to be added to the result of the TransferMechanism’s
function
or itsintegrator_function
, depending on whetherintegrator_mode
isTrue
orFalse
(seenoise
for details). If noise is specified as a single function, it can be a reference to a Function class or an instance of one; if a function is used in a list, it must be an instance.clip (tuple(float, float) or list [float, float] : default None) – specifies the allowable range for the result of
function
(seeclip
for details).integrator_mode (bool : False) – specifies whether or not the TransferMechanism is executed with (True) or without (False) integrating its
variable
using itsintegrator_function
before executing its primaryfunction
(see Execution for additional details).integrator_function (IntegratorFunction : default AdaptiveIntegrator) – specifies
IntegratorFunction
to use whenintegrator_mode
is True (see Execution with Integration for additional details).initial_value (value, list or np.ndarray : default Transfer_DEFAULT_BIAS) – specifies the starting value for integration when
integrator_mode
is True; must be the same lengthvariable
(see Initialization, Resetting and Resuming Integration for additional details).integration_rate (float : default 0.5) – specifies the rate of integration of when the TransferMechanism when
integrator_mode
is True (see Integration for additional details).on_resume_integrator_mode (CURRENT_VALUE, LAST_INTEGRATED_VALUE, or RESET : default CURRENT_VALUE) – specifies value used by the
integrator_function
when integration is resumed (see resuming integration for additional details).termination_measure (function or TimesScale : default Distance(metric=MAX_ABS_DIFF)) – specifies measure used to determine when execution of TransferMechanism is complete if
execute_until_finished
is True. If it is a function, it must take at least one argument, and optionally a second, both of which must be arrays, and must return either another array or a scalar; seetermination_measure
for additional details.termination_threshold (None or float : default None) – specifies value against which
termination_measure_value
is compared to determine when execution of TransferMechanism is complete; seetermination_measure
for additional details.termination_comparison_op (comparator keyword : default LESS_THAN_OR_EQUAL) – specifies how
termination_measure_value
is compared withtermination_threshold
to determine when execution of TransferMechanism is complete; seetermination_measure
for additional details.output_ports (str, list or np.ndarray : default RESULTS) – specifies the OutputPorts for the TransferMechanism; the keyword RESULTS (the default) specifies that one OutputPort be generated for each InputPort specified in the input_ports argument (see OutputPorts for additional details, and note <TransferMechanism_OutputPorts_Note>` in particular).
- noise¶
value is applied to the result of
integrator_function
ifintegrator_mode
is False; otherwise it is passed as thenoise
Parameter tointegrator_function
. If noise is a float or function, it is added to all elements of the array being transformed; if it is a function, it is executed independently for each element each time the TransferMechanism is executed. If noise is an array, it is applied Hadamard (elementwise) to the array being transformed; again, each function is executed independently for each corresponding element of the array each time the Mechanism is executed.Note
If noise is specified as a float or function in the constructor for the TransferMechanism, the noise Parameter cannot later be specified as a list or array, and vice versa.
Hint
To generate random noise that varies for every execution and across all elements of an array, a
DistributionFunction
should be used, that generates a new value on each execution. If noise is specified as a float, a function with a fixed output, or an array of either of these, then noise is simply an offset that is the same across all elements and executions.- Type
float, function or an array containing either or both
- clip¶
determines the allowable range for all elements of the result of
function
. The 1st item (index 0) determines the minimum allowable value of the result, and the 2nd item (index 1) determines the maximum allowable value; any element of the result that exceeds the specified minimum or maximum value is set to the value of clip that it exceeds.- Type
tuple(float, float)
- integrator_mode¶
determines whether the TransferMechanism uses its
integrator_function
to integrate itsvariable
when it executes (see TransferMechanism_Execution for additional details).- Type
bool
- integrator_function¶
the
IntegratorFunction
used whenintegrator_mode
is set toTrue
(see Integration for details).- Type
- initial_value¶
determines the starting value for the
integrator_function
whenintegrator_mode
isTrue
(see Initialization, Resetting and Resuming Integration for additional details).- Type
value, list or np.ndarray
- integration_rate¶
determines the rate at which the TransferMechanism’s variable is integrated when it is executed with
integrator_mode
set toTrue
; a higher value specifies a faster rate (see Integration for additional details).- Type
float
- on_resume_integrator_mode¶
determines value used by the
integrator_function
when integration is resumed, and must be one of the following keywords: CURRENT_VALUE, LAST_INTEGRATED_VALUE, or RESET (see resuming integration for additional details).- Type
CURRENT_VALUE, LAST_INTEGRATED_VALUE, or RESET
- termination_measure¶
used to determine when execution of the TransferMechanism is complete (i.e.,
is_finished
is True), ifexecute_until_finished
is True. If it is aTimeScale
, then execution terminates when the value of the Mechanism’s num_executions at that TimeScale is is equal totermination_threshold
. If it is a function, it is passed thevalue
andprevious_value
of the TransferMechanism; its result (termination_measure_value
) is compared withtermination_threshold
usingTransferMechanism.termination_comparison_op
, the result of which is used as the value ofis_finished
.Note
A Mechanism’s previous value is distinct from the
previous_value
attribute of itsintegrator_function
.- Type
function or TimeScale
- termination_measure_value¶
value returned by
termination_measure
; used to determine whenis_finished
is True.- Type
array or scalar
- termination_threshold¶
value with which
termination_measure_value
is compared to determine when execution of TransferMechanism is complete ifexecute_until_finished
is True.- Type
None or float
- termination_comparison_op¶
used to compare
termination_measure_value
withtermination_threshold
to determine when execution of TransferMechanism is complete ifexecute_until_finished
is True.- Type
Comparator
- standard_output_ports¶
list of Standard OutputPort that includes the following in addition to the
standard_output_ports
of a ProcessingMechanism:- COMBINE1d array
Element-wise (Hadamard) sum of all items of the TransferMechanism’s
value
(requires that they all have the same dimensionality).
- Type
list[dict]
- Returns
instance of TransferMechanism
- Return type
- _validate_params(request_set, target_set=None, context=None)¶
Validate FUNCTION and Mechanism params
- _instantiate_parameter_ports(function=None, context=None)¶
Call Port._instantiate_parameter_ports to instantiate a ParameterPort for each parameter with modulable=True
- This is a stub, implemented to allow Mechanism subclasses to override _instantiate_parameter_ports
or process InputPorts before and/or after call to _instantiate_parameter_ports :param function:
- _instantiate_output_ports(context=None)¶
Call Port._instantiate_output_ports to instantiate orderedDict of OutputPort(s)
- This is a stub, implemented to allow Mechanism subclasses to override _instantiate_output_ports
or process InputPorts before and/or after call to _instantiate_output_ports
- _execute(variable=None, context=None, runtime_params=None)¶
Execute TransferMechanism function and return transform of input
- reset(*args, force=False, context=None, **kwargs)¶
Reset
value
if Mechanisms is stateful.If the mechanism’s
function
is anIntegratorFunction
, or if the mechanism has andintegrator_function
(see TransferMechanism), this method effectively begins the function’s accumulation over again at the specified value, and updates related attributes on the mechanism. It also clears thevalue
history
, thus effectively setting the previous value toNone
.If the mechanism’s
function
is anIntegratorFunction
, itsreset
method:Calls the function’s own
reset
method (see Note below for details)Sets the mechanism’s
value
to the output of the function’s reset methodUpdates its
output ports
based on its newvalue
If the mechanism has an
integrator_function
, itsreset
method:(1) Calls the `integrator_function's <TransferMechanism.integrator_function>` own `reset <IntegratorFunction.reset>` method (see Note below for details) (2) Executes its `function <Mechanism_Base.function>` using the output of the `integrator_function's <TransferMechanism.integrator_function>` `reset <IntegratorFunction.reset>` method as the function's variable (3) Sets the mechanism's `value <Mechanism_Base.value>` to the output of its function (4) Updates its `output ports <Mechanism_Base.output_port>` based on its new `value <Mechanism_Base.value>`
Note
The reset method of an IntegratorFunction Function typically resets the function’s
previous_value
(and any otherstateful_attributes
) andvalue
to the quantity (or quantities) specified. Ifreset
is called without arguments, theinitializer
value (or the values of each of the attributes ininitializers
) is used instead. Thereset
method may vary across different Integrators. See individual functions for details on theirstateful_attributes
, as well as other reinitialization steps that the reset method may carry out.
- _parse_function_variable(variable, context=None)¶
Parses the variable passed in to a Component into a function_variable that can be used with the Function associated with this Component
- _instantiate_attributes_after_function(context=None)¶
Determine numberr of items expected by termination_measure
- _report_mechanism_execution(input, params=None, output=None, context=None)¶
Override super to report previous_input rather than input, and selected params
- is_finished(context=None)¶
Returns True when value of Mechanism reaches threhsold or if threshold is None.
- Note: if threshold is None or Mechanism not in integartor_mode,
implements single update (cycle) per call to _execute method (equivalent to setting Component.execute_until_finished = False)