{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Credits\nMost of the contents were taken from [This Notebook](https://www.kaggle.com/drcapa/cassava-leaf-disease-classification-starter-keras)"},{"metadata":{},"cell_type":"markdown","source":"# Intro\nWelcome to the Cassava Leaf Disease Classification competition.\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."},{"metadata":{},"cell_type":"markdown","source":"# Libraries"},{"metadata":{"trusted":true},"cell_type":"code","source":"%%capture\nimport sys\nsys.path.append('/kaggle/input/efficientnet-keras-dataset/efficientnet_kaggle')\n! pip install -e /kaggle/input/efficientnet-keras-dataset/efficientnet_kaggle","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport cv2\nimport matplotlib.pyplot as plt\nimport tensorflow as tf","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.utils import to_categorical, Sequence\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D, BatchNormalization\nfrom tensorflow.keras.optimizers import RMSprop,Adam","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"},{"metadata":{"trusted":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()","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":{},"cell_type":"markdown","source":"# EDA"},{"metadata":{"trusted":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":{},"cell_type":"markdown","source":"Distribution of the labels:"},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_bar(train_data, 'label')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Plot an image:"},{"metadata":{"trusted":true},"cell_type":"code","source":"img = cv2.imread(path+'train_images/'+'1000015157.jpg')\nplt.imshow(img)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prepare Data For Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 4\nimg_size = 128\nimg_channel = 3\neffnet = 0","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train Labels And Class Weights"},{"metadata":{"trusted":true},"cell_type":"code","source":"# \n# class_weight = dict(zip(range(0, 5), (.value_counts().sort_index()/len(train_data))))\n# class_weight","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import sklearn\ny_train = to_categorical(train_data['label'])\n\nweight = sklearn.utils.class_weight.compute_class_weight(class_weight = 'balanced', \n                                                classes = np.unique(train_data['label']),\n                                                y = train_data['label'])\nclass_weight = dict(zip(range(0, 5), weight))\nclass_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        return int(np.floor(len(self.list_IDs)/self.batch_size))\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.empty((self.batch_size, self.img_size, self.img_size, self.img_channel))\n        y = np.empty((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            img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n            X[i, ] = img\n            y[i, ] = self.labels[i]\n        X = X.astype('float32')/255.0\n#         X -= X.mean()\n#         X /= X.std()\n        return X, y","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Augmentation Pipeline (GPU)"},{"metadata":{"trusted":true},"cell_type":"code","source":"data_augmentation = tf.keras.Sequential([\n    tf.keras.layers.experimental.preprocessing.RandomFlip(),\n    tf.keras.layers.experimental.preprocessing.RandomRotation(0.1),\n#     tf.keras.layers.experimental.preprocessing.RandomZoom(height_factor = 0.2, width_factor = 0.2),\n    tf.keras.layers.experimental.preprocessing.RandomCrop(height = int(img_size*0.8), width = int(img_size*0.8)),\n    tf.keras.layers.experimental.preprocessing.Resizing(height = int(img_size), width = int(img_size), interpolation = 'area'),   \n])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Plot Some Samples"},{"metadata":{"trusted":true},"cell_type":"code","source":"label2name = {\"0\": \"Bacterial Blight\",\n\"1\": \"Brown Streak Disease\",\n\"2\": \"Green Mottle\",\n\"3\": \"Mosaic Disease\",\n\"4\": \"Healthy\"}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = DataGenerator(path+'train_images/', train_data['image_id'].tolist(), y_train, 8, img_size, img_channel)\nX, y = train_generator.__getitem__(0)\ny = np.max(y, axis = -1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def display(X, y):\n    samples = X.shape[0]\n    n_col = 4\n    n_row = samples//4\n    fig, ax  = plt.subplots(n_row, n_col, figsize = (n_col*5, n_row*5), constrained_layout = True)\n    for row in range(n_row):\n        for col in range(n_col):\n            ax[row][col].imshow(X[row*n_col + col])\n            ax[row][col].set_title(label2name[str(y[row*n_col + col])]+f'({str(y[row*n_col + col])})', fontsize = 15)\n            ax[row][col].set_xticks([]);\n            ax[row][col].set_yticks([]);\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Before Augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"display(X,y)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## After Augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"display(data_augmentation(X),y)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Callbacks"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_lr_callback(batch_size=8, show = False):\n    lr_start   = 0.000000825\n    lr_max     = 0.000000800 * 1 * batch_size\n    lr_min     = 0.000001\n    lr_ramp_ep = 5\n    lr_sus_ep  = 0\n    lr_decay   = 0.8\n   \n    def lrfn(epoch):\n        if epoch < lr_ramp_ep:\n            lr = (lr_max - lr_start) / lr_ramp_ep * epoch + lr_start\n            \n        elif epoch < lr_ramp_ep + lr_sus_ep:\n            lr = lr_max\n            \n        else:\n            lr = (lr_max - lr_min) * lr_decay**(epoch - lr_ramp_ep - lr_sus_ep) + lr_min\n            \n        return lr\n    \n    if show:\n        plt.figure(figsize = (8, 5))\n        plt.plot(np.arange(1, 12), [lrfn(x) for x in np.arange(1, 12)], marker = 'o')\n        plt.xlabel('epoch')\n        plt.ylabel('learaning_rate');\n        plt.show()\n        \n    lr_callback = tf.keras.callbacks.LearningRateScheduler(lrfn, verbose=True)\n    return lr_callback\n\n\n# Figure\nget_lr_callback(batch_size=8, show = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# CheckPoint"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_ckpt():\n    return tf.keras.callbacks.ModelCheckpoint('best.h5', \n                                        monitor='val_categorical_accuracy', \n                                        verbose=1,\n                                        save_best_only=True, \n                                        save_weights_only=True,\n                                        mode='max',\n                                        save_freq='epoch')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"import efficientnet.tfkeras as efn   \nmodel_dict = {0: efn.EfficientNetB0,\n              1: efn.EfficientNetB1,\n              2: efn.EfficientNetB2,\n              3: efn.EfficientNetB3,\n              4: efn.EfficientNetB4,\n              5: efn.EfficientNetB5,\n              6: efn.EfficientNetB6,\n              7: efn.EfficientNetB7,}\n\ndef get_model():\n    base_model = model_dict[effnet](input_shape=(img_size, img_size, img_channel),weights='imagenet',include_top=False)\n\n    model = tf.keras.Sequential([\n                                    data_augmentation,\n                                    base_model,\n                                    tf.keras.layers.GlobalAveragePooling2D(),\n                                    tf.keras.layers.Dense(64, activation = 'relu'),\n                                    tf.keras.layers.Dense(5, activation = 'softmax')\n                                ])\n    model.compile(optimizer=tf.keras.optimizers.Adam(lr=1e-4), loss='categorical_crossentropy', metrics=['categorical_accuracy'])\n    return model\n# model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\ntrain_idx, val_idx = train_test_split(train_data.index, test_size = 0.2, stratify = train_data['label'], random_state = 42)\nprint(f'Train: {len(train_idx)}')\nprint(f'Val: {len(val_idx)}')\ntrain_generator = DataGenerator(path+'train_images/', train_data['image_id'].loc[train_idx].tolist(), y_train[train_idx], batch_size, img_size, img_channel)\nval_generator   = DataGenerator(path+'train_images/', train_data['image_id'].loc[val_idx].tolist(), y_train[val_idx], batch_size, img_size, img_channel)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = 12\nmodel = get_model()\nhistory = model.fit(train_generator,\n                    steps_per_epoch = len(train_idx)//batch_size,\n                    validation_steps= len(val_idx)//batch_size,\n                    epochs = epochs,\n#                     class_weight = class_weight,\n                    validation_data = val_generator,\n                    callbacks = [\n                                 get_lr_callback(batch_size),\n                                 get_ckpt()],\n                   )\n# Figure\nplt.figure(figsize=(15,5))\nplt.plot(np.arange(len(model.history.history['categorical_accuracy'])),model.history.history['categorical_accuracy'],'-o',label='Train categorical_accuracy',color='#ff7f0e')\nplt.plot(np.arange(len(model.history.history['categorical_accuracy'])),model.history.history['val_categorical_accuracy'],'-o',label='Val categorical_accuracy',color='#1f77b4')\nx = np.argmax( model.history.history['val_categorical_accuracy'] ); y = np.max( model.history.history['val_categorical_accuracy'] )\nxdist = plt.xlim()[1] - plt.xlim()[0]; ydist = plt.ylim()[1] - plt.ylim()[0]\nplt.scatter(x,y,s=200,color='#1f77b4'); plt.text(x-0.03*xdist,y-0.13*ydist,'max categorical_accuracy\\n%.2f'%y,size=14)\nplt.ylabel('categorical_accuracy',size=14); plt.xlabel('Epoch',size=14)\nplt.legend(loc=2)\nplt2 = plt.gca().twinx()\nplt2.plot(np.arange(len(model.history.history['loss'])),model.history.history['loss'],'-o',label='Train Loss',color='#2ca02c')\nplt2.plot(np.arange(len(model.history.history['loss'])),model.history.history['val_loss'],'-o',label='Val Loss',color='#d62728')\nx = np.argmin( model.history.history['val_loss'] ); y = np.min( model.history.history['val_loss'] )\nydist = plt.ylim()[1] - plt.ylim()[0]\nplt.scatter(x,y,s=200,color='#d62728'); plt.text(x-0.03*xdist,y+0.05*ydist,'min loss',size=14)\nplt.ylabel('Loss',size=14)\nplt.legend(loc=3)\nplt.show()","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'], 1, img_size, img_channel)\nmodel.load_weights('best.h5')\npredict = model.predict(test_generator, verbose=1)\nsamp_subm['label'] = predict.argmax(axis=1)","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)\nsamp_subm","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}