{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\nimport numpy as np\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.applications import EfficientNetB4\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.layers import Dense, Dropout, Flatten,GlobalAveragePooling2D, BatchNormalization, Activation\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\n\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, classification_report\n\nimport glob\nimport os","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"#Constants\n\nBATCH_SIZE = 8\nSEED = 42\n\nos.environ['PYTHONHASHSEED'] = str(SEED)\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv('../input/cassava-leaf-disease-classification/train.csv')\ndf['path'] = '../input/cassava-leaf-disease-classification/train_images/' + df['image_id']\ndf.label.value_counts(normalize=True) * 100","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.label.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# size_per_label = 1000\n# g = df.groupby(\"label\")\n# df = g.apply(lambda x : x.sample(size_per_label, random_state = SEED)).reset_index(drop = True)\n# df.label.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train, X_valid = train_test_split(df, stratify = df.label, test_size = 0.1, random_state = SEED, shuffle=True)\n\ntrain_ds = tf.data.Dataset.from_tensor_slices((X_train.path.values, X_train.label.values))\nvalid_ds = tf.data.Dataset.from_tensor_slices((X_valid.path.values, X_valid.label.values))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\ntarget_size_dim = 512\n\ndef process_data_train(image_path, label):\n    # load the raw data from the file as a string\n    img = tf.io.read_file(image_path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.random_brightness(img, 0.3)\n    img = tf.image.random_flip_left_right(img, seed=None)\n    img = tf.image.random_flip_up_down(img)\n    img = tf.image.random_crop(img, size=[target_size_dim, target_size_dim, 3])\n    return img, label\n\ndef process_data_valid(image_path, label):\n    # load the raw data from the file as a string\n    img = tf.io.read_file(image_path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, [target_size_dim,target_size_dim])\n    return img, label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Set `num_parallel_calls` so multiple images are loaded/processed in parallel.\ntrain_ds = train_ds.map(process_data_train, num_parallel_calls=AUTOTUNE)\nvalid_ds = valid_ds.map(process_data_valid, num_parallel_calls=AUTOTUNE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for image, label in train_ds.take(1):\n    plt.imshow(image.numpy().astype('uint8'))\n    plt.show()\n    print(\"Image shape: \", image.numpy().shape)\n    print(\"Label: \", label.numpy())\n    \nfor image, label in train_ds.take(1):\n    plt.imshow(image.numpy().astype('uint8'))\n    plt.show()\n    print(\"Image shape: \", image.numpy().shape)\n    print(\"Label: \", label.numpy())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def configure_for_performance(ds, batch_size = 32):\n    ds = ds.cache('/kaggle/dump.tfcache') \n    \n    ds = ds.shuffle(buffer_size=1024)\n    ds = ds.batch(batch_size)\n    ds = ds.prefetch(buffer_size=AUTOTUNE)\n    return ds\n\nbatch_size = 8\n\ntrain_ds_batch = configure_for_performance(train_ds, batch_size)\nvalid_ds_batch = valid_ds.batch(batch_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"image_batch, label_batch = next(iter(train_ds_batch))\n\nplt.figure(figsize=(10, 10))\nfor i in range(8):\n    ax = plt.subplot(4, 4, i + 1)\n    plt.imshow(image_batch[i].numpy().astype(\"uint8\"))\n    label = label_batch[i].numpy()\n    plt.title(label)\n    plt.axis(\"off\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_augmentation = keras.Sequential(\n    [\n        tf.keras.layers.experimental.preprocessing.RandomRotation(0.2),\n        tf.keras.layers.experimental.preprocessing.RandomFlip(\"horizontal_and_vertical\")\n    ]\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"base_model = EfficientNetB4(weights='imagenet', include_top=False, drop_connect_rate=0.4)\nbase_model.trainable = False\n    \ninputs = tf.keras.layers.Input(shape = (target_size_dim, target_size_dim, 3))\nx = data_augmentation(inputs)\nx = base_model(x, training = False)\nx = GlobalAveragePooling2D()(x)\nx = Dense(256)(x)\nx = BatchNormalization()(x)\nx = Activation('relu')(x)\nx = Dropout(0.3)(x)\nx = Dense(5)(x)\noutputs = Activation('softmax', dtype = 'float32', name = 'predictions')(x)\n\nmodel = tf.keras.Model(inputs, outputs)\n    \nmodel.compile(optimizer = tf.keras.optimizers.Adam(lr = 1e-4),\n              loss = 'sparse_categorical_crossentropy',\n              metrics = ['sparse_categorical_accuracy'])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"weight_path_save = 'best_model.hdf5'\nlast_weight_path = 'last_model.hdf5'\n\ncheckpoint = ModelCheckpoint(\n                                weight_path_save, \n                                monitor= 'val_loss', \n                                verbose=1, \n                                save_best_only=True, \n                                mode= 'min', \n                                save_weights_only = False\n                            )\n\ncheckpoint_last = ModelCheckpoint(\n                                    last_weight_path, \n                                    monitor= 'val_loss', \n                                    verbose=1, \n                                    save_best_only=False, \n                                    mode= 'min', \n                                    save_weights_only = False\n                                 )\n\n\nearly = EarlyStopping(\n                        monitor = 'val_loss', \n                        mode = 'min', \n                        patience = 5\n                     )\n\nreduceLROnPlat = ReduceLROnPlateau(\n                                    monitor='val_loss',\n                                    factor=0.8,\n                                    patience=2,\n                                    verbose=1,\n                                    mode='auto',\n                                    epsilon=0.0001,\n                                    cooldown=5,\n                                    min_lr=0.00001\n                                  )\n\ncallbacks_list = [checkpoint, checkpoint_last, early, reduceLROnPlat]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epochs = 4\n\nhistory = model.fit(train_ds_batch, \n                    validation_data = valid_ds_batch,\n                    epochs = epochs, \n                    callbacks = callbacks_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def plot_hist(hist):\n    plt.figure(figsize=(15,5))\n    local_epochs = len(hist.history[\"sparse_categorical_accuracy\"])\n    plt.plot(np.arange(local_epochs, step=1), hist.history[\"sparse_categorical_accuracy\"], '-o', label='Train Accuracy',color='#ff7f0e')\n    plt.plot(np.arange(local_epochs, step=1), hist.history[\"val_sparse_categorical_accuracy\"], '-o',label='Val Accuracy',color='#1f77b4')\n    plt.xlabel('Epoch',size=14)\n    plt.ylabel('Accuracy',size=14)\n    plt.legend(loc=2)\n    \n    plt2 = plt.gca().twinx()\n    plt2.plot(np.arange(local_epochs, step=1) ,history.history['loss'],'-o',label='Train Loss',color='#2ca02c')\n    plt2.plot(np.arange(local_epochs, step=1) ,history.history['val_loss'],'-o',label='Val Loss',color='#d62728')\n    plt.legend(loc=3)\n    plt.ylabel('Loss',size=14)\n    plt.title(\"Model Accuracy and loss\")\n    \n    plt.savefig('loss.png')\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#plot_hist(history)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"base_model.trainable = True\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(optimizer = tf.keras.optimizers.RMSprop(lr = 1e-5),\n              loss = 'sparse_categorical_crossentropy',\n              metrics = ['sparse_categorical_accuracy'])\n\nfine_tune_epochs = 6\ntotal_epochs = epochs + fine_tune_epochs\n\nhistory_fine = model.fit(train_ds_batch,\n                         epochs = total_epochs,\n                         initial_epoch = history.epoch[-1] + 1,\n                         validation_data = valid_ds_batch,\n                         callbacks = callbacks_list)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"acc = history.history['sparse_categorical_accuracy'] + history_fine.history['sparse_categorical_accuracy']\nval_acc = history.history['val_sparse_categorical_accuracy'] + history_fine.history['val_sparse_categorical_accuracy']\n\nloss = history.history['loss'] + history_fine.history['loss']\nval_loss = history.history['val_loss'] + history_fine.history['val_loss']\n\nplt.figure(figsize=(8, 8))\nplt.subplot(2, 1, 1)\nplt.plot(acc, label='Training Accuracy')\nplt.plot(val_acc, label='Validation Accuracy')\nplt.ylim([0.65, 0.9])\nplt.plot([epochs-1,epochs-1],\n          plt.ylim(), label='Start Fine Tuning')\nplt.legend(loc='lower right')\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(2, 1, 2)\nplt.plot(loss, label='Training Loss')\nplt.plot(val_loss, label='Validation Loss')\nplt.ylim([0.3, 0.9])\nplt.plot([epochs-1,epochs-1],\n         plt.ylim(), label='Start Fine Tuning')\nplt.legend(loc='upper right')\nplt.title('Training and Validation Loss')\nplt.xlabel('epoch')\nplt.savefig('loss.png')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.load_weights(weight_path_save) ## load the best model or all your metrics would be on the last run not on the best one\npred_valid_y = model.predict(valid_ds_batch, workers=4, verbose = True)\npred_valid_y_labels = np.argmax(pred_valid_y, axis=-1)\n\nvalid_labels = np.concatenate([y.numpy() for x, y in valid_ds_batch], axis=0)\n\nprint(classification_report(valid_labels, pred_valid_y_labels ))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import json\nwith open('../input/cassava-leaf-disease-classification/label_num_to_disease_map.json') as file:\n    print(json.dumps(json.loads(file.read()), indent=4))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cm = confusion_matrix(valid_labels, pred_valid_y_labels )\ncm = cm / cm.sum(axis = 1, keepdims = True)\n\ndesc = np.array([\"CBB\", \"CBSD\", \"CGM\", \"CMD\", \"Healthy\"])\ncm = pd.DataFrame(data = cm, index = desc, columns = desc)\n\nimport seaborn as sns\nsns.heatmap(cm, annot = True, cmap = \"rocket_r\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import glob\n\ntest_images = glob.glob('../input/cassava-leaf-disease-classification/test_images/*.jpg')\ndf_test = pd.DataFrame(np.array(test_images), columns=['Path'])\n\ntest_ds = tf.data.Dataset.from_tensor_slices((df_test.Path.values))\n\n\ndef process_test(image_path):\n    # load the raw data from the file as a string\n    img = tf.io.read_file(image_path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.random_brightness(img, 0.3)\n    img = tf.image.random_flip_left_right(img, seed=None)\n    img = tf.image.random_flip_up_down(img)\n    img = tf.image.random_crop(img, size=[target_size_dim, target_size_dim, 3])\n    return img\n    \ntest_ds = test_ds.map(process_test, num_parallel_calls=AUTOTUNE).batch(batch_size*2)\n\npreds = []\nfor i in range(5):\n    \n    pred_test = model.predict(test_ds, workers=16, verbose=1)\n    preds.append(pred_test)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred_y = np.mean(preds, axis=0)\n\npred_y_argmax = np.argmax(pred_y, axis=-1)\n\ndf_test['image_id'] = df_test.Path.str.split('/').str[-1]\ndf_test['label'] = pred_y_argmax\ndf_test= df_test[['image_id','label']]\n\ndf_test.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}