{"cells":[{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h2 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\"><center>1. Cassava Leaf Disease Classification - Intorduction\n </center></h2>\n    \n<img src = \"https://i2.wp.com/agrihomegh.com/wp-content/uploads/2016/07/CassavaBB-source-www.plantwise.org_-e1490126745230.jpg?resize=640%2C468&ssl=1\">\n<br><br>\nAs the second-largest provider of carbohydrates in Africa, cassava is a key food security crop grown by smallholder farmers because it can withstand harsh conditions. \n    \nAt least 80% of household farms in Sub-Saharan Africa grow this starchy root, but viral diseases are major sources of poor yields. \n    \nWith the help of data science, it may be possible to identify common diseases so they can be treated.\n\nExisting methods of disease detection require farmers to solicit the help of government-funded agricultural experts to visually inspect and diagnose the plants. \n    \nThis suffers from being labor-intensive, low-supply and costly. \n    \nAs an added challenge, effective solutions for farmers must perform well under significant constraints, since African farmers may only have access to mobile-quality cameras with low-bandwidth.\n\nIn this competition, we are given a dataset of 21,367 labeled images collected during a regular survey in Uganda. \n    \nMost images were crowdsourced from farmers taking photos of their gardens, and annotated by experts at the National Crops Resources Research Institute (NaCRRI) in collaboration with the AI lab at Makerere University, Kampala. This is in a format that most realistically represents what farmers would need to diagnose in real life.\n\nOur goal is to classify each cassava image into four disease categories or a fifth category indicating a healthy leaf. \n    \nWith our help, farmers may be able to quickly identify diseased plants, potentially saving their crops before they inflict irreparable damage."},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h2 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\"><center>2. Import Libraries\n </center></h2>"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\n\nimport tensorflow as tf\n\nimport re\nimport math\n\nfrom matplotlib import pyplot as plt\nimport seaborn as sns\nfrom colorama import Fore, Back, Style\nimport cv2\n\nimport tensorflow.keras.backend as K\nfrom keras.applications import VGG19\nfrom keras.models import Sequential\nfrom keras.layers import Dense,Flatten,Conv2D,MaxPooling2D,Dropout\nfrom keras import optimizers","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h2 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\"><center>3. Files Availabe for the competition</center></h2>\n\n1) `[train/test]_images` - The full set of test images will only be available to your notebook when it is submitted for scoring. Expect to see roughly 15,000 images in the test set.\n\n2) `train.csv`\n* image_id the image file name.\n* label the ID code for the disease.\n\n3) `sample_submission.csv` -  A properly formatted sample submission, given the disclosed test set content.\n* image_id the image file name.\n* label the predicted ID code for the disease.\n\n4) `[train/test]_tfrecords` -  The image files in tfrecord format.\n\n5) `label_num_to_disease_map.json` - The mapping between each disease code and the real disease name."},{"metadata":{"trusted":true},"cell_type":"code","source":"# load train.csv and check\ntrain = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")\ntrain.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# check how many unique diseases are present in the dataset\nn_classes = train.label.nunique()\nn_classes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# lets take a look at the submission file\nsub = pd.read_csv(\"../input/cassava-leaf-disease-classification/sample_submission.csv\")\nsub.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h2 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\"><center>4. Exploratory Data Analysis\n </center></h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# check how many unique diseases are present in the dataset\nn_classes = train.label.nunique()\nn_classes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"List of unique classes(disease):\",train.label.unique())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.1 Class Mapping</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(Fore.BLUE + \"            Disease-Label Mapping\",Style.RESET_ALL)\nprint(\"----------------------------------------------\")\nprint(Fore.YELLOW + \"Label              Disease\",Style.RESET_ALL)\nprint(\"  0        Cassava Bacterial Blight (CBB)\\n\")\nprint(\"  1        Cassava Brown Streak Disease (CBSD)\\n\")\nprint(\"  2        Cassava Green Mottle (CGM)\\n\")\nprint(\"  3        Cassava Mosaic Disease (CMD)\\n\")\nprint(\"  4        Health\") \nprint(\"----------------------------------------------\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.2 Visualize Class Mapping</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# let's check class distribution\nfig = plt.figure(constrained_layout=True, figsize=(8,6))\n\nsns.countplot(train.label,             \n              alpha=0.9,              \n              order = train.label.value_counts().sort_values(ascending=False).index   \n             )\nplt.xlabel(\"Label\")\nplt.ylabel(\"Count\")\nplt.title('Class Distribution')\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Dataset is imbalanced, it has most of the images belonging to disease Cassava Mosaic Disease (CMD)\""},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.3 Add Image Path to Training Dataset</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# add image path to train\ntrain_dir = \"../input/cassava-leaf-disease-classification/train_images\"\n\n# update image names with the whole path\ndef append_ext(fn):\n    return train_dir+\"/\"+fn\n\ntrain[\"image_id\"]= train[\"image_id\"].apply(append_ext)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.4 Size of first 10 Images</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"### Let's check the size of top 10 images\nfiles = train.image_id[:10]\nprint(Fore.BLUE + \"Shape of files from training dataset\",Style.RESET_ALL)\nfor i in range(10):\n    im = cv2.imread(files[i])    \n    print(im.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We have images are of same size..good!"},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.5 Few Images from Cassava Bacterial Blight (CBB)</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# visualize few images belonging to disease: Cassava Bacterial Blight (CBB)\nclass_0 = train[train.label == 0]\n\nimages = []\n\nfor i in range(1,11):    \n    img=cv2.imread(class_0.image_id.iloc[i])   \n    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    images.append(img)\n\nf, ax = plt.subplots(5,2, figsize=(20,15))\nfor i, img in enumerate(images):        \n        ax[i//2, i%2].imshow(img)\n        ax[i//2, i%2].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"These are group images, wont be easy for models to extract patterns and make predictions "},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.6 Few Images from Cassava Brown Streak Disease (CBSD)</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# visualize few images belonging to disease Cassava Brown Streak Disease (CBSD)\nclass_1 = train[train.label == 1]\n\nimages = []\n\nfor i in range(1,11):    \n    img=cv2.imread(class_1.image_id.iloc[i])   \n    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    images.append(img)\n\nf, ax = plt.subplots(5,2, figsize=(20,15))\nfor i, img in enumerate(images):        \n        ax[i//2, i%2].imshow(img)\n        ax[i//2, i%2].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.7 Cassava Green Mottle (CGM)</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# visualize few images belonging to disease Cassava Green Mottle (CGM)\nclass_2 = train[train.label == 2]\n\nimages = []\n\nfor i in range(1,11):    \n    img=cv2.imread(class_2.image_id.iloc[i])   \n    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    images.append(img)\n\nf, ax = plt.subplots(5,2, figsize=(20,15))\nfor i, img in enumerate(images):        \n        ax[i//2, i%2].imshow(img)\n        ax[i//2, i%2].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Same observation for these set of images as well"},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.8 Cassava Mosaic Disease (CMD)</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# visualize few images from Cassava Mosaic Disease (CMD) disease\nclass_3 = train[train.label == 3]\n\nimages = []\n\nfor i in range(1,11):    \n    img=cv2.imread(class_3.image_id.iloc[i])   \n    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    images.append(img)\n\nf, ax = plt.subplots(5,2, figsize=(20,15))\nfor i, img in enumerate(images):        \n        ax[i//2, i%2].imshow(img)\n        ax[i//2, i%2].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">4.9 Health</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# visualize few images from class \"Health\"\nclass_4 = train[train.label == 4]\n\nimages = []\n\nfor i in range(1,11):    \n    img=cv2.imread(class_4.image_id.iloc[i])   \n    image = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    images.append(img)\n\nf, ax = plt.subplots(5,2, figsize=(20,15))\nfor i, img in enumerate(images):        \n        ax[i//2, i%2].imshow(img)\n        ax[i//2, i%2].axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h2 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\"><center>5. Model Training & Helper Functions </center></h2>\n\nEven though we can not make submission with \"internet option ON\", and hence can not use TPU for submission,but we can traing our model using TPU, save the model, load it in a seperate notebook and make predictions on test data."},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# TPU detection  \ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\nexcept ValueError:\n    tpu = None\n\n# TPUStrategy for distributed training\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: # default strategy that works on CPU and single GPU\n    strategy = tf.distribute.get_strategy()\n\nprint(\"Number of accelerators: \", strategy.num_replicas_in_sync)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from kaggle_datasets import KaggleDatasets\n\nGCS_DS_PATH = KaggleDatasets().get_gcs_path('cassava-leaf-disease-classification')\nprint(GCS_DS_PATH) # what do gcs paths look like?\n\nGCS_PATTERN_TRAIN = GCS_DS_PATH + \"/train_tfrecords/*.tfrec\"\nGCS_PATTERN_TEST  = GCS_DS_PATH + \"/test_tfrecords/*.tfrec\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.1. Declare Necessary Variables/Parameters</h3>\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# define parameters\nIMAGE_SIZE = [512, 512] # image size\n\nHEIGHT = 512\nWIDTH = 512\nCHANNELS = 3\n\nEPOCHS = 30 # no. of epochs to train the model\n\nVALIDATION_SPLIT = 0.19 # split ratio for training & validation datasets\n\nAUTO = tf.data.experimental.AUTOTUNE\n\nfilenames = tf.io.gfile.glob(GCS_PATTERN_TRAIN)\nsplit = int(len(filenames) * VALIDATION_SPLIT)\n\nTRAINING_FILENAMES = filenames[split:]\nVALIDATION_FILENAMES = filenames[:split]\nTEST_FILENAMES = tf.io.gfile.glob(GCS_PATTERN_TEST) \n\n# classes of disease\nCLASSES = ['Cassava Bacterial Blight (CBB)',\n           'Cassava Brown Streak Disease (CBSD)',\n           'Cassava Green Mottle (CGM)',\n           'Cassava Mosaic Disease (CMD)',\n           'Health']                                                                                                                 ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.2 Helper function - Set # 1</h3>\n"},{"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        \"target\": 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['target'], 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        \"image_name\": tf.io.FixedLenFeature([], tf.string),  # shape [] means single element\n    }\n    example = tf.io.parse_single_example(example, UNLABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    idnum = example['image_name']\n    return image, idnum # returns a dataset of image(s)\n\ndef 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\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO) # 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, num_parallel_calls=AUTO)\n    # returns a dataset of (image, label) pairs if labeled=True or (image, id) pairs if labeled=False\n    return dataset","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.3. Data Augmentation</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"def data_augment(image, label):\n    p_rotation = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_spatial = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_rotate = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_pixel = tf.random.uniform([], 0, 1.0, dtype=tf.float32)    \n    p_shear = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_crop = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    \n    # Shear\n    if p_shear > .2:\n        if p_shear > .6:\n            image = transform_shear(image, HEIGHT, shear=20.)\n        else:\n            image = transform_shear(image, HEIGHT, shear=-20.)\n    # Rotation\n    if p_rotation > .2:\n        if p_rotation > .6:\n            image = transform_rotation(image, HEIGHT, rotation=45.)\n        else:\n            image = transform_rotation(image, HEIGHT, rotation=-45.)\n    # Flips\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_flip_up_down(image)\n    if p_spatial > .75:\n        image = tf.image.transpose(image)\n    # Rotates\n    if p_rotate > .75:\n        image = tf.image.rot90(image, k=3) # rotate 270º\n    elif p_rotate > .5:\n        image = tf.image.rot90(image, k=2) # rotate 180º\n    elif p_rotate > .25:\n        image = tf.image.rot90(image, k=1) # rotate 90º\n    # Pixel-level transforms\n    if p_pixel >= .2:\n        if p_pixel >= .8:\n            image = tf.image.random_saturation(image, lower=.7, upper=1.3)\n        elif p_pixel >= .6:\n            image = tf.image.random_contrast(image, lower=.8, upper=1.2)\n        elif p_pixel >= .4:\n            image = tf.image.random_brightness(image, max_delta=.1)\n        else:\n            image = tf.image.adjust_gamma(image, gamma=.6)\n    # Crops\n    if p_crop > .7:\n        if p_crop > .9:\n            image = tf.image.central_crop(image, central_fraction=.6)\n        elif p_crop > .8:\n            image = tf.image.central_crop(image, central_fraction=.7)\n        else:\n            image = tf.image.central_crop(image, central_fraction=.8)\n    elif p_crop > .4:\n        crop_size = tf.random.uniform([], int(HEIGHT*.6), HEIGHT, dtype=tf.int32)\n        image = tf.image.random_crop(image, size=[crop_size, crop_size, CHANNELS])\n            \n    image = tf.image.resize(image, size=[HEIGHT, WIDTH])\n\n    return image, label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# data augmentation @cdeotte kernel: https://www.kaggle.com/cdeotte/rotation-augmentation-gpu-tpu-0-96\ndef transform_rotation(image, height, rotation):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image randomly rotated\n    DIM = height\n    XDIM = DIM%2 #fix for size 331\n    \n    rotation = rotation * tf.random.uniform([1],dtype='float32')\n    # CONVERT DEGREES TO RADIANS\n    rotation = math.pi * rotation / 180.\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    rotation_matrix = tf.reshape(tf.concat([c1,s1,zero, -s1,c1,zero, zero,zero,one],axis=0),[3,3])\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(rotation_matrix,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])\n\ndef transform_shear(image, height, shear):\n    # input image - is one image of size [dim,dim,3] not a batch of [b,dim,dim,3]\n    # output - image randomly sheared\n    DIM = height\n    XDIM = DIM%2 #fix for size 331\n    \n    shear = shear * tf.random.uniform([1],dtype='float32')\n    shear = math.pi * shear / 180.\n        \n    # SHEAR MATRIX\n    one = tf.constant([1],dtype='float32')\n    zero = tf.constant([0],dtype='float32')\n    c2 = tf.math.cos(shear)\n    s2 = tf.math.sin(shear)\n    shear_matrix = tf.reshape(tf.concat([one,s2,zero, zero,c2,zero, zero,zero,one],axis=0),[3,3])    \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(shear_matrix,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])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.4. Helper Functions - Set # 2 </h3>\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# another set of helper functions\ndef get_training_dataset():\n    dataset = load_dataset(TRAINING_FILENAMES, labeled=True)\n    dataset = dataset.map(data_augment, num_parallel_calls=AUTO)\n    dataset = dataset.repeat() # the training dataset must repeat for several epochs\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)\n    return dataset\n\ndef get_validation_dataset(ordered=False):\n    dataset = load_dataset(VALIDATION_FILENAMES, labeled=True, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\ndef 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(AUTO)\n    return dataset\n\ndef 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)\n\nNUM_TRAINING_IMAGES = count_data_items(TRAINING_FILENAMES)\nNUM_VALIDATION_IMAGES = count_data_items(VALIDATION_FILENAMES)\nNUM_TEST_IMAGES = count_data_items(TEST_FILENAMES)\nprint('Dataset: {} training images, {} validation images, {} unlabeled test images'.format(NUM_TRAINING_IMAGES, NUM_VALIDATION_IMAGES, NUM_TEST_IMAGES))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.5 Get Datasets</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Define the batch size. This will be 16 with TPU off and 128 (=16*8) with TPU on\nBATCH_SIZE = 16 * strategy.num_replicas_in_sync\n\nds_train = get_training_dataset()\nds_valid = get_validation_dataset()\nds_test = get_test_dataset()\n\nprint(\"Training:\", ds_train)\nprint (\"Validation:\", ds_valid)\nprint(\"Test:\", ds_test)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_true = []\nfor image,label in ds_valid:\n    y_true.append(label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.set_printoptions(threshold=15, linewidth=80)\n\nprint(\"Training data shapes:\")\nfor image, label in ds_train.take(3):\n    print(image.numpy().shape, label.numpy().shape)\nprint(\"Training data label examples:\", label.numpy())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.6. Visualizing Images again</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"def 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,\n                                     # 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\n    # 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_flower(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\n    # or square-ish rectangle\n    rows = int(math.sqrt(len(images)))\n    cols = len(images)//rows\n        \n    # size and spacing\n    FIGSIZE = 30.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_flower(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":"# visualize 20 images from ds_train\nds_iter = iter(ds_train.unbatch().batch(20))\none_batch = next(ds_iter)\ndisplay_batch_of_images(one_batch)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.7. Train the Model - VGG19 by freezing top 4 layers</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"#  Adding a densely connected classifier on top of the convolutional base\nwith strategy.scope():\n    conv_base = VGG19(weights='imagenet',include_top=False,input_shape=[*IMAGE_SIZE, 3])\n    \n    \n    # freezing the layers of pre-trained model\n    conv_base.trainable = False\n    \n    #conv_base.trainable = True\n    set_trainable = False\n\n    for layer in conv_base.layers:\n        if layer.name == 'block5_conv1' or 'block5_conv2' or 'block5_conv3'or 'block5_conv4':\n            set_trainable = True\n\n        if set_trainable:\n            layer.trainable = True\n        else:\n            layer.trainable = False\n            \n        \n    model = Sequential()\n    model.add(conv_base) # adding pre-trained conv base model\n    model.add(Flatten())\n    model.add(Dense(512, activation='relu'))\n    model.add(Dense(5, activation='softmax'))    \n    \n    \n    model.compile(\n    optimizer=optimizers.RMSprop(),\n    loss = 'sparse_categorical_crossentropy',\n    metrics=['sparse_categorical_accuracy'])\n\n\n    model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# steps per epoch calculation\nsteps_per_epoch = NUM_TRAINING_IMAGES // BATCH_SIZE\nvalidation_steps = NUM_VALIDATION_IMAGES //BATCH_SIZE\n\n# fit the model on training data and validate on validation dataset \nhistory = model.fit(ds_train, steps_per_epoch=steps_per_epoch, epochs=30,\n                validation_data=ds_valid, validation_steps=validation_steps)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.8 Model Evaluation</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# plotting the training results\nacc = history.history['sparse_categorical_accuracy']\nval_acc = history.history['val_sparse_categorical_accuracy']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(1, len(acc) + 1)\n\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'b', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'b', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\">5.9 Save the model</h3>"},{"metadata":{"trusted":true},"cell_type":"code","source":"#model.save('model.h5')\nmodel.save_weights('model.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n<a id=\"10\"></a>\n<h2 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" style='background:coral; border:0; color:blue' role=\"tab\" aria-controls=\"home\"><center>6. Model Evaluation </center></h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"# predictions and valuation on validation dataset\ndataset = get_validation_dataset()\ndataset = dataset.unbatch().batch(20)\nbatch = iter(dataset)\n\nimages, labels = next(batch)\nprobabilities = model.predict(images)\npredictions = np.argmax(probabilities, axis=-1)\ndisplay_batch_of_images((images, labels), predictions)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}