{"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":"# IMPORTS","metadata":{}},{"cell_type":"code","source":"import time\nstart = time.time()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport json\nfrom collections import Counter\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport itertools\nimport keras\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import GlobalAveragePooling2D, Flatten, Dense, Dropout, BatchNormalization\nfrom tensorflow.keras.optimizers import RMSprop, Adam, SGD\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\nfrom sklearn.model_selection import train_test_split\nfrom keras.preprocessing.image import ImageDataGenerator\n\nprint(\"Tensorflow version \" + tf.__version__)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"work_dir = '/kaggle/input/cassava-leaf-disease-classification/'\nos.listdir(work_dir) \ntrain_path = '/kaggle/input/cassava-leaf-disease-classification/train_images'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Labels","metadata":{}},{"cell_type":"code","source":"data = pd.read_csv(work_dir + 'train.csv')\nprint(Counter(data['label']))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data['label'].hist()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Add class name","metadata":{}},{"cell_type":"code","source":"file = open(work_dir + 'label_num_to_disease_map.json')\nreal_labels = json.load(file)\nreal_labels = {int(k):v for k,v in real_labels.items()}\n\n# Head\ndata['class_name'] = data.label.map(real_labels)\nprint(data.head(10))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(data['class_name'].unique())","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Show img classes","metadata":{}},{"cell_type":"code","source":"def show_img(images):\n    # 16 random images\n    random_images = [np.random.choice(images) for i in range(16)]\n\n    # Change size\n    plt.figure(figsize=(16,12))\n\n    # Plot\n    for i in range(16):\n        plt.subplot(4, 4, i + 1)\n        img = plt.imread(train_path + '/' + random_images[i])\n        plt.imshow(img)\n        plt.axis('off')\n\n    # Padding\n    plt.tight_layout()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask = data['label'] == 4\nclass_healthy = data[mask]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_img(class_healthy['image_id'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask = data['label'] == 3\nclassCMD = data[mask]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_img(classCMD['image_id'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask = data['label'] == 2\nclassCGM = data[mask]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_img(classCGM['image_id'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask = data['label'] == 1\nclassCBSD = data[mask]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_img(classCBSD['image_id'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask = data['label'] ==0\nclassCBB = data[mask]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_img(classCBB['image_id'])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Generation","metadata":{}},{"cell_type":"code","source":"# 90% of class\nclass0 = classCBB.sample(frac=0.9)\nclass1 = classCBSD.sample(frac=0.9)\nclass2 = classCGM.sample(frac=0.9)\nclass3 = classCMD.sample(frac=0.9)\nclass4 = class_healthy.sample(frac=0.9)\n\n# concat\nframes=[class0,class1,class2,class3,class4]\nfinalData = pd.concat(frames)\nprint('images =',len(finalData))\n\n# train_test_split with proportions(stratify)\ntrain,val = train_test_split(finalData, test_size = 0.05, random_state = 42, stratify = finalData['class_name'])\n\n# Creating additional data\nIMG_SIZE = 300\nsize = (IMG_SIZE,IMG_SIZE)\nn_CLASS = 5\n\ndatagen = ImageDataGenerator(\n    # appropriate\n    preprocessing_function = tf.keras.applications.efficientnet.preprocess_input,\n\n    # params\n    rotation_range = 60,\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    vertical_flip = True,\n    fill_mode = 'nearest')\n\n# initialize\ntrain_set = datagen.flow_from_dataframe(\n    train,\n    directory = train_path,\n    seed=42,\n    x_col = 'image_id',\n    y_col = 'class_name',\n    target_size = size,\n    class_mode = 'categorical',\n    interpolation = 'nearest',\n    shuffle = True,\n    batch_size = 32)\n\n# initialize\nval_set = datagen.flow_from_dataframe(\n    val,\n    directory = train_path,\n    seed=42,\n    x_col = 'image_id',\n    y_col = 'class_name',\n    target_size = size,\n    class_mode = 'categorical',\n    interpolation = 'nearest',\n    shuffle = True,\n    batch_size = 32)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def create_model():\n    model = Sequential()\n    model.add(tf.keras.applications.EfficientNetB3(input_shape = (IMG_SIZE, IMG_SIZE, 3), include_top = False, weights = 'imagenet', drop_connect_rate=0.6))\n    model.add(GlobalAveragePooling2D())\n    model.add(Flatten())\n    model.add(Dense(256, activation='relu', bias_regularizer=tf.keras.regularizers.L1L2(l1=0.01, l2=0.001)))\n    model.add(Dropout(0.5))\n    model.add(Dense(n_CLASS, activation = 'softmax'))\n    \n    return model\n\nleaf_model = create_model()\nleaf_model.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Fit","metadata":{}},{"cell_type":"code","source":"# steps\nEPOCHS = 15\nSTEP_SIZE_TRAIN = train_set.n//train_set.batch_size\nSTEP_SIZE_VALID = val_set.n//val_set.batch_size","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def Model_fit():\n    leaf_model = create_model()\n    \n    loss = tf.keras.losses.CategoricalCrossentropy(from_logits = False,\n                                                   label_smoothing=0.001,\n                                                   name='categorical_crossentropy')\n    \n    leaf_model.compile(optimizer = Adam(learning_rate = 2e-4),\n                        loss = loss,\n                        metrics = ['categorical_accuracy'])\n    \n    # Stopper\n    es = EarlyStopping(monitor='val_loss', mode='min', patience=5,\n                       restore_best_weights=True, verbose=1)\n    \n    # Save\n    checkpoint_cb = ModelCheckpoint('Cassava_model_best'+'.h5',\n                                    save_best_only=True,\n                                    monitor = 'val_loss',\n                                    mode='min')\n    \n    # Reduce learning rate\n    reduce_lr = ReduceLROnPlateau(monitor = 'val_loss',\n                                  factor = 0.3,\n                                  patience = 3,\n                                  min_lr = 1e-6,\n                                  mode = 'min',\n                                  verbose = 1)\n    \n    history = leaf_model.fit(train_set,\n                             validation_data = val_set,\n                             epochs= EPOCHS,\n                             batch_size = 32,\n                             steps_per_epoch = STEP_SIZE_TRAIN,\n                             validation_steps = STEP_SIZE_VALID,\n                             callbacks=[es, checkpoint_cb, reduce_lr])\n    \n    leaf_model.save('Cassava_model'+'.h5')\n    \n    return history","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def run_with_tpu():\n    # detect TPU\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n\n    # strategy\n    tpu_strategy = tf.distribute.experimental.TPUStrategy(tpu)\n    \n    with tpu_strategy.scope():\n        history = Model_fit()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"run_with_tpu()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Plot","metadata":{}},{"cell_type":"code","source":"acc = history.history['categorical_accuracy']\nval_acc = history.history['val_categorical_accuracy']\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs_range = range(EPOCHS)\n\nplt.figure(figsize=(8, 8))\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Training Accuracy')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy')\nplt.legend(loc='lower right')\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Training Loss')\nplt.plot(epochs_range, val_loss, label='Validation Loss')\nplt.legend(loc='upper right')\nplt.title('Training and Validation Loss')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Time","metadata":{}},{"cell_type":"code","source":"end = time.time()\nhours, rem = divmod(end-start, 3600)\nminutes, seconds = divmod(rem, 60)\nprint(\"{:0>2}:{:0>2}:{:05.2f}\".format(int(hours),int(minutes),seconds))","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}