{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Why this Competition?\nThis competiton provides another great opportunity for computer vision to be applied in real world and potential to have meaningful impact on people's lives. It is also a great oppertunity for us Data Science enthusiasts to understand the agricultural disease domain and nonetheless showcase our skills in a competitive setting. It also provides the unique oppertunities for beginners (myself included) to get their hands dirty and indulge is constructive discussions and knowledge sharing on this platform.\n\n# Problem Statement\nThis Competition requires us to classify the type of foliar disease an apple tree is having using the images of the tree/leaves/fruit. 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.\nThe scoring metric for this competition is also an interesting one for multi-label classification: **F1-Mean**.\n\n## Why bother?\nApples 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## Data Description:-\n* About 18,632 images showing the presence of various types of diseases. **A single photo might also contain multiple diseases**.\n\n## Expected Outcome:-\n* Detect the presence of all the diseases in a given image.\n\n## Problem Category:-\nFor the data and objective its is evident that this is a **multi-label classification problem** in the **Computer Vision** domain.\n\n# About this Notebook\n* Being a beginner myself, this notebook will focus solely on basics, getting to know the data and build a primitive yet effective model.\n    * This notebook will be updated several times as and when I learn new interesting stuff and think will be useful for the audience. Please also consider that I too am on a learning voyage here.\n* Our weapon of choice will be Deep-Learning through the journey of this notebook.\n* Model Details:-\n    * EfficientNet B4\n    * Epochs: 20\n    * Optimizer: Adam\n    * Loss Function: Categorical Crossentropy\n    * Scheduler: Constant LR with Reduction by 10x on plateau\n    * Augmentations: Simple Left-Right Top-Bottom flips and Brighness change\n    * Simple single multi-class classifier\n\n# Imports\nLet's start by importing some basic libraries that we require though our journey of this notebook."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# Asthetics\nimport warnings\nimport sklearn.exceptions\nwarnings.filterwarnings('ignore', category=DeprecationWarning)\nwarnings.filterwarnings('ignore', category=FutureWarning)\nwarnings.filterwarnings(\"ignore\", category=sklearn.exceptions.UndefinedMetricWarning)\n\n# General\nimport pandas as pd\npd.set_option('display.max_columns', None)\nimport numpy as np\nimport os\nimport time\nimport cv2\nimport random\nfrom kaggle_datasets import KaggleDatasets\n\n# Visialisation\nimport matplotlib.pyplot as plt\n%matplotlib inline\nimport seaborn as sns\nsns.set(style=\"whitegrid\")\nfrom plotly import graph_objs as go\nimport plotly.express as px\nimport plotly.figure_factory as ff\nfrom plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot\nfrom PIL import Image\n\n# Machine Learning\n# Pre Procesing\nfrom sklearn.preprocessing import LabelEncoder, OneHotEncoder\n# Models\nfrom sklearn.model_selection import train_test_split, cross_validate, StratifiedKFold, cross_val_score\n# Deep Learning\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import EfficientNetB4\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Dropout, Activation, BatchNormalization, GlobalAveragePooling2D\nfrom tensorflow.keras.callbacks import TensorBoard, EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.losses import CategoricalCrossentropy\nfrom tensorflow_addons.metrics import F1Score, FBetaScore\nfrom tensorflow_addons.callbacks import TQDMProgressBar\nfrom tensorflow.keras.utils import plot_model\n\n#Metrics\nfrom sklearn import metrics\nfrom sklearn.metrics import confusion_matrix, classification_report\n\nprint('TF',tf.__version__)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"RANDOM_SEED = 42","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def seed_everything(seed=RANDOM_SEED):\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    random.seed(seed)\n    tf.random.set_seed(seed)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"seed_everything()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_path = '../input/plant-pathology-2021-fgvc8'\n\nlabels_file_path = os.path.join(data_path, 'train.csv')\nsample_submission_path = os.path.join(data_path, 'sample_submission.csv')\ntrain_images_path = os.path.join(data_path, 'train_images')\ntest_images_path = os.path.join(data_path, 'test_images')\n\nprint(f'Label File path: {labels_file_path}')\nprint(f'Sample Submission File path: {sample_submission_path}')\nprint(f'Train Images path: {train_images_path}')\nprint(f'Test Images path: {test_images_path}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# EDA\nLet's start by reading the train file..."},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(labels_file_path)\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.describe()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We see that there are no missing data. Good for us. Now let's see what are those unique labels:-"},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df['labels'].unique()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Thus we have 6 different types of diseases + 1 healthy:-\n1. Healthy\n2. Scab\n3. Frog eye leaf spot\n4. Complex\n5. Cider apple rust\n6. Powdery mildew\n7. Rust\n\nAnd a tree can have multiple of those diseases at any point of time. Now let's see how many examples we have in each..."},{"metadata":{"trusted":true},"cell_type":"code","source":"ax = plt.subplots(figsize=(18, 6))\nsns.set_style(\"whitegrid\")\nsns.countplot(x='labels', data=train_df);\nplt.ylabel(\"No. of Observations\", size=20);\nplt.xlabel(\"Class Name\", size=20);\nplt.xticks(rotation=90);","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Observations:-\n1. We have very high representations of single diseases in the train dataset while combination of diseases is very rare.\n2. Arounf 51% of input data either belongs to Scab or Healthy category."},{"metadata":{},"cell_type":"markdown","source":"## Utils"},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_image(class_name, examples=2, labels_df=train_df, train_images_path=train_images_path):\n    image_list = labels_df[labels_df['labels'] == class_name]['image'].sample(frac=1)[:examples].to_list()\n    plt.figure(figsize=(20,10))\n    for i, img in enumerate(image_list):\n        full_path = os.path.join(train_images_path, img)\n        img = Image.open(full_path)\n        plt.subplot(1 ,examples, i%examples +1)\n        plt.axis('off')\n        plt.imshow(img)\n        plt.title(class_name)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's try to go through each disease category and try to answer the following questions:-\n1. What are the various types of diseases?\n2. How to identify each disease type?\n3. What are the unique identifying charecteristics of each disease?\n\nNow with these questions in mind, let's start cracking..."},{"metadata":{},"cell_type":"markdown","source":"## 1. Healthy\nFrom the class it is pretty clear that these images are of helthy trees. Let's have a look at them to understand what healthy trees look like so that we would have a baseline undersatnding."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='healthy', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Okay, this class is pretty straight forward. Clean green looking leaves are identifying charecterisctics of this class.  \n## 2. Scab  \nScab is serious disease of apples and ornamental crabapples, apple scab (Venturia inaequalis) attacks both leaves and fruit. The fungal disease forms pale yellow or olive-green spots on the upper surface of leaves. Dark, velvety spots may appear on the lower surface. Severely infected leaves become twisted and puckered and may drop early in the summer.\n\nSymptoms on fruit are similar to those found on leaves. Scabby spots are sunken and tan and may have velvety spores in the center. As these spots mature, they become larger and turn brown and corky. Infected fruit becomes distorted and may crack allowing entry of secondary organisms. Severely affected fruit may drop, especially when young.  \n\nLet's look at some examples..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='scab', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"According to the examples, scabs can be identified by:-\n1. Tiny spots on the leaves.\n2. The spots are usually yellow/brown in color.\n\n## 3. Frog eye leaf spot\nFirst, small purple spots form on the leaves. These spots gradually enlarge and eventually develop into lesions with a light tan interior, surrounded by a dark purple perimeter. Heavy infections of frog-eye leaf spot can cause leaves to turn yellow and drop.\n\nFrog eye leaf spot symptoms on tree trunks and limbs appear as cankers, which are reddish brown in colour and are slightly sunken. As the wood ages it becomes shrunken and layers of bark begin to peel back.\n\nFrog eye leaf spot also causes small purple black spots on the fruit. These spots eventually enlarge to form concentric brown rings.\n\nLet's look at some examples in our datatset..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='frog_eye_leaf_spot', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"According to the examples, Frog eye leaf spots can be identified by:-\n1. Small patches on the leaves.\n2. The pathes are usually brown in color.\n3. They have a distinctive ring type shape with an inner and outer rings.\n\n## 4. Complex\nAccording to data description:- Unhealthy leaves with too many diseases to classify visually will have the complex class, and may also have a subset of the diseases identified.\n\nLet's look at some examples of this disease type in our datatset..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='complex', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"This falls inline with the description as we see some leaves having new type of disease which we have not identified yet along with something that looks like scab.\n\n## 5. Cider apple rust\nCircular, yellow spots (lesions) appear on the upper surfaces of the leaves shortly after bloom. In late summer, brownish clusters of threads or cylindrical tubes (aecia) appear beneath the yellow leaf spots or on fruits and twigs. The spores associated with the threads or tubes infect the leaves (needles) and twigs of junipers during wet, warm weather.\n\nLet's look at some examples from out datatset..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='cider_apple_rust', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"According to the examples, Cider Apple Rusts can be identified by:-\n1. Small to Large patches on the leaves.\n2. The pathes are usually Yellow to Reddish in color.\n3. They have a distinctive color and yellow-red ring type structure when fully grown.\n\n## 6. Powdery Mildew\nPowdery mildew is a fungal disease that affects a wide range of plants.\n\nPowdery mildew is one of the easier plant diseases to identify, as its symptoms are quite distinctive. Infected plants display white powdery spots on the leaves and stems. The lower leaves are the most affected, but the mildew can appear on any above-ground part of the plant. As the disease progresses, the spots get larger and denser as large numbers of asexual spores are formed, and the mildew may spread up and down the length of the plant.\n\nLooking at some examples..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='powdery_mildew', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"According to the examples, Powdery Mildew can be identified by:-\n1. Large patches on the leaves.\n2. The leaves look like having some powerdy residue on them.\n3. The pathes/residue look white in color.\n\n## 7. Scab + Frog eye leaf spot\nThis is a combination of Scab and Grog eye leaf spot on single image... Let's see who those look..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='scab frog_eye_leaf_spot', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As seen in the images the leaves have small brown spots charecteristic of Scab, but larger ring shaped spots as well showing presence of Frog eye leaf spot as well.\n\n## 8. Scab + Frog eye leaf spot + Complex\nThis suggests that these images will be similar to the previous class... But might have some additional diseases as well.  \nLet's look at some examples..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='scab frog_eye_leaf_spot complex', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As expected we can see traces of Scab and Frog eye leaf spot majorly. APrt from those there is a hint of some other rusty disease which we have not encountered yet...\n\n## 9. Frog eye leaf spot + Complex\nSimilarly it is a combination of Frog eye leaf spot and some unkown disease. Looking at some images..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='frog_eye_leaf_spot complex', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The unkown disease varies from image to image. There is some images where the unknown disease looks like scab but in others its looks completely different. So classifying them under the complex umbrella makes sense...\n\n## 10. Rust + Frog eye leaf spot\nSimilarly this is a combination of Rust and Frog eye leaf spot. Let's see some examples..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='rust frog_eye_leaf_spot', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The rust looks very similar to cider apple rust and also clearly there is presence of Frog eye leaf spot with the carecteristic brown ring type structure.  \n\n## 11. Powdery Mildew + complex\nThis will have powdery mildew and some unknown disease in the images. Let's see some examples..."},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='powdery_mildew complex', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As expected the major component of the leaf image is Powdery Mildew while there are some little black spots present cause by some unkown disease.\n\n## 12. Rust + Complex"},{"metadata":{"trusted":true},"cell_type":"code","source":"show_image(class_name='rust complex', examples=4)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The images have the charecteristic rust sopt with some smaller spots and some brown pathces pertaining to some other disease.  \n\n**I think in the multiple disease category Rust actually means Cider Apple Rust that we have seen earlier. Thuse the same identifiers can be used to describe the same. This will be useful when we further persue other detailed models.**\n\n# Model Creation\nWe will create a basic small model as a baseline for this task. Before that let's define the data generators."},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH = 20\nIMG_DIM = 380\nEPOCHS = 30\nIMG_SHAPE = (IMG_DIM, IMG_DIM, 3)\nLR = 1e-5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# From https://www.kaggle.com/xhlulu/ranzcr-efficientnet-tpu-training\ndef auto_select_accelerator():\n    try:\n        tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n        tf.config.experimental_connect_to_cluster(tpu)\n        tf.tpu.experimental.initialize_tpu_system(tpu)\n        strategy = tf.distribute.experimental.TPUStrategy(tpu)\n        print(\"Running on TPU:\", tpu.master())\n    except ValueError:\n        strategy = tf.distribute.get_strategy()\n    print(f\"Running on {strategy.num_replicas_in_sync} replicas\")\n    \n    return strategy","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"COMPETITION_NAME = \"plant-pathology-2021-fgvc8\"\nstrategy = auto_select_accelerator()\nBATCH_SIZE = strategy.num_replicas_in_sync * BATCH\nGCS_DS_PATH = KaggleDatasets().get_gcs_path('plant-pathology-2021-fgvc8')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv(labels_file_path)\nsub_df = pd.read_csv(sample_submission_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"paths = GCS_DS_PATH + '/train_images/' + df['image']\ntest_paths = GCS_DS_PATH + '/test_images/' + sub_df['image']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# le = LabelEncoder()\n# le.fit(df['labels']);\n# df['labels'] = le.transform(df['labels'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_cols = 'labels'\n# labels = df[label_cols].values\n# labels = [[i] for i in labels]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"le = LabelEncoder()\nle.fit(df['labels']);\ninteger_encoded = le.transform(df['labels'])\n\nenc = OneHotEncoder(sparse=False)\ninteger_encoded = integer_encoded.reshape(len(integer_encoded), 1)\nonehot_encoded = enc.fit_transform(integer_encoded)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# label_map = dict(zip(le.classes_, le.transform(le.classes_)))\n# label_inv_map = {v: k for k, v in label_map.items()}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"(train_paths, valid_paths,\n train_labels, valid_labels) = train_test_split(paths, onehot_encoded, test_size=0.2, random_state=RANDOM_SEED)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_decoder(with_labels=True, target_size=(IMG_DIM, IMG_DIM), ext='jpg'):\n    def decode(path):\n        file_bytes = tf.io.read_file(path)\n        if ext == 'png':\n            img = tf.image.decode_png(file_bytes, channels=3)\n        elif ext in ['jpg', 'jpeg']:\n            img = tf.image.decode_jpeg(file_bytes, channels=3)\n        else:\n            raise ValueError(\"Image extension not supported\")\n\n        img = tf.cast(img, tf.float32) / 255.0\n        img = tf.image.resize(img, target_size)\n\n        return img\n    \n    def decode_with_labels(path, label):\n        return decode(path), label\n    \n    return decode_with_labels if with_labels else decode","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def build_augmenter(with_labels=True):\n    def augment(img):\n        img = tf.image.random_flip_left_right(img)\n        img = tf.image.random_flip_up_down(img)\n        img = tf.image.random_hue(img, 0.01)\n        img = tf.image.random_saturation(img, 0.70, 1.30)\n        img = tf.image.random_contrast(img, 0.80, 1.20)\n        img = tf.image.random_brightness(img, 0.2)\n        return img\n    \n    def augment_with_labels(img, label):\n        return augment(img), label\n    \n    return augment_with_labels if with_labels else augment","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# From https://www.kaggle.com/xhlulu/ranzcr-efficientnet-tpu-training\ndef build_dataset(paths, labels=None, bsize=BATCH, cache=True,\n                  decode_fn=None, augment_fn=None,\n                  augment=True, repeat=True, shuffle=1024,\n                  cache_dir=\"\"):\n    if cache_dir != \"\" and cache is True:\n        os.makedirs(cache_dir, exist_ok=True)\n    \n    if decode_fn is None:\n        decode_fn = build_decoder(labels is not None)\n    \n    if augment_fn is None:\n        augment_fn = build_augmenter(labels is not None)\n        \n    AUTO = tf.data.experimental.AUTOTUNE\n    slices = paths if labels is None else (paths, labels)\n    \n    dset = tf.data.Dataset.from_tensor_slices(slices)\n    dset = dset.map(decode_fn, num_parallel_calls=AUTO)\n    dset = dset.cache(cache_dir) if cache else dset\n    dset = dset.map(augment_fn, num_parallel_calls=AUTO) if augment else dset\n    dset = dset.repeat() if repeat else dset\n    dset = dset.shuffle(shuffle) if shuffle else dset\n    dset = dset.batch(bsize).prefetch(AUTO)\n    \n    return dset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_model(IMG_DIM=IMG_DIM, Num_Class=df['labels'].nunique()):\n    with strategy.scope():\n        IMG_SHAPE = (IMG_DIM, IMG_DIM, 3)\n        \n        feature_extractor = EfficientNetB4(input_shape=IMG_SHAPE,\n                                           include_top=False,\n                                           drop_connect_rate=0.2,\n                                           weights='imagenet')\n        feature_extractor.trainable = True\n\n        global_average_layer = GlobalAveragePooling2D()\n        dense_layer = Dense(256, activation='relu')\n        softmax_layer = Dense(train_df['labels'].nunique(), activation='softmax')\n        \n        clf_model = Sequential([feature_extractor, global_average_layer,\n                                Dropout(0.2), dense_layer, Dropout(0.2),\n                                softmax_layer])\n\n        clf_model.compile(\n            optimizer = Adam(lr=LR),\n            loss = CategoricalCrossentropy(label_smoothing=0.1),\n            metrics=[F1Score(num_classes=train_df['labels'].nunique(), average='macro'),\n                     'accuracy']\n        )\n\n        clf_model.summary()\n        return clf_model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"decoder = build_decoder(with_labels=True, target_size=(IMG_DIM, IMG_DIM))\ntest_decoder = build_decoder(with_labels=False, target_size=(IMG_DIM, IMG_DIM))\n\ntrain_dataset = build_dataset(\n    train_paths, train_labels, bsize=BATCH_SIZE, decode_fn=decoder\n)\n\nvalid_dataset = build_dataset(\n    valid_paths, valid_labels, bsize=BATCH_SIZE, decode_fn=decoder,\n    repeat=False, shuffle=False, augment=False\n)\n\ntest_dataset = build_dataset(\n    test_paths, cache=False, bsize=BATCH_SIZE, decode_fn=test_decoder,\n    repeat=False, shuffle=False, augment=False\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"STEPS_PER_EPOCH = train_paths.shape[0] // BATCH_SIZE\nVALID_STEPS = valid_paths.shape[0] // BATCH_SIZE\n\nearly = EarlyStopping(monitor='val_accuracy', min_delta=0.001, patience=10, verbose=0, mode='max', baseline=None, restore_best_weights=True)\nlr_reducer = ReduceLROnPlateau(monitor='val_auc', patience=5, min_lr=1e-6, mode='max')\ncheckpoint = ModelCheckpoint(monitor='val_accuracy', filepath='weights_EffB4.hdf5', mode='max', verbose=0, save_best_only=True)\ntqdm_callback = TQDMProgressBar()\n\ncallbacks_list = [lr_reducer, checkpoint, early, tqdm_callback]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"clf_model = get_model()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plot_model(clf_model, show_shapes=True, show_layer_names=True, to_file='model.png')\nimg = Image.open('model.png')\nplot_dim = (10, 15)\nax = plt.subplots(figsize=plot_dim)\nplt.imshow(img)\nplt.axis(\"off\")\nplt.tight_layout(pad=0)\nplt.show()\nos.remove('model.png')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"validation_steps=20\n\nloss0, f10, accuracy0 = clf_model.evaluate(x = valid_dataset, steps = validation_steps)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"initial loss: {:.2f}\".format(loss0))\nprint(\"initial accuracy: {:.2f}\".format(accuracy0))\nprint(\"initial F1: {:.2f}\".format(f10))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tf.keras.backend.clear_session()\nhistory = clf_model.fit(train_dataset,\n                        steps_per_epoch=STEPS_PER_EPOCH,\n                        epochs = EPOCHS,\n                        validation_data = valid_dataset,\n                        validation_steps=VALID_STEPS,\n                        callbacks=callbacks_list,\n                        verbose = 0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nf1 = history.history['f1_score']\nval_f1 = history.history['val_f1_score']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = go.Figure()\nfig.add_trace(go.Scatter(y = val_loss, name = 'Validation Loss', line = dict(color='royalblue', width=4)))\nfig.add_trace(go.Scatter(y = loss, name = 'Training Loss', line = dict(color='royalblue', width=4, dash='dash')))\n\nfig.update_layout(title = 'Trained Loss History', xaxis_title = 'Epoch', yaxis_title = 'Loss')\n\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = go.Figure()\nfig.add_trace(go.Scatter(y = val_acc, name = 'Validation Accuracy', line = dict(color='firebrick', width=4)))\nfig.add_trace(go.Scatter(y = acc, name = 'Training Accuracy', line = dict(color='firebrick', width=4, dash='dash')))\n\nfig.update_layout(title='Trained Accuracy History', xaxis_title='Epoch', yaxis_title='Accuracy')\n\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig = go.Figure()\nfig.add_trace(go.Scatter(y = val_f1, name = 'Validation F1 Score', line = dict(color='firebrick', width=4)))\nfig.add_trace(go.Scatter(y = f1, name = 'Training F1 Score', line = dict(color='firebrick', width=4, dash='dash')))\n\nfig.update_layout(title='Trained F1 History', xaxis_title='Epoch', yaxis_title='F1 Macro Score')\n\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Restore Best Weights"},{"metadata":{"trusted":true},"cell_type":"code","source":"clf_model.load_weights('./weights_EffB4.hdf5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Save History Info"},{"metadata":{"trusted":true},"cell_type":"code","source":"hist = pd.DataFrame(history.history)\nhist.to_csv('EffNet_B4_History.csv')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prediction And Submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"clf_model.predict(test_dataset, verbose=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preds = np.argmax(clf_model.predict(test_dataset, verbose=1), axis=1)\ninverted = le.inverse_transform(preds)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df[label_cols] = inverted\nsub_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df.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}