{"cells":[{"metadata":{},"cell_type":"markdown","source":"- A simple prototype\n- Efficientnet-b0\n- 10 epochs/32 batch_size\n- ReduceLROnPlateau\n- RandomCrop and Flip\n- Smooth label"},{"metadata":{},"cell_type":"markdown","source":"# 1. Import Packages"},{"metadata":{"trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport gc, cv2, os, warnings, random, time, math, json\nfrom tqdm import tqdm\nfrom sklearn.metrics import *\nfrom sklearn.model_selection import StratifiedKFold\n\nwarnings.filterwarnings(\"ignore\")\ninput_path = \"/kaggle/input/\"\noutput_path = \"/kaggle/working/\"","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import tensorflow as tf\nimport tensorflow.keras as keras\nimport tensorflow.keras.backend as K\nfrom tensorflow.keras.models import *\nfrom tensorflow.keras.layers import *\nfrom tensorflow.keras.optimizers import *\nfrom tensorflow.keras.optimizers.schedules import *\nfrom tensorflow.keras.activations import *\nfrom tensorflow.keras.losses import *\nfrom tensorflow.keras.metrics import *\nfrom tensorflow.keras.callbacks import *\nfrom tensorflow.keras.regularizers import *\nfrom tensorflow.keras.initializers import *\nfrom tensorflow.keras.utils import get_custom_objects","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install efficientnet\n!pip install image-classifiers==1.0.0b1\n\nfrom tensorflow.keras.applications import *\nfrom efficientnet.tfkeras import *\nfrom classification_models.tfkeras import Classifiers","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.mixed_precision import experimental\n\nexperimental.set_policy(experimental.Policy(\"mixed_float16\"))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"SEED = 2020\nos.environ[\"TF_DETERMINISTIC_OPS\"] = \"1\"\nos.environ[\"PYTHONHASHSEED\"] = str(SEED)\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 2. Preprocess Dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"def preprocess(target_size=(224, 224), augment=False):\n    size = (int(target_size[0] * 8 / 7), int(target_size[1] * 8 / 7))\n    \n    def _preprocess(filename, label):\n        image = tf.io.read_file(filename)\n        image = tf.image.decode_jpeg(image, channels=3)\n        image = tf.image.resize(image, size, method=tf.image.ResizeMethod.BICUBIC)\n        if augment:\n            image = tf.image.random_crop(image, (*target_size, 3))\n            image = tf.image.random_flip_left_right(image)\n            image = tf.image.random_flip_up_down(image)\n        else:\n            image = tf.image.central_crop(image, target_size[0] / size[0])\n        image = tf.clip_by_value(image, 0., 255.)\n        image = image / 255.\n        return image, label\n\n    return _preprocess\n\n\nclass CustomDataset(object):\n    def __init__(self, folds=5, fold=0, target_size=(224, 224), batch_size=32):\n        self.target_size = target_size\n        self.batch_size = batch_size\n        \n        self.autotune = tf.data.experimental.AUTOTUNE\n        self.table = pd.read_csv(input_path + \"cassava-leaf-disease-classification/train.csv\").values\n        self.classes = json.load(open(input_path + \"cassava-leaf-disease-classification/label_num_to_disease_map.json\", 'r'))\n        \n        filenames, labels = [], []\n        for i, j in self.table:\n            filenames.append(input_path + \"cassava-leaf-disease-classification/train_images/%s\" % i)\n            labels.append(j)\n        filenames, labels = np.asarray(filenames), np.asarray(labels)\n\n        split = StratifiedKFold(n_splits=folds, shuffle=True, random_state=SEED).split(filenames, labels)\n        labels = np.eye(len(self.classes))[labels].astype(np.float32)\n        for i in range(fold): next(split)\n        train_indices, val_indices = next(split)\n        self.train_len, self.val_len = len(train_indices), len(val_indices)\n        self.train_filenames, self.train_labels = filenames[train_indices], labels[train_indices]\n        self.val_filenames, self.val_labels = filenames[val_indices], labels[val_indices]\n        del filenames, labels, split, train_indices, val_indices \n        gc.collect()\n        \n        print(\"Number of train:\", self.train_len, \"\\nNumber of val:\", self.val_len)\n\n    def __len__(self):\n        return self.train_len + self.val_len\n    \n    def getTrainDataset(self):\n        return (tf.data.Dataset.from_tensor_slices((self.train_filenames, self.train_labels))\n                .shuffle(buffer_size=self.train_len, seed=SEED)\n                .cache()\n                .map(preprocess(target_size=self.target_size, augment=True), num_parallel_calls=self.autotune)\n                .batch(self.batch_size)\n                .prefetch(buffer_size=self.autotune)), self.train_len\n    \n    def getValidDataset(self):\n        return (tf.data.Dataset.from_tensor_slices((self.val_filenames, self.val_labels))\n                .map(preprocess(target_size=self.target_size), num_parallel_calls=self.autotune)\n                .batch(self.batch_size)\n                .cache()\n                .prefetch(buffer_size=self.autotune)), self.val_len\n    \n    def getClasses(self):\n        return self.classes","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 3. Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"class CustomClassifier(object):\n    def __init__(self, dataset):\n        self.train_dataset, self.train_len = dataset.getTrainDataset()\n        self.val_dataset, self.val_len = dataset.getValidDataset()\n        self.classes = list(dataset.getClasses().values())\n\n    def build(self, input_shape=(128, 128, 3)):\n        self.target_size = input_shape[:-1]\n        pretrained = EfficientNetB0(weights=\"imagenet\", include_top=False)\n        for layer in pretrained.layers: layer.trainable = True\n\n        i = Input(shape=input_shape)\n        x = pretrained(i)\n        x = GlobalAveragePooling2D()(x)\n        x = Dense(len(self.classes), use_bias=True)(x)\n        o = Activation(\"softmax\", dtype=\"float32\")(x)\n\n        self.clf = Model(i, o)\n        self.clf.compile(\n            optimizer=Adam(1e-4),\n            loss=lambda x, y: categorical_crossentropy(x, y, label_smoothing=0.1),\n            metrics=[\"accuracy\"]\n        )\n        self.clf.summary()\n        \n    def fit(self, epochs=100, batch_size=32):\n        self.clf.fit(\n            self.train_dataset, validation_data=self.val_dataset,\n            epochs=epochs, verbose=1,\n            callbacks=[\n                CSVLogger(output_path + \"history.csv\", separator=',', append=False),\n                ModelCheckpoint(output_path + \"model_check.h5\", save_best_only=True, save_weights_only=True, monitor=\"val_loss\"),\n            ],\n        )\n\n    def predict(self):\n        def metricsPrint(yTrue, yPred, classes):\n            print(classification_report(yTrue, yPred, target_names=classes, digits=4))\n\n        def cmDraw(yTrue, yPred, classes):\n            cm = confusion_matrix(yTrue, yPred, labels=range(len(classes)))\n            df = pd.DataFrame(cm, index=classes, columns=classes)\n            plt.figure(figsize=(len(classes) + 3, len(classes) + 3))\n            sns.heatmap(df, annot=True, fmt=\"d\", cmap=plt.cm.Blues)\n            plt.show()\n        \n        preds, targets = [], []\n        for i in self.val_dataset:\n            preds += list(np.argmax(self.clf.predict(i[0]), axis=-1))\n            targets += list(np.argmax(i[1].numpy(), axis=-1))\n        preds, targets = np.asarray(preds, dtype=np.int), np.asarray(targets, dtype=np.int)\n                            \n        metricsPrint(targets, preds, self.classes)\n        cmDraw(targets, preds, self.classes)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# 4. Fit"},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset = CustomDataset(folds=5, fold=0, target_size=(224, 224), batch_size=32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classifier = CustomClassifier(dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classifier.build(input_shape=(224, 224, 3))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classifier.fit(epochs=10, batch_size=32)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classifier.predict()","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}