{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Basic CNN with tensorflow and keras over the Plant Pathology Dataset\n\nCompanion notebook to understand how the model comes to decisions is available at https://www.kaggle.com/mreenav/interpreting-cnns-plant-pathology-2021","metadata":{}},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport keras\nfrom keras.preprocessing import image\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D, MaxPool2D, Flatten,Dense,Dropout,BatchNormalization\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import VGG16, InceptionResNetV2, ResNet50, Xception\nimport cv2\nfrom PIL import Image","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = '../input/plant-pathology-2021-fgvc8/'\ntrain_dir = path + 'train_images/'\ntest_dir = path + 'test_images/'\n#resized images\ntrain_paths = '../input/resized-plant2021/img_sz_256/' ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv('../input/plant-pathology-2021-fgvc8/train.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.labels.value_counts()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['labels'].unique()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['labels'] = df['labels'].astype(str)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(8,5))\nsns.countplot(data = df,y='labels')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_examples(label):\n    fig, ax = plt.subplots(1, 5, figsize=(25, 15))\n    ax = ax.ravel()\n    for i in range(5):\n        idx = df[df['labels']==label].index[i]\n        image = cv2.imread(train_paths+df.loc[idx, 'image'])\n        \n        image =cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        ax[i].imshow(image)\n        ax[i].set_title(label)\n        ax[i].set_xticklabels([])\n        ax[i].set_yticklabels([])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for labels in list(df['labels'].unique()):\n    plot_examples(labels)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Converting to multi-label problem\n#https://www.kaggle.com/shanmukh05/plant-pathology-2k21-baseline-tpu-training\n\ncount_dict = df.labels.value_counts()\nlabel2id = {\n    'scab': 0,\n    'frog_eye_leaf_spot' : 1,\n    'rust' : 2,\n    'complex' : 3,\n    'powdery_mildew' : 4,\n}\nNUM_CLASS = len(label2id)\nid2label = dict([(value, key) for key, value in label2id.items()])\ndf[\"labels\"] = df[\"labels\"].map(lambda x : [i for i in x.split(\" \") if i != \"healthy\"])\ndf[\"labels\"] = df[\"labels\"].map(lambda x : [label2id[i] for i in x])\ndf.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(rescale = 1./255.,\n                                   rotation_range = 40,\n                                   width_shift_range = 0.2,\n                                   height_shift_range = 0.2,\n                                   shear_range = 0.2,\n                                   zoom_range = 0.2,\n                                   horizontal_flip = True,\n                                   validation_split = 0.2)\ntest_datagen = ImageDataGenerator(rescale = 1./255,\n                                  validation_split = 0.2)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_generator = train_datagen.flow_from_dataframe(dataframe = df,\n                                                   directory = train_paths,\n                                                   target_size = (256,256),\n                                                   x_col = 'image',\n                                                   y_col = 'labels',\n                                                   batch_size = 128,\n                                                   color_mode = 'rgb',\n                                                   class_mode = 'categorical',\n                                                   subset = 'training')\n\ntest_generator = test_datagen.flow_from_dataframe(dataframe = df,\n                                                 directory = train_paths,\n                                                 target_size = (256,256),\n                                                 x_col = 'image',\n                                                 y_col = 'labels',\n                                                 batch_size = 128,\n                                                 color_mode = 'rgb',\n                                                 class_mode = 'categorical',\n                                                 subset = 'validation')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = tf.keras.Sequential([\n    tf.keras.layers.Conv2D(32, (3,3), input_shape=(256,256,3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),\n    tf.keras.layers.MaxPooling2D(2,2),\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(512, activation='relu'),\n    tf.keras.layers.Dense(NUM_CLASS, activation='sigmoid')\n])\nmodel.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"METRIC = \"val_f1_score\"\n\ndef create_callbacks(metric = METRIC):\n    \n    cpk_path = './best_model.h5'\n    \n    checkpoint = tf.keras.callbacks.ModelCheckpoint(\n        filepath=cpk_path,\n        monitor= metric,\n        mode='max',\n        save_best_only=True,\n        verbose=1,\n    )\n\n    reducelr = tf.keras.callbacks.ReduceLROnPlateau(\n        monitor= metric,\n        mode='max',\n        factor=0.2,\n        patience=3,\n        verbose=1\n    )\n\n    earlystop = tf.keras.callbacks.EarlyStopping(\n        monitor= metric,\n        mode='max',\n        patience=10, \n        verbose=1\n    )\n    \n    callbacks = [checkpoint, reducelr, earlystop]         \n    \n    return callbacks","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.optimizers import RMSprop,Adam\nimport tensorflow_addons as tfa\n\nepochs = 40\nbatch_size = 256\noptimizer = Adam(lr = 0.001)\nmodel.compile(optimizer = optimizer,\n             loss = 'binary_crossentropy',\n             metrics = ['accuracy', tfa.metrics.F1Score(num_classes = NUM_CLASS,average = \"macro\", name = \"f1_score\")])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"callbacks = create_callbacks()\nhistory = model.fit(train_generator,epochs = epochs,validation_data = test_generator,verbose=1, callbacks = callbacks)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"figure, axis = plt.subplots(2, 1, figsize=(15,15))\naxis.ravel()\naxis[0].plot(history.history['accuracy'],label='Training Data')\naxis[0].plot(history.history['val_accuracy'], label='Validation Data')\naxis[0].set(xlabel='Epochs',ylabel='Accuracy', title='Accuracy vs Epochs')\naxis[0].legend(loc=\"upper left\")\n\naxis[1].plot(history.history['loss'], label='Training Data')\naxis[1].plot(history.history['val_loss'], label='Validation Data')\naxis[1].set(xlabel='Epochs',ylabel='Loss', title='Categorical Crossentropy Loss vs Epochs')\naxis[1].legend(loc=\"upper left\")\n\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Acknowledgements\n\nStarter code used from this notebook by Ayush: \nhttps://www.kaggle.com/aayushmishra1512/plant-pathology-starter\n\nResized dataset used from:\nhttps://www.kaggle.com/ankursingh12/resized-plant2021","metadata":{}}]}