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
indexmust 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_functionas itsinitializerParameter. It can also be specified directly in the initializer argument of the constructor for anIntegratorFunctionassigned 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_valueof 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
resetmethod calls the reset method on itsintegrator_function, which can also be called directly. The key difference is that calling the Mechanism’sresetmethod also executes the Mechanism’sfunctionand updates itsoutput_ports. This is useful if the Mechanism’svalueor that of any of itsoutput_portswill 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
valueof the Mechanism as the starting value for resuming integration;LAST_INTEGRATED_VALUE - resume integration with whatever the
integrator_function’previous_valuewas whenintegrator_modewas last True;RESET - call the
integrator_functionsresetmethod, so that integration resumes usinginitial_valueas 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, itsnoiseandintegration_rateParameters are used to specify thenoiseandinitializerParameters 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_functiontake 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 configure 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
valuereaches the the value specified by thetermination_thresholdParameter. This is implemented by specifyingtermination_measurewith 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_valueis ignored). After each execution, the function is passed the Mechanism’s currentvalue, and the scalar returned is compared totermination_thresholdusing 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_thresholdat a particular TimeScale (e.g., within aRUNor aTRIAL). This is specified by assigning aTimeScaletotermination_measure; execution terminates when the number of executions at that TimeScale equals thetermination_threshold. Note that, in this case,termination_comparison_opis 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 range:
>>> 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 range specified in clip applies 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 integrator_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
functionor itsintegrator_function, depending on whetherintegrator_modeisTrueorFalse(seenoisefor 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(seeclipfor details).integrator_mode (bool : False) – specifies whether or not the TransferMechanism is executed with (True) or without (False) integrating its
variableusing itsintegrator_functionbefore executing its primaryfunction(see Execution for additional details).integrator_function (IntegratorFunction : default AdaptiveIntegrator) – specifies
IntegratorFunctionto use whenintegrator_modeis True (see Execution with Integration for additional details).initial_value (value, list or np.ndarray : 0) – specifies the starting value for integration when
integrator_modeis 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_modeis 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_functionwhen 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_finishedis 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_measurefor additional details.termination_threshold (None or float : default None) – specifies value against which
termination_measure_valueis compared to determine when execution of TransferMechanism is complete; seetermination_measurefor additional details.termination_comparison_op (comparator keyword : default LESS_THAN_OR_EQUAL) – specifies how
termination_measure_valueis compared withtermination_thresholdto determine when execution of TransferMechanism is complete; seetermination_measurefor 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_functionifintegrator_modeis False; otherwise it is passed as thenoiseParameter 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
DistributionFunctionshould 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. If either item isNone, no clipping is performed for that item. If thefunctionreturns an array, the clip is applied elementwise (i.e., the clip is applied to each element of the array independently). If either item is outside the interval of the function’srangeParameter after itsscaleandoffsetParameters have been applied (i.e., \(function.range(lower,upper) * scale + offset\)), a warning is issued and the corresponding items of clip are ignored.- Type:
tuple(float, float)
- integrator_mode¶
determines whether the TransferMechanism uses its
integrator_functionto integrate itsvariablewhen it executes (see TransferMechanism_Execution for additional details).- Type:
bool
- integrator_function¶
the
IntegratorFunctionused whenintegrator_modeis set toTrue(see Integration for details).- Type:
- initial_value¶
determines the starting value for the
integrator_functionwhenintegrator_modeisTrue(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_modeset 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_functionwhen 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_finishedis True), ifexecute_until_finishedis 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 thevalueandprevious_valueof the TransferMechanism; its result (termination_measure_value) is compared withtermination_thresholdusingTransferMechanism.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_valueattribute of itsintegrator_function.- Type:
function or TimeScale
- termination_measure_value¶
value returned by
termination_measure; used to determine whenis_finishedis True.- Type:
array or scalar
- termination_threshold¶
value with which
termination_measure_valueis compared to determine when execution of TransferMechanism is complete ifexecute_until_finishedis True.- Type:
None or float
- termination_comparison_op¶
used to compare
termination_measure_valuewithtermination_thresholdto determine when execution of TransferMechanism is complete ifexecute_until_finishedis True.- Type:
Comparator
- standard_output_ports¶
list of Standard OutputPort that includes the following in addition to the
standard_output_portsof 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_attributes_after_function(context=None)¶
Determine number of items expected by termination_measure and check clip if specified
- _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
valueif Mechanisms is stateful.If the mechanism’s
functionis 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 thevaluehistory, thus effectively setting the previous value toNone.If the mechanism’s
functionis anIntegratorFunction, itsresetmethod:Calls the function’s own
resetmethod (see Note below for details)Sets the mechanism’s
valueto the output of the function’s reset methodUpdates its
output portsbased on its newvalue
If the mechanism has an
integrator_function, itsresetmethod:(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) andvalueto the quantity (or quantities) specified. Ifresetis called without arguments, theinitializervalue (or the values of each of the attributes ininitializers) is used instead. Theresetmethod 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
- _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)