{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "name": "torch_to_onnx.ipynb", "provenance": [], "collapsed_sections": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "markdown", "metadata": { "id": "xAk44VAUMcI4" }, "source": [ "### The goal is to export the DevoLearn cell membrane segmentation model to ONNX and run inference using ONNX runtime.\n", "\n", "Link to tutorial - https://pytorch.org/tutorials/advanced/super_resolution_with_onnxruntime.html" ] }, { "cell_type": "code", "metadata": { "id": "1cvIRtSg1xPj" }, "source": [ "!pip install segmentation-models-pytorch\n", "!pip install onnx\n", "!git clone https://github.com/DevoLearn/devolearn.git\n", "!pip install onnxruntime" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "WI1phIjPDSHj" }, "source": [ "### Copy model into working directory:" ] }, { "cell_type": "code", "metadata": { "id": "IMUYNfr61OOc" }, "source": [ "!cp -r /content/drive/MyDrive/mydata/3d_seg_data/best_2.pth /content/" ], "execution_count": 3, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "P9r-q1crDZ74" }, "source": [ "### Import Libraries:" ] }, { "cell_type": "code", "metadata": { "id": "bo1ngsVb1mhk" }, "source": [ "import torch\n", "import segmentation_models_pytorch as smp\n", "import torch.onnx\n", "import numpy as np\n", "import onnx\n", "import onnxruntime as ort\n", "\n", "import cv2\n", "import matplotlib.pyplot as plt\n", "from PIL import Image" ], "execution_count": 5, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "plqmhQ3IDfIg" }, "source": [ "### Load model:\n", "`model.eval()` sets model to inference mode -\n", "* Normalization layers use running stats.\n", "* deactivate dropout layers" ] }, { "cell_type": "code", "metadata": { "id": "Ah3kvIEh1fT4" }, "source": [ "model = torch.load('/content/best_2.pth', map_location='cpu')\n", "model.eval()" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "ahpQaPJkELZi" }, "source": [ "### Define sample input `x` :\n", "* The values in this can be random as long as it is the right type and size.\n", "* In this case, `x` is a tensor, that corresponds to a batch of one single channel, 256x256 image.\n", "* Make sure `out` is valid." ] }, { "cell_type": "code", "metadata": { "id": "v6aHqHs21vSK" }, "source": [ "x = torch.randn(1, 1, 256, 256, requires_grad=False)\n", "out=model(x)" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "J5adRnBxFvr9" }, "source": [ "### Export model:\n" ] }, { "cell_type": "code", "metadata": { "id": "Cgn1VgKi30dT" }, "source": [ "torch.onnx.export(model, # model being run\n", " x, # model input (or a tuple for multiple inputs)\n", " \"membrane_segmentor.onnx\", # where to save the model (can be a file or file-like object)\n", " export_params=True, # store the trained parameter weights inside the model file\n", " opset_version=11, # the ONNX version to export the model to\n", " do_constant_folding=True, # whether to execute constant folding for optimization\n", " input_names = ['input'], # the model's input names\n", " output_names = ['output'], # the model's output names\n", " dynamic_axes={'input' : {0 : 'batch_size'}, # variable length axes\n", " 'output' : {0 : 'batch_size'}})" ], "execution_count": null, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "RYPqPCKhGRzJ" }, "source": [ "### Define `expand_dims_twice`:\n" ] }, { "cell_type": "code", "metadata": { "id": "vfHgRLatcbY3" }, "source": [ "def expand_dims_twice(arr):\n", " norm=(arr-np.min(arr))/(np.max(arr)-np.min(arr)) #normalize\n", " ret = np.expand_dims(np.expand_dims(norm, axis=0), axis=0)\n", " return(ret)" ], "execution_count": 9, "outputs": [] }, { "cell_type": "markdown", "metadata": { "id": "mOY7WkrEI7xi" }, "source": [ "### Run inference from ONNX file:\n", "The output image below the following cell is inferred from the ONNX model." ] }, { "cell_type": "code", "metadata": { "id": "dfAoZNQk4l9r", "colab": { "base_uri": "https://localhost:8080/", "height": 303 }, "outputId": "ee56876a-00a9-417e-9438-3c92e9b1219d" }, "source": [ "ort_session = ort.InferenceSession('membrane_segmentor.onnx')\n", "\n", "img = cv2.imread(\"/content/devolearn/devolearn/tests/sample_data/images/seg_sample.jpg\",0)\n", "resized = cv2.resize(img, (256,256),\n", " interpolation = cv2.INTER_NEAREST)\n", "\n", "print(\"dims before expand_dims_twice - \", resized.shape)\n", "img_unsqueeze = expand_dims_twice(resized)\n", "print(\"dims after expand_dims_twice - \", img_unsqueeze.shape)\n", "\n", "onnx_outputs = ort_session.run(None, {'input': img_unsqueeze.astype('float32')})\n", "plt.imshow(onnx_outputs[0][0][0])\n", "plt.show()" ], "execution_count": 12, "outputs": [ { "output_type": "stream", "text": [ "dims before expand_dims_twice - (256, 256)\n", "dims after expand_dims_twice - (1, 1, 256, 256)\n" ], "name": "stdout" }, { "output_type": "display_data", "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "tags": [], "needs_background": "light" } } ] }, { "cell_type": "code", "metadata": { "id": "YtmfEX4oqbCT" }, "source": [ "" ], "execution_count": null, "outputs": [] } ] }