{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Import Libraries"},{"metadata":{"trusted":true},"cell_type":"code","source":"%matplotlib inline\n%config InlineBackend.figure_format = 'retina'\nimport os\nimport glob\nimport json\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport cv2\nimport seaborn as sns\nfrom sklearn.metrics import confusion_matrix, classification_report\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D,GlobalAveragePooling2D, Flatten, Dense, Dropout, BatchNormalization\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping\nfrom tensorflow.keras.optimizers import Adam\n\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport logging\nlogger = tf.get_logger()\nlogger.setLevel(logging.ERROR)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(tf.__version__)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_files(base_dir, target_dir):\n    count = 0\n    path = get_path(base_dir, target_dir)\n    for dirname, _, filenames in os.walk(path):\n        for filename in filenames:\n            count+=len(glob.glob(os.path.join(dirname, filename)))\n        return path, count\n    \ndef get_path(base_dir, target_dir):\n    path = os.path.join(base_dir,target_dir)\n    return path","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Directory Setup"},{"metadata":{"scrolled":true,"trusted":true},"cell_type":"code","source":"base_dir = '/kaggle/input/cassava-leaf-disease-classification'\ntrain_dir = 'train_images'\nlabels_file = 'train.csv'\ntest_dir = 'test_images'\njson_file = 'label_num_to_disease_map.json'\n\ntrain_path, train_count = get_files(base_dir,train_dir)\ntest_path, test_count = get_files(base_dir,test_dir)\n\nwith open(get_path(base_dir,json_file)) as f:\n    class_names = json.load(f)\n    class_dict = pd.Series(class_names.values()).to_dict()\n    f.close()\n\ndata = pd.read_csv(get_path(base_dir, labels_file))\ndata['class_name'] = data.label.map(class_dict)\n\nprint(\"No of Train Images: {}\".format(train_count))\nprint(\"No of Test Images: {}\".format(test_count))\nprint(\"No of Classes: {}\".format(len(class_dict)))\nprint(\"Classes:\")\nfor v in class_dict.values():\n    print(\" \\u2022 {}\".format(v))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data['class_name'].value_counts().plot(kind='bar')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for dirname, _, filenames in os.walk(train_path):\n    for filename in filenames:\n        image = cv2.imread(os.path.join(train_path, filename))\n        image_size = image.shape\n        break\n\nimage_size","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Visualization"},{"metadata":{"trusted":true},"cell_type":"code","source":"def visualize_img(images):\n    fig = plt.figure(figsize=(20, 15))\n    for i,a in enumerate(images):\n        fig.add_subplot(4, 4, i+1, xticks=[], yticks=[])\n        path = get_path(train_path, a)\n        img = cv2.imread(path)\n        plt.imshow(img)\n        plt.title(data[data.image_id == a].class_name.values[0])\n    \nfig = plt.figure(figsize=(15, 15))\np=0\nfor i in range(5):\n    images = data[data.label == i].image_id\n    images = np.random.choice(images , 4)\n    visualize_img(images)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plotImages(images_arr):\n    fig, axes = plt.subplots(1, 5, figsize=(20,20))\n    axes = axes.flatten()\n    for img, ax in zip(images_arr, axes):\n        ax.imshow(img)\n    plt.tight_layout()\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Example of Image Augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 64\nIMG_SHAPE  = 224\n\ntrain_image_gen = ImageDataGenerator(rescale=1./255,\n                                     width_shift_range=0.1,\n                                     height_shift_range=0.1,\n                                     brightness_range=[0.2,1.0],\n                                     zoom_range=0.2,\n                                     horizontal_flip=True,\n                                     vertical_flip=True,\n                                     fill_mode='nearest')\n\ntrain_gen = train_image_gen.flow_from_dataframe(data,\n                                          directory=train_path,\n                                          x_col='image_id',\n                                          y_col='class_name',\n                                          class_mode='categorical',\n                                          batch_size=BATCH_SIZE,\n                                          shuffle=True,\n                                          target_size=(IMG_SHAPE,IMG_SHAPE))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"augmented_images = [train_gen[0][0][1] for i in range(5)]\nplotImages(augmented_images)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data Preprocessing"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import LabelBinarizer\n\ntrain, val = train_test_split(data, test_size = 0.25, random_state=42)\n\nlb = LabelBinarizer()\nlb.fit(data.label)\n\ntrain_lb = lb.transform(train.label)\nval_lb = lb.transform(val.label)\n\ntrain = train.reset_index().drop(labels='index', axis=1)\ny_train = pd.DataFrame(train_lb).add_prefix('label_')\n\nval = val.reset_index().drop(labels='index', axis=1)\ny_val = pd.DataFrame(val_lb).add_prefix('label_')\n\ntrain = pd.concat([train, y_train], axis=1)\nval = pd.concat([val, y_val], axis=1)\n\nprint(\"Training set has {} samples\".format(train.shape[0]))\nprint(\"Validation set has {} samples\".format(val.shape[0]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Helper Functions"},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 32\nIMG_SHAPE  = 224\nEPOCHS = 30\n\ndef gen():\n    train_image_gen = ImageDataGenerator(rescale=1./255,\n                                         width_shift_range=0.1,\n                                         height_shift_range=0.1,\n                                         brightness_range=[0.2,1.0],\n                                         zoom_range=0.2,\n                                         horizontal_flip=True,\n                                         vertical_flip=True,\n                                         fill_mode='nearest')\n\n    train_gen = train_image_gen.flow_from_dataframe(train,\n                                              directory=train_path,\n                                              x_col='image_id',\n                                              y_col=[f'label_{x}' for x in np.arange(5)],\n                                              class_mode='raw',\n                                              batch_size=BATCH_SIZE,\n                                              shuffle=True,\n                                              target_size=(IMG_SHAPE,IMG_SHAPE))\n\n\n    val_image_gen = ImageDataGenerator(rescale=1./255)\n\n    val_gen = val_image_gen.flow_from_dataframe(val,\n                                              directory=train_path,\n                                              x_col='image_id',\n                                              y_col= [f'label_{x}' for x in np.arange(5)],\n                                              class_mode='raw',\n                                              batch_size=BATCH_SIZE,\n                                              target_size=(IMG_SHAPE,IMG_SHAPE))\n    return train_gen, val_gen\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot(history):\n\n    training_accuracy = history.history['accuracy']\n    validation_accuracy = history.history['val_accuracy']\n\n    training_loss = history.history['loss']\n    validation_loss = history.history['val_loss']\n\n    epochs_range=range(len(training_accuracy))\n\n    plt.figure(figsize=(8, 8))\n    plt.subplot(1, 2, 1)\n    plt.plot(epochs_range, training_accuracy, label='Training Accuracy')\n    plt.plot(epochs_range, validation_accuracy, label='Validation Accuracy')\n    plt.legend(loc='lower right')\n    plt.title('Training and Validation Accuracy')\n\n    plt.subplot(1, 2, 2)\n    plt.plot(epochs_range, training_loss, label='Training Loss')\n    plt.plot(epochs_range, validation_loss, label='Validation Loss')\n    plt.legend(loc='upper right')\n    plt.title('Training and Validation Loss')\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image\ndef predict(image_path, model):\n    im = Image.open(image_path)\n    test_image = np.asarray(im)\n    processed_test_image = process_image(test_image)\n    processed_test_image = np.expand_dims(processed_test_image, axis = 0)\n    \n    ps = model.predict(processed_test_image)\n    return ps\n    \ndef process_image(image):\n    image = tf.cast(image , tf.float32)\n    image = tf.image.resize(image , (224 , 224))\n    image = image/255\n    image = image.numpy()\n    return image\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.utils import class_weight\n\nclass_weights = class_weight.compute_class_weight('balanced', np.unique(train['label']), train.label)\nclass_weights = dict(enumerate(class_weights))\nclass_weights","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Modeling"},{"metadata":{},"cell_type":"markdown","source":"1. **VGG-16 Model** "},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.applications import VGG16\nfrom tensorflow.keras.applications.vgg16 import preprocess_input as vgg16_preprocess\ntf.keras.backend.clear_session()\n\nbase = VGG16(weights = 'imagenet' , include_top=False, input_shape=(IMG_SHAPE, IMG_SHAPE, 3))   \n\nvgg16_model = Sequential()\nvgg16_model.add(base)\nvgg16_model.add(GlobalAveragePooling2D())\nvgg16_model.add(Dropout(0.5))\nvgg16_model.add(BatchNormalization())\nvgg16_model.add(Dense(128, activation='relu'))\nvgg16_model.add(Dropout(0.5))\nvgg16_model.add(Dense(5, activation='softmax'))\n\nvgg16_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.utils.vis_utils import plot_model\nplot_model(vgg16_model, to_file='vgg16_model.png', show_shapes=True, show_layer_names=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_gen, val_gen = gen()\n\noptm = Adam(lr=0.0001)\nvgg16_model.compile(loss='categorical_crossentropy', optimizer=optm, \n                  metrics=['accuracy'])\n\nEarlyStopping = EarlyStopping(monitor='val_loss',\n                              min_delta=.0001,\n                              patience=5,\n                              verbose=1,\n                              mode='auto',\n                              baseline=None,\n                              restore_best_weights=True)\n\nmodel_save = ModelCheckpoint('./vgg16.h5',\n                             save_best_only = True, \n                             save_weights_only = False,\n                             monitor = 'val_loss', \n                             mode = 'min', verbose = 1)\n\n\nvgg_history = vgg16_model.fit_generator(train_gen,\n                                    steps_per_epoch = train_gen.samples // BATCH_SIZE,\n                                    epochs = 30,\n                                    validation_data = val_gen,\n                                    validation_steps = val_gen.samples // BATCH_SIZE,\n                                    callbacks=[EarlyStopping, model_save])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot(vgg_history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images = os.listdir(test_path)    \nfor image in test_images:\n    vgg16_pred = predict(os.path.join(test_path, image) , vgg16_model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"vgg16_pred","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.argmax(vgg16_pred)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"vgg16_preds = vgg16_model.predict(val_gen)\nvgg16_preds = np.argmax(vgg16_preds, axis=-1)\norg_label = val['label'].astype('int')\n\nmatrix=confusion_matrix(org_label, vgg16_preds)\nsns.heatmap(matrix,square=True, annot=True, fmt='d', cbar=False,\n            xticklabels=['0', '1', '2', '3', '4'],\n            yticklabels=['0', '1', '2', '3', '4'])\nplt.xlabel('Predicted label')\nplt.ylabel('True label');\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"2. MobileNetV2"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.applications.mobilenet_v2 import MobileNetV2\n\nbase = MobileNetV2(weights = 'imagenet', include_top = False, input_shape = (224, 224, 3))\ntf.keras.backend.clear_session()\n\nfor layers in base.layers:   \n    layers.trainable = True\n    \nfor layer in base.layers[:100]:\n    layer.trainable =  False\n\nmobilenet_model = Sequential()\nmobilenet_model.add(base)\nmobilenet_model.add(GlobalAveragePooling2D())\nmobilenet_model.add(BatchNormalization())\nmobilenet_model.add(Dense(256, activation='relu'))\nmobilenet_model.add(Dropout(0.5))\nmobilenet_model.add(BatchNormalization())\nmobilenet_model.add(Dense(128, activation='relu'))\nmobilenet_model.add(Dropout(0.5))\nmobilenet_model.add(Dense(5, activation='softmax'))\n\nmobilenet_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.utils.vis_utils import plot_model\nplot_model(mobilenet_model, to_file='mobilenetV2.png', show_shapes=True, show_layer_names=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_gen, val_gen = gen()\n\noptm = Adam(lr=0.0001)\nmobilenet_model.compile(loss='categorical_crossentropy', optimizer=optm, \n                  metrics=['accuracy'])\n\nEarlyStopping = EarlyStopping(monitor='val_loss',\n                              min_delta=.0001,\n                              patience=3,\n                              verbose=1,\n                              mode='auto',\n                              baseline=None,\n                              restore_best_weights=True)\n\nmodel_save = ModelCheckpoint('./mobilenetV2.h5',\n                             save_best_only = True,\n                             save_weights_only = False,\n                             monitor = 'val_loss', \n                             mode = 'min', verbose = 1)\n\n\nmob_history = mobilenet_model.fit(train_gen,\n                              steps_per_epoch = train_gen.samples // BATCH_SIZE,\n                              epochs = EPOCHS,\n                              validation_data = val_gen,\n                              validation_steps = val_gen.samples // BATCH_SIZE,\n                              callbacks=[EarlyStopping, model_save])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot(mob_history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(mob_history.history['val_accuracy'][-4])\nprint(mob_history.history['val_loss'][-4])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images = os.listdir(test_path)    \nfor image in test_images:\n    mobilenet_pred = predict(os.path.join(test_path, image) , mobilenet_model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mobilenet_pred","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.argmax(mobilenet_pred)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"mob_preds = mobilenet_model.predict(val_gen)\nmob_preds = np.argmax(mob_preds, axis=-1)\norg_label = val['label'].astype('int')\n\nmatrix=confusion_matrix(org_label, mob_preds)\nsns.heatmap(matrix,square=True, annot=True, fmt='d', cbar=False,\n            xticklabels=['0', '1', '2', '3', '4'],\n            yticklabels=['0', '1', '2', '3', '4'])\nplt.xlabel('Predicted label')\nplt.ylabel('True label');","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"3. DenseNet169"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.applications.densenet import DenseNet169\nfrom tensorflow.keras.applications.densenet import preprocess_input as densenet_preprocess\nbase = DenseNet169(weights = 'imagenet', include_top = False, input_shape = (224, 224, 3))\ntf.keras.backend.clear_session()\n\nfor layer in base.layers:   \n    layer.trainable = False\n\ndensenet_model = Sequential()\ndensenet_model.add(base)\ndensenet_model.add(GlobalAveragePooling2D())\ndensenet_model.add(BatchNormalization())\ndensenet_model.add(Dense(256, activation='relu'))\ndensenet_model.add(Dropout(0.5))\ndensenet_model.add(BatchNormalization())\ndensenet_model.add(Dense(128, activation='relu'))\ndensenet_model.add(Dropout(0.5))\ndensenet_model.add(Dense(5, activation='softmax'))\n\ndensenet_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.utils.vis_utils import plot_model\nplot_model(densenet_model, to_file='densenet169.png', show_shapes=True, show_layer_names=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_gen, val_gen = gen()\n\noptm = Adam(lr=0.0001)\ndensenet_model.compile(loss='categorical_crossentropy', optimizer=optm, \n                  metrics=['accuracy'])\n\nEarlyStopping = EarlyStopping(monitor='val_loss',\n                              min_delta=.0001,\n                              patience=5,\n                              verbose=1,\n                              mode='auto',\n                              baseline=None,\n                              restore_best_weights=True)\n\nmodel_save = ModelCheckpoint('./densenet.h5',\n                             save_best_only = True,\n                             save_weights_only = False,\n                             monitor = 'val_loss', \n                             mode = 'min', verbose = 1)\n\n\ndense_history = densenet_model.fit_generator(train_gen,\n                              steps_per_epoch = train_gen.samples // BATCH_SIZE,\n                              epochs = EPOCHS,\n                              validation_data = val_gen,\n                              validation_steps = val_gen.samples // BATCH_SIZE,\n                              callbacks=[EarlyStopping, model_save])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot(dense_history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(dense_history.history['val_accuracy'][-5])\nprint(dense_history.history['val_loss'][-5])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images = os.listdir(test_path)    \nfor image in test_images:\n    densenet_pred = predict(os.path.join(test_path, image) , densenet_model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"densenet_pred","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"np.argmax(densenet_pred)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dense_preds = densenet_model.predict(val_gen)\ndense_preds = np.argmax(dense_preds, axis=-1)\norg_label = val['label'].astype('int')\n\nmatrix=confusion_matrix(org_label, dense_preds)\nsns.heatmap(matrix,square=True, annot=True, fmt='d', cbar=False,\n            xticklabels=['0', '1', '2', '3', '4'],\n            yticklabels=['0', '1', '2', '3', '4'])\nplt.xlabel('Predicted label')\nplt.ylabel('True label');","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Ensemble"},{"metadata":{"trusted":true},"cell_type":"code","source":"mobilenet_model = tf.keras.models.load_model(\"../input/cassava-models/mobilenetV2.h5\")\nvgg_model = tf.keras.models.load_model(\"../input/cassava-models/vgg16.h5\")\ndensenet_model = tf.keras.models.load_model(\"../input/cassava-models/densenet.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model1_list=[]\nmodel2_list=[]\nmodel3_list = []\npredicted_label_list = []\nactual_labels=[]\n\nval_images = val.image_id\nfor i in val_images:\n    actual_labels.append(int(val[val.image_id == i].label))   \nactual_labels = pd.Series(actual_labels)\n\nfor image in val_images:\n    model1_list.append(predict(os.path.join(train_path, image), densenet_model))\n    model2_list.append(predict(os.path.join(train_path, image), mobilenet_model))\n    model3_list.append(predict(os.path.join(train_path, image), vgg_model))\n\nfor dense, mob, vgg in zip(model1_list, model2_list, model3_list):\n    predicted_label_list.append(np.argmax(dense/np.linalg.norm(dense) + mob/np.linalg.norm(mob) + vgg/np.linalg.norm(vgg)))\n    \nprint(classification_report(actual_labels, predicted_label_list))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"matrix=confusion_matrix(actual_labels, predicted_label_list)\nsns.heatmap(matrix,square=True, annot=True, fmt='d', cbar=False,\n            xticklabels=['0', '1', '2', '3', '4'],\n            yticklabels=['0', '1', '2', '3', '4'])\nplt.xlabel('Predicted label')\nplt.ylabel('True label')","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}