Skip to content

Commit

Permalink
Refactor/execution mode compiled (#2550)
Browse files Browse the repository at this point in the history
* • composition.py
  - learn(): add error for use of ExecutionMode.LLVM or ExecutionMode.PyTorch

• autodiffcomposition.py
  - learn(): add warning for use of ExecutionMode.Python

• test_learning.py:
  - add test_execution_mode_pytorch_and_LLVM_errors

• test_autodiffcomposition.py:
  - add test_execution_mode_python_warning

* [skip ci]

* [skip ci]

* • llvm/__init__.py
  - add ExecutionMode.COMPILED (~ Python | PyTorch).

• compositon.py, autodiffcomposition.py, compositionrunner.py:
  - modifed to sue ExecutionMode.COMPILED for condionals

• test_autodiffcomposition.py:
  - test_execution_mode_python_error() replaces test_execution_mode_python_warning()

* -

* • Modification per Jan's suggestions

* • test_autodiffcomposition.py
  - test_execution_mode_python_error(): fix bug
  • Loading branch information
jdcpni authored Nov 25, 2022
1 parent 26bf706 commit 5d4ead3
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 26 deletions.
4 changes: 2 additions & 2 deletions conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ def pytest_generate_tests(metafunc):

if "autodiff_mode" in metafunc.fixturenames:
auto_modes = [
pnlvm.ExecutionMode.Python,
# pnlvm.ExecutionMode.PyTorch,
# pnlvm.ExecutionMode.Python,
pnlvm.ExecutionMode.PyTorch,
pytest.param(pnlvm.ExecutionMode.LLVMRun, marks=pytest.mark.llvm)
]
metafunc.parametrize("autodiff_mode", auto_modes)
Expand Down
23 changes: 13 additions & 10 deletions psyneulink/core/compositions/composition.py
Original file line number Diff line number Diff line change
Expand Up @@ -10395,7 +10395,7 @@ def learn(
from psyneulink.library.compositions import AutodiffComposition
runner = CompositionRunner(self)

if (execution_mode in {pnlvm.ExecutionMode.PyTorch, pnlvm.ExecutionMode.LLVM}
if ((execution_mode is not pnlvm.ExecutionMode.Python)
and not isinstance(self, AutodiffComposition)):
raise CompositionError(f"ExecutionMode.{execution_mode.name} cannot be used in the learn() method of "
f"'{self.name}' because it is not an {AutodiffComposition.componentCategory}")
Expand Down Expand Up @@ -10477,11 +10477,14 @@ def _execute_controller(self,
context=context,
node=self.controller)

if self.controller and not execution_mode:
if self.controller and not execution_mode & pnlvm.ExecutionMode.COMPILED:
context.execution_phase = ContextFlags.PROCESSING
self.controller.execute(context=context)

if execution_mode:
else:
assert (execution_mode == pnlvm.ExecutionMode.LLVM
or execution_mode & pnlvm.ExecutionMode._Fallback),\
f"PROGRAM ERROR: Unrecognized compiled execution_mode: '{execution_mode}'."
_comp_ex.execute_node(self.controller, context=context)

context.remove_flag(ContextFlags.PROCESSING)
Expand Down Expand Up @@ -10705,7 +10708,7 @@ def execute(
# Run compiled execution (if compiled execution was requested
# NOTE: This should be as high up as possible,
# but still after the context has been initialized
if execution_mode:
if execution_mode & pnlvm.ExecutionMode.COMPILED:
is_simulation = (context is not None and
ContextFlags.SIMULATION_MODE in context.runmode)
# Try running in Exec mode first
Expand Down Expand Up @@ -10819,7 +10822,7 @@ def execute(
inputs = self._validate_execution_inputs(inputs)
build_CIM_input = self._build_variable_for_input_CIM(inputs)

if execution_mode:
if execution_mode & pnlvm.ExecutionMode.COMPILED:
_comp_ex.execute_node(self.input_CIM, inputs, context)
# FIXME: parameter_CIM should be executed here as well,
# but node execution of nested compositions with
Expand Down Expand Up @@ -11024,7 +11027,7 @@ def execute(
# This ensures that the order in which nodes execute does not affect the results of this timestep
frozen_values = {}
new_values = {}
if execution_mode:
if execution_mode & pnlvm.ExecutionMode.COMPILED:
_comp_ex.freeze_values()

# PURGE LEARNING IF NOT ENABLED ----------------------------------------------------------------
Expand Down Expand Up @@ -11106,7 +11109,7 @@ def execute(
context.replace_flag(ContextFlags.PROCESSING, ContextFlags.LEARNING)

# Execute Mechanism
if execution_mode:
if execution_mode & pnlvm.ExecutionMode.COMPILED:
_comp_ex.execute_node(node, context=context)
else:
if node is not self.controller:
Expand All @@ -11129,7 +11132,7 @@ def execute(

elif isinstance(node, Composition):

if execution_mode:
if execution_mode & pnlvm.ExecutionMode.COMPILED:
# Invoking nested composition passes data via Python
# structures. Make sure all sources get their latest values
srcs = (proj.sender.owner for proj in node.input_CIM.afferents)
Expand Down Expand Up @@ -11168,7 +11171,7 @@ def execute(
execution_mode=nested_execution_mode)

# Get output info from nested execution
if execution_mode:
if execution_mode & pnlvm.ExecutionMode.COMPILED:
# Update result in binary data structure
_comp_ex.insert_node_output(node, ret)

Expand Down Expand Up @@ -11310,7 +11313,7 @@ def execute(
context=context)

# Extract result here
if execution_mode:
if execution_mode & pnlvm.ExecutionMode.COMPILED:
_comp_ex.freeze_values()
_comp_ex.execute_node(self.output_CIM, context=context)
report(self,
Expand Down
1 change: 1 addition & 0 deletions psyneulink/core/llvm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ class ExecutionMode(enum.Flag):
LLVMExec = LLVM | _Exec
PTXRun = PTX | _Run
PTXExec = PTX | _Exec
COMPILED = ~ (Python | PyTorch)


_binary_generation = 0
Expand Down
7 changes: 3 additions & 4 deletions psyneulink/library/compositions/autodiffcomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -634,10 +634,9 @@ def learn(self, *args, **kwargs):
if 'execution_mode' in kwargs:
execution_mode = kwargs['execution_mode']
if execution_mode == pnlvm.ExecutionMode.Python:
warnings.warn(f"{self.name}.learn() called with ExecutionMode.Python; "
f"learning will be executed using PyTorch; "
f"should use ExecutionMode.PyTorch for clarity, "
f"or a standard Composition for Python execution.)")
raise AutodiffCompositionError(f"{self.name} is an AutodiffComposition so its learn() "
f"cannot be called with execution_mode = ExecutionMode.Python; "
f"use ExecutionMode.PyTorch or ExecutionMode.LLVMRun.")
# OK, now that the user has been advised to use ExecutionMode.PyTorch and warned *not* to ExecutionMdoe.Python,
# convert ExecutionMode.PyTorch specification to ExecutionMode.Python for internal use (nice, eh?)
if execution_mode == pnlvm.ExecutionMode.PyTorch:
Expand Down
5 changes: 3 additions & 2 deletions psyneulink/library/compositions/compositionrunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ def run_learning(self,
---------
Outputs from the final execution
"""
if not execution_mode:

if not (execution_mode & pnlvm.ExecutionMode.COMPILED):
self._is_llvm_mode = False
else:
self._is_llvm_mode = True
Expand Down Expand Up @@ -195,7 +196,7 @@ def run_learning(self,
raise Exception("The minibatch size cannot be greater than the number of trials.")

early_stopper = None
if patience is not None and not execution_mode:
if patience is not None and not self._is_llvm_mode:
early_stopper = EarlyStopping(min_delta=min_delta, patience=patience)

if callable(stim_input) and not isgeneratorfunction(stim_input):
Expand Down
14 changes: 6 additions & 8 deletions tests/composition/test_autodiffcomposition.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from psyneulink.core.globals.keywords import TRAINING_SET, Loss
from psyneulink.core.components.mechanisms.processing.transfermechanism import TransferMechanism
from psyneulink.core.components.projections.pathway.mappingprojection import MappingProjection
from psyneulink.library.compositions.autodiffcomposition import AutodiffComposition
from psyneulink.library.compositions.autodiffcomposition import AutodiffComposition, AutodiffCompositionError
from psyneulink.core.compositions.report import ReportOutput

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -1770,22 +1770,20 @@ def test_params_stay_separate(self, autodiff_mode):
assert not np.allclose(pt_weights_hid, hid_map.parameters.matrix.get(None))
assert not np.allclose(pt_weights_out, out_map.parameters.matrix.get(None))

def test_execution_mode_python_warning(self):
def test_execution_mode_python_error(self):
A = TransferMechanism(name="learning-process-mech-A")
B = TransferMechanism(name="learning-process-mech-B")
adc = AutodiffComposition(name='AUTODIFFCOMP')
pway = adc.add_backpropagation_learning_pathway(pathway=[A,B])
# Call learn with default_variable specified for target (for comparison with missing target)
with pytest.warns(UserWarning) as warning:
with pytest.raises(AutodiffCompositionError) as error:
adc.learn(inputs={A: 1.0,
pway.target: 0.0},
execution_mode=pnl.ExecutionMode.Python,
num_trials=2)
assert repr(warning[1].message.args[0]) == '\'AUTODIFFCOMP.learn() called with ExecutionMode.Python; ' \
'learning will be executed using PyTorch; should use ' \
'ExecutionMode.PyTorch for clarity, or a standard Composition ' \
'for Python execution.)\''

assert error.value.error_value == 'AUTODIFFCOMP is an AutodiffComposition so its learn() ' \
'cannot be called with execution_mode = ExecutionMode.Python; ' \
'use ExecutionMode.PyTorch or ExecutionMode.LLVMRun.'

@pytest.mark.pytorch
@pytest.mark.actime
Expand Down

0 comments on commit 5d4ead3

Please sign in to comment.