{"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":"code","source":"import pandas as pd\nimport numpy as np\nimport os\nimport matplotlib.pyplot as plt\nfrom imgaug import augmenters as iaa\nimport cv2\nfrom PIL import Image\n%matplotlib inline\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.preprocessing import MultiLabelBinarizer\n\nimport seaborn as sns\nimport warnings\n    \nwarnings.filterwarnings(\"ignore\")\nplt.style.use('fivethirtyeight')","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2021-05-27T12:05:42.221229Z","iopub.execute_input":"2021-05-27T12:05:42.221761Z","iopub.status.idle":"2021-05-27T12:05:44.737217Z","shell.execute_reply.started":"2021-05-27T12:05:42.221628Z","shell.execute_reply":"2021-05-27T12:05:44.736176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<img src = \"https://empire-s3-production.bobvila.com/articles/wp-content/uploads/2012/09/uvm.edu-apple-tree.jpg\">\n\n# Problem Statement - Plant Pathology 2021 - FGVC8\n## Identify the category of foliar diseases in apple trees\n*Apples are one of the most important temperate fruit crops in the world. Foliar (leaf) diseases pose a major threat to the overall productivity and quality of apple orchards. The current process for disease diagnosis in apple orchards is based on manual scouting by humans, which is time-consuming and expensive.*\n\n*Although computer vision-based models have shown promise for plant disease identification, there are some limitations that need to be addressed. Large variations in visual symptoms of a single disease across different apple cultivars, or new varieties that originated under cultivation, are major challenges for computer vision-based disease identification. These variations arise from differences in natural and image capturing environments, for example, leaf color and leaf morphology, the age of infected tissues, non-uniform image background, and different light illumination during imaging etc.*\n\n*Plant Pathology 2020-FGVC7 challenge competition had a pilot dataset of 3,651 RGB images of foliar disease of apples. For Plant Pathology 2021-FGVC8, we have significantly increased the number of foliar disease images and added additional disease categories. This year’s dataset contains approximately 23,000 high-quality RGB images of apple foliar diseases, including a large expert-annotated disease dataset. This dataset reflects real field scenarios by representing non-homogeneous backgrounds of leaf images taken at different maturity stages and at different times of day under different focal camera settings.*\n\n<b>The main objective of the competition is to develop machine learning-based models to accurately classify a given leaf image from the test dataset to a particular disease category, and to identify an individual disease from multiple disease symptoms on a single leaf image.</b>","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.models import Sequential,Model\nimport tensorflow_addons as tfa\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras import layers\nfrom keras.layers import Activation, Dropout, Flatten, Dense, Input, Conv2D, MaxPooling2D, BatchNormalization, Concatenate, ReLU, LeakyReLU\nfrom keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import NASNetLarge, ResNet101, DenseNet121,InceptionResNetV2,Xception,MobileNetV2\nfrom tensorflow.keras.applications.resnet import preprocess_input\nfrom tensorflow.keras.metrics import Precision, Recall\nfrom tqdm.keras import TqdmCallback\n\nfrom keras.callbacks import ReduceLROnPlateau, EarlyStopping, ModelCheckpoint, ModelCheckpoint\n\nfrom keras.models import load_model","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-05-27T12:05:46.216723Z","iopub.execute_input":"2021-05-27T12:05:46.217163Z","iopub.status.idle":"2021-05-27T12:05:52.655691Z","shell.execute_reply.started":"2021-05-27T12:05:46.217115Z","shell.execute_reply":"2021-05-27T12:05:52.654263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATA = \"../input/plant-pathology-2021-fgvc8\"\nPATH_TO_TRAIN = DATA + '/train_images/'\ndata_train = pd.read_csv(os.path.join(DATA,'train.csv'))\nsubmission = pd.read_csv(os.path.join(DATA,'sample_submission.csv'))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-05-27T12:05:52.657944Z","iopub.execute_input":"2021-05-27T12:05:52.658471Z","iopub.status.idle":"2021-05-27T12:05:52.714625Z","shell.execute_reply.started":"2021-05-27T12:05:52.658421Z","shell.execute_reply":"2021-05-27T12:05:52.713227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_train.head()","metadata":{"execution":{"iopub.status.busy":"2021-05-27T12:05:52.717039Z","iopub.execute_input":"2021-05-27T12:05:52.717540Z","iopub.status.idle":"2021-05-27T12:05:52.746567Z","shell.execute_reply.started":"2021-05-27T12:05:52.717486Z","shell.execute_reply":"2021-05-27T12:05:52.745734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_train['labels'] = data_train['labels'].apply(lambda string: string.split(' '))\ndata_train","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-05-27T12:05:52.747744Z","iopub.execute_input":"2021-05-27T12:05:52.748204Z","iopub.status.idle":"2021-05-27T12:05:52.782014Z","shell.execute_reply.started":"2021-05-27T12:05:52.748167Z","shell.execute_reply":"2021-05-27T12:05:52.780826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = data_train['image'].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 = DATA+'/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()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-05-27T12:05:56.190217Z","iopub.execute_input":"2021-05-27T12:05:56.190599Z","iopub.status.idle":"2021-05-27T12:06:06.513558Z","shell.execute_reply.started":"2021-05-27T12:05:56.190565Z","shell.execute_reply":"2021-05-27T12:06:06.512271Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_gen = ImageDataGenerator( rotation_range = 10,\n    width_shift_range = 0.1,\n    height_shift_range = 0.1,\n    brightness_range = None,\n    shear_range = 0.1,\n    zoom_range = 0.1,\n    rescale = 1./255,\n    horizontal_flip=True,\n    vertical_flip=True,\n    \n    validation_split= 0.2)\n\ntrain_generator = data_gen.flow_from_dataframe(\n    data_train,\n    directory='../input/resized-plant2021/img_sz_256',\n    subset='training',\n    x_col='image',\n    y_col='labels',\n    target_size=(256,256),\n    color_mode='rgb',\n    class_mode='categorical',\n    batch_size=16,\n    shuffle=True,\n    seed= tf.random.set_seed(42)\n    )\nvalidation_generator = data_gen.flow_from_dataframe(\n    data_train,\n    directory='../input/resized-plant2021/img_sz_256',\n    subset='validation',\n    x_col='image',\n    y_col='labels',\n    target_size=(256,256),\n    color_mode='rgb',\n    class_mode='categorical',\n    batch_size=16,\n    shuffle=True,\n    seed= tf.random.set_seed(42)\n    )","metadata":{"execution":{"iopub.status.busy":"2021-05-27T12:06:06.515332Z","iopub.execute_input":"2021-05-27T12:06:06.515688Z","iopub.status.idle":"2021-05-27T12:06:50.891136Z","shell.execute_reply.started":"2021-05-27T12:06:06.515655Z","shell.execute_reply":"2021-05-27T12:06:50.889590Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def show_history(history):\n    fig, ax = plt.subplots(1, 2, figsize=(15,5))\n    ax[0].set_title('loss')\n    ax[0].plot(history.epoch, history.history[\"loss\"], label=\"Train loss\")\n    ax[0].plot(history.epoch, history.history[\"val_loss\"], label=\"Validation loss\")\n    ax[1].set_title('F1')\n    ax[1].plot(history.epoch, history.history[\"f1_score\"], label=\"Train f1\")\n    ax[1].plot(history.epoch, history.history[\"val_f1_score\"], label=\"Validation f1\")\n    ax[0].legend()\n    ax[1].legend()\n","metadata":{"execution":{"iopub.status.busy":"2021-05-27T12:07:19.711537Z","iopub.execute_input":"2021-05-27T12:07:19.712223Z","iopub.status.idle":"2021-05-27T12:07:19.719644Z","shell.execute_reply.started":"2021-05-27T12:07:19.712173Z","shell.execute_reply":"2021-05-27T12:07:19.718786Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_model(input_shape):\n    \n    dropRate = 0.25\n    \n    init = Input(input_shape)\n    x = BatchNormalization(axis=-1)(init)\n    x = Conv2D(8, (3, 3))(x)\n    x = ReLU()(x)\n    x = BatchNormalization(axis=-1)(x)\n    x = Conv2D(8, (3, 3))(x)\n    x = ReLU()(x)\n    x = BatchNormalization(axis=-1)(x)\n    x = Conv2D(16, (3, 3))(x)\n    x = ReLU()(x)\n    x = BatchNormalization(axis=-1)(x)\n    x = MaxPooling2D(pool_size=(2, 2))(x)\n    x = Dropout(dropRate)(x)\n    c1 = Conv2D(16, (3, 3), padding='same')(x)\n    c1 = ReLU()(c1)\n    c2 = Conv2D(16, (5, 5), padding='same')(x)\n    c2 = ReLU()(c2)\n    c3 = Conv2D(16, (7, 7), padding='same')(x)\n    c3 = ReLU()(c3)\n    c4 = Conv2D(16, (1, 1), padding='same')(x)\n    c4 = ReLU()(c4)\n    x = Concatenate()([c1, c2, c3, c4])\n    x = BatchNormalization(axis=-1)(x)\n    x = MaxPooling2D(pool_size=(2, 2))(x)\n    x = Dropout(dropRate)(x)\n    x = Conv2D(32, (3, 3))(x)\n    x = ReLU()(x)\n    x = BatchNormalization(axis=-1)(x)\n    x = MaxPooling2D(pool_size=(2, 2))(x)\n    x = Dropout(dropRate)(x)\n    x = Conv2D(64, (3, 3))(x)\n    x = ReLU()(x)\n    x = BatchNormalization(axis=-1)(x)\n    x = MaxPooling2D(pool_size=(2, 2))(x)\n    x = Dropout(dropRate)(x)\n    x = Conv2D(128, (3, 3))(x)\n    x = ReLU()(x)\n    x = BatchNormalization(axis=-1)(x)\n    x = MaxPooling2D(pool_size=(2, 2))(x)\n    x = Dropout(dropRate)(x)\n    x = Conv2D(256, (1, 1), activation='relu')(x)\n    x = BatchNormalization(axis=-1)(x)\n    x = MaxPooling2D(pool_size=(2, 2))(x)\n    x = Dropout(0.25)(x)\n    x = Flatten()(x)\n    x = Dropout(0.5)(x)\n    x = Dense(28)(x)\n    x = ReLU()(x)\n    x = BatchNormalization(axis=-1)(x)\n    x = Dropout(0.1)(x)\n    x = Dense(6)(x)\n    x = Activation('sigmoid')(x)\n    \n    model = Model(init, x)\n    \n    return model","metadata":{"execution":{"iopub.status.busy":"2021-05-27T12:08:02.821831Z","iopub.execute_input":"2021-05-27T12:08:02.822242Z","iopub.status.idle":"2021-05-27T12:08:02.844994Z","shell.execute_reply.started":"2021-05-27T12:08:02.822191Z","shell.execute_reply":"2021-05-27T12:08:02.843789Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = create_model(\n    input_shape=(256,256,3))\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2021-05-27T12:08:03.441707Z","iopub.execute_input":"2021-05-27T12:08:03.442341Z","iopub.status.idle":"2021-05-27T12:08:03.783313Z","shell.execute_reply.started":"2021-05-27T12:08:03.442296Z","shell.execute_reply":"2021-05-27T12:08:03.781711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"f1 = tfa.metrics.F1Score(num_classes=6, average='macro')\n\nearlystop=EarlyStopping(monitor=f1, patience=10, mode='max', restore_best_weights=True)\n\nreducelrplateau  = ReduceLROnPlateau(monitor='val_loss', patience=3, verbose=0.5, factor=0.5)\n\nmodel.compile(\n    loss='binary_crossentropy',  \n    optimizer=Adam(1e-3),\n    metrics=[f1])\n\nhistory = model.fit_generator(\n    train_generator,\n    steps_per_epoch=100,\n    validation_data=validation_generator,\n    epochs=50, \n    verbose=1,\n    callbacks=[earlystop,reducelrplateau,TqdmCallback(verbose=0)])","metadata":{"execution":{"iopub.status.busy":"2021-05-27T12:08:03.832465Z","iopub.execute_input":"2021-05-27T12:08:03.832851Z","iopub.status.idle":"2021-05-27T12:11:35.003609Z","shell.execute_reply.started":"2021-05-27T12:08:03.832813Z","shell.execute_reply":"2021-05-27T12:11:35.001652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_history(history)","metadata":{"execution":{"iopub.status.busy":"2021-05-26T15:01:14.153685Z","iopub.execute_input":"2021-05-26T15:01:14.154079Z","iopub.status.idle":"2021-05-26T15:01:14.444733Z","shell.execute_reply.started":"2021-05-26T15:01:14.154041Z","shell.execute_reply":"2021-05-26T15:01:14.443905Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# END\n<img src = \"https://media.giphy.com/media/9Ai5dIk8xvBm0/giphy.gif\">","metadata":{}}]}