{ "cells": [ { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "*Copyright (C) 2021 Intel Corporation*
\n", "*SPDX-License-Identifier: BSD-3-Clause*
\n", "*See: https://spdx.org/licenses/*\n", "\n", "---\n", "\n", "# Execution\n", "\n", "This tutorial covers how to execute single _Processes_ and networks of _Processes_, how to configure execution, how to pause, resume, and stop execution, and how to manually set up a _Compiler_ and _RunTime_ for more fine-grained control.\n", "\n", "## Recommended tutorials before starting:\n", "\n", "- [Installing Lava](./tutorial01_installing_lava.ipynb \"Tutorial on Installing Lava\")\n", "- [Processes](./tutorial02_processes.ipynb \"Tutorial on Processes\")\n", "- [ProcessModel](./tutorial03_process_models.ipynb \"Tutorial on ProcessModels\")\n", "\n", "## Configuring and starting execution\n", "To start executing a _Process_ call its method `run(condition=..., run_cfg=...)`. The execution must be configured by passing in both a _RunCondition_ and a _RunConfiguration_.\n", "\n", "#### Run conditions\n", "A _RunCondition_ specifies how long a _Process_ is executed.\n", "\n", "The run condition _RunSteps_ executes a _Process_ for a specified number time steps, here 42 in the example below. The execution will automatically pause after the specified number of time steps.\n", "You can also specify whether or not the call to `run()` will block the program flow." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "from lava.magma.core.run_conditions import RunSteps\n", "\n", "run_condition = RunSteps(num_steps=42, blocking=False)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The run condition _RunContinuous_ enables you to run a _Process_ continuously. In this case, the _Process_ will run indefinitely until you explicitly call `pause()` or `stop()` (see below). This call never blocks the program flow (blocking=False)." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "from lava.magma.core.run_conditions import RunContinuous\n", "\n", "run_condition = RunContinuous()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Run configurations\n", "A _RunConfig_ specifies on what devices the _Processes_ should be executed.\n", "Based on the _RunConfig_, a _Process_ selects and initializes exactly one\n", "of its associated [_ProcessModels_](./tutorial03_process_models.ipynb \"Tutorial on ProcessModels\"), which implement the behavior of the _Process_ in a particular programming language and for a particular computing resource.\n", "If the _Process_ has a _SubProcessModel_ composed of other _Processes_, the _RunConfig_ chooses the appropriate _ProcessModel_ implementation of the child _Process_.\n", "\n", "Lava currently supports execution on Loihi 2 using the predefined RunConfig Loihi2HwCfg. Simulation of Loihi executed on a single CPU is possible using the RunConfig Loihi1SimCfg.\n", "We will make more predefined run configurations available with the upcoming support for Loihi 1 and\n", "other devices such as GPUs.\n", "\n", "The example below specifies that the _Process_ (and all its connected _Processes_\n", "and _SubProcesses_) are executed in Python on a CPU." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "from lava.magma.core.run_configs import Loihi1SimCfg\n", "\n", "run_cfg = Loihi1SimCfg()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can now use both a _RunCondition_ and a _RunConfig_ to execute a simple leaky integrate-and-fire (LIF) neuron." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "from lava.proc.lif.process import LIF\n", "from lava.magma.core.run_conditions import RunSteps\n", "from lava.magma.core.run_configs import Loihi1SimCfg\n", "\n", "# create a Process for a LIF neuron\n", "lif = LIF(shape=(1,))\n", "\n", "# execute that Process for 42 time steps in simulation\n", "lif.run(condition=RunSteps(num_steps=42), run_cfg=Loihi1SimCfg())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Running multiple _Processes_\n", "\n", "Calling `run()` on a _Process_ will also execute all _Processes_ that are connected to it. In the example below, three _Processes_ _lif1_, _dense_, and _lif2_ are connected in a sequence. We call `run()` on _Process_ _lif2_. Since _lif2_ is connected to _dense_ and _dense_ is connected to _lif1_, all three _Processes_ will be executed. As demonstrated here, the execution will cover the entire connected network of _Processes_, irrespective of the direction in which the _Processes_ are connected." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from lava.proc.lif.process import LIF\n", "from lava.proc.dense.process import Dense\n", "from lava.magma.core.run_conditions import RunSteps\n", "from lava.magma.core.run_configs import Loihi1SimCfg\n", "\n", "# create processes\n", "lif1 = LIF(shape=(1,))\n", "dense = Dense(weights=np.eye(1))\n", "lif2 = LIF(shape=(1,))\n", "\n", "# connect the OutPort of lif1 to the InPort of dense\n", "lif1.s_out.connect(dense.s_in)\n", "# connect the OutPort of dense to the InPort of lif2\n", "dense.a_out.connect(lif2.a_in)\n", "\n", "# execute Process lif2 and all Processes connected to it (dense, lif1)\n", "lif2.run(condition=RunSteps(num_steps=42), run_cfg=Loihi1SimCfg())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pausing, resuming, and stopping execution\n", "\n", "Another way to execute _Processes_ is to use the _RunCondition_ _RunContinuous_ which runs the network non-blocking until the the execution is paused or stopped by the user.\n", "\n", "Calling the `pause()` method of a _Process_ pauses execution but preserves its state.\n", "The _Process_ can then be inspected and manipulated by the user, as shown in the example below.\n", "\n", "Afterward, execution can be resumed by calling `run()` again.\n", "\n", "Calling the `stop()` method of a _Process_ completely terminates its execution.\n", "Contrary to pausing execution, `stop()` does not preserve the state of the\n", "_Process_. If a _Process_ executed on a hardware device, the connection between\n", "the _Process_ and the device is terminated as well." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0.]\n" ] } ], "source": [ "import numpy as np\n", "from lava.proc.lif.process import LIF\n", "from lava.magma.core.run_conditions import RunContinuous\n", "from lava.magma.core.run_configs import Loihi1SimCfg\n", "\n", "lif3 = LIF(shape=(1, ))\n", "\n", "# start continuous execution\n", "lif3.run(condition=RunContinuous(), run_cfg=Loihi1SimCfg())\n", "\n", "# pause execution\n", "lif3.pause()\n", "\n", "# inspect the state of the Process, here, the voltage variable 'v'\n", "print(lif3.v.get())\n", "\n", "# manipulate the state of the Process, here, resetting the voltage to zero\n", "lif3.v.set(np.array([0]))\n", "\n", "# resume continuous execution\n", "lif3.run(condition=RunContinuous(), run_cfg=Loihi1SimCfg())\n", "\n", "# terminate execution;\n", "# after this, you no longer have access to the state of lif\n", "lif3.stop()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Manual compilation and execution\n", "\n", "In many cases, creating an instance of a _Process_ and calling its `run()`\n", "method is all you need to do. Calling `run()` internally first compiles\n", "the _Process_ and then starts execution. These steps can also be manually\n", "invoked in sequence, for instance to inspect or manipulate the _Process_ before\n", "starting execution.\n", "\n", "1. Instantiation stage: This is the call to the init-method of a _Process_,\n", "which instantiates an object of the _Process_." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "from lava.proc.lif.process import LIF\n", "from lava.proc.dense.process import Dense\n", "\n", "lif1 = LIF(shape=(1,))\n", "dense = Dense(weights=np.eye(1))\n", "lif2 = LIF(shape=(1,))" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "2. Configuration stage: After a _Process_ has been instantiated, it can be\n", "configured further through its public API and connected to other _Processes_ via\n", "its _Ports_. In addition, probes can be defined for Lava _Vars_ in order to\n", "record a time series of its evolution during execution." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "# connect the processes\n", "lif1.s_out.connect(dense.s_in)\n", "dense.a_out.connect(lif2.a_in)" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "3. Compile stage: After a _Process_ has been configured, it needs to be compiled to\n", "become executable. After the compilation stage, the state of the _Process_ can\n", "still be manipulated and inspected." ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "from lava.magma.compiler.compiler import Compiler\n", "from lava.magma.core.run_configs import Loihi1SimCfg\n", "\n", "# create a compiler\n", "compiler = Compiler()\n", "\n", "# compile the Process (and all connected Processes) into an executable\n", "executable = compiler.compile(lif2, run_cfg=Loihi1SimCfg())" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "4. Execution stage: When compilation is complete, _Processes_ can be\n", "executed. The execution stage ensures that the (prior) compilation stage has\n", "been completed and otherwise invokes it." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "from lava.magma.runtime.runtime import Runtime\n", "from lava.magma.core.run_conditions import RunSteps\n", "from lava.magma.core.process.message_interface_enum import ActorType\n", "\n", "# create and initialize a runtime\n", "mp = ActorType.MultiProcessing\n", "runtime = Runtime(exe=executable,\n", " message_infrastructure_type=mp)\n", "runtime.initialize()\n", "\n", "# start execution\n", "runtime.start(run_condition=RunSteps(num_steps=42))\n", "\n", "# stop execution\n", "runtime.stop()" ] }, { "cell_type": "markdown", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "The following does all of the above automatically:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "from lava.proc.lif.process import LIF\n", "from lava.proc.dense.process import Dense\n", "from lava.magma.core.run_conditions import RunSteps\n", "from lava.magma.core.run_configs import Loihi1SimCfg\n", "\n", "# create Processes\n", "lif = LIF(shape=(1,))\n", "dense = Dense(weights=np.eye(1))\n", "\n", "# connect Processes\n", "lif.s_out.connect(dense.s_in)\n", "\n", "# execute Processes\n", "lif.run(condition=RunSteps(num_steps=42), run_cfg=Loihi1SimCfg())\n", "\n", "# stop Processes\n", "lif.stop()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How to learn more?\n", "\n", "Learn more about Lava in the next tutorial about how to [transfer data between Processes](./tutorial05_connect_processes.ipynb).\n", "\n", "If you want to find out more about how to compile and execute _Processes_, have a look at the [Lava documentation](https://lava-nc.org/ \"Lava Documentation\") or dive into the [Compiler](https://github.com/lava-nc/lava/tree/main/src/lava/magma/compiler/ \"Compiler Source Code\") and [RunTime source code](https://github.com/lava-nc/lava/tree/main/src/lava/magma/runtime/ \"Runtime Source Code\").\n", "\n", "To receive regular updates on the latest developments and releases of the Lava Software Framework please subscribe to the [INRC newsletter](http://eepurl.com/hJCyhb \"INRC Newsletter\")." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.8.10 ('lava_nx_env')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.10" }, "vscode": { "interpreter": { "hash": "7ebb4c32c029abbab1fd16ef4d8ac43152261b56d4033e55d2744ce843ecba08" } } }, "nbformat": 4, "nbformat_minor": 1 }