{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport json\n\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport cv2\nimport albumentations as A\nfrom sklearn import metrics as sk_metrics\n\nfrom PIL import Image\nfrom timeit import default_timer as timer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import h5py\nf1 = h5py.File('../input/resnet50-pretrained/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5', 'r')\nprint(list(f1.keys()))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Importing necessary libs\n\nimport random\nfrom sklearn.model_selection import train_test_split\n\nimport tensorflow as tf\nfrom tensorflow.keras import layers\nfrom tensorflow.keras import models\nfrom tensorflow.keras.optimizers import Adam, SGD\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\nfrom tensorflow.keras.applications import ResNet50\nfrom tensorflow.keras.utils import plot_model\n\nimport pickle\nfrom keras.applications.resnet50 import ResNet50 as ResModel","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BASE_PATH = '../input/cassava-leaf-disease-classification/'\nTRAIN_PATH = os.path.join(BASE_PATH, 'train_images')\nTEST_PATH = '../input/cassava-leaf-disease-classification/test_images/'\nMODEL_BASE = '../input/resnet50'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = pd.read_csv(\"../input/cassava-leaf-disease-classification/train.csv\")\ndf_train.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dist = df_train['label'].value_counts().reset_index()\ndist.columns = [\n    'label',\n    'percentage'\n]\ndist['percentage'] /= len(df_train)\nlabels = dist['label']\nsizes = dist['percentage']\n\nfig1, ax1 = plt.subplots()\nax1.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=90)\nax1.axis('equal')  # Equal aspect ratio ensures that pie is drawn as a circle.\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Clearly, most popular disease is label - 3. "},{"metadata":{"trusted":true},"cell_type":"code","source":"# json to label mapping to get better understanding\nwith open(\"../input/cassava-leaf-disease-classification/label_num_to_disease_map.json\") as f:\n    map_dis = json.loads(f.read())\n    map_dis = {int(k) : v for k, v in map_dis.items()}\n\nprint(json.dumps(map_dis, indent=4))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Cassava Mosaic Disease - CMD is the most frequent disese.\n\nLet's check the number of samples in train dir, samples in each class and the dimensions"},{"metadata":{"trusted":true},"cell_type":"code","source":"inp_files = os.listdir(TRAIN_PATH)\nprint(f\"Number of training samples: {len(inp_files)}\")\nprint(f\"Number of samples in each  class: \\n {df_train['label'].value_counts()}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Dimensions of first 300 images\nimg_shapes = {}\nfor image_name in os.listdir(os.path.join(BASE_PATH, \"train_images\"))[:300]:\n    image = cv2.imread(os.path.join(BASE_PATH, \"train_images\", image_name))\n    img_shapes[image.shape] = img_shapes.get(image.shape, 0) + 1\n\nprint(img_shapes)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Loading the classes names to the train dataframe to map class with the disease better"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train[\"class_name\"] = df_train[\"label\"].map(map_dis)\ndf_train","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's see the image distribution in the dataset (train)"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(8, 4))\nsns.countplot(y=\"class_name\", data=df_train);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There's a clear imbalance in the distribution. This can lead to discrimination against the classes on test data.\n### Possible ways to reduce imbalance\n* Try different models and see what fits best - IMP: Accuracy is the key metric, so can't change that\n* ReSampling \n    * Undersampling majority class\n    * Oversampling minority class\n* Generate synthetic samples"},{"metadata":{},"cell_type":"markdown","source":"### First let's plot some images from the dataset and take a look at them"},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot(class_id, label):\n    plot_list = df_train[df_train[\"label\"] == class_id].sample(2)['image_id'].tolist()\n    labels = [label for i in range(len(plot_list))]\n    size = np.sqrt(2)\n    if int(size)*int(size) < 2:\n        size = int(size) + 1\n    \n    plt.figure(figsize=(20, 20))\n    for index, (image_id, label) in enumerate(zip(plot_list, labels)):\n        plt.subplot(size, size, index + 1)\n        image = cv2.imread(os.path.join('../input/cassava-leaf-disease-classification/', \"train_images\", image_id))\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        \n        plt.imshow(image)\n        plt.title(label, fontsize=12)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plotting 2 images from each class\nfor key in map_dis:\n    plot(int(key), map_dis[key])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Split dataset for train and validation\n20% for val"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = df_train.astype({\"label\": str})\ntrain, test = train_test_split(df_train, test_size = 0.2, random_state = 42)\nprint(train.shape, test.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Creating ImageDataDenerator to augment and create batches"},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 224\nsize = (IMG_SIZE,IMG_SIZE)\n\ndatagen = ImageDataGenerator(\n                    rotation_range = 40,\n                    width_shift_range = 0.2,\n                    height_shift_range = 0.2,\n                    shear_range = 0.2,\n                    zoom_range = 0.2,\n                    horizontal_flip = True,\n                    vertical_flip = True,\n                    fill_mode = 'nearest'\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_gen = datagen.flow_from_dataframe(\n                    train,\n                    directory = TRAIN_PATH,\n                    x_col = \"image_id\",\n                    y_col = \"label\",\n                    target_size = size,\n                    class_mode = \"categorical\",\n                    batch_size = 64,\n                    shuffle = True,\n                    seed = 42,\n                    interpolation = \"nearest\"\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_gen = datagen.flow_from_dataframe(\n                    test,\n                    directory = TRAIN_PATH,\n                    x_col = \"image_id\",\n                    y_col = \"label\",\n                    target_size = size,\n                    class_mode = \"categorical\",\n                    batch_size = 64,\n                    shuffle = False,\n                    seed = 42,\n                    interpolation = \"nearest\"\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Creating a RESNET50 model with pretrained imagenet weights"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Defining the std params / hyperparams\n\nN_CLASS = 5\nEPOCHS=50\nlearn_rate=.001\nsgd=SGD(lr=learn_rate,momentum=.9,nesterov=False)\n\nSTEP_SIZE_TRAIN = train_gen.n//train_gen.batch_size\nSTEP_SIZE_VALID = valid_gen.n//valid_gen.batch_size","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**NOTE:** Play around with optimizers and loss."},{"metadata":{},"cell_type":"markdown","source":"### Defining a couple of \"fine-tunable\" hyperparameters such as Learning Rate Annealer, Checkpoint\n**(NOTE: Experiment with these the most and fine tune it over time. Currently  using the std vals)**"},{"metadata":{"trusted":true},"cell_type":"code","source":"lrr = ReduceLROnPlateau(monitor = 'val_acc',\n                              factor = 0.2,\n                              patience = 3,\n                              min_lr = 0.001,\n                              mode = 'min',\n                              verbose = 1)\n\n# Saving model with min val loss\ncheckpoint = ModelCheckpoint('best_model.hdf5', \n                             monitor = 'val_loss',\n                             verbose = 1,\n                             mode = 'min', \n                             save_best_only = True)\n\nearly_stop = EarlyStopping(monitor = 'val_loss',\n                               patience = 5,\n                               mode = 'min',\n                               restore_best_weights = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Defining Base model with imagenet weights and adding custom layers"},{"metadata":{"trusted":true},"cell_type":"code","source":"base_model = ResNet50(include_top = False, weights = 'imagenet', input_shape = (IMG_SIZE, IMG_SIZE, 3), classes = N_CLASS)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Addinng Layers to the Resnet50\n\nmodel_resnet=models.Sequential()\n#Add the Dense layers along with activation and batch normalization\nmodel_resnet.add(base_model)\nmodel_resnet.add(layers.Flatten())\n#Add the Dense layers along with activation and batch normalization\nmodel_resnet.add(layers.Dense(1024,activation=('relu')))\nmodel_resnet.add(layers.Dense(512,activation=('relu'))) \nmodel_resnet.add(layers.Dropout(.4))\nmodel_resnet.add(layers.Dense(256,activation=('relu'))) \nmodel_resnet.add(layers.Dropout(.3))\nmodel_resnet.add(layers.Dense(128,activation=('relu')))\nmodel_resnet.add(layers.Dropout(.2))\nmodel_resnet.add(layers.Dense(N_CLASS,activation=('softmax')))\n\n#Summary of ResNet50 Model\nmodel_resnet.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Compiling the model\nmodel_resnet.compile(optimizer = sgd, loss = 'categorical_crossentropy', metrics = ['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Training and Plots"},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model_resnet.fit(train_gen,\n                    validation_data = valid_gen,\n                    epochs = EPOCHS,\n                    steps_per_epoch = STEP_SIZE_TRAIN,\n                    validation_steps = STEP_SIZE_VALID,\n                    callbacks = [early_stop, checkpoint, lrr]\n                   )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model Evaluation"},{"metadata":{"trusted":true},"cell_type":"code","source":"model_resnet.evaluate_generator(generator = valid_gen, steps = STEP_SIZE_VALID)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(len(acc))\n\nplt.plot(epochs, acc, 'c-', label='Training accuracy')\nplt.plot(epochs, val_acc, 'y-', label='Validation accuracy')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(epochs, loss, 'c-', label='Training Loss')\nplt.plot(epochs, val_loss, 'y-', label='Validation Loss')\nplt.title('Training and validation loss')\nplt.legend()\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## print(predictions)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Once the entire code runs successfully, shift to the submission notebook.\nCross check that \"best_model.hf5\" is saved in output dir"}],"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}