{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas  as pd","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv(\"../input/landmark-recognition-2020/train.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['filename'] = train.id.str[0] + \"/\" + train.id.str[1] + \"/\" + train.id.str[2] + \"/\" + train.id + \".jpg\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train[\"label\"] = train['landmark_id'].astype(str)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub = pd.read_csv(\"../input/landmark-recognition-2020/sample_submission.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub['filename'] = sub.id.str[0] + \"/\" + sub.id.str[1] + \"/\" + sub.id.str[2] + \"/\" + sub.id + \"jpg\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y = train['landmark_id'].values\ny","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"num_classes = np.max(y)\nnum_classes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from collections import Counter\ncount = Counter(y).most_common(1000)\ncount","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"k_labels = [c[0] for c in count]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_keep = train[train['landmark_id'].isin(k_labels)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_keep","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"val_rate = 0.25\nbatch_size = 32","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator\ndatagen = ImageDataGenerator(validation_split=val_rate)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dir = \"../input/landmark-recognition-2020/train/\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_gen = datagen.flow_from_dataframe(train_keep, directory=dir, x_col=\"filename\", y_col=\"label\", weight_col=None, \n                                        target_size=(256, 256), color_mode=\"rgb\", classes=None, class_mode=\"categorical\",\n                                       batch_size=batch_size, shuffle=True, subset=\"training\", interpolation=\"nearest\",\n                                       validate_filenames=False)\nval_gen = datagen.flow_from_dataframe(train_keep, directory=dir, x_col=\"filename\", y_col=\"label\", weight_col=None,\n                                     target_size=(256, 256), color_mode=\"rgb\",classes=None, class_mode=\"categorical\", \n                                     batch_size=batch_size, shuffle=True, subset=\"validation\",interpolation=\"nearest\", \n                                     validate_filenames=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.applications import MobileNetV2\nfrom keras.utils import to_categorical\nfrom keras.layers import Dense\nfrom keras import Model\nfrom keras.callbacks import ModelCheckpoint\nfrom keras.models import load_model\n\nfrom keras.callbacks import ReduceLROnPlateau\nfrom keras.optimizers import Adam\nimport tensorflow as tf\nlearning_rate_reduction = ReduceLROnPlateau(monitor = 'categorical_accuracy', patience = 3, verbose = 1, \n                                           factor = 0.2, min_lr = 0.00001)\n\noptimizer = Adam(lr = .0001, beta_1 = .9, beta_2 = .999, epsilon = None, decay = .0, amsgrad = False)\n\n# from keras.preprocessing.image import ImageDataGenerator\n# from keras.applications import MobileNetV2\n# from keras.utils import to_categorical\n# from keras.layers import Dense\n# from keras import Model\n# from keras.callbacks import ModelCheckpoint\n# from keras.models import load_model\n# from tensorflow.keras.applications.xception import Xception\n# import tensorflow as tf\n# import tensorflow.keras.layers as L","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"try:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()  # TPU detection. No parameters necessary if TPU_NAME environment variable is set. On Kaggle this is always the case.\n    print('Running on TPU ', tpu.master())\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nelse:\n    strategy = tf.distribute.get_strategy() # default distribution strategy in Tensorflow. Works on CPU and single GPU.\n\nprint(\"REPLICAS: \", strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope():\n    pretrained_model = tf.keras.applications.ResNet50V2(\n    weights='imagenet',\n    include_top=False ,\n    input_shape=(256,256,3)\n    )\n    pretrained_model.trainable = False\n    \n    model = tf.keras.Sequential([\n        # To a base pretrained on ImageNet to extract features from images...\n        pretrained_model,\n        # ... attach a new head to act as a classifier.\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.Dense(1000, activation='softmax')\n    ])\n    model.compile(\n        optimizer='adam',\n        loss = 'categorical_crossentropy',\n        metrics=['categorical_accuracy'],\n    )\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from kaggle_datasets import KaggleDatasets\nimport math, re, os, random\nimport numpy as np\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom sklearn.model_selection import StratifiedKFold\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\nfrom tensorflow.keras.optimizers import Adam\n\nprint(\"Tensorflow version \" + tf.__version__)\nGCS_DS_PATH = KaggleDatasets().get_gcs_path() # you can list the bucket with \"!gsutil ls $GCS_DS_PATH\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMAGE_SIZE = [256, 256] # at this size, a GPU will run out of memory. Use the TPU\nEPOCHS = 5\n# BATCH_SIZE = 16 * strategy.num_replicas_in_sync\nBATCH_SIZE = 16 * 8\n\nSEED = 42\nNUM_TRAINING_IMAGES = 188811\nNUM_TEST_IMAGES = 62937\nSTEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def random_blockout(img, sl = 0.1, sh = 0.2, rl = 0.4):\n    p = random.random()\n    if p >= 0.25:\n        w, h, c = IMAGE_SIZE[0], IMAGE_SIZE[1], 3\n        origin_area = tf.cast(h * w, tf.float32)\n\n        e_size_l = tf.cast(tf.round(tf.sqrt(origin_area * sl * rl)), tf.int32)\n        e_size_h = tf.cast(tf.round(tf.sqrt(origin_area * sh / rl)), tf.int32)\n\n        e_height_h = tf.minimum(e_size_h, h)\n        e_width_h = tf.minimum(e_size_h, w)\n\n        erase_height = tf.random.uniform(shape = [], minval = e_size_l, maxval = e_height_h, dtype = tf.int32)\n        erase_width = tf.random.uniform(shape = [], minval = e_size_l, maxval = e_width_h, dtype = tf.int32)\n\n        erase_area = tf.zeros(shape = [erase_height, erase_width, c])\n        erase_area = tf.cast(erase_area, tf.uint8)\n\n        pad_h = h - erase_height\n        pad_top = tf.random.uniform(shape = [], minval = 0, maxval = pad_h, dtype = tf.int32)\n        pad_bottom = pad_h - pad_top\n\n        pad_w = w - erase_width\n        pad_left = tf.random.uniform(shape = [], minval = 0, maxval = pad_w, dtype = tf.int32)\n        pad_right = pad_w - pad_left\n\n        erase_mask = tf.pad([erase_area], [[0,0],[pad_top, pad_bottom], [pad_left, pad_right], [0,0]], constant_values=1)\n        erase_mask = tf.squeeze(erase_mask, axis = 0)\n        erased_img = tf.multiply(tf.cast(img,tf.float32), tf.cast(erase_mask, tf.float32))\n\n        return tf.cast(erased_img, img.dtype)\n    else:\n        return tf.cast(img, img.dtype)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def decode_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0  # convert image to floats in [0, 1] range\n    image = tf.reshape(image, [*IMAGE_SIZE, 3]) # explicit size needed for TPU\n    return image\n\ndef read_labeled_tfrecord(example):\n    LABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n        \"class\": tf.io.FixedLenFeature([], tf.int64),  # shape [] means single element\n    }\n    example = tf.io.parse_single_example(example, LABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    label = tf.cast(example['class'], tf.int32)\n    return image, label # returns a dataset of (image, label) pairs\n\ndef read_unlabeled_tfrecord(example):\n    UNLABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n        \"id\": tf.io.FixedLenFeature([], tf.string),  # shape [] means single element\n        # class is missing, this competitions's challenge is to predict flower classes for the test dataset\n    }\n    example = tf.io.parse_single_example(example, UNLABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    idnum = example['id']\n    return image, idnum # returns a dataset of image(s)\n\ndef load_dataset(filenames, labeled=True, ordered=False):\n    # Read from TFRecords. For optimal performance, reading from multiple files at once and\n    # disregarding data order. Order does not matter since we will be shuffling the data anyway.\n\n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False # disable order, increase speed\n\n    dataset = tf.data.TFRecordDataset(filenames) # automatically interleaves reads from multiple files\n    dataset = dataset.with_options(ignore_order) # uses data as soon as it streams in, rather than in its original order\n    dataset = dataset.map(read_labeled_tfrecord if labeled else read_unlabeled_tfrecord)\n    # returns a dataset of (image, label) pairs if labeled=True or (image, id) pairs if labeled=False\n    return dataset\n\ndef data_augment(image, label):\n    # data augmentation. Thanks to the dataset.prefetch(AUTO) statement in the next function (below),\n    # this happens essentially for free on TPU. Data pipeline code is executed on the \"CPU\" part\n    # of the TPU while the TPU itself is computing gradients.\n\n    image = tf.image.random_flip_left_right(image, seed=SEED)\n    image = random_blockout(image)\n    return image, label\n\ndef get_training_dataset():\n    dataset = load_dataset(tf.io.gfile.glob(GCS_DS_PATH + '/tfrecords-jpeg-224x224/train/*.tfrec'), labeled=True)\n    dataset = dataset.map(data_augment)\n    dataset = dataset.repeat() # the training dataset must repeat for several epochs\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    return dataset\n\ndef get_validation_dataset():\n    dataset = load_dataset(tf.io.gfile.glob(GCS_DS_PATH + '/tfrecords-jpeg-224x224/val/*.tfrec'), labeled=True, ordered=False)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.cache()\n    return dataset\n\ndef get_test_dataset(ordered=False):\n    dataset = load_dataset(tf.io.gfile.glob(GCS_DS_PATH + '/tfrecords-jpeg-224x224/test/*.tfrec'), labeled=False, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"import tensorflow as tf \nimport tensorflow.keras as tfk\nimport numpy as np \nimport glob\nimport pandas as pd \nfrom skimage import io, transform\nfrom tqdm.notebook import tqdm\n\ntpu = tf.distribute.cluster_resolver.TPUClusterResolver()\ntf.config.experimental_connect_to_cluster(tpu)\ntf.tpu.experimental.initialize_tpu_system(tpu)\nstrategy = tf.distribute.experimental.TPUStrategy(tpu)\n\nlearning_rate = 0.01        \n\nwith strategy.scope():\n    \n    model = tfk.models.Sequential()\n    \n    pt = tfk.applications.resnet.ResNet50 \n\n    \n    ptmod = pt(include_top=False\n                , weights='imagenet'\n                , input_tensor=None\n                , input_shape=(256, 256, 3)\n                , pooling = 'avg')\n\n\n    model.add(ptmod)\n#     model.add(tfk.layers.Dropout(rate = 0.5))\n#     model.add(GlobalAveragePooling2D())\n    model.add(tfk.layers.Dense(1000))\n    model.add(tfk.layers.Activation('softmax'))\n    \n    optimizer = tfk.optimizers.Adam(learning_rate = learning_rate)\n\n\n    model.compile(loss='categorical_crossentropy', optimizer=optimizer)\n\n    model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# training_dataset = get_training_dataset()\n# validation_dataset = get_validation_dataset()\n\n# with strategy.scope():\n#     pretrained_model = tf.keras.applications.ResNet50V2(\n#     weights='imagenet',\n#     include_top=False ,\n#     input_shape=[*IMAGE_SIZE, 3]\n#     )\n#     pretrained_model.trainable = False\n    \n#     model = tf.keras.Sequential([\n#         # To a base pretrained on ImageNet to extract features from images...\n#         pretrained_model,\n#         # ... attach a new head to act as a classifier.\n#         tf.keras.layers.GlobalAveragePooling2D(),\n#         tf.keras.layers.Dense(1000, activation='softmax')\n#     ])\n#     model.compile(\n#         optimizer='adam',\n#         loss = 'sparse_categorical_crossentropy',\n#         metrics=['sparse_categorical_accuracy'],\n#     )\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Kaggle Staff\nNot quite, if you use a TPU to train on a public Kaggle dataset, the GCS costs (because data will be coming from GCS in that case as well) will be covered by Kaggle.\nTraining on your own private bucket is not yet officially supported. I expect it will work if you know how to set IAMs correctly. If you manage to make it work, you are still paying for usage of your own bucket.\n\nAlso, if you do make private buckets work, tell us how you did it exactly. It is not a feature we focused on at launch but we still want to hear about the user experience, especially if it could be improved.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"historical = model.fit_generator(train_gen, \n          steps_per_epoch=STEPS_PER_EPOCH, \n          epochs = EPOCHS,\n          callbacks = [learning_rate_reduction],\n          validation_data=val_gen)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"sub = pd.read_csv(\"/kaggle/input/landmark-recognition-2020/sample_submission.csv\")\nsub[\"filename\"] = sub.id.str[0]+\"/\"+sub.id.str[1]+\"/\"+sub.id.str[2]+\"/\"+sub.id+\".jpg\"\nsub","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_gen = ImageDataGenerator().flow_from_dataframe(\n    sub,\n    directory=\"/kaggle/input/landmark-recognition-2020/test/\",\n    x_col=\"filename\",\n    y_col=None,\n    weight_col=None,\n    target_size=(256, 256),\n    color_mode=\"rgb\",\n    classes=None,\n    class_mode=None,\n    batch_size=1,\n    shuffle=True,\n    subset=None,\n    interpolation=\"nearest\",\n    validate_filenames=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_pred_one_hot = model.predict_generator(test_gen, verbose=1, steps=len(sub))\ny_pred = np.argmax(y_pred_one_hot, axis=-1)\ny_prob = np.max(y_pred_one_hot, axis=-1)\nprint(y_pred.shape, y_prob.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_uniq = np.unique(train_keep.landmark_id.values)\n\ny_pred = [y_uniq[Y] for Y in y_pred]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(len(sub)):\n    sub.loc[i, \"landmarks\"] = str(y_pred[i])+\" \"+str(y_prob[i])\nsub = sub.drop(columns=\"filename\")\nsub.to_csv(\"submission.csv\", index=False)\nsub\n","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}