{"cells":[{"metadata":{},"cell_type":"markdown","source":"<center><h1> Introduction </h1></center>\n"},{"metadata":{},"cell_type":"markdown","source":"* **Competition** - Given a set of images of Cassava leaves we need to classify them as one of the four diseases or healthy.\n* **Data** - A collection of 21397 labelled images\n* **Evaluation** - Classification accuracy"},{"metadata":{},"cell_type":"markdown","source":"We will take a quick look at the data files and train our model in this notebook. The model can be saved and used for inference in a later notebook."},{"metadata":{},"cell_type":"markdown","source":"<center><h1> Importing necessary libraries </h1></center> "},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\nimport os\nROOT_DIR = '../input/cassava-leaf-disease-classification/'\nos.listdir(ROOT_DIR)\n\nimport json # to read in the 'label_num_to_disease_map.json' file","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport plotly.express as px\nimport seaborn as sns\nimport cv2\nimport random","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers\nfrom tensorflow.keras import models\nfrom tensorflow.keras.optimizers import Adam\n\nfrom tensorflow.keras.preprocessing.image import load_img\nfrom tensorflow.keras.preprocessing.image import img_to_array\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\nfrom tensorflow.keras.applications import EfficientNetB1\nfrom tensorflow.keras.utils import plot_model","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# set the training and test directory paths\nTRAIN_DIR = '../input/cassava-leaf-disease-classification/train_images/'\nTEST_DIR = '../input/cassava-leaf-disease-classification/test_images/'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# set seed\nseed = 42\n\ndef seed_everything(seed):\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    \nseed_everything(seed)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<center><h1> Data exploration </h1></center> "},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(ROOT_DIR + 'train.csv')\nsample_df = pd.read_csv(ROOT_DIR + 'sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_df.shape, sample_df.shape)\ndisplay(train_df.head())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f = open(ROOT_DIR + 'label_num_to_disease_map.json')\ndata = json.load(f)\nprint(json.dumps(data, indent = 2))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"z = train_df.sample(20)\ndisplay(z)\nimages, labels = z['image_id'].tolist(), z['label'].tolist()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<center><h1> Plotting 20 randomly sampled images with class </h1></center> "},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize = (20,20))\nfor i in range(20):\n    plt.subplot(4,5,i+1)\n    img = cv2.imread(TRAIN_DIR + images[i])\n    img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)\n    plt.imshow(img)\n    plt.title(data[str(labels[i])])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<center><h1> Plotting a count plot and pie chart for class distribution. </h1></center> "},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.set_style('whitegrid')\nsns.countplot(x = 'label', data = train_df, palette = 'Pastel1');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pie_df = train_df['label'].value_counts().reset_index()\npie_df.columns = ['label', 'count']\nfig = px.pie(pie_df, values = 'count', names = 'label', color_discrete_sequence = px.colors.qualitative.Pastel)\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"There is a class imbalance problem here. The Cassava Mosaic Disease (CMD) samples are more compared to other classes. We can solve this by either upsampling other class samples or downsampling the CMD samples."},{"metadata":{},"cell_type":"markdown","source":"<center><h1> Split dataset for training and validation </h1></center> \n<center> Reserving 15% of data for validation </center>"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = train_df.astype({\"label\": str})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train, test = train_test_split(train_df, test_size = 0.15, random_state = seed)\nprint(train.shape, test.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<center><h1> Creating ImageDataGenerator to generate data in batches and perform image augmentation. </h1></center> "},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 240\nsize = (IMG_SIZE,IMG_SIZE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"datagen = ImageDataGenerator(\n                    rotation_range = 30,\n                    width_shift_range = 0.2,\n                    height_shift_range = 0.2,\n                    shear_range = 0.2,\n                    zoom_range = 0.2,\n                    brightness_range = [0.5,1.5],\n                    horizontal_flip = True,\n                    vertical_flip = True,\n                    fill_mode = 'nearest'\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"validgen = ImageDataGenerator()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = datagen.flow_from_dataframe(\n                    train,\n                    directory = TRAIN_DIR,\n                    x_col = \"image_id\",\n                    y_col = \"label\",\n                    target_size = size,\n                    class_mode = \"sparse\",\n                    batch_size = 32,\n                    shuffle = True,\n                    seed = seed,\n                    interpolation = \"nearest\"\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_generator = validgen.flow_from_dataframe(\n                    test,\n                    directory = TRAIN_DIR,\n                    x_col = \"image_id\",\n                    y_col = \"label\",\n                    target_size = size,\n                    class_mode = \"sparse\",\n                    batch_size = 32,\n                    shuffle = False,\n                    seed = seed,\n                    interpolation = \"nearest\"\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<center><h2> Visualizing some of the augmented images </h2></center>"},{"metadata":{},"cell_type":"markdown","source":"### Image before Augmentation"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"img = cv2.imread(os.path.join(TRAIN_DIR,'1000201771.jpg'))\nimg = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)\nplt.imshow(img)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Images after Augmentation"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"plt.figure(figsize = (10,10))\n# set the title\nplt.title('Augmented Images')\n# load the image\nimg = load_img(os.path.join(TRAIN_DIR,'1000201771.jpg'))\n# convert to numpy array\ndata = img_to_array(img)\n# expand dimension to one sample\nsamples = np.expand_dims(data, 0)\n# iterator\nitr = datagen.flow(samples, batch_size = 1)\n# generate samples and plot\nfor i in range(12):\n    # define subplot\n    plt.subplot(4,3,i+1)\n    # generate batch of images\n    batch = itr.next()\n    # convert to unsigned integers for viewing\n    image = batch[0].astype('uint8')\n    # plot raw pixel data\n    plt.imshow(image)\n# show the figure\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<center><h1> Model creation and training </h1></center> "},{"metadata":{"trusted":true},"cell_type":"code","source":"NUM_CLASSES = 5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def create_model():\n    \n    model = models.Sequential()\n    # initialize EfficientNetB model with input shape as (240,240,3)\n    model.add(EfficientNetB1(input_shape = (IMG_SIZE, IMG_SIZE, 3), include_top = False, weights = 'imagenet'))\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dense(256, activation = 'relu'))\n    model.add(layers.Dropout(0.5))\n    model.add(layers.Dense(NUM_CLASSES, activation = 'softmax'))\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = create_model()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(loss = 'sparse_categorical_crossentropy',\n             optimizer = Adam(learning_rate = 0.001),\n             metrics = ['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Stop training when the validation loss metric has stopped decreasing for 5 epochs.\n#early_stopping = EarlyStopping(monitor = 'val_loss',\n                              # patience = 5,\n                               #mode = 'min',\n                               #restore_best_weights = True)\n\n# Save the model with the minimum validation loss\ncheckpoint = ModelCheckpoint('best_model.hdf5', \n                             monitor = 'val_loss',\n                             verbose = 1,\n                             mode = 'min', \n                             save_best_only = True)\n# reduce learning rate\nreduce_lr = ReduceLROnPlateau(monitor = 'val_loss',\n                              factor = 0.2,\n                              patience = 3,\n                              min_lr = 0.001,\n                              mode = 'min',\n                              verbose = 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nSTEP_SIZE_TRAIN = train_generator.n//train_generator.batch_size\nSTEP_SIZE_VALID = valid_generator.n//valid_generator.batch_size","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit(train_generator,\n                    validation_data = valid_generator,\n                    epochs = 5,\n                    steps_per_epoch = STEP_SIZE_TRAIN,\n                    validation_steps = STEP_SIZE_VALID,\n                    callbacks = [checkpoint, reduce_lr]\n                   )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_model(model, show_shapes = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<center><h1> Model evaluation </h1></center> "},{"metadata":{"trusted":true},"cell_type":"code","source":"model.evaluate_generator(generator = valid_generator, 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":"val1=max(acc)\nprint(val1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit(train_generator,\n                    validation_data = valid_generator,\n                    epochs = 20,\n                    steps_per_epoch = STEP_SIZE_TRAIN,\n                    validation_steps = STEP_SIZE_VALID,\n                    callbacks = [checkpoint, reduce_lr]\n                   )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_model(model, show_shapes = True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acc1 = history.history['accuracy']\nval_acc1 = history.history['val_accuracy']\nloss1 = history.history['loss']\nval_loss1 = history.history['val_loss']\n\nepochs1 = range(len(acc1))\n\nplt.plot(epochs1, acc1, 'c-', label='Training accuracy')\nplt.plot(epochs1, val_acc1, 'y-', label='Validation accuracy')\nplt.title('Training and validation accuracy')\nplt.legend()\n\nplt.figure()\n\nplt.plot(epochs1, loss1, 'c-', label='Training Loss')\nplt.plot(epochs1, val_loss1, '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":"val2=max(acc1)\nprint(val2)","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}