{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Executing app locally\n", "\n", "## Executing and Inspecting App in Jupyter Notebook\n", "\n", "You can define Operators and Application in Jupyter Notebook." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "from monai.deploy.conditions import CountCondition\n", "from monai.deploy.core import (Application, ConditionType, ExecutionContext, InputContext,\n", " Operator, OperatorSpec, OutputContext)\n", "\n", "class TaskA(Operator):\n", " def setup(self, spec: OperatorSpec):\n", " spec.input(\"input_path\").condition(ConditionType.NONE) # optional input\n", " spec.output(\"A\")\n", "\n", " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n", " input_path = op_input.receive(\"input_path\") # Get input path via named input. Not used here.\n", " if not input_path:\n", " print(\"TaskA receives None at optional input.\")\n", " data = 1\n", " op_output.emit(data, \"A\")\n", " print(f\"TaskA emits {data}\")\n", "\n", "class TaskB(Operator):\n", " def setup(self, spec: OperatorSpec):\n", " spec.input(\"input\")\n", " spec.output(\"B\").condition(ConditionType.NONE) # optional output, not requiring receiver\n", "\n", " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n", " input_data = op_input.receive(\"input\")\n", " print(f\"TaskB receives {input_data}\")\n", "\n", " output_data = input_data + 1\n", " op_output.emit(output_data, \"B\")\n", " print(f\"TaskB emits {output_data}\")\n", "\n", "class App(Application):\n", " def compose(self):\n", " taskA = TaskA(self, CountCondition(self, 1), name=\"Task A\") # self and name are required\n", " taskB = TaskB(self, name=\"Task B\")\n", " self.add_flow(taskA, taskB) # Need not explicitly connect single output and input\n", "\n", "if __name__ == \"__main__\":\n", " App().run()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Once an Application class (`App`) is defined, you can instantiate the application and execute with Application.run() method.\n", "\n", "Since the above example doesn't use input or output paths, we need not them, otherwise, environment variables can be used to provide the paths, as in this [example](../getting_started/tutorials/simple_app)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "app = App()\n", "app.run()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "app.argv" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can access [Graph](/modules/_autosummary/monai.deploy.core.graphs.Graph) object through `Application.graph`" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(app.graph)\n", "graph = app.graph\n", "print(f\"graph.context: {graph.context}\")\n", "operators = graph.get_nodes()\n", "print(f\"get_nodes.get_nodes(): {operators}\")\n", "print(f\"graph.is_root(operators[0]): {graph.is_root(operators[0])}\")\n", "print(f\"graph.is_leaf(operators[1]): {graph.is_leaf(operators[1])}\")\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Executing Application\n", "\n", "Once the application is verified inside Jupyter notebook, we can write the whole application as a file(`app.py`) with the following lines at the end of the file:\n", "\n", "```python\n", "if __name__ == \"__main__\":\n", " App(do_run=True)\n", "```\n", "\n", "Above lines are needed to execute the application code by using `python` interpreter." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%writefile app.py\n", "from monai.deploy.conditions import CountCondition\n", "from monai.deploy.core import (Application, ConditionType, ExecutionContext, InputContext,\n", " Operator, OperatorSpec, OutputContext)\n", "\n", "class TaskA(Operator):\n", " def setup(self, spec: OperatorSpec):\n", " spec.input(\"input_path\").condition(ConditionType.NONE) # optional input\n", " spec.output(\"A\")\n", "\n", " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n", " input_path = op_input.receive(\"input_path\") # Get input path via named input. Not used here.\n", " if not input_path:\n", " print(\"TaskA receives None at optional input.\")\n", " data = 1\n", " op_output.emit(data, \"A\")\n", " print(f\"TaskA emits {data}\")\n", "\n", "class TaskB(Operator):\n", " def setup(self, spec: OperatorSpec):\n", " spec.input(\"input\")\n", " spec.output(\"B\").condition(ConditionType.NONE) # optional output, not requiring receiver\n", "\n", " def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):\n", " input_data = op_input.receive(\"input\")\n", " print(f\"TaskB receives {input_data}\")\n", "\n", " output_data = input_data + 1\n", " op_output.emit(output_data, \"B\")\n", " print(f\"TaskB emits {output_data}\")\n", "\n", "class App(Application):\n", " def compose(self):\n", " taskA = TaskA(self, CountCondition(self, 1), name=\"Task A\") # self and name are required\n", " taskB = TaskB(self, name=\"Task B\")\n", " self.add_flow(taskA, taskB) # Need not explicitly connect single output and input\n", "\n", "if __name__ == \"__main__\":\n", " App().run()\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's run the application" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "!python app.py" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "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" } }, "nbformat": 4, "nbformat_minor": 4 }