{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "037905b6",
   "metadata": {},
   "source": [
    "# Pre/Post Processing for ImageNet based classification model\n",
    "### First check onnxruntime-extensions is installed in the Python environment"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "230fba23",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Name: onnxruntime-extensions\n",
      "Version: 0.4.2+febe63a\n",
      "Summary: ONNXRuntime Extensions\n",
      "Home-page: https://github.com/microsoft/onnxruntime-extensions\n",
      "Author: Microsoft Corporation\n",
      "Author-email: onnx@microsoft.com\n",
      "License: MIT License\n",
      "Location: c:\\g\\ortext\n",
      "Requires: numpy, onnx, onnxruntime\n",
      "Required-by: \n"
     ]
    }
   ],
   "source": [
    "!pip show onnxruntime_extensions\n",
    "from matplotlib.pyplot import imshow"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8470c79c",
   "metadata": {},
   "source": [
    "Load an image for test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "4673b4ba",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x2c91ddedeb0>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 37268 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy\n",
    "from PIL import Image\n",
    "img = Image.open('../test/data/pineapple.jpg')\n",
    "img_npy = numpy.asarray(img.convert('RGB'))\n",
    "img.size, img_npy.shape\n",
    "%matplotlib inline\n",
    "imshow(img)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b778bf2",
   "metadata": {},
   "source": [
    "Try the pre-processing built-in Python function in onnxruntime_extensions, Note the normalized image was miscolored due to the image RGB value normalization."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "9e85d156",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\g\\ortext\\onnxruntime_extensions\\pnp\\_onnx_ops.py:71: UserWarning: The maximum opset needed by this model is only 9.\n",
      "  warnings.warn('The maximum opset needed by this model is only %d.' % op_version)\n",
      "Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x2c92280a550>"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 37172 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from onnxruntime_extensions import pnp\n",
    "pre = pnp.PreMobileNet(size=224)\n",
    "img2 = pre.forward(img_npy)\n",
    "%matplotlib inline\n",
    "imshow(img2.squeeze(0).permute(1, 2, 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e43dd668",
   "metadata": {},
   "source": [
    "Try the pre-processing in torchvision"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "33340c2e",
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Clipping input data to the valid range for imshow with RGB data ([0..1] for floats or [0..255] for integers).\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x2c922df1430>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "[encoded data, 35876 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "from torchvision import transforms as T\n",
    "pre_torch=T.Compose([\n",
    "   T.Resize(256),\n",
    "   T.CenterCrop(224),\n",
    "   T.ToTensor(),\n",
    "   T.Normalize(\n",
    "        mean=[0.485, 0.456, 0.406],\n",
    "        std=[0.229, 0.224, 0.225]\n",
    "   )\n",
    "])\n",
    "\n",
    "img3 = pre_torch(img.convert('RGB'))\n",
    "%matplotlib inline\n",
    "imshow(img3.permute(1, 2, 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "87d48bff",
   "metadata": {},
   "source": [
    "The processed images are identical after the different processing ways.\n",
    "\n",
    "### Integrate the preprocessing into a model trained on ImageNet dataset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "fb9b24b1",
   "metadata": {},
   "outputs": [],
   "source": [
    "import onnx\n",
    "import torch\n",
    "from onnxruntime_extensions import PyOrtFunction, pnp\n",
    "\n",
    "\n",
    "mnv2 = onnx.load_model('../test/data/mobilev2.onnx')\n",
    "full_model = pnp.SequenceProcessingModule(pnp.PreMobileNet(224),\n",
    "                                          mnv2,\n",
    "                                          pnp.PostMobileNet())\n",
    "\n",
    "ids, probabilities = full_model.forward(torch.from_numpy(img_npy))\n",
    "full_onnx_model = pnp.export(full_model, torch.from_numpy(img_npy), opset_version=11, output_path='temp_exmobilev2.onnx')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "73a0609d",
   "metadata": {},
   "source": [
    "### Verify the built full model\n",
    "Let me try the model embedded with preprocessing operations"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "1a913ca0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "953"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "full_model_func = PyOrtFunction.from_model(full_onnx_model)\n",
    "ids, probabilities = full_model_func(img_npy)\n",
    "ids[0][0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b062631a",
   "metadata": {},
   "source": [
    "Convert the the image class id number to image class text."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "6d0e00f0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "top-1 obj=pineapple, ananas prob=99.85%\n"
     ]
    }
   ],
   "source": [
    "import ast\n",
    "idx = ids[0][0].item()\n",
    "text = \"{}\".format(idx)\n",
    "with open('../test/data/imagenet1000_clsidx_to_labels.txt', 'r') as f:\n",
    "    labels = ast.literal_eval(f.read())\n",
    "    text = labels[idx]\n",
    "print(\"top-1 obj={} prob={:.2%}\".format(text, probabilities[0][0]))"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "d813e4d267de4daed45500e68ebcbe2c00b78daf6ae3f558b6b4058bb32157a6"
  },
  "kernelspec": {
   "display_name": "Python 3.8.0 64-bit ('gpu': conda)",
   "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.9.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
