{"cells":[{"metadata":{},"cell_type":"markdown","source":"# STARTER\n\nHello, this is my first competition notebook. \n\nPlease feel free for giving the suggestions. I hope this notebook helps you. \n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nfrom tensorflow.keras import models, layers\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\nfrom tensorflow.keras.applications import ResNet50, DenseNet121, EfficientNetB0\nfrom keras.optimizers import Adam\nimport os, cv2, json\nfrom plotly.subplots import make_subplots\nimport plotly.graph_objs as go\nimport keras\n# ignoring warnings\nimport warnings\nwarnings.simplefilter(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# For easy acces to files\nWORK_DIR = \"../input/cassava-leaf-disease-classification/\"\nos.listdir(WORK_DIR)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with open('../input/cassava-leaf-disease-classification/label_num_to_disease_map.json', 'r') as file:\n    labels = json.load(file)\n    \nlabels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data = pd.read_csv(WORK_DIR + \"train.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data.isnull().values.any()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data.dtypes","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We need to convert the \"int\" datatype in \"str\" because flow_from_dataframe only takes \"lst/str\" as input\ndata.label = data.label.astype(\"str\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data.label.value_counts()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"1. ### **We have 21397 images for training and don't have an equal number of photos for each class.** \n\n "},{"metadata":{},"cell_type":"markdown","source":"# Image Visualization\n\n\n#### Let's first visualize the general data set. \n#### Visualize by class later"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = make_subplots(rows=1, cols=2,\n            specs=[[{\"type\": \"xy\"}, {\"type\": \"domain\"}]],)\n# value_counts: to count number of images in each class with respect to disease_name column\n# Bar plot \nt1 = go.Bar(x=data['label'].value_counts().index, \n            y=data['label'].value_counts().values,\n            text=data['label'].value_counts().values,\n            textposition='auto',name='Count',\n           marker_color='indianred')\n#Pie chart with labels and counts\nt2 = go.Pie(labels=data['label'].value_counts().index,\n           values=data['label'].value_counts().values,\n           hole=0.3)\nfig.add_trace(t1,row=1, col=1)\nfig.add_trace(t2,row=1, col=2)\nfig.update_layout(title='Distribution of Class Labels')\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<b> We can see that the data is imblanced and having the most number of images of label 3 disease.</b>  <br>\n '0': 'Cassava Bacterial Blight (CBB)' <br>\n '1': 'Cassava Brown Streak Disease (CBSD)'<br>\n '2': 'Cassava Green Mottle (CGM)'<br>\n '3': 'Cassava Mosaic Disease (CMD)'<br>\n '4': 'Healthy'"},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 512","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,12))\ndata_sample = data.sample(9).reset_index(drop=True)\n\nfor i in range(8):\n    plt.subplot(2,4,i+1)\n    \n    img = cv2.imread(WORK_DIR + \"train_images/\" + data_sample.image_id[i])\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    \n    plt.axis(\"off\")\n    plt.imshow(img)\n    plt.title(labels.get(data_sample.label[i]))\n    \nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Cassava Bacterial Blight (CBB)**"},{"metadata":{"trusted":true},"cell_type":"code","source":"labels.get(\"0\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,12))\ndata_sample = data[data.label==\"0\"].sample(4).reset_index(drop=True)\nfor i in range(4):\n    plt.subplot(1,4,i+1)\n    \n    img = cv2.imread(WORK_DIR + \"train_images/\" + data_sample.image_id[i])\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    \n    plt.axis(\"off\")\n    plt.imshow(img)\n    plt.title(labels.get(data_sample.label[i]))\n    \nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Cassava Brown Streak Disease (CBSD)**"},{"metadata":{"trusted":true},"cell_type":"code","source":"labels.get(\"1\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,12))\ndata_sample = data[data.label==\"1\"].sample(4).reset_index(drop=True)\nfor i in range(4):\n    plt.subplot(1,4,i+1)\n    \n    img = cv2.imread(WORK_DIR + \"train_images/\" + data_sample.image_id[i])\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    \n    plt.axis(\"off\")\n    plt.imshow(img)\n    plt.title(labels.get(data_sample.label[i]))\n    \nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Cassava Green Mottle (CGM)**"},{"metadata":{"trusted":true},"cell_type":"code","source":"labels.get(\"2\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,12))\ndata_sample = data[data.label==\"2\"].sample(4).reset_index(drop=True)\nfor i in range(4):\n    plt.subplot(1,4,i+1)\n    \n    img = cv2.imread(WORK_DIR + \"train_images/\" + data_sample.image_id[i])\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    \n    plt.axis(\"off\")\n    plt.imshow(img)\n    plt.title(labels.get(data_sample.label[i]))\n    \nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Cassava Mosaic Disease (CMD)**"},{"metadata":{"trusted":true},"cell_type":"code","source":"labels.get(\"3\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,12))\ndata_sample = data[data.label==\"3\"].sample(4).reset_index(drop=True)\nfor i in range(4):\n    plt.subplot(1,4,i+1)\n    \n    img = cv2.imread(WORK_DIR + \"train_images/\" + data_sample.image_id[i])\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    \n    plt.axis(\"off\")\n    plt.imshow(img)\n    plt.title(labels.get(data_sample.label[i]))\n    \nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Healthy**"},{"metadata":{"trusted":true},"cell_type":"code","source":"labels.get(\"4\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15,12))\ndata_sample = data[data.label==\"4\"].sample(4).reset_index(drop=True)\nfor i in range(4):\n    plt.subplot(1,4,i+1)\n    \n    img = cv2.imread(WORK_DIR + \"train_images/\" + data_sample.image_id[i])\n    img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    \n    plt.axis(\"off\")\n    plt.imshow(img)\n    plt.title(labels.get(data_sample.label[i]))\n    \nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Image Preprocessing, Data Augmentetion\n\n\n**ImageDataGenerator:** Generate batches of tensor image data with real-time data augmentation.\n\n**flow_from_dataframe:** Takes the dataframe and the path to a directory + generates batches.\nThe generated batches contain augmented/normalized data.\n\n\nhttps://keras.io/api/preprocessing/image/"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_generator = ImageDataGenerator(\n                                    #featurewise_center=False,                                    \n                                    #samplewise_center=False,\n                                    #featurewise_std_normalization=False,\n                                    #samplewise_std_normalization=False, \n                                    #zca_whitening=False,\n                                    #zca_epsilon=1e-06,\n                                    rotation_range=90,\n                                    width_shift_range=0.2,\n                                    height_shift_range=0.2,\n                                    #brightness_range=None,\n                                    shear_range=25,\n                                    zoom_range=0.3,\n                                    #channel_shift_range=0.0,\n                                    #fill_mode=\"nearest\",\n                                    #cval=0.0,\n                                    horizontal_flip=True,\n                                    vertical_flip=True,\n                                    #rescale=None,\n                                    #preprocessing_function=None,\n                                    #data_format=None,\n                                    validation_split=0.2,\n                                    #dtype=None,\n) \\\n        .flow_from_dataframe(\n                            data,\n                            directory = WORK_DIR + \"train_images\",\n                            x_col = \"image_id\",\n                            y_col = \"label\",\n                            #weight_col = None,\n                            target_size = (IMG_SIZE, IMG_SIZE),\n                            #color_mode = \"rgb\",\n                            #classes = 'sparse',\n                            class_mode = \"categorical\",\n                            batch_size = 8,\n                            shuffle = True,\n                            #seed = 34,\n                            #save_to_dir = None,\n                            #save_prefix = \"\",\n                            #save_format = \"png\",\n                            subset = \"training\",\n                            #interpolation = \"nearest\",\n                            #validate_filenames = True\n)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_generator = ImageDataGenerator(\n                                    validation_split = 0.2\n) \\\n        .flow_from_dataframe(\n                            data,\n                            directory = WORK_DIR + \"train_images\",\n                            x_col = \"image_id\",\n                            y_col = \"label\",\n                            target_size = (IMG_SIZE, IMG_SIZE),\n                            class_mode = \"categorical\",\n                            batch_size = 8,\n                            shuffle = True,\n                            subset = \"validation\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_generator.class_indices","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model\n\nActually I can say that this is my first experience in transfer learning. I found a good repo on GitHub for benchmarking. Thats why I used EfficientNet.\n\nhttps://github.com/weiaicunzai/awesome-image-classification"},{"metadata":{"trusted":true},"cell_type":"code","source":"def modelEfficientNetB0():\n    \n    model = models.Sequential()\n    model.add(EfficientNetB0(include_top = False, weights = \"imagenet\",\n                            input_shape=(IMG_SIZE,IMG_SIZE, 3)))\n    model.add(layers.GlobalAveragePooling2D())\n    model.add(layers.Dense(5, activation = \"softmax\"))\n    \n    return model ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = modelEfficientNetB0()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Callbacks\n\n**ModelCheckpoint**: Callback to save the Keras model or model weights at some frequency.\n\n**EarlyStopping**: Stop training when a monitored metric has stopped improving.\n\n**ReduceLROnPlateau**: Reduce learning rate when a metric has stopped improving.\n\n\nhttps://keras.io/api/callbacks/"},{"metadata":{"trusted":true},"cell_type":"code","source":"model_check = ModelCheckpoint(\n                            \"./sectry.h5\",\n                            monitor = \"val_loss\",\n                            verbose = 1,\n                            save_best_only = True,\n                            save_weights_only = False,\n                            mode = \"min\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"early_stop= EarlyStopping(\n                                monitor = \"val_loss\",\n                                min_delta=0.001,\n                                patience=5,\n                                verbose=1,\n                                mode=\"min\",\n                                #baseline=None,\n                                restore_best_weights=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"reduce_lr = ReduceLROnPlateau(\n                                monitor=\"val_loss\",\n                                factor=0.3,\n                                patience=3,\n                                verbose=1,\n                                mode=\"min\",\n                                min_delta=0.0001,\n                                #cooldown=0,\n                                #min_lr=0\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(optimizer = \"adam\",\n            loss = \"categorical_crossentropy\",\n            metrics = [\"accuracy\"])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 8\nSTEPS_PER_EPOCH = len(train_generator) / BATCH_SIZE\nVALIDATION_STEPS = len(valid_generator) / BATCH_SIZE\nEPOCHS = 20","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit_generator(train_generator,\n                            epochs = EPOCHS,\n                            steps_per_epoch = STEPS_PER_EPOCH,  \n                            validation_data = valid_generator,\n                            validation_steps = VALIDATION_STEPS,  \n                            callbacks = [model_check,early_stop,reduce_lr])\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15, 5))\nplt.plot(history.history['accuracy'], 'b*-', label=\"train_acc\")\nplt.plot(history.history['val_accuracy'], 'r*-', label=\"val_acc\")\nplt.grid()\nplt.title(\"train_acc vs val_acc\")\nplt.ylabel(\"Accuracy\")\nplt.xlabel(\"Epochs\")\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(15, 5))\nplt.plot(history.history['loss'], 'b*-', label=\"train_loss\")\nplt.plot(history.history['val_loss'], 'r*-', label=\"val_loss\")\nplt.grid()\nplt.title(\"train_loss - val_loss\")\nplt.ylabel(\"Loss\")\nplt.xlabel(\"Epochs\")\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# **Submission****"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = keras.models.load_model(\"./sectry.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = []\nsample_sub = pd.read_csv('../input/cassava-leaf-disease-classification/sample_submission.csv')\n\nfor image in sample_sub.image_id:\n    img = keras.preprocessing.image.load_img('../input/cassava-leaf-disease-classification/test_images/' + image)\n    img = keras.preprocessing.image.img_to_array(img)\n    img = keras.preprocessing.image.smart_resize(img, (512, 512))\n    img = np.expand_dims(img, 0)\n    prediction = model.predict(img)\n    preds.append(np.argmax(prediction))\n\nmy_submission = pd.DataFrame({'image_id': sample_sub.image_id, 'label': preds})\nmy_submission.to_csv('submission.csv', index=False) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# sample_sub = pd.read_csv(\"../input/cassava-leaf-disease-classification/sample_submission.csv\")\n# preds = []\n\n# for image_id in sample_sub.image_id:\n#     image = cv2.imread('../input/cassava-leaf-disease-classification/test_images/'+image_id)\n#     image = cv2.resize(image,(512,512))\n#     image = np.expand_dims(image, axis = 0)\n#     preds.append(np.argmax(model.predict(image)))\n\n# sample_sub['label'] = preds\n# sample_sub.to_csv('submission.csv', index = False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"my_submission","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}