{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Cassava disease classification (keras)"},{"metadata":{},"cell_type":"markdown","source":"# Import libs"},{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","execution":{"iopub.execute_input":"2021-01-23T05:37:37.525855Z","iopub.status.busy":"2021-01-23T05:37:37.525287Z","iopub.status.idle":"2021-01-23T05:37:43.26379Z","shell.execute_reply":"2021-01-23T05:37:43.263089Z"},"papermill":{"duration":5.763759,"end_time":"2021-01-23T05:37:43.263904","exception":false,"start_time":"2021-01-23T05:37:37.500145","status":"completed"},"tags":[],"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":{"papermill":{"duration":0.015692,"end_time":"2021-01-23T05:37:43.29623","exception":false,"start_time":"2021-01-23T05:37:43.280538","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# csv file"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:43.33199Z","iopub.status.busy":"2021-01-23T05:37:43.331423Z","iopub.status.idle":"2021-01-23T05:37:43.33519Z","shell.execute_reply":"2021-01-23T05:37:43.334773Z"},"papermill":{"duration":0.022855,"end_time":"2021-01-23T05:37:43.335274","exception":false,"start_time":"2021-01-23T05:37:43.312419","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"img_folder = '../input/cassava-leaf-disease-classification/train_images/'","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:43.374814Z","iopub.status.busy":"2021-01-23T05:37:43.374282Z","iopub.status.idle":"2021-01-23T05:37:43.436179Z","shell.execute_reply":"2021-01-23T05:37:43.435415Z"},"papermill":{"duration":0.084862,"end_time":"2021-01-23T05:37:43.436267","exception":false,"start_time":"2021-01-23T05:37:43.351405","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"samples_data = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")\nsamples_data = shuffle(samples_data, random_state=42)\nsamples_data[\"filepath\"] = img_folder+samples_data[\"image_id\"]\nsamples_data.head()\n","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:43.476159Z","iopub.status.busy":"2021-01-23T05:37:43.474529Z","iopub.status.idle":"2021-01-23T05:37:43.476899Z","shell.execute_reply":"2021-01-23T05:37:43.477375Z"},"papermill":{"duration":0.024329,"end_time":"2021-01-23T05:37:43.477487","exception":false,"start_time":"2021-01-23T05:37:43.453158","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"batch_size = 8\nimg_size = 512\ninput_shape = (img_size,img_size, 3)\ndropout = 0.4\ntraining_percen = 0.8\ntraining_length = int(len(samples_data)*training_percen)\nvalidation_item_count = len(samples_data)-int(len(samples_data)*training_percen)\ntraining_df = samples_data[:training_length]\nvalidation_df = samples_data[training_length:]\n","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.016623,"end_time":"2021-01-23T05:37:43.553306","exception":false,"start_time":"2021-01-23T05:37:43.536683","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# import images "},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:45.891481Z","iopub.status.busy":"2021-01-23T05:37:45.890846Z","iopub.status.idle":"2021-01-23T05:37:45.905181Z","shell.execute_reply":"2021-01-23T05:37:45.904522Z"},"papermill":{"duration":2.335197,"end_time":"2021-01-23T05:37:45.905299","exception":false,"start_time":"2021-01-23T05:37:43.570102","status":"completed"},"tags":[],"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":{},"cell_type":"markdown","source":"# Load images from path"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:45.948652Z","iopub.status.busy":"2021-01-23T05:37:45.94809Z","iopub.status.idle":"2021-01-23T05:37:46.044885Z","shell.execute_reply":"2021-01-23T05:37:46.04429Z"},"papermill":{"duration":0.122088,"end_time":"2021-01-23T05:37:46.044982","exception":false,"start_time":"2021-01-23T05:37:45.922894","status":"completed"},"tags":[],"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":{"papermill":{"duration":0.017031,"end_time":"2021-01-23T05:37:46.079295","exception":false,"start_time":"2021-01-23T05:37:46.062264","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Rescaling images"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:46.123526Z","iopub.status.busy":"2021-01-23T05:37:46.122565Z","iopub.status.idle":"2021-01-23T05:37:46.185023Z","shell.execute_reply":"2021-01-23T05:37:46.184518Z"},"papermill":{"duration":0.088653,"end_time":"2021-01-23T05:37:46.185122","exception":false,"start_time":"2021-01-23T05:37:46.096469","status":"completed"},"tags":[],"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":{"papermill":{"duration":0.016929,"end_time":"2021-01-23T05:37:46.219227","exception":false,"start_time":"2021-01-23T05:37:46.202298","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Data Augmentation \n\n"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:46.262728Z","iopub.status.busy":"2021-01-23T05:37:46.262207Z","iopub.status.idle":"2021-01-23T05:37:46.560517Z","shell.execute_reply":"2021-01-23T05:37:46.56Z"},"papermill":{"duration":0.324532,"end_time":"2021-01-23T05:37:46.560631","exception":false,"start_time":"2021-01-23T05:37:46.236099","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"augmentation = tf.keras.Sequential(\n    [\n        layers.experimental.preprocessing.RandomCrop(height=img_size, width=img_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":{},"cell_type":"markdown","source":"# Build model-transfer learning(EfficientNetB3)"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:46.601951Z","iopub.status.busy":"2021-01-23T05:37:46.601323Z","iopub.status.idle":"2021-01-23T05:37:53.428174Z","shell.execute_reply":"2021-01-23T05:37:53.428758Z"},"papermill":{"duration":6.850756,"end_time":"2021-01-23T05:37:53.42893","exception":false,"start_time":"2021-01-23T05:37:46.578174","status":"completed"},"tags":[],"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)\n\ninputs = Input(shape=input_shape)\naugmented = augmentation(inputs)\nefficientnet = efficientnet(augmented)\npooling = layers.GlobalAveragePooling2D()(efficientnet)\ndropout = layers.Dropout(dropout)(pooling)\noutputs = Dense(5, activation=\"softmax\")(dropout)\nmodel = Model(inputs=inputs, outputs=outputs)\n    \nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:53.469706Z","iopub.status.busy":"2021-01-23T05:37:53.468341Z","iopub.status.idle":"2021-01-23T05:37:53.471231Z","shell.execute_reply":"2021-01-23T05:37:53.470819Z"},"papermill":{"duration":0.024152,"end_time":"2021-01-23T05:37:53.471314","exception":false,"start_time":"2021-01-23T05:37:53.447162","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"epochs = 3","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":0.017508,"end_time":"2021-01-23T05:37:53.506804","exception":false,"start_time":"2021-01-23T05:37:53.489296","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# callbacks"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:53.562941Z","iopub.status.busy":"2021-01-23T05:37:53.562111Z","iopub.status.idle":"2021-01-23T05:37:53.569706Z","shell.execute_reply":"2021-01-23T05:37:53.569263Z"},"papermill":{"duration":0.044635,"end_time":"2021-01-23T05:37:53.569785","exception":false,"start_time":"2021-01-23T05:37:53.52515","status":"completed"},"tags":[],"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":{"papermill":{"duration":0.0181,"end_time":"2021-01-23T05:37:53.605455","exception":false,"start_time":"2021-01-23T05:37:53.587355","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Training Model"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T05:37:53.647111Z","iopub.status.busy":"2021-01-23T05:37:53.646597Z","iopub.status.idle":"2021-01-23T12:35:46.180006Z","shell.execute_reply":"2021-01-23T12:35:46.179466Z"},"papermill":{"duration":25072.556455,"end_time":"2021-01-23T12:35:46.180117","exception":false,"start_time":"2021-01-23T05:37:53.623662","status":"completed"},"tags":[],"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":"history.history","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":12.320485,"end_time":"2021-01-23T12:36:36.789385","exception":false,"start_time":"2021-01-23T12:36:24.4689","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# Plotting"},{"metadata":{},"cell_type":"markdown","source":"## Accuracy graph"},{"metadata":{"trusted":true},"cell_type":"code","source":"history_dict = history.history\n\nacc = history_dict['accuracy']\nval_acc = history_dict['val_accuracy']\nepochs = range(1, len(acc) + 1)\nline1 = plt.plot(epochs, acc, label='train_Accuracy', color='red')\nline2 = plt.plot(epochs, val_acc, label='Val_acuuracy',color='green')\n\nplt.title('Accuracy ~ Epochs graph', fontsize=20)\nplt.xlabel('Epochs') \nplt.ylabel('Accuracy')\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Loss graph"},{"metadata":{"trusted":true},"cell_type":"code","source":"history_dict = history.history\n\nloss = history_dict['loss']\nval_loss = history_dict['val_loss']\nepochs = range(1, len(acc) + 1)\nline1 = plt.plot(epochs, loss, label='train_Accuracy', color='red')\nline2 = plt.plot(epochs, val_loss, label='Val_acuuracy',color='green')\n\nplt.title('Loss ~ Epochs graph', fontsize=20)\nplt.xlabel('Epochs') \nplt.ylabel('Loss')\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"papermill":{"duration":12.51465,"end_time":"2021-01-23T12:37:28.545852","exception":false,"start_time":"2021-01-23T12:37:16.031202","status":"completed"},"tags":[]},"cell_type":"markdown","source":"# load model"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T12:37:53.880113Z","iopub.status.busy":"2021-01-23T12:37:53.864751Z","iopub.status.idle":"2021-01-23T12:37:54.168929Z","shell.execute_reply":"2021-01-23T12:37:54.16796Z"},"papermill":{"duration":13.280015,"end_time":"2021-01-23T12:37:54.169038","exception":false,"start_time":"2021-01-23T12:37:40.889023","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"model.load_weights(\"best_model.h5\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## scan and augmentation"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T12:39:11.235354Z","iopub.status.busy":"2021-01-23T12:39:11.234814Z","iopub.status.idle":"2021-01-23T12:39:11.810472Z","shell.execute_reply":"2021-01-23T12:39:11.809985Z"},"papermill":{"duration":13.638167,"end_time":"2021-01-23T12:39:11.810587","exception":false,"start_time":"2021-01-23T12:38:58.17242","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def scan_img(img_path, crop_size=512):\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\ntest_augmentation = 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":{},"cell_type":"markdown","source":"## predict"},{"metadata":{"execution":{"iopub.execute_input":"2021-01-23T12:39:37.221508Z","iopub.status.busy":"2021-01-23T12:39:37.220972Z","iopub.status.idle":"2021-01-23T12:39:39.859954Z","shell.execute_reply":"2021-01-23T12:39:39.859477Z"},"papermill":{"duration":14.98317,"end_time":"2021-01-23T12:39:39.860056","exception":false,"start_time":"2021-01-23T12:39:24.876886","status":"completed"},"tags":[],"trusted":true},"cell_type":"code","source":"def predict(image_filename, folder, TTA_runs=4):\n\n    \n    localised_predictions = []\n    local_image_list = scan_img(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_augmentation(duplicated_local_image)\n        \n        predictions = model.predict(augmented_images)\n        localised_predictions.append(np.sum(predictions, axis=0))\n    \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 predictions(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(image_filename, folder))\n    return predictions\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image\ntest_dir = '../input/cassava-leaf-disease-classification/test_images/'\ntest_imgs = os.listdir(test_dir)\n\npredictions = predictions(test_imgs, test_dir)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submission file making"},{"metadata":{"trusted":true},"cell_type":"code","source":"submission = pd.DataFrame({'image_id': test_imgs, 'label': predictions})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission.to_csv('submission.csv', index = False)","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}