{"cells":[{"metadata":{},"cell_type":"markdown","source":"In this notebook we will see how we can convert a pytorch model into a format that is valid for submission.\nThis notebook is just to show how we can convert a pretrained resnet_18 model to submission format for this competition.\nThe model is not trained and this notebook will generate 0.0 score on LB but doesnt give you error while submission.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install onnx2keras","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torchvision.models import resnet18\nimport onnx\nfrom onnx2keras import onnx_to_keras\nimport numpy as np\n\nimport os\nimport cv2\nimport glob\n\nimport tensorflow as tf\nimport keras\nfrom keras.models import load_model, save_model\nfrom keras.layers import Input, GlobalAveragePooling2D, GlobalMaxPooling2D\nimport keras.backend as K\nfrom keras.models import Model, load_model\nfrom keras.applications import VGG16\nfrom keras.applications.vgg16 import preprocess_input\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"class Flatten(nn.Module):\n    def forward(self, input):\n        return input.view(input.size(0), -1)\n\nclass BaseNet(nn.Module):   \n    def __init__(self, features):\n        super(BaseNet, self).__init__()\n        self.output_dim = 512\n        self.features = nn.Sequential(*features)\n        self.pool = nn.AvgPool2d(kernel_size = 1, stride = (4, 4))\n        self.flatten = Flatten()\n        self.fc1 = nn.Linear(512, self.output_dim, bias = True)\n    \n    def forward(self, x):\n        x = self.features(x)\n        x = self.pool(x)\n        x = self.flatten(x)\n        x = self.fc1(x)\n        return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"resnet = resnet18(pretrained = True)\nfeatures = list(resnet.children())[:-2]\nmodel = BaseNet(features)\nmodel.to(device)\n\nprint(model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dummy_input = torch.randn(1, 3, 128, 128, device='cpu')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"input_names = ['input_image']\noutput_names = ['global_descriptor']\n\ntorch.onnx.export(model, dummy_input, \"resnet18.onnx\", verbose=True, input_names=input_names, output_names=output_names)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"onnx_model = onnx.load('resnet18.onnx')\nk_model = onnx_to_keras(onnx_model, ['input_image'], change_ordering = True)\nk_model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Once we have our keras model ready we can use the strategy provided [here](https://www.kaggle.com/mayukh18/creating-submission-from-your-own-model)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"input_image = Input((128,128,3))\noutput = k_model(input_image)\n\nmodel = Model(inputs=[input_image], outputs=[output])\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MyModel(tf.keras.Model):\n    def __init__(self):\n        super(MyModel, self).__init__()\n        self.model = model\n    \n    @tf.function(input_signature=[\n      tf.TensorSpec(shape=[None, None, 3], dtype=tf.uint8, name='input_image')\n    ])\n    def call(self, input_image):\n        output_tensors = {}\n        \n        # resizing\n        im = tf.image.resize(input_image, (128,128))\n        \n        # preprocessing\n        im = preprocess_input(im)\n        \n        extracted_features = self.model(tf.convert_to_tensor([im], dtype=tf.uint8))[0]\n        output_tensors['global_descriptor'] = tf.identity(extracted_features, name='global_descriptor')\n        return output_tensors","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"m = MyModel()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"served_function = m.call\ntf.saved_model.save(m, export_dir=\"./my_model\", signatures={'serving_default': served_function})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from zipfile import ZipFile\n\nwith ZipFile('submission.zip','w') as zip:           \n    zip.write('./my_model/saved_model.pb', arcname='saved_model.pb') \n    zip.write('./my_model/variables/variables.data-00000-of-00001', arcname='variables/variables.data-00000-of-00001')\n    zip.write('./my_model/variables/variables.data-00000-of-00001', arcname='variables/variables.index') ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Once the model is created you need to download the model and upload it to a separate notebook for submission.\nIf this helps please upvote this notebook.\nThanks.","execution_count":null}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}