{"cells":[{"metadata":{},"cell_type":"markdown","source":"This note book is 1st draft. This note has two big problems (I wrote the last section). If you know solutions, please teach me!!!","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import math\nimport os\nimport gc\nimport glob\nimport numpy as np\nnp.random.seed(0)\n\n\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow.keras.applications import ResNet50\nimport tensorflow.keras.layers as L\nfrom sklearn.model_selection import train_test_split\n\nfrom PIL import Image\nimport matplotlib.pyplot as plt\n%matplotlib inline\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Read Image","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv(\"../input/landmark-retrieval-2020/train.csv\")\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv(\"../input/landmark-retrieval-2020/train.csv\")\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_image_path(image_id):\n    root_path = \"../input/landmark-retrieval-2020/train/\"\n    extension = \".jpg\"\n    image_paht = root_path + image_id[0] + \"/\" + image_id[1] + \"/\" + image_id[2] + \"/\" \\\n                 + image_id + extension\n    return image_paht","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train[\"path\"] = train[\"id\"].map(get_image_path)\ntrain[\"path\"][0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = plt.figure(figsize=(20, 12))\nim = Image.open(train[\"path\"][999])\nplt.imshow(im)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training Setting","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"num_classes = len(set(train[\"landmark_id\"]))\nprint(\"There are \",num_classes, \"classes in training data.\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\nlabels = np.array(train[\"landmark_id\"])\nlab=LabelEncoder()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are so many trainig data, I choose appropriate size data randomlly. \n\nTo save GPU time, I just use ~ 1% of training data. ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# You should change data size here!\ntrain_len = len(train) // 100\ntrain = train.sample(n=train_len)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels=lab.fit_transform(train[\"landmark_id\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train, X_test, y_train, y_test = train_test_split(np.array(train[\"path\"]), labels, test_size=0.33, random_state=42)\ndel labels\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# tf.dataset setting\nAUTO = tf.data.experimental.AUTOTUNE\n\n# training configuration\nEPOCHS = 3 #10\nBATCH_SIZE = 8\n\n# for model\nIMAGE_SIZE = 64","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def decode_image(filename, image_size=(IMAGE_SIZE, IMAGE_SIZE)):\n    image = tf.io.read_file(filename)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0\n    image = tf.image.resize(image, image_size)\n    return image\n    \ndef to_onehot(label):\n    label = tf.one_hot(tf.cast(label, tf.int32), num_classes)\n    label = tf.cast(label, tf.int32)\n    return label\n\n#def data_augment(image):\n#    image = tf.image.random_flip_left_right(image)\n#    image = tf.image.random_flip_up_down(image)\n#    \n#    return image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\nimage_ds_train = tf.data.Dataset.from_tensor_slices(X_train).map(decode_image)\nlabel_ds_train = tf.data.Dataset.from_tensor_slices(y_train).map(to_onehot)\nimage_ds_test = tf.data.Dataset.from_tensor_slices(X_test).map(decode_image)\nlabel_ds_test = tf.data.Dataset.from_tensor_slices(y_test).map(to_onehot)\n\ntrain_dataset = tf.data.Dataset.zip((image_ds_train, label_ds_train)).shuffle(1024).repeat().batch(BATCH_SIZE).prefetch(buffer_size=AUTOTUNE)\nvalid_dataset = tf.data.Dataset.zip((image_ds_test, label_ds_test)).batch(BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model & Training\n\nNow, I use my private pretrained ResNet50 Model.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"model = tf.keras.Sequential([\n        ResNet50(\n            include_top=False, weights=None,\n            input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3)\n        ),\n        L.GlobalAveragePooling2D(),\n        L.Dense(num_classes, activation='sigmoid')\n    ])\n\nmodel.compile(\n        optimizer='adam',\n        loss = 'categorical_crossentropy',\n        metrics=['accuracy']\n    )\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"STEPS_PER_EPOCH = y_train.shape[0] // BATCH_SIZE\n\nhistory = model.fit(\n    train_dataset, \n    batch_size=BATCH_SIZE,\n    epochs=EPOCHS, \n    validation_data=valid_dataset,\n    steps_per_epoch=STEPS_PER_EPOCH\n#     callbacks=[],\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def display_training_curves(training, validation, title, subplot):\n    \"\"\"\n    Source: https://www.kaggle.com/mgornergoogle/getting-started-with-100-flowers-on-tpu\n    \"\"\"\n    if subplot%10==1: # set up the subplots on the first call\n        plt.subplots(figsize=(10,10), facecolor='#F0F0F0')\n        plt.tight_layout()\n    ax = plt.subplot(subplot)\n    ax.set_facecolor('#F8F8F8')\n    ax.plot(training)\n    ax.plot(validation)\n    ax.set_title('model '+ title)\n    ax.set_ylabel(title)\n    #ax.set_ylim(0.28,1.05)\n    ax.set_xlabel('epoch')\n    ax.legend(['train', 'valid.'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"display_training_curves(\n    history.history['loss'], \n    history.history['val_loss'], \n    'loss', 211)\ndisplay_training_curves(\n    history.history['accuracy'], \n    history.history['val_accuracy'], \n    'accuracy', 212)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Export Model","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"I also struggled submit. \n\nRequirement:\n  - The SavedModel should take a [H,W,3] uint8 tensor as input.\n  - The output should be a dict containing key 'global_descriptor' mapped to a [D] float tensor.\n  \nRefferd kaggle contents:\n\n  https://www.kaggle.com/mayukh18/creating-submission-from-your-own-model  \n  https://www.kaggle.com/c/landmark-retrieval-2020/discussion/163350\n\nYou should also reffer following document.  \nhttps://www.tensorflow.org/api_docs/python/tf/saved_model/save","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class ExportModel(tf.Module):\n    def __init__(self, model):\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 my_serve(self, input_image):\n        input_image = tf.cast(input_image, tf.float32) / 255        # pre-processing\n        input_image = tf.image.resize(input_image, (IMAGE_SIZE, IMAGE_SIZE))\n        input_image = tf.expand_dims(input_image, 0)\n        probabilities = self.model(input_image)[0]                # prediction from model\n        named_output_tensors = {}\n        named_output_tensors['global_descriptor'] = tf.identity(probabilities,name='global_descriptor')\n        return named_output_tensors","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tf.keras.backend.set_learning_phase(0) # Make sure no weight update happens\nserving_model = ExportModel(model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tf.saved_model.save(serving_model, \"./submission\",\n                    signatures={'serving_default': serving_model.my_serve})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from zipfile import ZipFile\n\nvariables_datas = glob.glob(\"./submission/variables/*\")\n\nwith ZipFile('submission.zip','w') as zip:  \n    zip.write('./submission/saved_model.pb', arcname='saved_model.pb') \n\n    for data in variables_datas:\n        path = \"variables/\" + data.split(\"/\")[-1]\n        zip.write(data, arcname=path)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Problems\n\n- I still don't success to sumbit.\n  ~~I think, I may success to save my model as saved_model but why??? \n  Notebook Exceeded Allowed Compute occur...;(\n- Memory leak occur while trainig.\n  Even I use tf.data.Dataset for trainig, CPU RAM continuauslly increase and finally memory leak occur.","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}