{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"!saved_model_cli show --dir \"../input/baseline-landmark-retrieval-model/baseline_landmark_retrieval_model\" --all","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\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","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are varying shapes of images as you can see below, meaning we'll need to resize images inside the model.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"files = glob.glob(\"../input/landmark-retrieval-2020/train/a/b/c/*.jpg\")\nfor i in range(10):\n    im = cv2.imread(files[i])\n    print(im.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now let's load our model. In this case the vanilla VGG16 pretrained model of Keras for demonstration purposes. Since this is not trained on any retrieval dataset, the score will most probably be zero.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"backend, layers, models, keras_utils = tf.keras.backend, tf.keras.layers, tf.keras.models, tf.keras.utils","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_swish():\n\n    def swish(x):\n        \"\"\"Swish activation function: x * sigmoid(x).\n        Reference: [Searching for Activation Functions](https://arxiv.org/abs/1710.05941)\n        \"\"\"\n\n        if backend.backend() == 'tensorflow':\n            try:\n                # The native TF implementation has a more\n                # memory-efficient gradient implementation\n                return backend.tf.nn.swish(x)\n            except AttributeError:\n                pass\n\n        return x * backend.sigmoid(x)\n\n    return swish\n\n\ndef get_dropout():\n    \"\"\"Wrapper over custom dropout. Fix problem of ``None`` shape for tf.keras.\n    It is not possible to define FixedDropout class as global object,\n    because we do not have modules for inheritance at first time.\n    Issue:\n        https://github.com/tensorflow/tensorflow/issues/30946\n    \"\"\"\n\n    class FixedDropout(layers.Dropout):\n        def _get_noise_shape(self, inputs):\n            if self.noise_shape is None:\n                return self.noise_shape\n\n            symbolic_shape = backend.shape(inputs)\n            noise_shape = [symbolic_shape[axis] if shape is None else shape\n                           for axis, shape in enumerate(self.noise_shape)]\n            return tuple(noise_shape)\n\n    return FixedDropout","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = tf.keras.models.load_model('../input/saving-model-iteration/saved_iteration_1.h5', compile=False, \n                                   custom_objects={'FixedDropout':get_dropout(),'swish':get_swish()})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights('../input/landmark-metric-learning/efficientnet-b0.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# backbone_name = 'efficientnet-b0'\n# if backbone_name.startswith('efficientnet'):\n#     model_fn = getattr(efn, f'EfficientNetB{backbone_name[-1]}')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# # vgg = VGG16(input_shape=(224,224,3), weights=None, include_top=False)\n# # vgg.load_weights(\"../input/keras-pretrained-models/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5\")\n\n# # input_image = Input((224,224,3))\n# # x = vgg(input_image)\n# # output = GlobalMaxPooling2D()(x)\n\n# # model = Model(inputs=[input_image], outputs=[output])\n# # model.summary()\n# model = build_model(engine=model_fn, input_shape=(IMG_SIZE, IMG_SIZE, 3), weights='imagenet') \n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Now the main part! The *input_image* will be in it's own variable shape and hence we need to resize it within the model.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow as tf\n\nclass 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, [256,256])\n        # preprocessing\n        im = tf.cast(im, tf.float32)\n        im = im / 255.0\n        \n        extracted_features = self.model(tf.convert_to_tensor([im], dtype=tf.float32))[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":"markdown","source":"Now we create and save our model instance.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"m = MyModel() #creating our model instance\n\nserved_function = m.call\ntf.saved_model.save(\n      m, export_dir=\"./my_model\", signatures={'serving_default': served_function})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!ls ./my_model/variables","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-00002', arcname='variables/variables.data-00000-of-00002')\n    zip.write('./my_model/variables/variables.data-00001-of-00002', arcname='variables/variables.data-00001-of-00002') \n    zip.write('./my_model/variables/variables.index', arcname='variables/variables.index') ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Last but not the least, let's visualize our model to see if the structure is as per the requirements.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"!saved_model_cli show --dir ./my_model/ --all","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"Please upvote and let me know if this helps!","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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}