{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Intro\nWelcome to the [Cassava Leaf Disease Classification](https://www.kaggle.com/c/cassava-leaf-disease-classification) competition.\n![](https://storage.googleapis.com/kaggle-competitions/kaggle/13836/logos/header.png)\n\nThere are 5 classifications (click for further informations):\n* 0: [Cassava Bacterial Blight (CBB)](https://en.wikipedia.org/wiki/Bacterial_blight_of_cassava)\n* 1: [Cassava Brown Streak Disease (CBSD)](https://en.wikipedia.org/wiki/Cassava_brown_streak_virus_disease)\n* 2: [Cassava Green Mottle (CGM)](https://en.wikipedia.org/wiki/Cassava_green_mottle_virus)\n* 3: [Cassava Mosaic Disease (CMD)](https://en.wikipedia.org/wiki/Cassava_mosaic_virus)\n* 4: Healthy\"\n\nWe will give a simple starter notebook based on a CNN.\n\n<span style=\"color: royalblue;\">Please vote the notebook up if it helps you. Thank you. </span>"},{"metadata":{},"cell_type":"markdown","source":"# Libraries\nWe load some standard libraries and packages of sklearn and keras."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport cv2\nimport matplotlib.pyplot as plt\nimport json\nimport random\n\nfrom sklearn.metrics import confusion_matrix\nfrom mlxtend.plotting import plot_confusion_matrix\n\nfrom keras.utils import to_categorical, Sequence\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D, BatchNormalization\nfrom keras.optimizers import RMSprop,Adam\nfrom keras.applications import ResNet50","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Path"},{"metadata":{"trusted":true},"cell_type":"code","source":"path = '/kaggle/input/cassava-leaf-disease-classification/'\nos.listdir(path)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Functions\nWe define some helper functions for visualizations."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"def plot_bar(data, name):\n    data_label = data[name].value_counts().sort_index()\n    dict_train = dict(zip(data_label.keys(), ((data_label.sort_index())).tolist()))\n    names = list(dict_train.keys())\n    values = list(dict_train.values())\n    plt.bar(names, values)\n    plt.grid()\n    plt.show()\n    \ndef plot_examples(label=0):\n    fig, axs = plt.subplots(1, 5, figsize=(25, 12))\n    fig.subplots_adjust(hspace = .2, wspace=.2)\n    axs = axs.ravel()\n    for i in range(5):\n        idx = train_data[train_data['label']==label].index[i]\n        img = cv2.imread(path+'train_images/'+train_data.loc[idx, 'image_id'])\n        axs[i].imshow(img)\n        axs[i].set_title(label_data[str(train_data.loc[idx, 'label'])])\n        axs[i].set_xticklabels([])\n        axs[i].set_yticklabels([])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","collapsed":true,"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":false},"cell_type":"markdown","source":"# Load Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_data = pd.read_csv(path+'train.csv')\nsamp_subm = pd.read_csv(path+'sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with open(path+'label_num_to_disease_map.json') as json_file:\n    label_data = json.load(json_file)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# EDA"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"print('number of train data:', len(train_data))\nprint('number of train images:', len(os.listdir(path+'train_images/')))\nprint('number of test images:', len(os.listdir(path+'test_images/')))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_data","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Distribution of the labels. As we can see there is a class imbalance in terms of class 3. The proportion of class 3 is about 61%."},{"metadata":{"trusted":true},"cell_type":"code","source":"len(train_data[train_data['label']==3])/len(train_data.index)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"plot_bar(train_data, 'label')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There are serveral techniques to overcome this drawback of class imbalance:\n1. Remove instances from the majority class 3.\n2. Data augmentation to use to add extra samples from the minority classes. In our context of images, this is generally achieved by adding distortion to the data by performing translation, rotation, varying the scale as well as by adding different types of noise such as Gaussian or Poisson.\n3. Additional use if the dropout and regularization methods.\n\nIn the section **Prepare Data** we want to start with reduction on images for class 3."},{"metadata":{},"cell_type":"markdown","source":"# Some Examples"},{"metadata":{},"cell_type":"markdown","source":"## Healthy"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"plot_examples(label=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Cassava Bacterial Blight (CBB)"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"plot_examples(label=0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Cassava Brown Streak Disease (CBSD)"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"plot_examples(label=1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Cassava Green Mottle (CGM)"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"plot_examples(label=2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Cassava Mosaic Disease (CMD)"},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"plot_examples(label=3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prepare Data"},{"metadata":{},"cell_type":"markdown","source":"To overcome the drawback of class imbalance we reduce randomly about 10,500 images of class 3."},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"ids_label_3 = list(train_data[train_data['label']==3].index)\nids_label_3_subset = random.sample(ids_label_3, 10500)\ntrain_data.drop(train_data.index[ids_label_3_subset], inplace=True)\ntrain_data.index = range(len(train_data.index))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_bar(train_data, 'label')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Parameters"},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 64\nimg_size = 256\nimg_channel = 3","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train Labels And Class Weights"},{"metadata":{"trusted":true},"cell_type":"code","source":"y_train = to_categorical(train_data['label'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class_weight = dict(zip(range(0, 5), (train_data['label'].value_counts().sort_index()/len(train_data))))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class_weight","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Image Data Generator"},{"metadata":{"trusted":true},"cell_type":"code","source":"class DataGenerator(Sequence):\n    def __init__(self, path, list_IDs, labels, batch_size, img_size, img_channel):\n        self.path = path\n        self.list_IDs = list_IDs\n        self.labels = labels\n        self.batch_size = batch_size\n        self.img_size = img_size\n        self.img_channel = img_channel\n        self.indexes = np.arange(len(self.list_IDs))\n        \n    def __len__(self):\n        len_ = int(len(self.list_IDs)/self.batch_size)\n        if len_*self.batch_size < len(self.list_IDs):\n            len_ += 1\n        return len_\n    \n    \n    def __getitem__(self, index):\n        indexes = self.indexes[index*self.batch_size:(index+1)*self.batch_size]\n        list_IDs_temp = [self.list_IDs[k] for k in indexes]\n        X, y = self.__data_generation(list_IDs_temp)\n        return X, y\n\n    \n    def __data_generation(self, list_IDs_temp):\n        X = np.zeros((self.batch_size, self.img_size, self.img_size, self.img_channel))\n        y = np.zeros((self.batch_size, 5), dtype=int)\n        for i, ID in enumerate(list_IDs_temp):\n            data_file = cv2.imread(self.path+ID)\n            img = cv2.resize(data_file, (self.img_size, self.img_size))\n            X[i, ] = img/255.\n            y[i, ] = self.labels[i]\n        return X, y","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"weights='../input/models/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"conv_base = ResNet50(include_top=False,\n                     weights=weights,\n                     input_shape=(img_size, img_size, img_channel))\nconv_base.trainable = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = Sequential()\nmodel.add(conv_base)\nmodel.add(Flatten())\nmodel.add(Dense(64, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(Dense(64, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(Dropout(0.1))\nmodel.add(Dense(5, activation='softmax'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(optimizer=Adam(lr=0.001), loss='categorical_crossentropy', metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = 10","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = DataGenerator(path+'train_images/', train_data['image_id'], y_train, batch_size, img_size, img_channel)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(generator=train_generator,\n                              epochs = epochs)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Predict Test Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_generator = DataGenerator(path+'test_images/', samp_subm['image_id'], samp_subm['label'], len(samp_subm), img_size, img_channel)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predict = model.predict_generator(test_generator, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"samp_subm['label'] = predict.argmax(axis=1)[0:len(samp_subm)]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Export Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"samp_subm.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Analyse Wrong Predictions\nWe analyse the predictions on the train set."},{"metadata":{"trusted":true},"cell_type":"code","source":"pred = model.predict_generator(train_generator, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"conf_mat = confusion_matrix(y_train.argmax(axis=1)[0:len(train_data)], pred.argmax(axis=1)[0:len(train_data)])\nfig, ax = plot_confusion_matrix(conf_mat=conf_mat,\n                                show_normed=False,\n                                show_absolute=True,\n                                figsize=(8, 8))\nfig.show()","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}