{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "# Python inference tutorial - Multi Process Service and Model Scheduler\n",
    "\n",
    "This tutorial will walk you through the inference process using The Model Scheduler.\n",
    "\n",
    "**Requirements:**\n",
    "\n",
    "* Run HailoRT Multi-Process Service before running inference. See installation steps in [Multi-Process Service](../../inference/inference.rst)\n",
    "* Run the notebook inside the Python virtual environment: ```source hailo_virtualenv/bin/activate```\n",
    "\n",
    "It is recommended to use the command ``hailo tutorial`` (when inside the virtualenv) to open a Jupyter server that contains the tutorials."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Running Inference using HailoRT\n",
    "\n",
    "In this example we will use the Model Scheduler to run inference on multiple models.\n",
    "Each model is represented by an HEF which is built using the Hailo Dataflow Compiler.\n",
    "An HEF is Hailo's binary format for neural networks. The HEF files contain:\n",
    "\n",
    "* Target HW configuration\n",
    "* Weights\n",
    "* Metadata for HailoRT (e.g. input/output scaling)\n",
    "\n",
    "The Model Scheduler is an HailoRT component that comes to enhance and simplify the usage\n",
    "of the same Hailo device by multiple networks. The responsibility for activating/deactivating the network\n",
    "groups is now under HailoRT, and done **automatically** without user application intervention.\n",
    "In order to use the Model Scheduler, create the VDevice with scheduler enabled, configure all models to the device, and start inference on all models:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "from multiprocessing import Process\n",
    "from hailo_platform import (HEF, VDevice, HailoStreamInterface, InferVStreams, ConfigureParams,\n",
    "    InputVStreamParams, OutputVStreamParams, InputVStreams, OutputVStreams, FormatType, HailoSchedulingAlgorithm)\n",
    "\n",
    "\n",
    "# Define the function to run inference on the model\n",
    "def infer(network_group, input_vstreams_params, output_vstreams_params, input_data):\n",
    "    rep_count = 100\n",
    "    with InferVStreams(network_group, input_vstreams_params, output_vstreams_params) as infer_pipeline:\n",
    "        for i in range(rep_count):\n",
    "            infer_results = infer_pipeline.infer(input_data)\n",
    "\n",
    "\n",
    "# Loading compiled HEFs:\n",
    "first_hef_path = '../hefs/resnet_v1_18.hef'\n",
    "second_hef_path = '../hefs/shortcut_net.hef'\n",
    "first_hef = HEF(first_hef_path)\n",
    "second_hef = HEF(second_hef_path)\n",
    "hefs = [first_hef, second_hef]\n",
    "\n",
    "# Creating the VDevice target with scheduler enabled\n",
    "params = VDevice.create_params()\n",
    "params.scheduling_algorithm = HailoSchedulingAlgorithm.ROUND_ROBIN\n",
    "with VDevice(params) as target:\n",
    "    infer_processes = []\n",
    "\n",
    "    # Configure network groups\n",
    "    for hef in hefs:\n",
    "        configure_params = ConfigureParams.create_from_hef(hef=hef, interface=HailoStreamInterface.PCIe)\n",
    "        network_groups = target.configure(hef, configure_params)\n",
    "        network_group = network_groups[0]\n",
    "\n",
    "        # Create input and output virtual streams params\n",
    "        # Quantized argument signifies whether or not the incoming data is already quantized.\n",
    "        # Data is quantized by HailoRT if and only if quantized == False.\n",
    "        input_vstreams_params = InputVStreamParams.make(network_group, quantized=False, format_type=FormatType.FLOAT32)\n",
    "        output_vstreams_params = OutputVStreamParams.make(network_group, quantized=True, format_type=FormatType.UINT8)\n",
    "\n",
    "        # Define dataset params\n",
    "        input_vstream_info = hef.get_input_vstream_infos()[0]\n",
    "        image_height, image_width, channels = input_vstream_info.shape\n",
    "        num_of_frames = 10\n",
    "        low, high = 2, 20\n",
    "\n",
    "        # Generate random dataset\n",
    "        dataset = np.random.randint(low, high, (num_of_frames, image_height, image_width, channels)).astype(np.float32)\n",
    "        input_data = {input_vstream_info.name: dataset}\n",
    "\n",
    "        # Create infer process\n",
    "        infer_process = Process(target=infer, args=(network_group, input_vstreams_params, output_vstreams_params, input_data))\n",
    "        infer_processes.append(infer_process)\n",
    "\n",
    "    print(f'Starting streaming on multiple models using scheduler')\n",
    "    for infer_process in infer_processes:\n",
    "        infer_process.start()\n",
    "    for infer_process in infer_processes:\n",
    "        infer_process.join()\n",
    "\n",
    "    print('Done inference')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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": 2
}
