{"cells":[{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":0.039382,"end_time":"2020-11-19T21:45:23.042097","exception":false,"start_time":"2020-11-19T21:45:23.002715","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Introduction\n**Who this notebook is for**  \nThis notebook is for anyone interested in creating a baseline model using Tensor Processing Units (TPUs) and begin making submissions to the Cassava Leaf Disease Classification competition. If you've taken the **[Kaggle Intro to Deep Learning](https://www.kaggle.com/learn/intro-to-deep-learning)** and//or the **[Kaggle Computer Vision](https://www.kaggle.com/learn/computer-vision)** course you'll find this notebook to be a good starting place to bridge what you've learned in our micro-courses and applying that knowledge to get started in a competition.  \n\n**TPUs with TensorFlow**  \nWe'll be using TensorFlow and Keras to build our computer vision model, and using TPUs to both train our model and make predictions. If you'd like to learn about more about TPUs be sure to check out our **[Learn With Me: Getting Started with Tensor Processing Units (TPUs)](https://youtu.be/1pdwRQ1DQfY)** video.  \n\n**References**  \nThis notebook was built using the following amazing resources created by Kagglers:\n- **Martin Gorner:** [Getting Started With 100 Flowers on TPU](https://www.kaggle.com/mgornergoogle/getting-started-with-100-flowers-on-tpu)\n- **Amy Jang:** [TensorFlow + Transfer Learning: Melanoma](https://www.kaggle.com/amyjang/tensorflow-transfer-learning-melanoma)\n- **Phil Culliton:** [A Simple TF 2.1 Notebook](https://www.kaggle.com/philculliton/a-simple-tf-2-1-notebook)"},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"papermill":{"duration":0.035886,"end_time":"2020-11-19T21:45:23.118837","exception":false,"start_time":"2020-11-19T21:45:23.082951","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Tensor Processing Units (TPUs)\n\nTensor Processing Units (TPUs) are hardware accelerators that are specialized for deep learning tasks. All Kagglers have 30 hours of free TPU time each week, and can use up to 3 hours in a single session (although if you'd like to increase your TPU quota consider submitting an exemplary TPU notebook to our **[TPU Star program](https://www.kaggle.com/tpu-prize)**!)   \n\nYou can read through the Kaggle documentation on TPUs **[here](https://www.kaggle.com/docs/tpu)**, and check out the TPU Star notebooks **[here](https://www.kaggle.com/tpu-stars)**."},{"metadata":{"papermill":{"duration":0.037375,"end_time":"2020-11-19T21:45:23.192515","exception":false,"start_time":"2020-11-19T21:45:23.15514","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Set up environment"},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:45:23.274004Z","iopub.status.busy":"2020-11-19T21:45:23.273154Z","iopub.status.idle":"2020-11-19T21:45:30.119096Z","shell.execute_reply":"2020-11-19T21:45:30.119725Z"},"papermill":{"duration":6.890298,"end_time":"2020-11-19T21:45:30.119979","exception":false,"start_time":"2020-11-19T21:45:23.229681","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"import math, re, os\nimport tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom kaggle_datasets import KaggleDatasets\nfrom tensorflow import keras\nfrom functools import partial\nfrom sklearn.model_selection import train_test_split\nimport tensorflow_hub as hub\nprint(\"Tensorflow version \" + tf.__version__)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras import backend as K","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"XLA_ACCELERATE = True\n\n\nif XLA_ACCELERATE:\n    tf.config.optimizer.set_jit(True)\n    print('Accelerated Linear Algebra enabled')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install -q efficientnet\nimport efficientnet.tfkeras as enet","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.037444,"end_time":"2020-11-19T21:45:30.195328","exception":false,"start_time":"2020-11-19T21:45:30.157884","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Detect TPU\nWhat we're doing with our code here is making sure that we'll be sending our data across a TPU. What you're looking for is a printout of `Number of replicas: 8`, corresponding to the 8 cores of a TPU. If your printout instead says `Number of replicas: 1` you likely do not have TPUs enabled in your notebook.   \n\nTo enable TPUs navigate to the panel on the right and click on `Accelerator`. Choose TPU from the dropdown.  \n\nIf you'd like more TPU troubleshooting and optimization guidelines check out our **[Learn With Me: Troubleshooting and Optimizing TPUs video](https://youtu.be/BSeWHzjMHMU)**.  "},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:45:30.373218Z","iopub.status.busy":"2020-11-19T21:45:30.372403Z","iopub.status.idle":"2020-11-19T21:45:34.382672Z","shell.execute_reply":"2020-11-19T21:45:34.382035Z"},"papermill":{"duration":4.150374,"end_time":"2020-11-19T21:45:34.382816","exception":false,"start_time":"2020-11-19T21:45:30.232442","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"try:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Device:', tpu.master())\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nexcept:\n    strategy = tf.distribute.get_strategy()\nprint('Number of replicas:', strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.038122,"end_time":"2020-11-19T21:45:34.458722","exception":false,"start_time":"2020-11-19T21:45:34.4206","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Set up variables\nWe'll set up some of our variables for our notebook here. \n\nIf by chance you're using a private dataset, you'll also want to make sure that you have the **Google Cloud Software Development Kit (SDK)** attached to your notebook. You can find the Google Cloud SDK under the `Add-ons` dropdown menu at the top of your notebook. Documentation for the **Google Cloud Software Development Kit (SDK)** can be found **[here](https://www.kaggle.com/product-feedback/163416)**."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:45:34.555293Z","iopub.status.busy":"2020-11-19T21:45:34.541822Z","iopub.status.idle":"2020-11-19T21:47:59.71579Z","shell.execute_reply":"2020-11-19T21:47:59.714961Z"},"papermill":{"duration":145.219568,"end_time":"2020-11-19T21:47:59.715925","exception":false,"start_time":"2020-11-19T21:45:34.496357","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\nGCS_PATH = KaggleDatasets().get_gcs_path('cassava-leaf-disease-classification')\nBATCH_SIZE = 8 * strategy.num_replicas_in_sync\nIMAGE_SIZE = [512, 512]\n# IMAGE_SIZE = [224, 224]\nCLASSES = ['0', '1', '2', '3', '4']\nEPOCHS = 25","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data = pd.read_csv('../input/cassava-leaf-disease-classification/train.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# class_weights = (((1/train_data['label'].value_counts())*len(train_data))/5.).to_dict()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# class_weights","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.037843,"end_time":"2020-11-19T21:47:59.792061","exception":false,"start_time":"2020-11-19T21:47:59.754218","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Load the data\nIf you've primarily worked with notebooks in Learn, you've maybe noticed that data import and formatting is taken care of for you. But because we're working with competition data we'll have to handle this part of the pipeline ourselves.   \n\nThe data we're working with have been formatted into `TFRecords`, which are a format for storing a sequence of binary records. `TFRecords` work _really_ well with TPUs, and allow us to send a small number of large files across the TPU for processing.   \n\nIf you'd like to learn more about `TFRecords` and maybe even try creating them yourself, check out this **[TFRecords Basics notebook](https://www.kaggle.com/ryanholbrook/tfrecords-basics)** and **[corresponding video](https://youtu.be/KgjaC9VeOi8)** from Kaggle Data Scientist Ryan Holbrook.  \n\nBecause our data consists of `training` and `test` images only, we're going to split our `training` data into `training` and `validation` data using the `train_test_split()` function. "},{"metadata":{"papermill":{"duration":0.038439,"end_time":"2020-11-19T21:47:59.869037","exception":false,"start_time":"2020-11-19T21:47:59.830598","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## Decode the data\nIn the code chunk below we'll set up a series of functions that allow us to convert our images into tensors so that we can utilize them in our model. We'll also normalize our data. Our images are using a \"Red, Blue, Green (RBG)\" scale that has a range of [0, 255], and by normalizing it we'll set each pixel's value to a number in the range of [0, 1]. "},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:47:59.952622Z","iopub.status.busy":"2020-11-19T21:47:59.951868Z","iopub.status.idle":"2020-11-19T21:47:59.954997Z","shell.execute_reply":"2020-11-19T21:47:59.955558Z"},"papermill":{"duration":0.04859,"end_time":"2020-11-19T21:47:59.955731","exception":false,"start_time":"2020-11-19T21:47:59.907141","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def decode_image(image):\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n#     image = tf.image.resize(image, IMAGE_SIZE)\n    return image","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.039515,"end_time":"2020-11-19T21:48:00.034969","exception":false,"start_time":"2020-11-19T21:47:59.995454","status":"completed"},"tags":[]},"cell_type":"markdown","source":"If you think back to **[Intro to Machine Learning](https://www.kaggle.com/learn/intro-to-machine-learning)** you might remember how we set up variables like `X` and `y`, representing our `features`, `X`, and `prediction target`, `y`. This code is accomplishing something similar, although instead of using the labels `X` and `y`, our `features` are represented by the term `image` and our `prediction target` by the term `target`.  \n\nYou might also notice that this function accounts for unlabeled images. This is because our test image doesn't have any labels.  "},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:00.123967Z","iopub.status.busy":"2020-11-19T21:48:00.123143Z","iopub.status.idle":"2020-11-19T21:48:00.126902Z","shell.execute_reply":"2020-11-19T21:48:00.126284Z"},"papermill":{"duration":0.052475,"end_time":"2020-11-19T21:48:00.127039","exception":false,"start_time":"2020-11-19T21:48:00.074564","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def read_tfrecord(example, labeled):\n    tfrecord_format = {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"target\": tf.io.FixedLenFeature([], tf.int64)\n    } if labeled else {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"image_name\": tf.io.FixedLenFeature([], tf.string)\n    }\n    example = tf.io.parse_single_example(example, tfrecord_format)\n    image = decode_image(example['image'])\n    if labeled:\n        label = tf.cast(example['target'], tf.int32)\n        return image, label\n    idnum = example['image_name']\n    return image, idnum","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.038946,"end_time":"2020-11-19T21:48:00.205445","exception":false,"start_time":"2020-11-19T21:48:00.166499","status":"completed"},"tags":[]},"cell_type":"markdown","source":"We'll use the following function to load our dataset. One of the advantages of a TPU is that we can run multiple files across the TPU at once, and this accounts for the speed advantages of using a TPU. To capitalize on that, we want to make sure that we're using data as soon as it streams in, rather than creating a data streaming bottleneck."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:00.325942Z","iopub.status.busy":"2020-11-19T21:48:00.324875Z","iopub.status.idle":"2020-11-19T21:48:00.327502Z","shell.execute_reply":"2020-11-19T21:48:00.328493Z"},"papermill":{"duration":0.073623,"end_time":"2020-11-19T21:48:00.328703","exception":false,"start_time":"2020-11-19T21:48:00.25508","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def load_dataset(filenames, labeled=True, ordered=False):\n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False # disable order, increase speed\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE) # 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(partial(read_tfrecord, labeled=labeled), num_parallel_calls=AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.03958,"end_time":"2020-11-19T21:48:00.416432","exception":false,"start_time":"2020-11-19T21:48:00.376852","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## A note on using train_test_split()\nWhile I used `train_test_split()` to create both a `training` and `validation` dataset, consider exploring **[cross validation instead](https://www.kaggle.com/dansbecker/cross-validation)**."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:00.683596Z","iopub.status.busy":"2020-11-19T21:48:00.607588Z","iopub.status.idle":"2020-11-19T21:48:00.687244Z","shell.execute_reply":"2020-11-19T21:48:00.686445Z"},"papermill":{"duration":0.225941,"end_time":"2020-11-19T21:48:00.687385","exception":false,"start_time":"2020-11-19T21:48:00.461444","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"_, VALID_FILENAMES = train_test_split(\n    tf.io.gfile.glob(GCS_PATH + '/train_tfrecords/ld_train*.tfrec'),\n    test_size=0.35, random_state=5\n)\n\nTEST_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/test_tfrecords/ld_test*.tfrec')\n\nTRAINING_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/train_tfrecords/ld_train*.tfrec')","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.038372,"end_time":"2020-11-19T21:48:00.765394","exception":false,"start_time":"2020-11-19T21:48:00.727022","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## Adding in augmentations \nYou learned about augmentations in the **[Computer Vision: Data Augmentation](https://www.kaggle.com/ryanholbrook/data-augmentation)** lesson on Kaggle Learn, and here I've applied an augmentation available to us through TensorFlow. You can read more about these augmentations (as well as all of the other augmentations available to you!) in the **[TensorFlow tf.image documentation](https://www.tensorflow.org/api_docs/python/tf/image)**.  \n\nIf you're interested in learning how to create and use custom augmentations, check out these **[Rotation Augmentation GPU/TPU](https://www.kaggle.com/cdeotte/rotation-augmentation-gpu-tpu-0-96)** and **[CutMix and MixUp on GPU/TPU](https://www.kaggle.com/cdeotte/cutmix-and-mixup-on-gpu-tpu)** from Kaggle Grandmaster Chris Deotte."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:00.849827Z","iopub.status.busy":"2020-11-19T21:48:00.848867Z","iopub.status.idle":"2020-11-19T21:48:00.85179Z","shell.execute_reply":"2020-11-19T21:48:00.85115Z"},"papermill":{"duration":0.047715,"end_time":"2020-11-19T21:48:00.851918","exception":false,"start_time":"2020-11-19T21:48:00.804203","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# def data_augment(image, label):\n#     # Thanks to the dataset.prefetch(AUTO) statement in the following function this happens essentially for free on TPU. \n#     # Data pipeline code is executed on the \"CPU\" part of the TPU while the TPU itself is computing gradients.\n#     image = tf.image.random_flip_left_right(image)\n#     return image, label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"aug = tf.keras.Sequential([\n    tf.keras.layers.experimental.preprocessing.RandomFlip(),\n    tf.keras.layers.experimental.preprocessing.RandomRotation(0.7),\n    tf.keras.layers.experimental.preprocessing.RandomTranslation(0.6,0.6),\n    tf.keras.layers.experimental.preprocessing.RandomContrast((0.5,1))\n])","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.038742,"end_time":"2020-11-19T21:48:00.930185","exception":false,"start_time":"2020-11-19T21:48:00.891443","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## Define data loading methods\nThe following functions will be used to load our `training`, `validation`, and `test` datasets, as well as print out the number of images in each dataset."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:01.018921Z","iopub.status.busy":"2020-11-19T21:48:01.017912Z","iopub.status.idle":"2020-11-19T21:48:01.02164Z","shell.execute_reply":"2020-11-19T21:48:01.020852Z"},"papermill":{"duration":0.052326,"end_time":"2020-11-19T21:48:01.021791","exception":false,"start_time":"2020-11-19T21:48:00.969465","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def get_training_dataset():\n    dataset = load_dataset(TRAINING_FILENAMES, labeled=True).cache()  \n#     dataset = dataset  \n    dataset = dataset.repeat()\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE).map(lambda x,y: (aug(x, training=True), tf.one_hot(y, depth =5)), num_parallel_calls=AUTOTUNE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:01.109616Z","iopub.status.busy":"2020-11-19T21:48:01.108559Z","iopub.status.idle":"2020-11-19T21:48:01.111418Z","shell.execute_reply":"2020-11-19T21:48:01.111986Z"},"papermill":{"duration":0.049787,"end_time":"2020-11-19T21:48:01.112145","exception":false,"start_time":"2020-11-19T21:48:01.062358","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def get_validation_dataset(ordered=False):\n    dataset = load_dataset(VALID_FILENAMES, labeled=True, ordered=ordered).cache()\n    dataset = dataset.batch(BATCH_SIZE).map(lambda x,y: (x, tf.one_hot(y, depth =5)), num_parallel_calls=AUTOTUNE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:01.204402Z","iopub.status.busy":"2020-11-19T21:48:01.203418Z","iopub.status.idle":"2020-11-19T21:48:01.207545Z","shell.execute_reply":"2020-11-19T21:48:01.20682Z"},"papermill":{"duration":0.050395,"end_time":"2020-11-19T21:48:01.207665","exception":false,"start_time":"2020-11-19T21:48:01.15727","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def get_test_dataset(ordered=False):\n    dataset = load_dataset(TEST_FILENAMES, labeled=False, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:01.301631Z","iopub.status.busy":"2020-11-19T21:48:01.30084Z","iopub.status.idle":"2020-11-19T21:48:01.304479Z","shell.execute_reply":"2020-11-19T21:48:01.303807Z"},"papermill":{"duration":0.05422,"end_time":"2020-11-19T21:48:01.304611","exception":false,"start_time":"2020-11-19T21:48:01.250391","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def count_data_items(filenames):\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in filenames]\n    return np.sum(n)","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:01.39253Z","iopub.status.busy":"2020-11-19T21:48:01.391743Z","iopub.status.idle":"2020-11-19T21:48:01.395039Z","shell.execute_reply":"2020-11-19T21:48:01.395972Z"},"papermill":{"duration":0.051209,"end_time":"2020-11-19T21:48:01.396198","exception":false,"start_time":"2020-11-19T21:48:01.344989","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"NUM_TRAINING_IMAGES = count_data_items(TRAINING_FILENAMES)\nNUM_VALIDATION_IMAGES = count_data_items(VALID_FILENAMES)\nNUM_TEST_IMAGES = count_data_items(TEST_FILENAMES)\n\nprint('Dataset: {} training images, {} validation images, {} (unlabeled) test images'.format(\n    NUM_TRAINING_IMAGES, NUM_VALIDATION_IMAGES, NUM_TEST_IMAGES))","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.041086,"end_time":"2020-11-19T21:48:01.478205","exception":false,"start_time":"2020-11-19T21:48:01.437119","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Brief exploratory data analysis (EDA)\nFirst we'll print out the shapes and labels for a sample of each of our three datasets:"},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:01.575573Z","iopub.status.busy":"2020-11-19T21:48:01.574436Z","iopub.status.idle":"2020-11-19T21:48:18.597144Z","shell.execute_reply":"2020-11-19T21:48:18.596204Z"},"papermill":{"duration":17.07767,"end_time":"2020-11-19T21:48:18.597304","exception":false,"start_time":"2020-11-19T21:48:01.519634","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"print(\"Training data shapes:\")\nfor image, label in get_training_dataset().take(3):\n    print(image.numpy().shape, label.numpy().shape)\nprint(\"Training data label examples:\", label.numpy())\nprint(\"Validation data shapes:\")\nfor image, label in get_validation_dataset().take(3):\n    print(image.numpy().shape, label.numpy().shape)\nprint(\"Validation data label examples:\", label.numpy())\nprint(\"Test data shapes:\")\nfor image, idnum in get_test_dataset().take(3):\n    print(image.numpy().shape, idnum.numpy().shape)\nprint(\"Test data IDs:\", idnum.numpy().astype('U')) # U=unicode string","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.044101,"end_time":"2020-11-19T21:48:18.6862","exception":false,"start_time":"2020-11-19T21:48:18.642099","status":"completed"},"tags":[]},"cell_type":"markdown","source":"The following code chunk sets up a series of functions that will print out a grid of images. The grid of images will contain images and their corresponding labels."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:18.782198Z","iopub.status.busy":"2020-11-19T21:48:18.781353Z","iopub.status.idle":"2020-11-19T21:48:18.808005Z","shell.execute_reply":"2020-11-19T21:48:18.807301Z"},"papermill":{"duration":0.077342,"end_time":"2020-11-19T21:48:18.808133","exception":false,"start_time":"2020-11-19T21:48:18.730791","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# numpy and matplotlib defaults\nnp.set_printoptions(threshold=15, linewidth=80)\n\ndef batch_to_numpy_images_and_labels(data):\n    images, labels = data\n    numpy_images = images.numpy()\n    numpy_labels = labels.numpy()\n    if numpy_labels.dtype == object: # binary string in this case, these are image ID strings\n        numpy_labels = [None for _ in enumerate(numpy_images)]\n    # If no labels, only image IDs, return None for labels (this is the case for test data)\n    if None in numpy_labels:\n        return numpy_images, numpy_labels\n    return numpy_images, tf.argmax(numpy_labels, axis=-1)\n\ndef title_from_label_and_target(label, correct_label):\n    if correct_label is None:\n        return CLASSES[label], True\n    correct = (label == correct_label)\n    return \"{} [{}{}{}]\".format(CLASSES[label], 'OK' if correct else 'NO', u\"\\u2192\" if not correct else '',\n                                CLASSES[correct_label] if not correct else ''), correct\n\ndef display_one_plant(image, title, subplot, red=False, titlesize=16):\n    plt.subplot(*subplot)\n    plt.axis('off')\n    plt.imshow(image)\n    if len(title) > 0:\n        plt.title(title, fontsize=int(titlesize) if not red else int(titlesize/1.2), color='red' if red else 'black', fontdict={'verticalalignment':'center'}, pad=int(titlesize/1.5))\n    return (subplot[0], subplot[1], subplot[2]+1)\n\ndef display_batch_of_images(databatch, predictions=None):\n    \"\"\"This will work with:\n    display_batch_of_images(images)\n    display_batch_of_images(images, predictions)\n    display_batch_of_images((images, labels))\n    display_batch_of_images((images, labels), predictions)\n    \"\"\"\n    # data\n    images, labels = batch_to_numpy_images_and_labels(databatch)\n    if labels is None:\n        labels = [None for _ in enumerate(images)]\n        \n    # auto-squaring: this will drop data that does not fit into square or square-ish rectangle\n    rows = int(math.sqrt(len(images)))\n    cols = len(images)//rows\n        \n    # size and spacing\n    FIGSIZE = 13.0\n    SPACING = 0.1\n    subplot=(rows,cols,1)\n    if rows < cols:\n        plt.figure(figsize=(FIGSIZE,FIGSIZE/cols*rows))\n    else:\n        plt.figure(figsize=(FIGSIZE/rows*cols,FIGSIZE))\n    \n    # display\n    for i, (image, label) in enumerate(zip(images[:rows*cols], labels[:rows*cols])):\n        title = '' if label is None else CLASSES[label]\n        correct = True\n        if predictions is not None:\n            title, correct = title_from_label_and_target(predictions[i], label)\n        dynamic_titlesize = FIGSIZE*SPACING/max(rows,cols)*40+3 # magic formula tested to work from 1x1 to 10x10 images\n        subplot = display_one_plant(image, title, subplot, not correct, titlesize=dynamic_titlesize)\n    \n    #layout\n    plt.tight_layout()\n    if label is None and predictions is None:\n        plt.subplots_adjust(wspace=0, hspace=0)\n    else:\n        plt.subplots_adjust(wspace=SPACING, hspace=SPACING)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:18.904519Z","iopub.status.busy":"2020-11-19T21:48:18.903424Z","iopub.status.idle":"2020-11-19T21:48:18.956871Z","shell.execute_reply":"2020-11-19T21:48:18.956219Z"},"papermill":{"duration":0.104176,"end_time":"2020-11-19T21:48:18.957003","exception":false,"start_time":"2020-11-19T21:48:18.852827","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# load our training dataset for EDA\ntraining_dataset = get_training_dataset()\ntraining_dataset = training_dataset.unbatch().batch(20)\ntrain_batch = iter(training_dataset)","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:20.176923Z","iopub.status.busy":"2020-11-19T21:48:20.175758Z","iopub.status.idle":"2020-11-19T21:48:22.374002Z","shell.execute_reply":"2020-11-19T21:48:22.374605Z"},"papermill":{"duration":3.371477,"end_time":"2020-11-19T21:48:22.374778","exception":false,"start_time":"2020-11-19T21:48:19.003301","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# run this cell again for another randomized set of training images\ndisplay_batch_of_images(next(train_batch))","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.086379,"end_time":"2020-11-19T21:48:22.547481","exception":false,"start_time":"2020-11-19T21:48:22.461102","status":"completed"},"tags":[]},"cell_type":"markdown","source":"You can also modify the above code to look at your `validation` and `test` data, like this:"},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:22.732786Z","iopub.status.busy":"2020-11-19T21:48:22.731592Z","iopub.status.idle":"2020-11-19T21:48:22.769732Z","shell.execute_reply":"2020-11-19T21:48:22.768929Z"},"papermill":{"duration":0.136485,"end_time":"2020-11-19T21:48:22.769878","exception":false,"start_time":"2020-11-19T21:48:22.633393","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# load our validation dataset for EDA\nvalidation_dataset = get_validation_dataset()\nvalidation_dataset = validation_dataset.unbatch().batch(20)\nvalid_batch = iter(validation_dataset)","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:22.946423Z","iopub.status.busy":"2020-11-19T21:48:22.945571Z","iopub.status.idle":"2020-11-19T21:48:26.010139Z","shell.execute_reply":"2020-11-19T21:48:26.010819Z"},"papermill":{"duration":3.155802,"end_time":"2020-11-19T21:48:26.010993","exception":false,"start_time":"2020-11-19T21:48:22.855191","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# run this cell again for another randomized set of training images\ndisplay_batch_of_images(next(valid_batch))","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:26.368142Z","iopub.status.busy":"2020-11-19T21:48:26.367301Z","iopub.status.idle":"2020-11-19T21:48:26.410393Z","shell.execute_reply":"2020-11-19T21:48:26.411021Z"},"papermill":{"duration":0.232531,"end_time":"2020-11-19T21:48:26.411209","exception":false,"start_time":"2020-11-19T21:48:26.178678","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# load our test dataset for EDA\ntesting_dataset = get_test_dataset()\ntesting_dataset = testing_dataset.unbatch().batch(20)\ntest_batch = iter(testing_dataset)","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:26.744678Z","iopub.status.busy":"2020-11-19T21:48:26.743913Z","iopub.status.idle":"2020-11-19T21:48:27.89988Z","shell.execute_reply":"2020-11-19T21:48:27.900494Z"},"papermill":{"duration":1.333241,"end_time":"2020-11-19T21:48:27.900651","exception":false,"start_time":"2020-11-19T21:48:26.56741","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# we only have one test image\ndisplay_batch_of_images(next(test_batch))","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:28.8307Z","iopub.status.busy":"2020-11-19T21:48:28.829632Z","iopub.status.idle":"2020-11-19T21:48:28.833152Z","shell.execute_reply":"2020-11-19T21:48:28.832481Z"},"papermill":{"duration":0.248904,"end_time":"2020-11-19T21:48:28.83328","exception":false,"start_time":"2020-11-19T21:48:28.584376","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# lr_scheduler = keras.optimizers.schedules.ExponentialDecay(\n#     initial_learning_rate=1e-5, \n#     decay_steps=10000, \n#     decay_rate=0.9)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def compute_class_freqs(labels):\n    \"\"\"\n    Compute positive and negative frequences for each class.\n\n    Args:\n        labels (np.array): matrix of labels, size (num_examples, num_classes)\n    Returns:\n        positive_frequencies (np.array): array of positive frequences for each\n                                         class, size (num_classes)\n        negative_frequencies (np.array): array of negative frequences for each\n                                         class, size (num_classes)\n    \"\"\"\n    ### START CODE HERE (REPLACE INSTANCES OF 'None' with your code) ###\n    \n    # total number of patients (rows)\n    N = labels.shape[0]\n    \n    positive_frequencies = np.mean(labels, axis=0)\n    negative_frequencies = 1 - positive_frequencies\n\n    ### END CODE HERE ###\n    return positive_frequencies, negative_frequencies","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data['label'].values[:10]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"freq_pos, freq_neg = compute_class_freqs(tf.one_hot(train_data['label'].values, depth=5))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import seaborn as sns\n\ndata = pd.DataFrame({\"Class\": CLASSES, \"Label\": \"Positive\", \"Value\": freq_pos})\ndata = data.append([{\"Class\": CLASSES[l], \"Label\": \"Negative\", \"Value\": v} for l,v in enumerate(freq_neg)], ignore_index=True)\nplt.xticks(rotation=90)\nf = sns.barplot(x=\"Class\", y=\"Value\", hue=\"Label\" ,data=data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pos_weights = freq_neg\nneg_weights = freq_pos\npos_contribution = freq_pos * pos_weights \nneg_contribution = freq_neg * neg_weights","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data = pd.DataFrame({\"Class\": CLASSES, \"Label\": \"Positive\", \"Value\": pos_contribution})\ndata = data.append([{\"Class\": CLASSES[l], \"Label\": \"Negative\", \"Value\": v} \n                        for l,v in enumerate(neg_contribution)], ignore_index=True)\nplt.xticks(rotation=90)\nsns.barplot(x=\"Class\", y=\"Value\", hue=\"Label\" ,data=data);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_weighted_loss(pos_weights, neg_weights, epsilon=1e-7):\n    \"\"\"\n    Return weighted loss function given negative weights and positive weights.\n\n    Args:\n      pos_weights (np.array): array of positive weights for each class, size (num_classes)\n      neg_weights (np.array): array of negative weights for each class, size (num_classes)\n    \n    Returns:\n      weighted_loss (function): weighted loss function\n    \"\"\"\n    def weighted_loss(y_true, y_pred):\n        \"\"\"\n        Return weighted loss value. \n\n        Args:\n            y_true (Tensor): Tensor of true labels, size is (num_examples, num_classes)\n            y_pred (Tensor): Tensor of predicted labels, size is (num_examples, num_classes)\n        Returns:\n            loss (Tensor): overall scalar loss summed across all classes\n        \"\"\"\n        # initialize loss to zero\n        loss = 0.0\n        \n        ### START CODE HERE (REPLACE INSTANCES OF 'None' with your code) ###\n\n        loss_pos = -1. * K.sum(K.mean(pos_weights * y_true * K.log(y_pred+epsilon), axis=0))\n        loss_neg = -1. * K.sum(K.mean(neg_weights * (1 - y_true) * K.log(1-y_pred+epsilon), axis=0))\n        return loss_pos+loss_neg\n    \n        ### END CODE HERE ###\n    return weighted_loss","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.22538,"end_time":"2020-11-19T21:48:29.285377","exception":false,"start_time":"2020-11-19T21:48:29.059997","status":"completed"},"tags":[]},"cell_type":"markdown","source":"## Building our model\nIn order to ensure that our model is trained on the TPU, we build it using `with strategy.scope()`.    \n\nThis model was built using transfer learning, meaning that we have a _pre-trained model_ (ResNet50) as our base model and then the customizable model built using `tf.keras.Sequential`. If you're new to transfer learning I recommend setting `base_model.trainable` to **False**, but _do_ encourage you to change which base model you're using (more options are available in the **[`tf.keras.applications` Module](https://www.tensorflow.org/api_docs/python/tf/keras/applications)** documentation) as well iterate on the custom model. \n"},{"metadata":{"trusted":true},"cell_type":"code","source":"EPOCHS = 50","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:29.74622Z","iopub.status.busy":"2020-11-19T21:48:29.745069Z","iopub.status.idle":"2020-11-19T21:48:49.158244Z","shell.execute_reply":"2020-11-19T21:48:49.157378Z"},"papermill":{"duration":19.661572,"end_time":"2020-11-19T21:48:49.158413","exception":false,"start_time":"2020-11-19T21:48:29.496841","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"\nwith strategy.scope():\n    eb7 = enet.EfficientNetB7(input_shape=[*IMAGE_SIZE, 3], weights='noisy-student', include_top=False)\n    eb7.trainable = True\n\n    model = tf.keras.Sequential([\n        eb7,\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.Dense(len(CLASSES), activation='softmax')\n    ])\n    \n    \n#     for layer in model.layers:\n#         if isinstance(layer, tf.keras.layers.BatchNormalization):\n#             # we do aggressive exponential smoothing of batch norm\n#             # parameters to faster adjust to our new dataset\n#             layer.momentum = 0.99\n    \n    \n    model.compile(\n    optimizer=tf.keras.optimizers.Adam(0.0001),\n    loss = get_weighted_loss(pos_weights, neg_weights),\n    metrics=['acc'],\n    )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"##### # Learning Rate Schedule for Fine Tuning #\ndef exponential_lr(epoch,\n                   start_lr = 0.0001, min_lr = 0.00001, max_lr = 0.0001,\n                   rampup_epochs = 5, sustain_epochs = 0,\n                   exp_decay = 0.8):\n\n    def lr(epoch, start_lr, min_lr, max_lr, rampup_epochs, sustain_epochs, exp_decay):\n        # linear increase from start to rampup_epochs\n        if epoch < rampup_epochs:\n            lr = ((max_lr - start_lr) /\n                  rampup_epochs * epoch + start_lr)\n        # constant max_lr during sustain_epochs\n        elif epoch < rampup_epochs + sustain_epochs:\n            lr = max_lr\n        # exponential decay towards min_lr\n        else:\n            lr = ((max_lr - min_lr) *\n                  exp_decay**(epoch - rampup_epochs - sustain_epochs) +\n                  min_lr)\n        return lr\n    return lr(epoch,\n              start_lr,\n              min_lr,\n              max_lr,\n              rampup_epochs,\n              sustain_epochs,\n              exp_decay)\n\n\n\nrng = [i for i in range(50)]\ny = [exponential_lr(x) for x in rng]\nplt.plot(rng, y)\nprint(\"Learning rate schedule: {:.3g} to {:.3g} to {:.3g}\".format(y[0], max(y), y[-1]))","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.174404,"end_time":"2020-11-19T21:48:49.513099","exception":false,"start_time":"2020-11-19T21:48:49.338695","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Train the model\nAs our model is training you'll see a printout for each epoch, and can also monitor TPU usage by clicking on the TPU metrics in the toolbar at the top right of your notebook."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T21:48:49.868188Z","iopub.status.busy":"2020-11-19T21:48:49.867432Z","iopub.status.idle":"2020-11-19T21:48:49.93567Z","shell.execute_reply":"2020-11-19T21:48:49.936263Z"},"papermill":{"duration":0.249051,"end_time":"2020-11-19T21:48:49.936435","exception":false,"start_time":"2020-11-19T21:48:49.687384","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# load data\ntrain_dataset = get_training_dataset()\nvalid_dataset = get_validation_dataset()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.callbacks import ModelCheckpoint\nfilepath=\"flower1.h5\"\ncheckpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=True, mode='min')\nlr_callback = tf.keras.callbacks.LearningRateScheduler(exponential_lr, verbose=True)\nes = tf.keras.callbacks.EarlyStopping(\n    monitor='val_loss', min_delta=0, patience=6, verbose=1, restore_best_weights=True)\n\n# Define training epochs\nEPOCHS = 50\nSTEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\nVALID_STEPS = NUM_VALIDATION_IMAGES // BATCH_SIZE\n\nhistory = model.fit(\n    train_dataset,\n    validation_data=valid_dataset,\n    epochs=EPOCHS,\n    steps_per_epoch=STEPS_PER_EPOCH,\n    validation_steps=VALID_STEPS,\n    callbacks=[lr_callback, checkpoint, es],\n#     class_weight= class_weights\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights('./flower1.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# from keras.utils.generic_utils import get_custom_objects\n\n# get_custom_objects().update({'my_custom_func': get_weighted_loss})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# model.trainable=True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"##### # Learning Rate Schedule for Fine Tuning #\n# def exponential_lr(epoch,\n#                    start_lr = 0.0001, min_lr = 0.00001, max_lr = 0.0001,\n#                    rampup_epochs = 3, sustain_epochs = 0,\n#                    exp_decay = 0.8):\n\n#     def lr(epoch, start_lr, min_lr, max_lr, rampup_epochs, sustain_epochs, exp_decay):\n#         # linear increase from start to rampup_epochs\n#         if epoch < rampup_epochs:\n#             lr = ((max_lr - start_lr) /\n#                   rampup_epochs * epoch + start_lr)\n#         # constant max_lr during sustain_epochs\n#         elif epoch < rampup_epochs + sustain_epochs:\n#             lr = max_lr\n#         # exponential decay towards min_lr\n#         else:\n#             lr = ((max_lr - min_lr) *\n#                   exp_decay**(epoch - rampup_epochs - sustain_epochs) +\n#                   min_lr)\n#         return lr\n#     return lr(epoch,\n#               start_lr,\n#               min_lr,\n#               max_lr,\n#               rampup_epochs,\n#               sustain_epochs,\n#               exp_decay)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# from tensorflow.keras.callbacks import ModelCheckpoint\n# filepath=\"flower2\"\n# checkpoint = ModelCheckpoint(filepath, monitor='val_loss', verbose=1, save_best_only=True, mode='min')\n# lr_callback = tf.keras.callbacks.LearningRateScheduler(exponential_lr, verbose=True)\n# es = tf.keras.callbacks.EarlyStopping(\n#     monitor='val_loss', min_delta=0, patience=10, verbose=1, restore_best_weights=True)\n\n# # Define training epochs\n# EPOCHS = 25\n# STEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\n# VALID_STEPS = NUM_VALIDATION_IMAGES // BATCH_SIZE\n\n# history = model.fit(\n#     train_dataset,\n#     validation_data=valid_dataset,\n#     epochs=EPOCHS,\n#     steps_per_epoch=STEPS_PER_EPOCH,\n#     validation_steps=VALID_STEPS,\n#     callbacks=[lr_callback, checkpoint, es],\n# #     class_weight= class_weights\n# )","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":1.245239,"end_time":"2020-11-19T22:04:54.493139","exception":false,"start_time":"2020-11-19T22:04:53.2479","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Evaluating our model\nThe first chunk of code is provided to show you where the variables in the second chunk of code came from. As you can see, there's a lot of room for improvement in this model, but because we're using TPUs and have a relatively short training time, we're able to iterate on our model fairly rapidly."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T22:04:57.050462Z","iopub.status.busy":"2020-11-19T22:04:57.0494Z","iopub.status.idle":"2020-11-19T22:04:57.053166Z","shell.execute_reply":"2020-11-19T22:04:57.053855Z"},"papermill":{"duration":1.31245,"end_time":"2020-11-19T22:04:57.054025","exception":false,"start_time":"2020-11-19T22:04:55.741575","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# print out variables available to us\nprint(history.history.keys())","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T22:04:59.5746Z","iopub.status.busy":"2020-11-19T22:04:59.573814Z","iopub.status.idle":"2020-11-19T22:04:59.983142Z","shell.execute_reply":"2020-11-19T22:04:59.982506Z"},"papermill":{"duration":1.671861,"end_time":"2020-11-19T22:04:59.983272","exception":false,"start_time":"2020-11-19T22:04:58.311411","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# create learning curves to evaluate model performance\nhistory_frame = pd.DataFrame(history.history)\nhistory_frame.loc[:, ['loss', 'val_loss']].plot()\nhistory_frame.loc[:, ['acc', 'val_acc']].plot();","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset = get_validation_dataset()\ndataset = dataset.unbatch().batch(20)\nbatch = iter(dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"temp = next(batch)\nimages, _ = temp\nprobabilities = model.predict(images)\n# probabilities2 = model2.predict(images)\n# probabilities = alpha*probabilities1+(1-alpha)*probabilities2\npredictions = np.argmax(probabilities, axis=-1)\ndisplay_batch_of_images(temp, predictions)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cmdataset = get_validation_dataset(ordered=True)\nimages_ds = cmdataset.map(lambda image, label: image)\nlabels_ds = cmdataset.map(lambda image, label: label).unbatch()\n\ncm_correct_labels = next(iter(labels_ds.batch(NUM_VALIDATION_IMAGES))).numpy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cm_correct_labels.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cm_probabilities = model.predict(images_ds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom sklearn.metrics import f1_score, precision_score, recall_score, confusion_matrix\n\ndef display_confusion_matrix(cmat, score, precision, recall):\n    plt.figure(figsize=(15,15))\n    ax = plt.gca()\n    sns.heatmap(cmat, annot=True, ax=ax)\n#     ax.matshow(cmat, cmap='Reds')\n    ax.set_xticks(range(len(CLASSES)))\n    ax.set_xticklabels(CLASSES, fontdict={'fontsize': 15})\n    plt.setp(ax.get_xticklabels(), rotation=45, ha=\"left\", rotation_mode=\"anchor\")\n    ax.set_yticks(range(len(CLASSES)))\n    ax.set_yticklabels(CLASSES, fontdict={'fontsize': 15})\n    plt.setp(ax.get_yticklabels(), rotation=45, ha=\"right\", rotation_mode=\"anchor\")\n    ax.set_xlabel('Actual', fontdict={'fontsize': 15})\n    ax.set_ylabel('Prediction', fontdict={'fontsize': 15})\n    \n    titlestring = \"\"\n    if score is not None:\n        titlestring += 'f1 = {:.3f} '.format(score)\n    if precision is not None:\n        titlestring += '\\nprecision = {:.3f} '.format(precision)\n    if recall is not None:\n        titlestring += '\\nrecall = {:.3f} '.format(recall)\n    if len(titlestring) > 0:\n        ax.text(-1, -1, titlestring, fontdict={'fontsize': 18, 'horizontalalignment':'right', 'verticalalignment':'top', 'color':'#804040'})\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cm_correct_labels = np.argmax(cm_correct_labels, axis =-1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cm_predictions = np.argmax(cm_probabilities, axis=-1)\n\nlabels = range(len(CLASSES))\ncmat = confusion_matrix(\n    cm_correct_labels,\n    cm_predictions,\n    labels=labels,\n)\ncmat = (cmat.T / cmat.sum(axis=1)).T # normalize","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"score = f1_score(\n    cm_correct_labels,\n    cm_predictions,\n    labels=labels,\n    average='macro',\n)\nprecision = precision_score(\n    cm_correct_labels,\n    cm_predictions,\n    labels=labels,\n    average='macro',\n)\nrecall = recall_score(\n    cm_correct_labels,\n    cm_predictions,\n    labels=labels,\n    average='macro',\n)\ndisplay_confusion_matrix(cmat, score, precision, recall)","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":1.326243,"end_time":"2020-11-19T22:05:02.628032","exception":false,"start_time":"2020-11-19T22:05:01.301789","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Making predictions\nNow that we've trained our model we can use it to make predictions! "},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T22:05:05.184942Z","iopub.status.busy":"2020-11-19T22:05:05.183725Z","iopub.status.idle":"2020-11-19T22:05:05.18757Z","shell.execute_reply":"2020-11-19T22:05:05.186823Z"},"papermill":{"duration":1.270192,"end_time":"2020-11-19T22:05:05.187694","exception":false,"start_time":"2020-11-19T22:05:03.917502","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# # this code will convert our test image data to a float32 \n# def to_float32(image, label):\n#     return tf.cast(image, tf.float32), label","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T22:05:07.746039Z","iopub.status.busy":"2020-11-19T22:05:07.744935Z","iopub.status.idle":"2020-11-19T22:05:22.234912Z","shell.execute_reply":"2020-11-19T22:05:22.235492Z"},"papermill":{"duration":15.776858,"end_time":"2020-11-19T22:05:22.235661","exception":false,"start_time":"2020-11-19T22:05:06.458803","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# test_ds = get_test_dataset(ordered=True) \n# test_ds = test_ds.map(to_float32)\n\n# print('Computing predictions...')\n# test_images_ds = testing_dataset\n# test_images_ds = test_ds.map(lambda image, idnum: image)\n# probabilities = model.predict(test_images_ds)\n# predictions = np.argmax(probabilities, axis=-1)\n# print(predictions)","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":1.271799,"end_time":"2020-11-19T22:05:24.759257","exception":false,"start_time":"2020-11-19T22:05:23.487458","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Creating a submission file\nNow that we've trained a model and made predictions we're ready to submit to the competition! You can run the following code below to get your submission file."},{"metadata":{"execution":{"iopub.execute_input":"2020-11-19T22:05:27.316025Z","iopub.status.busy":"2020-11-19T22:05:27.315202Z","iopub.status.idle":"2020-11-19T22:05:28.241598Z","shell.execute_reply":"2020-11-19T22:05:28.24078Z"},"papermill":{"duration":2.185537,"end_time":"2020-11-19T22:05:28.241723","exception":false,"start_time":"2020-11-19T22:05:26.056186","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"# print('Generating submission.csv file...')\n# test_ids_ds = test_ds.map(lambda image, idnum: idnum).unbatch()\n# test_ids = next(iter(test_ids_ds.batch(NUM_TEST_IMAGES))).numpy().astype('U') # all in one batch\n# np.savetxt('submission.csv', np.rec.fromarrays([test_ids, predictions]), fmt=['%s', '%d'], delimiter=',', header='id,label', comments='')\n# !head submission.csv","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":1.255302,"end_time":"2020-11-19T22:05:30.746339","exception":false,"start_time":"2020-11-19T22:05:29.491037","status":"completed"},"tags":[]},"cell_type":"markdown","source":"Be aware that because this is a code competition with a hidden test set, internet and TPUs cannot be enabled on your submission notebook. Therefore TPUs will only be available for training models. For a walk-through on how to train on TPUs and run inference/submit on GPUs, see our [TPU Docs](https://www.kaggle.com/docs/tpu#tpu6)."}],"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}