{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Introduction\n\n![](https://scx2.b-cdn.net/gfx/news/2019/3-geneeditingt.jpg)\n\n\n### About Notebook:\n\nWhile creating this notebook I aimed for building upon baseline TPU notebook with some additions and new neural network architectures like augmentations, efficientnet etc. We'll be using Keras/TF while TPUs computing power to it's extend! \n\n### About Competition:\n\nCassava is the third-largest source of food carbohydrates in the tropics, after rice and maize. Cassava is a major staple food in the developing world, providing a basic diet for over half a billion people. It is one of the most drought-tolerant crops, capable of growing on marginal soils. Nigeria is the world's largest producer of cassava, while Thailand is the largest exporter of cassava starch. \n\n#### Problem:\n\nWhile it's being one of the most drought-tolerant crops they are pretty vulnerable viral diseases and causing major poor yields even causing famines. More surveys need to be conducted so that the disease spread and variant affinity can be better understood. \n\n#### Solution:\n\nTo stop spread of the disease, discouragement of affected varieties as crops can be more quickly done with tracking. With the help of data science, it may be possible to identify common diseases so they can be treated.\n\n#### Goals:\n\nOur task is to classify each cassava image into four disease categories or a fifth category indicating a healthy leaf. By applying machine learning identification for this specific problem, farmers may be able to quickly identify diseased plants, potentially saving their crops before they inflict irreparable damage.\n\n#### Eval Metric:\n\nOur predictions will be eveluated based on their categorization accuracy.\n\n#### References:\n\n- [Getting Started: TPUs + Cassava Leaf Disease](https://www.kaggle.com/jessemostipak/getting-started-tpus-cassava-leaf-disease)\n- [Rotation Augmentation GPU/TPU - [0.96+]](https://www.kaggle.com/cdeotte/rotation-augmentation-gpu-tpu-0-96)\n- [Cassava TFRecords 512x512](https://www.kaggle.com/spidermandance/cassava-tfrecords-512x512)\n"},{"metadata":{},"cell_type":"markdown","source":"# Loading Packages"},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"import sys\nsys.path.append('/kaggle/input/efficientnet-keras-dataset/efficientnet_kaggle')\n! pip install -e /kaggle/input/efficientnet-keras-dataset/efficientnet_kaggle","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import math, re, os\nimport pandas as pd\nimport plotly.express as px\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\nimport tensorflow.keras.backend as K\nimport efficientnet.tfkeras as efn\nfrom sklearn.model_selection import train_test_split\nprint(\"Tensorflow version \" + tf.__version__)\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Target Distribution\n\n### We got pretty unbalanced data, that might be the one of the biggest obstacles we going to encounter. If we look closely we can see that only 12% of the data consists of healthy plants. Meanwhile most of the data (61%) being \"Cassava Mosaic Disease (CMD)\" examples."},{"metadata":{"trusted":true},"cell_type":"code","source":"train = pd.read_csv('../input/cassava-leaf-disease-classification/train.csv')\ntrain['disease'] = train.label.map({0:\"Cassava Bacterial Blight (CBB)\",\n1:\"Cassava Brown Streak Disease (CBSD)\",\n2:\"Cassava Green Mottle (CGM)\",\n3:\"Cassava Mosaic Disease (CMD)\",\n4:\"Healthy\"})\ndiseases = train.disease.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nfig = px.pie(diseases,\n             values='disease',\n             names=diseases.index,\n             #color_discrete_sequence=orange_black,\n             hole=.4)\nfig.update_traces(textinfo='percent+label', pull=0.05)\nfig.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Setting TPU\n\n### Here we setting TPU as main device for training. Depending on your image sizes you can train bigger batches for faster training with these monster TPUs."},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"DEVICE = 'TPU'\nMIXED_PRECISION = True\nXLA_ACCELERATE = True\n\n# We set our TPU settings here mixed_precision to use bigger batches\n\nif DEVICE == 'TPU':\n    print('Connecting to TPU...')\n    try:\n        tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n        print('Running on TPU ', tpu.master())\n    except ValueError:\n        print('Could not connect to TPU')\n        tpu = None\n\n    if tpu:\n        try:\n            print('initializing  TPU ...')\n            tf.config.experimental_connect_to_cluster(tpu)\n            tf.tpu.experimental.initialize_tpu_system(tpu)\n            strategy = tf.distribute.experimental.TPUStrategy(tpu)            \n            print('TPU initialized')\n            if MIXED_PRECISION:\n                from tensorflow.keras.mixed_precision import experimental as mixed_precision\n                policy = tf.keras.mixed_precision.experimental.Policy('mixed_bfloat16')\n                mixed_precision.set_policy(policy)\n                print('Mixed precision enabled')\n            if XLA_ACCELERATE:\n                    tf.config.optimizer.set_jit(True)\n                    print('Accelerated Linear Algebra enabled')\n                 \n        except _:\n            print('failed to initialize TPU')\n    else:\n        DEVICE = 'GPU'\n\nif DEVICE != 'TPU':\n    print('Using default strategy for CPU and single GPU')\n    strategy = tf.distribute.get_strategy()\n\nif DEVICE == 'GPU':\n    print('Num GPUs Available: ', len(tf.config.experimental.list_physical_devices('GPU')))\n    if MIXED_PRECISION:\n        from tensorflow.keras.mixed_precision import experimental as mixed_precision\n        policy = tf.keras.mixed_precision.experimental.Policy('mixed_float16')\n        mixed_precision.set_policy(policy)\n        print('Mixed precision enabled')\n    if XLA_ACCELERATE:\n        tf.config.optimizer.set_jit(True)\n        print('Accelerated Linear Algebra enabled')\n    \n\nAUTOTUNE    = tf.data.experimental.AUTOTUNE\nREPLICAS = strategy.num_replicas_in_sync\nprint(f'REPLICAS: {REPLICAS}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Loading TFrecods\n\nHere we set our tfrecord paths and also adjust some config for next phrases"},{"metadata":{"trusted":true},"cell_type":"code","source":"GCS_PATHTE = KaggleDatasets().get_gcs_path('cassava-leaf-disease-classification')\nGCS_PATH =KaggleDatasets().get_gcs_path('cassava-tfrecords-512x512')\nBATCH_SIZE = 16 * strategy.num_replicas_in_sync\nIMAGE_SIZE = [512, 512]\nCLASSES = ['0', '1', '2', '3', '4']\nEPOCHS = 12","execution_count":null,"outputs":[]},{"metadata":{"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    return image","execution_count":null,"outputs":[]},{"metadata":{"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":{},"cell_type":"markdown","source":"# Augmentations\n\n### This is the part where we set some settings for our further image augmentations for better generalizing."},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_mat(rotation, shear, height_zoom, width_zoom, height_shift, width_shift):\n    \n    # Most of the augmentations and transforms from here:\n    # https://www.kaggle.com/cdeotte/rotation-augmentation-gpu-tpu-0-96\n        \n    # CONVERT DEGREES TO RADIANS\n    rotation = math.pi * rotation / 180.\n    shear    = math.pi * shear    / 180.\n\n    def get_3x3_mat(lst):\n        return tf.reshape(tf.concat([lst],axis=0), [3,3])\n    \n    # ROTATION MATRIX\n    c1   = tf.math.cos(rotation)\n    s1   = tf.math.sin(rotation)\n    one  = tf.constant([1],dtype='float32')\n    zero = tf.constant([0],dtype='float32')\n    \n    rotation_matrix = get_3x3_mat([c1,   s1,   zero, \n                                   -s1,  c1,   zero, \n                                   zero, zero, one])    \n    # SHEAR MATRIX\n    c2 = tf.math.cos(shear)\n    s2 = tf.math.sin(shear)    \n    \n    shear_matrix = get_3x3_mat([one,  s2,   zero, \n                                zero, c2,   zero, \n                                zero, zero, one])        \n    # ZOOM MATRIX\n    zoom_matrix = get_3x3_mat([one/height_zoom, zero,           zero, \n                               zero,            one/width_zoom, zero, \n                               zero,            zero,           one])    \n    # SHIFT MATRIX\n    shift_matrix = get_3x3_mat([one,  zero, height_shift, \n                                zero, one,  width_shift, \n                                zero, zero, one])\n    \n    return K.dot(K.dot(rotation_matrix, shear_matrix), \n                 K.dot(zoom_matrix,     shift_matrix))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def transform(image, label):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image randomly rotated, sheared, zoomed, and shifted\n    DIM = 512\n    XDIM = DIM%2 #fix for size 331\n    \n    if 0.5 > tf.random.uniform([1], minval = 0, maxval = 1):\n        rot = 15. * tf.random.normal([1],dtype='float32')\n    else:\n        rot = 180. * tf.random.normal([1],dtype='float32')\n    shr = 5. * tf.random.normal([1],dtype='float32') \n    h_zoom = 1.0 + tf.random.normal([1],dtype='float32')/10.\n    w_zoom = 1.0 + tf.random.normal([1],dtype='float32')/10.\n    h_shift = 16. * tf.random.normal([1],dtype='float32') \n    w_shift = 16. * tf.random.normal([1],dtype='float32') \n  \n    # GET TRANSFORMATION MATRIX\n    m = get_mat(rot,shr,h_zoom,w_zoom,h_shift,w_shift) \n\n    # LIST DESTINATION PIXEL INDICES\n    x = tf.repeat( tf.range(DIM//2,-DIM//2,-1), DIM )\n    y = tf.tile( tf.range(-DIM//2,DIM//2),[DIM] )\n    z = tf.ones([DIM*DIM],dtype='int32')\n    idx = tf.stack( [x,y,z] )\n    \n    # ROTATE DESTINATION PIXELS ONTO ORIGIN PIXELS\n    idx2 = K.dot(m,tf.cast(idx,dtype='float32'))\n    idx2 = K.cast(idx2,dtype='int32')\n    idx2 = K.clip(idx2,-DIM//2+XDIM+1,DIM//2)\n    \n    # FIND ORIGIN PIXEL VALUES           \n    idx3 = tf.stack( [DIM//2-idx2[0,], DIM//2-1+idx2[1,]] )\n    d = tf.gather_nd(image,tf.transpose(idx3))\n        \n    return tf.reshape(d,[DIM,DIM,3]), label","execution_count":null,"outputs":[]},{"metadata":{"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":{"trusted":true},"cell_type":"code","source":"TRAINING_FILENAMES, VALID_FILENAMES = train_test_split(\n    tf.io.gfile.glob(GCS_PATH + '/ld_train*.tfrec'),\n    test_size=0.2, random_state=5\n)\n\nTEST_FILENAMES = tf.io.gfile.glob(GCS_PATHTE + '/test_tfrecords/ld_test*.tfrec')","execution_count":null,"outputs":[]},{"metadata":{"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    image = tf.image.random_flip_up_down(image)\n    image = tf.image.random_hue(image, 0.01)\n    image = tf.image.random_saturation(image, 0.7, 1.3)\n    image = tf.image.random_contrast(image, 0.8, 1.2)\n    image = tf.image.random_brightness(image, 0.1)\n    return image, label\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Decoding tfrecords\n\n### Here we load our datasets, apply our preprocessing steps and get them ready for TPUs."},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_training_dataset():\n    dataset = load_dataset(TRAINING_FILENAMES, labeled=True)  \n    dataset = dataset.map(data_augment, num_parallel_calls=AUTOTUNE) \n    dataset = dataset.map(transform, num_parallel_calls = AUTOTUNE)\n    dataset = dataset.repeat()\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_validation_dataset(ordered=False, cache=True):\n    dataset = load_dataset(VALID_FILENAMES, labeled=True, ordered=ordered) \n    dataset = dataset.batch(BATCH_SIZE)\n    if cache:\n        dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTOTUNE)\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{"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":{"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":{"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":{},"cell_type":"markdown","source":"# Displaying Augmented Train Images\n\n### As you can see below we transform the images with random augmentations for each step of the training."},{"metadata":{"trusted":true,"_kg_hide-input":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    return numpy_images, numpy_labels\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":{"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":{"trusted":true},"cell_type":"code","source":"display_batch_of_images(next(train_batch))","execution_count":null,"outputs":[]},{"metadata":{"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":{"trusted":true},"cell_type":"code","source":"display_batch_of_images(next(valid_batch))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"testing_dataset = get_test_dataset()\ntesting_dataset = testing_dataset.unbatch().batch(20)\ntest_batch = iter(testing_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"display_batch_of_images(next(test_batch))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Efficientnet Model\n\n### Here I'm using kinda basic version of the efficientnet model, it's not too complex for the sake of the baseline approach. You can choose different efficientnets (B5-6), add more layers or even concat couple effnets."},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_model():\n    \n    # Basic model with effnet B4 noisy-student\n\n    model_input = tf.keras.Input(shape=(512, 512, 3),\n                                 name='img_input')\n\n\n\n    x = efn.EfficientNetB4(include_top=False,\n                           weights='noisy-student',\n                           input_shape=(512, 512, 3),\n                           pooling='avg')(model_input)\n    x = tf.keras.layers.Dense(len(CLASSES), activation='softmax',)(x)\n\n\n    model = tf.keras.Model(model_input, x, name='nnetwork')\n    model.summary()\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"lr_scheduler = keras.optimizers.schedules.ExponentialDecay(\n    initial_learning_rate=3e-4, \n    decay_steps=10000, \n    decay_rate=0.9)\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def compileNewModel():\n    \n    ''' Configuring the model with losses and metrics. '''    \n    \n    with strategy.scope():\n        model = get_model()\n\n    with strategy.scope():\n        model.compile(tf.keras.optimizers.Adam(learning_rate=lr_scheduler, epsilon=0.001),\n                      loss=[\n                          tf.keras.losses.SparseCategoricalCrossentropy(),\n                      ],\n                      metrics=[tf.keras.metrics.SparseCategoricalAccuracy(name='sparse_categorical_accuracy')])\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = get_training_dataset()\nvalid_dataset = get_validation_dataset()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"STEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\nVALID_STEPS = NUM_VALIDATION_IMAGES // BATCH_SIZE","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training\n\n### Here we train our images using efficientnet pre trained weights, actually it's a heavy work but with TPU's we train them in no time!"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = compileNewModel()\nhistory = model.fit(train_dataset, \n                    steps_per_epoch=STEPS_PER_EPOCH, \n                    epochs=EPOCHS,\n                    validation_data=valid_dataset,\n                    validation_steps=VALID_STEPS)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# this code will convert our test image data to a float32 \ndef to_float32(image, label):\n    return tf.cast(image, tf.float32), label","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Predicting\n\n### Firstly let's predict our holdout set. When we check the predicted distributions they seem pretty close to train distribution, which is pretty good sign!"},{"metadata":{"trusted":true},"cell_type":"code","source":"validation_dataset = get_validation_dataset()\nvalid_ds = get_validation_dataset(ordered=True, cache=False)\nvalid_ds = valid_ds.map(to_float32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Computing predictions for holdout set...')\nvalid_images_ds = validation_dataset\nvalid_images_ds = valid_ds.map(lambda image, idnum: image)\nv_probabilities = model.predict(valid_images_ds)\nv_predictions = np.argmax(v_probabilities.astype(np.float32), axis=-1)","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"df = pd.DataFrame(data=v_predictions, columns=['disease'])","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"df['disease'] = df.disease.map({0:\"Cassava Bacterial Blight (CBB)\",\n1:\"Cassava Brown Streak Disease (CBSD)\",\n2:\"Cassava Green Mottle (CGM)\",\n3:\"Cassava Mosaic Disease (CMD)\",\n4:\"Healthy\"})\ndiseases = df.disease.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"\nfig = px.pie(diseases,\n             values='disease',\n             names=diseases.index,\n             #color_discrete_sequence=orange_black,\n             hole=.4)\nfig.update_traces(textinfo='percent+label', pull=0.05)\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Now we're going to predict our single test example..."},{"metadata":{"trusted":true},"cell_type":"code","source":"testing_dataset = get_test_dataset()\ntest_ds = get_test_dataset(ordered=True) \ntest_ds = test_ds.map(to_float32)\n\nprint('Computing predictions...')\ntest_images_ds = testing_dataset\ntest_images_ds = test_ds.map(lambda image, idnum: image)\nprobabilities = model.predict(test_images_ds)\npredictions = np.argmax(probabilities.astype(np.float32), axis=-1)\nprint(predictions)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Generating submission.csv file...')\ntest_ids_ds = test_ds.map(lambda image, idnum: idnum).unbatch()\ntest_ids = next(iter(test_ids_ds.batch(NUM_TEST_IMAGES))).numpy().astype('U') # all in one batch\nnp.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":{},"cell_type":"markdown","source":"# The End\n\n### Thank you all for going all the way through here, I hope you enjoyed it and you find it helpful. If you liked it please don't forhet to upvote and feel free to give feedbacks and ask questions in comments. \n\n### Happy coding all!"}],"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}