{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Casava Leaf Disease Classification with Pre-trained Model\nA pre-trained model has been previously trained on a dataset and contains the weights and biases that represent the features of whichever dataset it was trained on. Learned features are often transferable to different data. For example, a model trained on a large dataset of bird images will contain learned features like edges or horizontal lines that you would be transferable your dataset. "},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas  as pd\nimport numpy as np\nimport matplotlib.pyplot  as plt\nfrom sklearn.utils import shuffle\nimport cv2\n\nimport tensorflow as tf \nfrom tensorflow.keras import applications\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.layers import Dense, Dropout, BatchNormalization, GlobalAveragePooling2D","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Define Dataset path**"},{"metadata":{"trusted":true},"cell_type":"code","source":"data_path = \"../input/cassava-leaf-disease-classification/\"\ntrain_csv_data_path = data_path+\"train.csv\"\nlabel_json_data_path = data_path+\"label_num_to_disease_map.json\"\nimages_dir_data_path = data_path+\"train_images\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv = pd.read_csv(train_csv_data_path)\ntrain_csv['label'] = train_csv['label'].astype('string')\n\nlabel_class = pd.read_json(label_json_data_path, orient='index')\nlabel_class = label_class.values.flatten().tolist()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We have 5 labels in our dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Label names :\")\nfor i, label in enumerate(label_class):\n    print(f\" {i}. {label}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_csv.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data agumentation and pre-processing using Keras"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_gen = ImageDataGenerator(\n                                rotation_range=360,\n                                width_shift_range=0.1,\n                                height_shift_range=0.1,\n                                brightness_range=[0.1,0.9],\n                                shear_range=25,\n                                zoom_range=0.3,\n                                channel_shift_range=0.1,\n                                horizontal_flip=True,\n                                vertical_flip=True,\n                                rescale=1/255,\n                                validation_split=0.15\n                               )\n                                    \n    \nvalid_gen = ImageDataGenerator(rescale=1/255,\n                               validation_split = 0.15\n                              )\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 18\nIMG_SIZE = 224","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = train_gen.flow_from_dataframe(\n                            dataframe=train_csv,\n                            directory = images_dir_data_path,\n                            x_col = \"image_id\",\n                            y_col = \"label\",\n                            target_size = (IMG_SIZE, IMG_SIZE),\n                            class_mode = \"categorical\",\n                            batch_size = BATCH_SIZE,\n                            shuffle = True,\n                            subset = \"training\",\n\n)\n\nvalid_generator = valid_gen.flow_from_dataframe(\n                            dataframe=train_csv,\n                            directory = images_dir_data_path,\n                            x_col = \"image_id\",\n                            y_col = \"label\",\n                            target_size = (IMG_SIZE, IMG_SIZE),\n                            class_mode = \"categorical\",\n                            batch_size = BATCH_SIZE,\n                            shuffle = False,\n                            subset = \"validation\"\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch = next(train_generator)\nimages = batch[0]\nlabels = batch[1]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Plot Images"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(12,9))\nfor i, (img, label) in enumerate(zip(images, labels)):\n    plt.subplot(2,3, i%6 +1)\n    plt.axis('off')\n    plt.imshow(img)\n    plt.title(label_class[np.argmax(label)])\n    \n    if i==15:\n        break","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Building The Model"},{"metadata":{},"cell_type":"markdown","source":"# ResNet-152\nDeeper neural networks are more difficult to train. We present a residual learning framework to ease the training of networks that are substantially deeper than those used previously. We explicitly reformulate the layers as learning residual functions with reference to the layer inputs, instead of learning unreferenced functions. We provide comprehensive empirical evidence showing that these residual networks are easier to optimize, and can gain accuracy from considerably increased depth. On the ImageNet dataset we evaluate residual nets with a depth of up to 152 layers---8x deeper than VGG nets but still having lower complexity.\n\nAn ensemble of these residual nets achieves 3.57% error on the ImageNet test set. This result won the 1st place on the ILSVRC 2015 classification task. We also present analysis on CIFAR-10 with 100 and 1000 layers.\n\nThe depth of representations is of central importance for many visual recognition tasks. Solely due to our extremely deep representations, we obtain a 28% relative improvement on the COCO object detection dataset. Deep residual nets are foundations of our submissions to ILSVRC & COCO 2015 competitions, where we also won the 1st places on the tasks of ImageNet detection, ImageNet localization, COCO detection, and COCO segmentation.\n\n[Paper link](https://arxiv.org/abs/1512.03385)\n\n![](https://i.imgur.com/nyYh5xH.jpg)"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Loading the ResNet152 architecture with imagenet weights as base\n#base = tf.keras.applications.ResNet152(include_top=False, weights='imagenet',input_shape=[IMG_SIZE,IMG_SIZE,3])","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"#base.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# model = tf.keras.Sequential()\n# model.add(base)\n# model.add(BatchNormalization(axis=-1))\n# model.add(GlobalAveragePooling2D())\n# model.add(Dropout(0.5))\n# model.add(Dense(5, activation='softmax'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = tf.keras.models.load_model(\"../input/trained3/10feb.h5\") #../input/trained3/trained3.h5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(loss=tf.keras.losses.CategoricalCrossentropy(), optimizer=tf.keras.optimizers.Adamax(learning_rate=0.01), metrics=['acc'])","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":true,"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n#from tf.keras.callbacks import ModelCheckpoint,EarlyStopping,ReduceLROnPlateau\n\nmodel_save = tf.keras.callbacks.ModelCheckpoint(\"Model\", \n                             save_best_only = True, \n                             save_weights_only = True,\n                             monitor = 'val_loss', \n                             mode = 'min', verbose = 1)\nearly_stop = tf.keras.callbacks.EarlyStopping(monitor = 'acc', min_delta = 0.001, \n                           patience = 5, mode = 'min', verbose = 1,\n                           restore_best_weights = True)\nreduce_lr = tf.keras.callbacks.ReduceLROnPlateau(monitor = 'val_loss', factor = 0.3, \n                              patience = 2, min_delta = 0.001, \n                              mode = 'min', verbose = 1)\ncheckpoint = tf.keras.callbacks.ModelCheckpoint('model{epoch:08d}.h5', period=5)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training The Model"},{"metadata":{},"cell_type":"markdown","source":"Loading the saved model\n"},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"# history = model.fit(\n#       train_generator,\n#       steps_per_epoch=train_generator.samples // train_generator.batch_size,\n#       epochs=30,\n#       validation_data=valid_generator,\n#       validation_steps = valid_generator.samples // valid_generator.batch_size,\n#       batch_size=BATCH_SIZE,\n#       callbacks = [checkpoint]\n#       )\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# model.save('model.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Training and validation acc/loss"},{"metadata":{},"cell_type":"markdown","source":"Acc and val_acc are measured to evaluate your model fitting. When there is a significant difference between these two, your model is overfitting. The validation accuracy (val_acc) should be equal or slightly less than the training accuracy (acc) to be a better model. "},{"metadata":{"trusted":true},"cell_type":"code","source":"# import matplotlib.pyplot as plt\n\n# acc = history.history['acc']\n# val_acc = history.history['val_acc']\n\n\n# epochs = range(len(acc))\n\n# plt.plot(epochs, acc, 'bo', label='Training acc')\n# plt.plot(epochs, val_acc, 'bo', label='Validation acc')\n# plt.title('Training and validation accuracy')\n# plt.legend()\n\n# plt.figure()\n\n# plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# import matplotlib.pyplot as plt\n\n# loss = history.history['loss']\n# val_loss = history.history['val_loss']\n\n# epochs = range(len(acc))\n\n# plt.plot(epochs, loss, 'bo', label='Training loss')\n# plt.plot(epochs, val_loss, 'bo', label='Validation loss')\n# plt.title('Training and validation loss')\n# plt.legend()\n\n# plt.figure()\n\n# plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Evaluation Metrics\n"},{"metadata":{},"cell_type":"markdown","source":"### Confusion Matrix\nA confusion matrix is a table that is often used to describe the performance of a classification model (or \"classifier\") on a set of test data for which the true values are known. The confusion matrix itself is relatively simple to understand, but the related terminology can be confusing."},{"metadata":{},"cell_type":"markdown","source":"### Load Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"loaded_model = tf.keras.models.load_model(\"../input/trained3/10feb.h5\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Confusion Matrix"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import classification_report, confusion_matrix\n\n#num_of_test_samples = 3209\n#batch_size = 1\nY_pred = loaded_model.predict_generator(valid_generator, valid_generator.samples // valid_generator.batch_size + 5)\ny_pred = np.argmax(Y_pred, axis=1)\nprint('Confusion Matrix')\nprint(confusion_matrix(valid_generator.classes, y_pred))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Classification Report"},{"metadata":{"trusted":true},"cell_type":"code","source":"target_names = list(train_generator.class_indices.keys()) # Classes\nprint(classification_report(valid_generator.classes, y_pred, target_names=target_names))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import seaborn as sns\n\ncm = confusion_matrix(valid_generator.classes, y_pred)\nlabels = ['Cassava Bacterial Blight (CBB)', 'Cassava Brown Streak Disease (CBSD)', 'Cassava Green Mottle (CGM)', 'Cassava Mosaic Disease (CMD)','Healthy']\nplt.figure(figsize=(8,6))\nsns.heatmap(cm,xticklabels=labels, yticklabels=labels, annot=True, fmt='d', cmap=\"Blues\", vmin = 0.2);\nplt.title('Confusion Matrix')\nplt.ylabel('True Class')\nplt.xlabel('Predicted Class')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Area Under Curve (AUC)\nThe Area Under the Curve (AUC) is the measure of the ability of a classifier to distinguish between classes and is used as a summary of the ROC curve. The higher the AUC, the better the performance of the model at distinguishing between the positive and negative classes."},{"metadata":{"trusted":true},"cell_type":"code","source":"# from sklearn.preprocessing import LabelBinarizer\n# from sklearn.metrics import roc_curve\n# from sklearn.metrics import auc\n\n# from sklearn.metrics import roc_curve, auc, roc_auc_score\n# import matplotlib.pyplot as plt\n\n# # make a prediction\n# y_pred_keras = loaded_model.predict_generator(valid_generator, valid_generator.samples // valid_generator.batch_size+5) #(test_gen, steps=len(df_val), verbose=1)\n# fpr_keras, tpr_keras, thresholds_keras = roc_curve(valid_generator.classes, y_pred_keras)\n# auc_keras = auc(fpr_keras, tpr_keras)\n\n\n# plt.figure(1)\n# plt.plot([0, 1], [0, 1], 'k--')\n# plt.plot(fpr_keras, tpr_keras, label='area = {:.3f}'.format(auc_keras))\n# plt.xlabel('False positive rate')\n# plt.ylabel('True positive rate')\n# plt.title('ROC curve')\n# plt.legend(loc='best')\n# plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_img_path = data_path+\"test_images/2216849948.jpg\"\n\nimg = cv2.imread(test_img_path)\nresized_img = cv2.resize(img, (IMG_SIZE, IMG_SIZE)).reshape(-1, IMG_SIZE, IMG_SIZE, 3)/255\n\nplt.figure(figsize=(8,4))\nplt.title(\"TEST IMAGE\")\nplt.imshow(resized_img[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = []\nss = pd.read_csv(data_path+'sample_submission.csv')\n\nfor image in ss.image_id:\n    img = tf.keras.preprocessing.image.load_img(data_path+'test_images/' + image)\n    img = tf.keras.preprocessing.image.img_to_array(img)\n    img = tf.keras.preprocessing.image.smart_resize(img, (IMG_SIZE, IMG_SIZE))\n    img = tf.reshape(img, (-1, IMG_SIZE, IMG_SIZE, 3))\n    prediction = loaded_model.predict(img/255)\n    preds.append(np.argmax(prediction))\n\nmy_submission = pd.DataFrame({'image_id': ss.image_id, 'label': preds})\nmy_submission.to_csv('submission.csv', index=False) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Submission file ouput\nprint(\"Submission File: \\n---------------\\n\")\nprint(my_submission.head()) # Predicted Output","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Please see my another notebook [Cassava Leaf Deisease Classification](https://www.kaggle.com/mnavaidd/casava-leaf-disease-classification)"},{"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}