{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Importing Libraries/Packages. 📦"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom PIL import Image\nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom tqdm import tqdm\nfrom sklearn.utils import shuffle\nfrom sklearn.utils import class_weight\nfrom sklearn.preprocessing import minmax_scale\nimport random\nimport cv2\nfrom imgaug import augmenters as iaa\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.layers import Dense, Dropout, Activation, Input, BatchNormalization, GlobalAveragePooling2D\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping\nfrom tensorflow.keras.experimental import CosineDecay\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.applications import EfficientNetB3\nfrom tensorflow.keras.layers.experimental.preprocessing import RandomCrop,CenterCrop, RandomRotation","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# ***Adding filepath to the csv file***"},{"metadata":{"trusted":true},"cell_type":"code","source":"training_folder = '../input/cassava-leaf-disease-classification/train_images/'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"samples_df = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")\nsamples_df = shuffle(samples_df, random_state=42)\nsamples_df[\"filepath\"] = training_folder+samples_df[\"image_id\"]\nsamples_df.head()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"training_percentage = 0.8\ntraining_item_count = int(len(samples_df)*training_percentage)\nvalidation_item_count = len(samples_df)-int(len(samples_df)*training_percentage)\ntraining_df = samples_df[:training_item_count]\nvalidation_df = samples_df[training_item_count:]\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 8\nimage_size = 512\ninput_shape = (image_size, image_size, 3)\ndropout_rate = 0.4\nclasses_to_predict = sorted(training_df.label.unique())","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"#  Using <code>tf.data</code> to import images 🎞📸"},{"metadata":{"trusted":true},"cell_type":"code","source":"training_data = tf.data.Dataset.from_tensor_slices((training_df.filepath.values, training_df.label.values))\nvalidation_data = tf.data.Dataset.from_tensor_slices((validation_df.filepath.values, validation_df.label.values))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_image_and_label_from_path(image_path, label):\n    img = tf.io.read_file(image_path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    return img, label\n\nAUTOTUNE = tf.data.experimental.AUTOTUNE\n\ntraining_data = training_data.map(load_image_and_label_from_path, num_parallel_calls=AUTOTUNE)\nvalidation_data = validation_data.map(load_image_and_label_from_path, num_parallel_calls=AUTOTUNE)\n\n\ntraining_data_batches = training_data.shuffle(buffer_size=1000).batch(batch_size).prefetch(buffer_size=AUTOTUNE)\nvalidation_data_batches = validation_data.shuffle(buffer_size=1000).batch(batch_size).prefetch(buffer_size=AUTOTUNE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Rescaling the image by dividing each pixel by 255📏"},{"metadata":{"trusted":true},"cell_type":"code","source":"adapt_data = tf.data.Dataset.from_tensor_slices(training_df.filepath.values)\ndef adapt_mode(image_path):\n    img = tf.io.read_file(image_path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = layers.experimental.preprocessing.Rescaling(1.0 / 255)(img)\n    return img\n\nadapt_data = adapt_data.map(adapt_mode, num_parallel_calls=AUTOTUNE)\nadapt_data_batches = adapt_data.shuffle(buffer_size=1000).batch(batch_size).prefetch(buffer_size=AUTOTUNE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data Augmentation \n\nData Augmenetation is used to increase the amount of train data so that we have enough data for training the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"data_augmentation_layers = tf.keras.Sequential(\n    [\n        layers.experimental.preprocessing.RandomCrop(height=image_size, width=image_size),\n        layers.experimental.preprocessing.RandomFlip(\"horizontal_and_vertical\"),\n        layers.experimental.preprocessing.RandomRotation(0.25),\n        layers.experimental.preprocessing.RandomZoom((-0.2, 0)),\n        layers.experimental.preprocessing.RandomContrast((0.2,0.2))\n    ]\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"efficientnet = EfficientNetB3(weights=\"../input/keras-efficientnetb3-no-top-weights/efficientnetb3_notop.h5\", \n                              include_top=False, \n                              input_shape=input_shape, \n                              drop_connect_rate=dropout_rate)\n\ninputs = Input(shape=input_shape)\naugmented = data_augmentation_layers(inputs)\nefficientnet = efficientnet(augmented)\npooling = layers.GlobalAveragePooling2D()(efficientnet)\ndropout = layers.Dropout(dropout_rate)(pooling)\noutputs = Dense(len(classes_to_predict), activation=\"softmax\")(dropout)\nmodel = Model(inputs=inputs, outputs=outputs)\n    \nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = 20","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 📲CallBacks"},{"metadata":{"trusted":true},"cell_type":"code","source":"\ndecay_steps = int(round(len(training_df)/batch_size))*epochs\ncosine_decay = CosineDecay(initial_learning_rate=1e-4, decay_steps=decay_steps, alpha=0.3)\n\ncallbacks = [ModelCheckpoint(filepath='best_model.h5', monitor='val_loss', save_best_only=True)]\n\nmodel.compile(loss=\"sparse_categorical_crossentropy\", optimizer=tf.keras.optimizers.Adam(cosine_decay), metrics=[\"accuracy\"])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training Model 👨‍🏫"},{"metadata":{"trusted":true},"cell_type":"code","source":"\nhistory = model.fit(training_data_batches,\n                  epochs = epochs, \n                  validation_data=validation_data_batches,\n                  callbacks=callbacks)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Plotting our loss 📈📊"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('Loss over epochs')\nplt.ylabel('Loss')\nplt.xlabel('Epoch')\nplt.legend(['Train', 'Validation'], loc='best')\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 🚚 Importing our model 🚛"},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights(\"./best_model.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Displaying Sample Images"},{"metadata":{"trusted":true},"cell_type":"code","source":"def scan_over_image(img_path, crop_size=512):\n    '''\n    Will extract 512x512 images covering the whole original image\n    with some overlap between images\n    '''\n    \n    img = Image.open(img_path)\n    img_height, img_width = img.size\n    img = np.array(img)\n    \n    y = random.randint(0,img_height-crop_size)\n    x = random.randint(0,img_width-crop_size)\n\n    x_img_origins = [0,img_width-crop_size]\n    y_img_origins = [0,img_height-crop_size]\n    img_list = []\n    for x in x_img_origins:\n        for y in y_img_origins:\n            img_list.append(img[x:x+crop_size , y:y+crop_size,:])\n  \n    return np.array(img_list)\n\n\n\ndef display_samples(img_path):\n    '''\n    Display all 512x512 images extracted from original images\n    '''\n    \n    img_list = scan_over_image(img_path)\n    sample_number = len(img_list)\n    fig = plt.figure(figsize = (8,sample_number))\n    for i in range(0,sample_number):\n        ax = fig.add_subplot(2, 4, i+1)\n        ax.imshow(img_list[i])\n        ax.set_title(str(i))\n    plt.tight_layout()\n    plt.show()\n\ndisplay_samples(\"../input/cassava-leaf-disease-classification/train_images/3412658650.jpg\")\n\ntest_time_augmentation_layers = tf.keras.Sequential(\n    [\n        layers.experimental.preprocessing.RandomFlip(\"horizontal_and_vertical\"),\n        layers.experimental.preprocessing.RandomZoom((-0.2, 0)),\n        layers.experimental.preprocessing.RandomContrast((0.2,0.2))\n    ]\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict_and_vote(image_filename, folder, TTA_runs=4):\n    '''\n    Run the model over 4 local areas of the given image,\n    before making a decision depending on the most predicted\n    disease.\n    '''\n    \n    #apply TTA to each of the 4 images and sum all predictions for each local image\n    localised_predictions = []\n    local_image_list = scan_over_image(folder+image_filename)\n    for local_image in local_image_list:\n        duplicated_local_image = tf.convert_to_tensor(np.array([local_image for i in range(TTA_runs)]))\n        augmented_images = test_time_augmentation_layers(duplicated_local_image)\n        \n        predictions = model.predict(augmented_images)\n        localised_predictions.append(np.sum(predictions, axis=0))\n    \n    #sum all predictions from all 4 images and retrieve the index of the highest value\n    global_predictions = np.sum(np.array(localised_predictions),axis=0)\n    final_prediction = np.argmax(global_predictions)\n    \n    return final_prediction\n\n\n\ndef run_predictions_over_image_list(image_list, folder):\n    predictions = []\n    with tqdm(total=len(image_list)) as pbar:\n        for image_filename in image_list:\n            pbar.update(1)\n            predictions.append(predict_and_vote(image_filename, folder))\n    return predictions\n\n\n\n# validation_df[\"results\"] = run_predictions_over_image_list(validation_df[\"image_id\"], training_folder)\n\ntest_folder = '../input/cassava-leaf-disease-classification/test_images/'\nsubmission_df = pd.DataFrame(columns={\"image_id\",\"label\"})\nsubmission_df[\"image_id\"] =  os.listdir(test_folder)\nsubmission_df[\"label\"] = run_predictions_over_image_list(submission_df[\"image_id\"], test_folder)\n# result = run_predictions_over_image_list(submission_df[\"image_id\"], test_folder)\n# submission_df[\"label\"] = result","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Predicting for test data 📀💿"},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df.to_csv(\"submission.csv\", index=False) ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<div><h2> 📌 Please Upvote the notebook 👍👍 and write your suggestions✍.</h2> </div>"}],"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}