{"cells":[{"metadata":{},"cell_type":"markdown","source":"<h1><center>Cassava Leaf Disease Classification</center></h1>\n<center><img src=\"https://images.unsplash.com/photo-1536882240095-0379873feb4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=1051&q=80\" width=\"60%\"></center>"},{"metadata":{},"cell_type":"markdown","source":"### In this notebook, I will use different keras available models to see how they affect the results.\n### Here is the complete list of <a href='https://keras.io/api/applications/'>[keras available models] </a> . Please feel to fork this notebook and tweak it using different models/processings. I would be happy to discuss the results. <span style=\"color:red\">Please do not forget to upvote</span>. \n\n### Version 5 updates: using ResNet152V2 + adding dropout.\n#### <span style=\"color:green\">Please note that each Keras Application expects a specific kind of input preprocessing. For ResNetV2, call tf.keras.applications.resnet_v2.preprocess_input on your inputs before passing them to the model.</span>."},{"metadata":{},"cell_type":"markdown","source":"# Part 1 - Training"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Importing useful libraries\n\nimport pandas as pd \nimport numpy as np\nimport os\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n# ML tools \nimport keras\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Flatten, Activation, Conv2D, MaxPooling2D, Dropout, Conv2D,MaxPooling2D,GlobalAveragePooling2D\nfrom keras.optimizers import Adam\nfrom tensorflow.keras import Model\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import ResNet152V2, VGG16, InceptionResNetV2, EfficientNetB0,Xception, ResNet50, NASNetLarge\nfrom keras import optimizers\nimport tensorflow.keras.backend as K\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau, ModelCheckpoint, EarlyStopping\n\n# Visualization tools\nimport matplotlib.pyplot as plt\nimport seaborn as sns","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"df_target = pd.read_csv('../input/cassava-leaf-disease-classification/train.csv')\ndisplay(df_target.head(3))\nprint(df_target.shape)\ndf_sample = pd.read_csv('../input/cassava-leaf-disease-classification/sample_submission.csv')\ndisplay(df_target.head(3))\nprint(df_target.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_target['label'] = df_target['label'].astype('str')\ndisplay(df_target.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"n_classes = 5\nbatch_size = 64\nimg_size = 224\nn_epochs = 30","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## ImageDataGenerator"},{"metadata":{},"cell_type":"markdown","source":"The goal of applying data augmentation is to increase the generalizability of the model. Imagedatagenerator works with taking a batch of training examples and applying different random transformations to each image in the batch, for example: vertical flip, zoom, or rotation and pass the the batch with original or transformed images for the training. Therefore, we are not increasing the dataset size, but adding more variety to it. It should be noted that the training and validation folders should be seperate, otherwise, the augmentation will be implemented on the validation set too; which is not desirable. There is one way to perform the augmentation only on the training which is shown below by defining two different generators with passing validation_split in both. "},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img\n\n\nimage_generator = ImageDataGenerator(\n        validation_split=0.15,\n        horizontal_flip=True,\n        vertical_flip = True,\n        rotation_range=30,\n        zoom_range = 0.25,\n        shear_range = 0.15,\n        fill_mode='nearest'\n)\n\nimage_generator_valid = ImageDataGenerator(validation_split=0.15)\n                                                   \ntrain_generator = image_generator.flow_from_dataframe(\n        dataframe = df_target,\n        directory='../input/cassava-leaf-disease-classification/train_images',\n        x_col = 'image_id',\n        y_col = 'label',     \n        target_size=(img_size, img_size),\n        batch_size=batch_size,\n        subset='training',\n        class_mode='sparse') \n\nvalid_generator=image_generator_valid.flow_from_dataframe(\n    dataframe = df_target,\n    directory='../input/cassava-leaf-disease-classification/train_images',\n    x_col = 'image_id',\n    y_col = 'label', \n    target_size=(img_size, img_size),\n    batch_size=batch_size,\n    subset='validation',\n    class_mode='sparse') ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Here are how images look like after passing through image generator. "},{"metadata":{"trusted":true},"cell_type":"code","source":"for j in range(6):\n    aug_images = [train_generator[0][0][j]/255 for i in range(6)]\n    fig, axes = plt.subplots(1, 6, figsize=(24,24))\n    axes = axes.flatten()\n    for img, ax in zip(aug_images, axes):\n        ax.imshow(img)\n        ax.axis('off')\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"net = ResNet152V2(weights='imagenet', \n                  include_top = False, \n                  input_shape=(img_size, img_size, 3))\n# net.trainable = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"inp = keras.layers.Input([img_size, img_size, 3])\nx = keras.applications.resnet_v2.preprocess_input(inp)\nx = net(x)\nx= GlobalAveragePooling2D()(x)\nx = Dropout(0.2)(x)\noutput = Dense(n_classes, activation='softmax')(x)\nmodel = Model(inp, output)\nmodel.summary()\nmodel.compile(optimizers.Adam(lr=5e-4),loss='sparse_categorical_crossentropy',metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Defining callbacks to monitor the validation accuracy and save the model\n\n\nrlr = ReduceLROnPlateau(monitor = 'val_accuracy', factor = 0.2, patience = 2, verbose = 0, \n                                min_delta = 1e-4, min_lr = 1e-6, mode = 'max')\n        \nckp = ModelCheckpoint('model.h5',monitor = 'val_accuracy',\n                      verbose = 0, save_best_only = True, mode = 'max')\n        \nes = EarlyStopping(monitor = 'val_accuracy', min_delta = 1e-4, patience = 5, mode = 'max', \n                    restore_best_weights = True, verbose = 0)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(generator=train_generator,                      \n                    validation_data=valid_generator,                                       \n                    epochs=n_epochs,\n                    callbacks=[rlr,es,ckp],\n                    verbose=2)\nK.clear_session()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Here are the curves showing training and validation losses and accuracies over epochs. "},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nplt.rcParams.update({'font.size': 16})\nhist = pd.DataFrame(history.history)\nfig, (ax1, ax2) = plt.subplots(figsize=(12,12),nrows=2, ncols=1)\nhist['loss'].plot(ax=ax1,c='k',label='training loss')\nhist['val_loss'].plot(ax=ax1,c='r',linestyle='--', label='validation loss')\nax1.legend()\nhist['accuracy'].plot(ax=ax2,c='k',label='training accuracy')\nhist['val_accuracy'].plot(ax=ax2,c='r',linestyle='--',label='validation accuracy')\nax2.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"### The model is saved using the checkpoint callback.\n## For the results, please see the second notebook <a href='https://www.kaggle.com/sinamhd9/efficientnetb0-in-keras-part-2-inference/'> [Part 2]</a>\n\n## Please upvote this notebook if you find it useful. Thanks!"},{"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}