{"cells":[{"metadata":{},"cell_type":"markdown","source":"\n<img src=\"https://storage.googleapis.com/kaggle-competitions/kaggle/13836/logos/header.png?t=2020-10-01-17-22-54\">\n<center>\n<h1 style=\"color:red;font-weight:700;font-size:3em\">Cassava Leaf Disease Classification</h1>\n<h3 style=\"color:red;font-weight:700;font-size:1.5em\">Identify the type of disease present on a Cassava Leaf image</h3>\n</center>\n\n<center>\n<div class=\"list-group\" id=\"list-tab\" role=\"tablist\">\n  <h3 class=\"list-group-item list-group-item-action active\" data-toggle=\"list\" role=\"tab\" aria-controls=\"home\">Table of Contents</h3>\n  <a class=\"list-group-item list-group-item-action\" data-toggle=\"list\" href=\"#explore\" role=\"tab\" aria-controls=\"profile\" target=\"_self\">Explore The Data<span class=\"badge badge-primary badge-pill\">1</span></a>\n    <a class=\"list-group-item list-group-item-action\" data-toggle=\"list\" href=\"#data-prep\" role=\"tab\" aria-controls=\"profile\" target=\"_self\">Data-Prep<span class=\"badge badge-primary badge-pill\">2</span></a>\n  <a class=\"list-group-item list-group-item-action\" data-toggle=\"list\" href=\"#Model\" role=\"tab\" aria-controls=\"messages\" target=\"_self\">Model-Building<span class=\"badge badge-primary badge-pill\">3</span></a>\n</div>\n</center>"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-output":true,"_kg_hide-input":true},"cell_type":"code","source":"\n\nimport numpy as np \nimport pandas as pd \nimport os\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport tensorflow as tf\nimport tensorflow.keras.layers as L\nimport tensorflow.keras.backend as K\nimport sys\nimport cv2\nimport json\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport random\nfrom sklearn.metrics import accuracy_score\nfrom PIL import Image\n\ndef seedAll(seed):\n    random.seed(seed)\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    os.environ[\"PYTHONHASHSEED\"] = str(seed)\n\nseedAll(42)\nPATH = \"../input/cassava-leaf-disease-classification/\"","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# <a id=\"explore\">Explore the Data</a>"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(f\"Number of Images in the train set {len(os.listdir(os.path.join(PATH,'train_images/')))}\")\nprint(f\"Number of Images in the test set {len(os.listdir(os.path.join(PATH,'test_images/')))}\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Woahhh! Strange!! Only one image in the test set?\nNot really! This is a code competition where submission has to be made through a notebook. The test set is not visible to the participant and is only visible to the notebook when the submission is being evaluated. All operations on the test set must be applied to the images in the test_images folder. During evaluation this folder will be replaced by the actual test set."},{"metadata":{"trusted":true},"cell_type":"code","source":"img =cv2.imread(PATH+\"/train_images/1000015157.jpg\")\nprint(f\"Shape of images in train_set: {img.shape}\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Load the data"},{"metadata":{"trusted":true},"cell_type":"code","source":"with open(os.path.join(PATH,'label_num_to_disease_map.json')) as file:\n    mapping = json.loads(file.read())\n    \nprint(mapping)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(os.path.join(PATH,'train.csv'))\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's create a column with the name of the diseases"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.loc[:,\"disease_name\"] = train_df.label.astype(str).map(mapping)\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## A look at the images"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def viz_batch(length=15,folder=\"train_images/\"):\n    plt.figure(figsize=(5*3,5*int(length/3)))\n    a = train_df.sample(length)\n    for i in range(length):\n        img = a.iloc[i][\"image_id\"]\n        image = cv2.cvtColor(cv2.imread(os.path.join(PATH,folder,img)),cv2.COLOR_BGR2RGB)\n        label = a.iloc[i][\"disease_name\"]\n        \n        plt.subplot(int(length/3),3,i+1)\n        plt.imshow(image)\n        plt.title(label);\n    plt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"viz_batch(length=9)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# <a id=\"data-prep\">Data-Prep</a>"},{"metadata":{},"cell_type":"markdown","source":"#### A look at the class distribution in the train set reveals a huge class imbalance. We will therefore compute the weights to be assigned to each class"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure()\nsns.countplot(train_df.label)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"#compute weights\nweights={}\nref = train_df[train_df.label==3].shape[0]\nfor i in range(5):\n    weights[i]= ref/train_df[train_df.label==i].shape[0]\nprint(weights)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# <a id=\"Model\"> Model Building </a>"},{"metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"def build_model():\n    inp = L.Input(shape=(128,128,3))\n    \n    \n    block1 = L.Conv2D(32,(3,3),name=\"block1_conv2\")(inp)\n    block1 = L.Conv2D(32,(1,1),activation=\"relu\",name=\"block1_conv1\")(block1)\n    block1 = L.BatchNormalization()(block1)\n    block1 = L.Activation(\"relu\")(block1)\n    block1 = L.MaxPooling2D((2,2))(block1)\n    \n    side_out = block1\n    side_out =  L.Conv2D(32,(4,4),strides=2,activation=\"relu\",name='first_skip')(side_out)\n    \n    block1 = L.Conv2D(32,(3,3),name=\"block1_conv3\")(block1)\n    block1 = L.BatchNormalization()(block1)\n    block1 = L.Activation(\"relu\")(block1)\n    block1 = L.MaxPooling2D((2,2))(block1)\n    \n    block1 = L.Concatenate(axis=3)([block1,side_out])\n    \n    block2 = L.Conv2D(64,(3,3),name=\"block2_conv2\")(block1)\n    block2 = L.BatchNormalization()(block2)\n    block2 = L.Activation(\"relu\")(block2)\n    block2 = L.MaxPooling2D((2,2))(block2)\n    \n    side_out2 = block2\n    side_out2 =  L.Conv2D(64,(4,4),strides=2,activation=\"relu\",name='second_skip')(side_out2)\n    \n    block2 = L.Conv2D(64,(3,3),name=\"block2_conv3\")(block2)\n    block2 = L.BatchNormalization()(block2)\n    block2 = L.Activation(\"relu\")(block2)\n    block2 = L.MaxPooling2D((2,2))(block2)\n    \n    block2 = L.Concatenate(axis=3)([block2,side_out2]) \n    \n    out = L.GlobalAveragePooling2D()(block2)\n    out = L.Dense(50,activation=\"relu\",kernel_initializer=\"he_normal\")(out)\n    out = L.Dense(5,activation=\"softmax\",kernel_initializer=\"he_normal\")(out)\n    \n    model = tf.keras.Model(inputs=inp,outputs=out)\n    model.compile(loss=\"categorical_crossentropy\",optimizer=\"adam\",metrics=[\"accuracy\"])\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_model2():\n    inp = L.Input(shape=(128,128,3))\n    model = tf.keras.applications.resnet50.ResNet50(include_top=False,weights='../input/resnet50/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5',input_tensor=inp)\n    for layer in model.layers:\n        layer.trainable=True\n    \n    for layer in model.layers[:-50]:\n        if not isinstance(layer,L.BatchNormalization):\n            layer.trainable=False\n    \n    out = L.Flatten()(model.output)\n    out = L.Dense(50,activation=\"relu\",kernel_initializer=\"he_normal\")(out)\n    out = L.Dense(5,activation=\"softmax\",kernel_initializer=\"he_normal\")(out)\n    \n    model_fin = tf.keras.Model(inputs=inp,outputs=out)\n    model_fin.compile(loss=\"categorical_crossentropy\",optimizer=\"adam\",metrics=[\"accuracy\"])\n    return model_fin","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = build_model2()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"tf.keras.utils.plot_model(model)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# <a id=\"training\">Model-Training</a>"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":false,"_kg_hide-output":false},"cell_type":"code","source":"from sklearn.model_selection import StratifiedKFold\nkf = StratifiedKFold(n_splits=5)\n\nfor id,(tr_,te_) in enumerate(kf.split(train_df[\"image_id\"],y=train_df[\"label\"])):\n    train_df.loc[te_,'kfold']=id","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df[\"label\"] = train_df[\"label\"].astype(str)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ss = pd.read_csv('../input/cassava-leaf-disease-classification/sample_submission.csv')\nss.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"reduce_lr = tf.keras.callbacks.ReduceLROnPlateau(monitor = 'val_loss', factor = 0.1, \n                              patience = 2, min_delta = 0.001, \n                              mode = 'min', verbose = 1)\nmodel_save = tf.keras.callbacks.ModelCheckpoint('./best_baseline_model.h5', \n                             save_best_only = True, \n                             save_weights_only = True,\n                             monitor = 'val_loss', \n                             mode = 'min', verbose = 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":false,"_kg_hide-output":false},"cell_type":"code","source":"histories = []\npreds = np.zeros((len(ss),1,5))\n\n\n\nX_train = train_df[train_df.kfold!=0]\nval_df = train_df[train_df.kfold==0]\n\ntrain_generator = ImageDataGenerator(preprocessing_function = tf.keras.applications.resnet50.preprocess_input,\n                                 zoom_range = 0.15,\n                                 cval = 0.,\n                                 horizontal_flip = True,\n                                 vertical_flip = True,\n                                 shear_range = 0.15,\n                                 height_shift_range = 0.15,\n                                 width_shift_range = 0.15)\n\ntrain_set = train_generator.flow_from_dataframe(X_train,\n                         directory = '../input/cassava-leaf-disease-classification/train_images/',\n                         x_col = \"image_id\",\n                         y_col = \"label\",\n                         target_size = (128, 128),\n                         batch_size = 64)\n\nval_generator = ImageDataGenerator(preprocessing_function = tf.keras.applications.resnet50.preprocess_input,\n                                 zoom_range = 0.15,\n                                 cval = 0.,\n                                 horizontal_flip = True,\n                                 vertical_flip = True,\n                                 shear_range = 0.15,\n                                 height_shift_range = 0.15,\n                                 width_shift_range = 0.15)\n\nval_set = val_generator.flow_from_dataframe(val_df,\n                         directory = '../input/cassava-leaf-disease-classification/train_images/',\n                         x_col = \"image_id\",\n                         y_col = \"label\",\n                         target_size = (128, 128),\n                         batch_size = 64)\n\nK.clear_session()                                                                  \nmodel = build_model2()\n\nhistory = model.fit_generator(train_set,\n                              epochs=15,\n                              steps_per_epoch=int(len(X_train)/64),\n                              validation_data = val_set,\n                              callbacks=[model_save,reduce_lr]\n                             )\n\nhistories.append(history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":false,"_kg_hide-output":false},"cell_type":"code","source":"val_pred = []\nfor img in val_df.image_id:\n    img = Image.open('../input/cassava-leaf-disease-classification/train_images/'+img)\n    img = np.asarray(img.resize((128,128)))\n    img = tf.keras.applications.resnet50.preprocess_input(img)\n    val_pred.append(np.argmax(model.predict(np.stack([img]))))\nprint('validation score: {}'.format(accuracy_score(val_df.label.astype(int),val_pred)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":false,"_kg_hide-output":false},"cell_type":"code","source":"pred = []\npreds = np.zeros((len(ss),1,5))\nfor img in ss.image_id:\n    img = Image.open('../input/cassava-leaf-disease-classification/test_images/'+img)\n    img = np.asarray(img.resize((128,128)))\n    img = tf.keras.applications.resnet50.preprocess_input(img)\n    pred.append(np.argmax(model.predict(np.stack([img]))))\n\nss[\"label\"] = pred","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ss.to_csv('submission.csv',index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure()\nplt.subplot(1,2,1)\nfor history in histories:\n    plt.plot(history.history[\"val_loss\"],color=\"green\")\n    plt.plot(history.history[\"loss\"],color=\"red\")\nplt.subplot(1,2,2)\nfor history in histories:\n    plt.plot(history.history[\"val_accuracy\"],color=\"green\")\n    plt.plot(history.history[\"accuracy\"],color=\"red\")","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}