{"cells":[{"metadata":{},"cell_type":"markdown","source":"Fortunately for us, the baseline was saved in tf1.x's graph mode, which allows us to see the entire graph, with all of it's nodes and variables. \n\nStep1: extract all of the variables from the baseline, with their names and values.\n\n*Note: This code needs to be run with disabled eager execution, and I used tf1.15, so I won't run it here, but I'll import it as a dataset.*","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"import tensorflow.compat.v1 as tf\nfrom tensorflow.compat.v1.saved_model import tag_constants\ntf.disable_eager_execution()\nimport numpy as np\nimport pandas as pd\n\nconfig = tf.ConfigProto()\nconfig.gpu_options.allow_growth = True\ngraph = tf.Graph()\nwith graph.as_default():\n    with tf.Session(config=config) as sess:\n        tf.saved_model.loader.load(\n            sess,\n            [tag_constants.SERVING],\n            '../baseline/submission/baseline_landmark_retrieval_model/',\n        )\n        ops = graph.get_operations()\n        gvs = tf.global_variables()\n        node_vars = [n.name for n in graph.as_graph_def().node]\n        var_names = [gv.name for gv in tf.global_variables()]\n        \n        vars = sess.run(tf.global_variables())\n\n#exporting the names and shapes of the variables\nbaseline_map = []\nfor i in range(523):\n    baseline_map.append([gvs[i].name, gvs[i].shape])\nbaseline_map = pd.DataFrame(baseline_map, columns=[\"Weight_name\", \"Weight_shape\"])\n\n#the baseline didn't use biases in the conv2d layers, so I'm adding a placeholder for it. This is needed because the tf.keras.applications.Resnet101 uses bias\nfor i in range(baseline_map.shape[0]):\n    baseline_map_d.append([\"\",baseline_map.Weight_name.loc[i], baseline_map.Weight_shape.loc[i]])\n    if baseline_map.Weight_name.loc[i].split(\"/\")[-1] == \"weights:0\":\n        baseline_map_d.append([\"Dummy\",\"Bias\", \"?\"])\n        \nbaseline_map_d = pd.DataFrame(baseline_map_d, columns=[\"is_dummy\", \"Name\", \"Shape\"])\nbaseline_map_d.to_csv(\"baseline_map_d.csv\", index=False)\n\n#saving the weights\nvars = np.array(vars)\nnp.save(\"baseline_w.npy\", vars)\n\n#saving the names of the weights\nvar_names = np.array(var_names)\nnp.save(\"baseline_w_names.npy\", var_names)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Step 2: We need to extract the names and shapes from the tf.keras.applications.Resnet101. \nUnfortunately they will be in a different order, so I had to create a lookup table for the variables. The baseline and the keras resnet saves the shortcut connections weights in a different order. Because I had to manually create a lookup table I won't run this here either.","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"import tensorflow as tf\nimport pandas as pd\n\nmodel = tf.keras.applications.ResNet101V2(include_top=False, weights=\"imagenet\")\n\nlayer_map = []\nlayer_len = len(model.layers)\n\nfor i in range(layer_len):\n    layer = model.layers[i]\n    if (isinstance(layer, tf.python.keras.layers.convolutional.Conv2D) | \n        isinstance(layer, tf.python.keras.layers.normalization_v2.BatchNormalization)):\n        w = layer.weights\n        for j in range(len(w)):\n            layer_map.append([i, layer.name, layer.weights[j].name, layer.weights[j].shape])\n            \n\nkeras_map = pd.DataFrame(layer_map, columns=[\"Layer_id\", \"Layer_name\", \"Weight_name\", \"Weights_shape\"])\nkeras_map.to_csv(\"keras_mapv2.csv\", index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Step 3: Importing the weights to the keras model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow as tf\nimport pandas as pd\nimport numpy as np\n\n\nb_weights = np.load(\"../input/landmark2020-weight-export-intermediate/baseline_w.npy\", allow_pickle=True)\nb_weight_names = np.load(\"../input/landmark2020-weight-export-intermediate/baseline_w_names.npy\", allow_pickle=True)\n\n#this is the lookup table I created\ndf = pd.read_csv(\"../input/landmark2020-weight-export-intermediate/dict_converter_v2.csv\", sep=\";\")\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class GeMPoolingLayer(tf.keras.layers.Layer):\n    def __init__(self):\n        super().__init__()\n        self.p = 3.0\n        self.eps = 1e-6\n\n    def call(self, inputs):\n        inputs = tf.clip_by_value(inputs, clip_value_min=1e-6, clip_value_max=tf.reduce_max(inputs))\n        inputs = tf.pow(inputs, self.p)\n        inputs = tf.reduce_mean(inputs, axis=[1, 2], keepdims=False)\n        inputs = tf.pow(inputs, 1./self.p)\n        return inputs\n    \nclass Model(tf.keras.Model):\n    def __init__(self):\n        super(Model, self).__init__()\n        self.backbone = tf.keras.applications.ResNet101(include_top=False, weights=None)\n        #to make sure we won't forget to turn the biases off, let's do it here :)\n        layer_len = len(self.backbone.layers)\n\n        for i in range(layer_len):\n            layer = self.backbone.layers[i]\n            if isinstance(layer, tf.python.keras.layers.convolutional.Conv2D):\n                self.backbone.layers[i].use_bias = False\n        \n        self.pooling = GeMPoolingLayer()\n        self.dense = tf.keras.layers.Dense(2048, name='features')\n        \n    def call(self, x, training=False):\n        x = self.backbone(x, training)\n        x = self.pooling(x)\n        return self.dense(x)\n    \nmodel = Model()\nmodel.build([None,None,None,3])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"###importing the resnet weights\nlayer_names = df.Layer_name.unique()\n\nfor l in layer_names:\n    temp = []\n    w_count = len(model.backbone.get_layer(l).weights)\n    for i in range(w_count):\n        w_name = model.backbone.get_layer(l).weights[i].name\n        if \"bias\" in w_name:\n            temp.append(model.backbone.get_layer(l).weights[i].numpy())\n        else:\n            bw_name = df[df.Keras_name == w_name].Baseline_Name.values[0]\n            w_id = np.where(b_weight_names==bw_name)[0][0]\n            temp.append(b_weights[w_id])\n    model.backbone.get_layer(l).set_weights(temp)\n    \n####setting dense weights\nmodel.dense.set_weights([b_weights[-2], b_weights[-1]])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#saving the weights\nmodel.save_weights(\"landmark2020_baseline.h5\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's compare the outputs with the baseline","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"x = tf.random.normal((1,224,224,3), dtype=tf.float32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"baseline = tf.saved_model.load('../input/baseline-landmark-retrieval-model/baseline_landmark_retrieval_model/')\nbaseline = baseline.prune(\n    feeds=[\"ResizeBilinear:0\"],\n    fetches=[\"l2_normalization:0\"],\n)\nbaseline_out = baseline(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"keras_out = tf.math.l2_normalize(model(x, training=False))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"keras_out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"baseline_out\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The outputs are almost the same, but not exactly, this is because of the float conversions.","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}