Executing app locally¶
Executing and Inspecting App in Jupyter Notebook¶
You can define Operators and Application in Jupyter Notebook.
from monai.deploy.conditions import CountCondition
from monai.deploy.core import (Application, ConditionType, ExecutionContext, InputContext,
Operator, OperatorSpec, OutputContext)
class TaskA(Operator):
def setup(self, spec: OperatorSpec):
spec.input("input_path").condition(ConditionType.NONE) # optional input
spec.output("A")
def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
input_path = op_input.receive("input_path") # Get input path via named input. Not used here.
if not input_path:
print("TaskA receives None at optional input.")
data = 1
op_output.emit(data, "A")
print(f"TaskA emits {data}")
class TaskB(Operator):
def setup(self, spec: OperatorSpec):
spec.input("input")
spec.output("B").condition(ConditionType.NONE) # optional output, not requiring receiver
def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
input_data = op_input.receive("input")
print(f"TaskB receives {input_data}")
output_data = input_data + 1
op_output.emit(output_data, "B")
print(f"TaskB emits {output_data}")
class App(Application):
def compose(self):
taskA = TaskA(self, CountCondition(self, 1), name="Task A") # self and name are required
taskB = TaskB(self, name="Task B")
self.add_flow(taskA, taskB) # Need not explicitly connect single output and input
if __name__ == "__main__":
App().run()
Once an Application class (App
) is defined, you can instantiate the application and execute with Application.run() method.
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.
app = App()
app.run()
app.argv
You can access Graph object through Application.graph
print(app.graph)
graph = app.graph
print(f"graph.context: {graph.context}")
operators = graph.get_nodes()
print(f"get_nodes.get_nodes(): {operators}")
print(f"graph.is_root(operators[0]): {graph.is_root(operators[0])}")
print(f"graph.is_leaf(operators[1]): {graph.is_leaf(operators[1])}")
Executing Application¶
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:
if __name__ == "__main__":
App(do_run=True)
Above lines are needed to execute the application code by using python
interpreter.
%%writefile app.py
from monai.deploy.conditions import CountCondition
from monai.deploy.core import (Application, ConditionType, ExecutionContext, InputContext,
Operator, OperatorSpec, OutputContext)
class TaskA(Operator):
def setup(self, spec: OperatorSpec):
spec.input("input_path").condition(ConditionType.NONE) # optional input
spec.output("A")
def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
input_path = op_input.receive("input_path") # Get input path via named input. Not used here.
if not input_path:
print("TaskA receives None at optional input.")
data = 1
op_output.emit(data, "A")
print(f"TaskA emits {data}")
class TaskB(Operator):
def setup(self, spec: OperatorSpec):
spec.input("input")
spec.output("B").condition(ConditionType.NONE) # optional output, not requiring receiver
def compute(self, op_input: InputContext, op_output: OutputContext, context: ExecutionContext):
input_data = op_input.receive("input")
print(f"TaskB receives {input_data}")
output_data = input_data + 1
op_output.emit(output_data, "B")
print(f"TaskB emits {output_data}")
class App(Application):
def compose(self):
taskA = TaskA(self, CountCondition(self, 1), name="Task A") # self and name are required
taskB = TaskB(self, name="Task B")
self.add_flow(taskA, taskB) # Need not explicitly connect single output and input
if __name__ == "__main__":
App().run()
Let’s run the application
!python app.py