{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"collapsed":true,"_kg_hide-output":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import json, cv2\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport tensorflow as tf \nimport keras\nfrom tqdm.notebook import tqdm","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"base_path = \"../input/cassava-leaf-disease-classification/\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with open(base_path + \"label_num_to_disease_map.json\") as file:\n    map_classes = json.loads(file.read())\n    \nprint(json.dumps(map_classes, indent=4))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We can see there are 5 classes, where 0-3 indicates diseases and 4 indicates a healthy cassava plant"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Loading train.csv\ntr = pd.read_csv(base_path + 'train.csv')\n\n#Mapping label names to each label per image\ntr[\"label_name\"] = tr[\"label\"].astype(str).map(map_classes)\n\ntr.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Loadding the sample submission file\nss = pd.read_csv(base_path + 'sample_submission.csv')\nss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Get the number of train images\nlen(os.listdir(base_path + 'train_images/'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Checking the shape of images\nsize_dict = {}\nfor ind, i in tqdm(enumerate(os.listdir(base_path + 'train_images/'))):\n    size_dict[ind] = cv2.imread(base_path + 'train_images/' + i).shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#We can see all shapes are same viz. 600 x 800 x 3\ndf_size = pd.DataFrame(size_dict, index = ['Height', 'Width', 'Channels']).T\ndisplay(df_size.head())\ndisplay(df_size.tail())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.countplot(tr['label_name'])\nplt.title('# of each label in the dataset')\nplt.xticks(rotation= 60);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Plot random images and their labels\nrandom_index = np.random.randint(0, tr.shape[0]-1, 16)\n\nfig, axes = plt.subplots(4, 4, figsize = (15, 15))\naxes = axes.ravel()\n\nfor ind, i in enumerate(random_index):\n    img = cv2.imread(base_path + '/train_images/' + tr.iloc[i, [0]].values[0])\n    label = tr.iloc[i, [2]].values[0]\n    axes[ind].imshow(img)\n    axes[ind].set_title(label)\n    axes[ind].axis('off')\n    \nplt.subplots_adjust(hspace = 0.4);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Modelling"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Flatten, Dropout, Activation, BatchNormalization\nfrom tensorflow.keras.callbacks import ModelCheckpoint, ReduceLROnPlateau, EarlyStopping","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Trrain Validation Split\nX = tr['image_id']\nY = tr['label']\n\nX_train, X_val, y_train, y_val = train_test_split(X, Y, test_size = 0.3, stratify = Y)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Converting target to strings as it is classification problem\ny_train = y_train.astype(str)\ny_val = y_val.astype(str)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Since we used stratify argument, the distribution is maintained in train and test set\n\nplt.figure(figsize = (15, 6))\nplt.subplot(1, 2, 1)\nsns.countplot(y_train)\nplt.title('Train Disribution')\nplt.subplot(1, 2, 2)\nsns.countplot(y_val)\nplt.title('Test Disribution');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Combining IDV and DV to pass it to Image Generator\ntrain = pd.concat([X_train, y_train], axis=1)\nvalid = pd.concat([X_val, y_val], axis=1)\n\nprint('Train Shape: ', train.shape)\nprint('Val Shape: ', valid.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Creating Training Generator\nBATCH_SIZE  = 16\ntrain_generator = tf.keras.preprocessing.image.ImageDataGenerator(\n                        rescale=1./255\n                    ).flow_from_dataframe(train,\n                                     directory = os.path.join(base_path, \"train_images\"),\n                                     x_col = \"image_id\",\n                                     y_col = \"label\",\n                                     target_size = (300, 400),\n                                     batch_size = BATCH_SIZE,\n                                     class_mode = \"categorical\", \n                                     shuffle = False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Creating Validation Generator\nBATCH_SIZE  = 16\nvalid_generator = tf.keras.preprocessing.image.ImageDataGenerator(\n                        rescale=1./255\n                    ).flow_from_dataframe(valid,\n                                     directory = os.path.join(base_path, \"train_images\"),\n                                     x_col = \"image_id\",\n                                     y_col = \"label\",\n                                     target_size = (300, 400),\n                                     batch_size = BATCH_SIZE,\n                                     class_mode = \"categorical\",\n                                     shuffle = False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Loading model architecture for prediction. The training code is in another notebook. I have used the \n#upload notebook option to import the saved weights. Internet should be on, for downloading the weights.\n\nbase_model = tf.keras.applications.Xception(\n            include_top=False,\n            input_tensor=None,\n            input_shape=(300, 400, 3),\n            pooling=None,\n            weights = 'imagenet',\n            classifier_activation=\"softmax\",\n        )\n\nclasses_to_predict = sorted(tr.label.unique())\nfor layer in base_model.layers:\n    layer.trainable = False\n    \nmodel = Sequential()\nmodel.add(base_model)\n    \nmodel.add(GlobalAveragePooling2D())\nmodel.add(Dense(256))\nmodel.add(BatchNormalization())\nmodel.add(Activation('relu'))\nmodel.add(Dropout(0.4))\n\nmodel.add(Dense(len(classes_to_predict), activation=\"softmax\"))\n    \nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights(\"../input/cassava-leaf-disease-transfer-learning/xception_best_model.h5\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Model Performance"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.metrics import confusion_matrix, accuracy_score, recall_score, precision_score","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_predictions = model.predict_generator(train_generator, verbose=1)\nval_prediction = model.predict_generator(valid_generator, verbose = 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_preds = np.argmax(train_predictions, axis=1)\nval_preds = np.argmax(val_prediction, axis=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Train Accuracy Score:', accuracy_score(y_train.astype(int), train_preds))\nprint('Train Recall Score:', recall_score(y_train.astype(int), train_preds, average = 'weighted'))\nprint('Train Precision Score:', precision_score(y_train.astype(int), train_preds, average = 'weighted'))\nprint('Train Confusion Matrix: \\n', \n        confusion_matrix(y_train.astype(int), train_preds))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print('Validation Accuracy Score:', accuracy_score(y_val.astype(int), val_preds))\nprint('Validation Recall Score:', recall_score(y_val.astype(int), val_preds, average = 'weighted'))\nprint('Validation Precision Score:', precision_score(y_val.astype(int), val_preds, average = 'weighted'))\nprint('Validation Confusion Matrix: \\n', \n        confusion_matrix(y_val.astype(int), val_preds))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Prediction for test set\ntest_folder = '../input/cassava-leaf-disease-classification/test_images/'\nss[\"image_id\"] =  os.listdir(test_folder)\nss[\"label\"] = 0\n\ntest_datagen = tf.keras.preprocessing.image.ImageDataGenerator(\n    rescale=1. / 255\n)\n\ntest_generator = test_datagen.flow_from_dataframe(\n    dataframe = ss,\n    x_col='image_id',\n    y_col='label',\n    directory= test_folder,\n    target_size=target_size,\n    batch_size=1,\n    class_mode=None)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Saving as csv file\npredictions = model.predict_generator(test_generator, verbose=0)\nss[\"label\"] = predictions.argmax(axis=1)\nss.to_csv(\"submission.csv\", index=False)","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}