{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport json, cv2, os\nimport tensorflow as tf\n\nfrom tensorflow.keras.applications import EfficientNetB3\nfrom tensorflow.keras.applications.resnet50 import preprocess_input\nfrom tensorflow.keras.applications import ResNet50\nfrom tensorflow.keras.optimizers import Adam, SGD, RMSprop\nfrom tensorflow.keras.losses import CategoricalCrossentropy\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.utils import Sequence\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras.preprocessing.image import load_img, img_to_array\n\nfrom tensorflow.keras.layers import Input, Dense, Flatten, ReLU, LeakyReLU,\\\n            Dropout, BatchNormalization, GlobalAvgPool2D, GlobalMaxPool2D, ELU\nfrom tensorflow.keras.models import Model\n\nfrom tensorflow.keras.metrics import CategoricalAccuracy, Accuracy\n\nfrom sklearn.model_selection import KFold, StratifiedKFold\nfrom sklearn.model_selection import train_test_split\nimport albumentations as A","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Setting up the work dir\nWORK_DIR = \"/kaggle/input/cassava-leaf-disease-classification\"\nos.listdir(WORK_DIR)\n\n# Read labels for classes\nwith open(os.path.join(WORK_DIR, 'label_num_to_disease_map.json'), 'r') as file:\n    labels = json.load(file)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Test random image \ndata = pd.read_csv(os.path.join(WORK_DIR, 'train.csv'))\nrand_idx = np.random.randint(data.shape[0])\nrand_fname = data.iloc[rand_idx, 0]\ntrain_images_folder = os.path.join(WORK_DIR, 'train_images')\ntest_images_folder = os.path.join(WORK_DIR, 'test_images')\nrand_fpath = os.path.join(train_images_folder, rand_fname)\n\nImage.open(rand_fpath)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class MyGeneratorUnWeighted(tf.keras.utils.Sequence):\n    def __init__(self, x, y, \n                 batch_size, \n                 img_size, \n                 num_classes,\n                 augment_img,\n                 imgs_folder,\n                 img_preproc=False):\n        self.x, self.y = x, y\n        self.img_height, self.img_width = img_size\n        self.batch_size = batch_size\n        self.img_preproc = img_preproc\n        self.augment_img = augment_img\n        self.num_classes = num_classes\n        self.imgs_folder = imgs_folder\n\n    def __len__(self):\n        return int(np.ceil(len(self.x) / float(self.batch_size)))\n    \n    def _augment(self, img):\n        transform = A.Compose([\n            A.RandomCrop(p=0.5,\n                         width=int(self.img_width / 1.3), \n                         height=int(self.img_height / 1.3)),\n            A.HorizontalFlip(p=0.5),\n            A.VerticalFlip(p=0.5),\n            A.RandomBrightnessContrast(p=0.2, \n                                      brightness_limit=0.1,\n                                      contrast_limit=0.1),\n            A.ShiftScaleRotate(p=0.5),\n            A.RandomRotate90(),\n            A.Blur(p=0.2, blur_limit=2),\n            A.OpticalDistortion(distort_limit=0.2,\n                                shift_limit=0.05,\n                                border_mode=4),\n            A.GridDistortion(distort_limit=0.2, \n                             border_mode=4),\n            A.HueSaturationValue(hue_shift_limit=10,\n                                 sat_shift_limit=30,\n                                 val_shift_limit=40,),\n            A.CLAHE(),\n            A.ImageCompression(quality_lower=85),\n        ])\n        return transform(image=img)['image']\n        \n    def preproc_imgs(self, img):\n        img = img / 255\n        imagenet_mean = [0.485, 0.456, 0.406]\n        imagenet_std = [0.229, 0.224, 0.225]\n        img = (img - np.tile(imagenet_mean, (self.img_height, self.img_width, 1))) /\\\n                     np.tile(imagenet_std, (self.img_height, self.img_width, 1))\n        return img\n\n\n    def __getitem__(self, idx):\n        batch_x = np.zeros((self.batch_size, self.img_height, self.img_width, 3))\n        batch_y = np.zeros(self.batch_size)\n        \n        x = self.x[idx * self.batch_size: (idx + 1) * self.batch_size]\n        y = self.y[idx * self.batch_size: (idx + 1) * self.batch_size]\n        \n        for n, (i, l) in enumerate(zip(x, y)):\n            img = load_img(os.path.join(self.imgs_folder, i))\n            img = img_to_array(img, dtype='uint8')\n            \n            if self.augment_img:\n                img = self._augment(img)\n                \n            img = cv2.resize(img, (self.img_height, self.img_width))\n            \n            if self.img_preproc:\n                img = self.preproc_imgs(img)\n                \n            batch_x[n] = img\n            batch_y[n] = l\n            \n        return batch_x, to_categorical(batch_y, \n                        num_classes=self.num_classes)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Train-test split for experimenting\nx_train, x_test, y_train, y_test =\\\n        train_test_split(data.image_id, data.label, test_size=0.25)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Augmentation setting up\nplt.figure(figsize=(16, 28))\n\nfor n in range(6):\n    plt.subplot(3, 2, n+1)\n    \n    check_gen = MyGeneratorUnWeighted(x_train, y_train, \n                                   batch_size=1, \n                                   img_preproc=None,\n                                   augment_img=True,\n                                   imgs_folder=train_images_folder,\n                                   num_classes=5,\n                                   img_size=(384, 384))\n    \n    check_img = check_gen.__getitem__(0)[0][0] / 255\n\n    plt.imshow(check_img);\n    plt.axis('off')\nplt.show();","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"net_cfg = {\n    'num_classes': 5,\n    'img_height': 512,\n    'img_width': 512,\n    'img_channels': 3,\n    'batch_size': 8,\n    'backbone': EfficientNetB3(include_top=False, weights=None),\n    'preproc_img': True,\n    'augment_img': True,\n    'num_epochs': 5,\n    'class_weights': None,\n    'num_folds': 3,\n    'backbone_trainable': True,\n    'use_dropout': True,\n    'activation': ELU(),\n    'opt': Adam(lr=0.0001),\n    'criterion': CategoricalCrossentropy(),\n    'metrics': [CategoricalAccuracy()]\n}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class CassavaNet():\n    def __init__(self, model_name, net_cfg, \n                 x_train, y_train,\n                 x_test, y_test):\n        self.model_name = model_name\n        self.num_classes = net_cfg['num_classes']\n        self.batch_size = net_cfg['batch_size']\n        self.img_height = net_cfg['img_height']\n        self.img_width = net_cfg['img_width']\n        self.img_channels = net_cfg['img_channels']\n        self.preproc_img = net_cfg['preproc_img']\n        self.augment_img = net_cfg['augment_img']\n        self.backbone = net_cfg['backbone']\n        self.backbone.trainable = net_cfg['backbone_trainable']\n            \n        inputs = Input(shape=(self.img_height, \n                              self.img_width, \n                              self.img_channels))\n        \n        x = BatchNormalization()(inputs)\n    \n        x = self.backbone(x)\n        x = GlobalAvgPool2D()(x)\n        x = Dense(64)(x)\n        x = BatchNormalization()(x)\n        x = net_cfg['activation'](x)\n        \n        if net_cfg['use_dropout']:\n            x = Dropout(0.05)(x)\n\n        outputs = Dense(self.num_classes, \n                        activation='softmax')(x)\n    \n        self.model = Model(inputs, outputs)\n        self.opt = net_cfg['opt']\n        self.criterion = net_cfg['criterion']\n        self.metrics = net_cfg['metrics']\n        self.class_weights = net_cfg['class_weights']\n        self.x_train = x_train\n        self.y_train = y_train\n        self.x_test = x_test\n        self.y_test = y_test\n        \n        cb_tensorboard = tf.keras.callbacks.TensorBoard(log_dir='./logs', )\n        cb_checpoint = tf.keras.callbacks.ModelCheckpoint(filepath=self.model_name + '.weights.hdf5',\n                                                      monitor='val_loss',\n                                                      verbose=1,\n                                                      save_best_only=True)\n        cb_earlystop = tf.keras.callbacks.EarlyStopping(monitor='val_loss',\n                                                        patience=4,\n                                                        verbose=0,\n                                                        restore_best_weights=True)\n        self.callbacks = [cb_checpoint, cb_earlystop]\n    \n        \n        self.traingen = MyGeneratorUnWeighted(self.x_train, self.y_train, \n                               batch_size=self.batch_size, \n                               img_preproc=self.preproc_img,\n                               augment_img=self.augment_img,\n                               imgs_folder=train_images_folder,\n                               num_classes=self.num_classes,\n                               img_size=(self.img_height, self.img_width))\n        self.testgen = MyGeneratorUnWeighted(self.x_test, self.y_test,               \n                              batch_size=self.batch_size, \n                              img_preproc=self.preproc_img,\n                              augment_img=False,\n                              imgs_folder=train_images_folder,\n                              num_classes=self.num_classes,\n                              img_size=(self.img_height, self.img_width))\n        \n        print(self.model.summary())\n            \n    def _compile(self):\n        self.model.compile(optimizer=self.opt, \n                           loss=self.criterion,\n                           metrics=self.metrics)\n    \n    def train(self):\n        self._compile()\n        \n        self.history = self.model.fit_generator(generator=self.traingen,                                 \n                                    steps_per_epoch=self.traingen.__len__(),\n                                    epochs=net_cfg['num_epochs'],\n                                    validation_data=self.testgen,\n                                    validation_steps=self.testgen.__len__(),\n                                    workers=-1,\n                                    callbacks=self.callbacks, \n                                    class_weight=self.class_weights\n                                               )\n        \n    def visualize_batch(self):\n        gentest_images, gentest_labels = self.traingen.__getitem__(0)\n        gentest_images = gentest_images[:16]\n\n        plt.figure(figsize=(16, 16))\n\n        for n, (i, l) in enumerate(zip(gentest_images, gentest_labels)):\n            plt.subplot(4, 4, n+1)\n            plt.imshow(i * 255 + 127.5)\n            plt.axis('off')\n\n        plt.show();\n        \n    def plot_hist(self):\n        if self.history:\n            plt.figure(figsize=(16, 16))\n            fig, axes = plt.subplots(nrows=1, ncols=2)\n            ax1, ax2 = axes\n            \n            ax1.plot(self.history.history['loss'],\n                     label='Loss')\n            ax1.plot(self.history.history['val_loss'],\n                    label='Val Loss')\n            ax1.legend()\n            \n            ax2.plot(self.history.history['categorical_accuracy'],\n                     label='Categorical Accuracy')\n            ax2.plot(self.history.history['val_categorical_accuracy'],\n                    label='Val Categorical Accuracy')\n            ax2.legend()\n            \n            plt.show();","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"# Run training\nskf = StratifiedKFold(n_splits=net_cfg['num_folds'], \n                      random_state=None, \n                      shuffle=True)\n\nfor fold, (train_skf_idx, test_skf_idx) in enumerate(skf.split(data.image_id, data.label)):\n    print(f'...Fold # {fold}...')\n    x_train = data.iloc[train_skf_idx, 0]\n    y_train = data.iloc[train_skf_idx, 1]\n    x_test = data.iloc[test_skf_idx, 0]\n    y_test = data.iloc[test_skf_idx, 1]\n    \n    cassava_net = CassavaNet('m'+str(fold), net_cfg, \n                             x_train[:], y_train[:],\n                             x_test[:], y_test[:])\n    \n    cassava_net.train()\n    \n    del cassava_net","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def preproc_imgs(fname):\n    img = load_img(fname)\n    img = img_to_array(img, dtype='uint8')\n    img = cv2.resize(img, (net_cfg['img_height'], net_cfg['img_width']))\n    img = img / 255\n    imagenet_mean = [0.485, 0.456, 0.406]\n    imagenet_std = [0.229, 0.224, 0.225]\n    img = (img - np.tile(imagenet_mean, (net_cfg['img_height'], net_cfg['img_width'], 1))) /\\\n                 np.tile(imagenet_std, (net_cfg['img_height'], net_cfg['img_width'], 1))\n    img = np.expand_dims(img, axis=0)\n    return img","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict_ensemble(num_models, test_imgs_folder):\n    models_preds = []\n    fnames = os.listdir(test_imgs_folder)\n    \n    with open('submission.csv', 'w') as submission:\n        submission.write('image_id,label\\n')\n        \n        for m in range(num_models):\n            models_preds.append([])\n            cassava_net = CassavaNet('m' + str(m), net_cfg, \n                                 x_train[:], y_train[:],\n                                 x_test[:], y_test[:])\n\n            cassava_net.model.reset_states()\n\n            cassava_net.model.load_weights('m' + str(m) + '.weights.hdf5')\n\n            for fname in fnames:\n                fname = os.path.join(test_imgs_folder, fname)\n                img = preproc_imgs(fname)            \n                prediction = np.argmax(cassava_net.model.predict(img), axis=1)[0]\n                models_preds[m].append(prediction)\n                \n        models_preds = np.array(models_preds).T\n        \n        for num, fname in enumerate(fnames):\n            this_pred = np.argmax(np.bincount(models_preds[num]))\n            submission.write(f'{fname},{this_pred}\\n')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predict_ensemble(net_cfg['num_folds'], test_images_folder)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!head submission.csv","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}