{"cells":[{"metadata":{},"cell_type":"markdown","source":"<h1> Cassava Leaf Disease Classification </h1>\n<h2>Identify the type of disease present on a Cassava Leaf image </h2>\n<img src  = \"https://cookingwithoutborders.files.wordpress.com/2011/12/cassava-leaves.jpg\"> <br>\n\n<i> Cassava is a root vegetable. It is the underground part of the cassava shrub, which has the Latin name Manihot esculenta. Like potatoes and yams, it is a tuber crop. Cassava roots have a similar shape to sweet potatoes.\n\nPeople can also eat the leaves of the cassava plant. Humans living along the banks of the Amazon River in South America grew and consumed cassava hundreds of years before Christopher Columbus first voyaged there.\n\nToday, more than 80 countries throughout the tropics grow cassava, and it is a primary component of the diet of more than 800 million people around the world. It is popular because it is a hardy crop that is resistant to drought and does not require much fertilizer, although it is vulnerable to bacterial and viral diseases. </i>\n\n<h3> Usage </h3>\n<i>Cassava is a rich, affordable source of carbohydrates. It can provide more calories per acre of the crop than other cereals, which makes it a very useful crop in the developing world.\n\nPeople prepare and eat cassava in various ways in different parts of the world, with baking and boiling being the most common methods. In some places, people ferment cassava before using it.\n\nIt is essential to peel cassava and never eat it raw. It contains dangerous levels of cyanide unless a person cooks it thoroughly before eating it.</i>\n\nDishes that people can make using cassava include:\n\n* bread, which can contain cassava flour only, or both cassava and wheat flour\n* French fries\n* mashed cassava\n* cassava chips\n* cassava bread soaked in coconut milk\n* cassava cake\n* cassava in coconut sauce\n* yuca con mojo, a Cuban dish that combines cassava with a sauce comprising citrus juices, garlic, onion, cilantro, cumin, and oregano\n\nIn addition to eating cassava, people also use it for:\n\n* making tapioca, which is a common dessert food\n* making starch and flour products, which people can use to make gluten-free bread\n* feeding animals\n* making medications, fabrics, paper, and building materials, such as plywood.\nScientists may eventually be able to replace high-fructose corn syrup with cassava starch. Researchers are also hoping that cassava could be a source of the alcohol that manufacturers use to make polystyrene, PVC, and other industrial products. <br>\n---> [Ref here](https://www.medicalnewstoday.com/articles/323756)"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport seaborn as sns\nimport os\nimport json\nimport cv2\nimport itertools\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\nfrom tqdm import tqdm\nfrom PIL import Image","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import keras\n\nimport tensorflow as tf\nfrom tensorflow.python.keras import backend as K\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix,classification_report\n\n\nfrom keras.models import Sequential, Model,load_model\nfrom keras.preprocessing.image import ImageDataGenerator,load_img, img_to_array\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D, MaxPooling2D, Dense, Dropout, Input, Flatten,BatchNormalization,Activation\nfrom keras.layers import GlobalMaxPooling2D\nfrom keras.models import Model\nfrom keras.optimizers import Adam, SGD, RMSprop\nfrom keras.callbacks import ModelCheckpoint, Callback, EarlyStopping,ReduceLROnPlateau\nfrom keras.utils import to_categorical\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom keras.utils.vis_utils import plot_model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Defining data path\nIMAGE_PATH = \"../input/cassava-leaf-disease-classification/\"\nWORK_DIR = './'\n\ntrain_df = pd.read_csv('../input/cassava-leaf-disease-classification/train.csv')\nsubmission_csv = pd.read_csv(os.path.join(IMAGE_PATH, \"sample_submission.csv\"))\n\n\n#Training data\nprint('Training data shape: ', train_df.shape)\ntrain_df.head(5)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with open(os.path.join('../input/cassava-leaf-disease-classification', \"label_num_to_disease_map.json\")) as file:\n    map_classes = json.loads(file.read())\n    \nprint(json.dumps(map_classes))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['Classes'] = train_df['label'].astype(str).map(map_classes)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Total number of images in the dataset(train+test)\nprint(\"Total images in Train set: \",train_df['image_id'].count())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Null values and Data types\nprint('Train Set')\nprint(train_df.info())\nprint('-------------')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(17, 5))\nsns.countplot(\"Classes\", data=train_df);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"images = train_df['image_id'].values\n\n# Extract 9 random images from it\nrandom_images = [np.random.choice(images) for i in range(9)]\n\n# Location of the image dir\nimg_dir = IMAGE_PATH+'/train_images'\n\nprint('Display Random Images')\n\n# Adjust the size of your images\nplt.figure(figsize=(10,8))\n\n# Iterate and plot random images\nfor i in range(9):\n    plt.subplot(3, 3, i + 1)\n    img = plt.imread(os.path.join(img_dir, random_images[i]))\n    plt.imshow(img, cmap='gray')\n    plt.axis('off')\n    \n# Adjust subplot parameters to give specified padding\nplt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"CBB = train_df[train_df['Classes']=='Cassava Bacterial Blight (CBB)']\nhealthy = train_df[train_df['Classes']=='Healthy']\nCBSD = train_df[train_df['Classes']=='Cassava Brown Streak Disease (CBSD)']\nCMD = train_df[train_df['Classes']=='Cassava Mosaic Disease (CMD)']\nCGM = train_df[train_df['Classes']=='Cassava Green Mottle (CGM)']\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"images = CBB['image_id'].values\n\n# Extract 9 random images from it\nrandom_images = [np.random.choice(images) for i in range(9)]\n\n# Location of the image dir\nimg_dir = IMAGE_PATH+'/train_images'\n\nprint('Display CBB Images')\n\n# Adjust the size of your images\nplt.figure(figsize=(10,8))\n\n# Iterate and plot random images\nfor i in range(9):\n    plt.subplot(3, 3, i + 1)\n    img = plt.imread(os.path.join(img_dir, random_images[i]))\n    plt.imshow(img, cmap='gray')\n    plt.axis('off')\n    \n# Adjust subplot parameters to give specified padding\nplt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"images = healthy['image_id'].values\n\n# Extract 9 random images from it\nrandom_images = [np.random.choice(images) for i in range(9)]\n\n# Location of the image dir\nimg_dir = IMAGE_PATH+'/train_images'\n\nprint('Display Healthy Images')\n\n# Adjust the size of your images\nplt.figure(figsize=(10,8))\n\n# Iterate and plot random images\nfor i in range(9):\n    plt.subplot(3, 3, i + 1)\n    img = plt.imread(os.path.join(img_dir, random_images[i]))\n    plt.imshow(img, cmap='gray')\n    plt.axis('off')\n    \n# Adjust subplot parameters to give specified padding\nplt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"images = CBSD['image_id'].values\n\n# Extract 9 random images from it\nrandom_images = [np.random.choice(images) for i in range(9)]\n\n# Location of the image dir\nimg_dir = IMAGE_PATH+'/train_images'\n\nprint('Display CBSD Images')\n\n# Adjust the size of your images\nplt.figure(figsize=(10,8))\n\n# Iterate and plot random images\nfor i in range(9):\n    plt.subplot(3, 3, i + 1)\n    img = plt.imread(os.path.join(img_dir, random_images[i]))\n    plt.imshow(img, cmap='gray')\n    plt.axis('off')\n    \n# Adjust subplot parameters to give specified padding\nplt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"images = CMD['image_id'].values\n\n# Extract 9 random images from it\nrandom_images = [np.random.choice(images) for i in range(9)]\n\n# Location of the image dir\nimg_dir = IMAGE_PATH+'/train_images'\n\nprint('Display CMD Images')\n\n# Adjust the size of your images\nplt.figure(figsize=(10,8))\n\n# Iterate and plot random images\nfor i in range(9):\n    plt.subplot(3, 3, i + 1)\n    img = plt.imread(os.path.join(img_dir, random_images[i]))\n    plt.imshow(img, cmap='gray')\n    plt.axis('off')\n    \n# Adjust subplot parameters to give specified padding\nplt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"images = CGM['image_id'].values\n\n# Extract 9 random images from it\nrandom_images = [np.random.choice(images) for i in range(9)]\n\n# Location of the image dir\nimg_dir = IMAGE_PATH+'/train_images'\n\nprint('Display CGM Images')\n\n# Adjust the size of your images\nplt.figure(figsize=(10,8))\n\n# Iterate and plot random images\nfor i in range(9):\n    plt.subplot(3, 3, i + 1)\n    img = plt.imread(os.path.join(img_dir, random_images[i]))\n    plt.imshow(img, cmap='gray')\n    plt.axis('off')\n    \n# Adjust subplot parameters to give specified padding\nplt.tight_layout()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f = plt.figure(figsize=(16,8))\nf.add_subplot(1,2, 1)\n\nsample_img = train_df['image_id'][0]\nraw_image = plt.imread(os.path.join(img_dir, sample_img))\nplt.imshow(raw_image, cmap='gray')\nplt.colorbar()\nplt.title('Image')\nprint(f\"Image dimensions:  {raw_image.shape[0],raw_image.shape[1]}\")\nprint(f\"Maximum pixel value : {raw_image.max():.1f} ; Minimum pixel value:{raw_image.min():.1f}\")\nprint(f\"Mean value of the pixels : {raw_image.mean():.1f} ; Standard deviation : {raw_image.std():.1f}\")\n\nf.add_subplot(1,2, 2)\n\n#_ = plt.hist(raw_image.ravel(),bins = 256, color = 'orange',)\n_ = plt.hist(raw_image[:, :, 0].ravel(), bins = 256, color = 'red', alpha = 0.5)\n_ = plt.hist(raw_image[:, :, 1].ravel(), bins = 256, color = 'Green', alpha = 0.5)\n_ = plt.hist(raw_image[:, :, 2].ravel(), bins = 256, color = 'Blue', alpha = 0.5)\n_ = plt.xlabel('Intensity Value')\n_ = plt.ylabel('Count')\n_ = plt.legend(['Red_Channel', 'Green_Channel', 'Blue_Channel'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"f = plt.figure(figsize=(16,8))\nf.add_subplot(1,2, 1)\n\nsample_img = train_df['image_id'][1]\nraw_image = plt.imread(os.path.join(img_dir, sample_img))\nplt.imshow(raw_image, cmap='gray')\nplt.colorbar()\nplt.title('Image')\nprint(f\"Image dimensions:  {raw_image.shape[0],raw_image.shape[1]}\")\nprint(f\"Maximum pixel value : {raw_image.max():.1f} ; Minimum pixel value:{raw_image.min():.1f}\")\nprint(f\"Mean value of the pixels : {raw_image.mean():.1f} ; Standard deviation : {raw_image.std():.1f}\")\n\nf.add_subplot(1,2, 2)\n\n#_ = plt.hist(raw_image.ravel(),bins = 256, color = 'orange',)\n_ = plt.hist(raw_image[:, :, 0].ravel(), bins = 256, color = 'red', alpha = 0.5)\n_ = plt.hist(raw_image[:, :, 1].ravel(), bins = 256, color = 'Green', alpha = 0.5)\n_ = plt.hist(raw_image[:, :, 2].ravel(), bins = 256, color = 'Blue', alpha = 0.5)\n_ = plt.xlabel('Intensity Value')\n_ = plt.ylabel('Count')\n_ = plt.legend(['Red_Channel', 'Green_Channel', 'Blue_Channel'])\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 320\nlabels=[]\ndata=[]\nfor i in range(train_df.shape[0]):\n    data.append(img_dir +'/'+ train_df['image_id'].iloc[i])\n    labels.append(train_df['label'].iloc[i])\ndf=pd.DataFrame(data)\ndf.columns=['images']\ndf['target']=labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(df['images'],df['target'], test_size=0.2, random_state=1234)\n\ntrain=pd.DataFrame(X_train)\ntrain.columns=['images']\ntrain['target']=y_train\ntrain['target'] = train['target'].astype('string')\n\n\nvalidation=pd.DataFrame(X_val)\nvalidation.columns=['images']\nvalidation['target']=y_val\nvalidation['target'] = validation['target'].astype('string')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_datagen = ImageDataGenerator(rotation_range=360,\n                                width_shift_range=0.1,\n                                height_shift_range=0.1,\n                                brightness_range=[0.2,1.5],\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)\ntest_datagen = ImageDataGenerator(rescale=1./255,validation_split = 0.2)\ntrain_generator = train_datagen.flow_from_dataframe(train,x_col = 'images',y_col = 'target',target_size=(IMG_SIZE, IMG_SIZE),batch_size=32,class_mode='categorical')\nvalidation_generator = test_datagen.flow_from_dataframe(validation,x_col = 'images',y_col = 'target',target_size=(IMG_SIZE, IMG_SIZE),batch_size=32,class_mode='categorical')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Initialising the CNN\nmodel = tf.keras.models.Sequential()\n\n# Step 1 - Convolution\nmodel.add(tf.keras.layers.Conv2D(filters=32,padding=\"same\",kernel_size=3, activation='relu', input_shape=[IMG_SIZE, IMG_SIZE, 3]))\n\n# Step 2 - Pooling\nmodel.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2))\n\n# Adding a second convolutional layer\nmodel.add(tf.keras.layers.Conv2D(filters=64,padding='same',kernel_size=3, activation='relu'))\nmodel.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2))\n\n# Adding a third convolutional layer\nmodel.add(tf.keras.layers.Conv2D(filters=128,padding='same',kernel_size=3, activation='relu'))\nmodel.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2))\n\n\nmodel.add(tf.keras.layers.Conv2D(filters=256,padding='same',kernel_size=3, activation='relu'))\nmodel.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2))\n\n# Adding a five convolutional layer\nmodel.add(tf.keras.layers.Conv2D(filters=256,padding='same',kernel_size=3, activation='relu'))\nmodel.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2))\n\nmodel.add(tf.keras.layers.Conv2D(filters=256,padding='same',kernel_size=3, activation='relu'))\nmodel.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2))\n\n\n# Adding a six convolutional layer\n\n\nmodel.add(tf.keras.layers.Conv2D(filters=512,padding='same',kernel_size=3, activation='relu'))\nmodel.add(tf.keras.layers.MaxPool2D(pool_size=2, strides=2))\n\nmodel.add(tf.keras.layers.Dropout(0.5))\n\n\n\n# Step 3 - Flattening\nmodel.add(tf.keras.layers.Flatten())\n\n# Step 4 - Full Connection\nmodel.add(tf.keras.layers.Dense(units=512, activation='relu'))\n\nmodel.add(tf.keras.layers.Dropout(0.5))\n\nmodel.add(tf.keras.layers.Dense(units=1024, activation='relu'))\n\nmodel.add(tf.keras.layers.Dropout(0.5))\n\n\n# Step 5 - Output Layer\nmodel.add(tf.keras.layers.Dense(units=5, activation='softmax')) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()\nplot_model(model, to_file='model_plot.png', show_shapes=True, show_layer_names=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"opt = Adam(lr=0.001)\nmodel.compile(loss = 'categorical_crossentropy', metrics=['acc'],optimizer=opt)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"nb_epochs = 100\nbatch_size=32\nnb_train_steps = train.shape[0]//batch_size\nnb_val_steps=validation.shape[0]//batch_size\nprint(\"Number of training and validation steps: {} and {}\".format(nb_train_steps,nb_val_steps))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# Adapted  from - https://gist.github.com/swanandM/260f73ec7c89a2fb540e37169ba728bc\ndef plot_history(history):\n    loss_list = [s for s in history.history.keys() if 'loss' in s and 'val' not in s]\n    val_loss_list = [s for s in history.history.keys() if 'loss' in s and 'val' in s]\n    acc_list = [s for s in history.history.keys() if 'acc' in s and 'val' not in s]\n    val_acc_list = [s for s in history.history.keys() if 'acc' in s and 'val' in s]\n    \n    if len(loss_list) == 0:\n        print('Loss is missing in history')\n        return \n    \n    ## As loss always exists\n    epochs = range(1,len(history.history[loss_list[0]]) + 1)\n    \n    ## Loss\n    plt.figure(1)\n    for l in loss_list:\n        plt.plot(epochs, history.history[l], 'b', label='Training loss (' + str(str(format(history.history[l][-1],'.5f'))+')'))\n    for l in val_loss_list:\n        plt.plot(epochs, history.history[l], 'g', label='Validation loss (' + str(str(format(history.history[l][-1],'.5f'))+')'))\n    \n    plt.title('Loss')\n    plt.xlabel('Epochs')\n    plt.ylabel('Loss')\n    plt.legend()\n    \n    ## Accuracy\n    plt.figure(2)\n    for l in acc_list:\n        plt.plot(epochs, history.history[l], 'b', label='Training accuracy (' + str(format(history.history[l][-1],'.5f'))+')')\n    for l in val_acc_list:    \n        plt.plot(epochs, history.history[l], 'g', label='Validation accuracy (' + str(format(history.history[l][-1],'.5f'))+')')\n\n    plt.title('Accuracy')\n    plt.xlabel('Epochs')\n    plt.ylabel('Accuracy')\n    plt.legend()\n    plt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cb=[EarlyStopping(patience = 5,verbose = 1,restore_best_weights = True),ReduceLROnPlateau(patience = 2, verbose = 1),ModelCheckpoint(filepath = WORK_DIR,save_best_only=True)]\nhistory = model.fit_generator(\n    train_generator,\n    steps_per_epoch=nb_train_steps,\n    epochs=nb_epochs,\n    validation_data=validation_generator,\n    callbacks=cb,\n    validation_steps=nb_val_steps)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_history(history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"target=[]\nfor image_id in submission_csv.image_id:\n    img=cv2.imread(str(IMAGE_PATH + \"test_images/\" + str(image_id)))\n    img = cv2.resize(img, (320,320))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    img=np.reshape(img,(1,320,320,3))\n    target.append(np.argmax(model.predict(img)))\n\n\nsubmission_csv['label']=target","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_csv.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}