{"cells":[{"metadata":{},"cell_type":"markdown","source":"### This is a simple and minimal TPU baseline + basic EDA + futher Tips to improve."},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install -q efficientnet","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os, cv2\nimport numpy as np\nimport pandas as pd \nimport tensorflow as tf\nfrom kaggle_datasets import KaggleDatasets\nfrom matplotlib import pyplot as plt\nfrom sklearn.model_selection import train_test_split\nimport efficientnet.tfkeras as efn","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# This is basically -1\nAUTO = tf.data.experimental.AUTOTUNE\n\n# Cluster Resolver for Google Cloud TPUs.\ntpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n\n# Connects to the given cluster.\ntf.config.experimental_connect_to_cluster(tpu)\n\n# Initialize the TPU devices.\ntf.tpu.experimental.initialize_tpu_system(tpu)\n\n# TPU distribution strategy implementation.\nstrategy = tf.distribute.experimental.TPUStrategy(tpu)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Basic EDA"},{"metadata":{"trusted":true},"cell_type":"code","source":"home_dir = '../input/cassava-leaf-disease-classification/train_images/'\nprint(\"Total number of train leafs: {}\".format(len(os.listdir(home_dir))))\nimg = cv2.imread(os.path.join(home_dir, os.listdir(home_dir)[0]))\ntrain_csv = pd.read_csv('../input/cassava-leaf-disease-classification/train.csv')\nprint('Number of train_ids: {0}, Number of labeled: {1}'.format(train_csv.image_id.count(),train_csv.label.count())) \nprint(\"Num of null labels:\", train_csv.label.isna().sum()) # all images are labeled\nprint('Image shape:',img.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# labels\ntrain_json = pd.read_json('../input/cassava-leaf-disease-classification/label_num_to_disease_map.json', typ='series')\ntrain_json ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# labels distibution\n\nvalues = train_csv.label.value_counts()\nlabels = ['Cassava Bacterial Blight', 'Cassava Brown Streak Disease', 'Cassava Green Mottle', 'Cassava Mosaic Disease', 'Healthy']\nsizes = [values[0], values[1], values[2], values[3], values[4]]\ncolors = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue']\nexplode = (0, 0, 0, 0, 0.1)  # explode 1st slice\n\n# Plot\nplt.rcParams.update({'font.size': 22})\nplt.figure(figsize=(10,10))\nplt.pie(sizes, explode=explode, labels=labels, colors=colors,\nautopct='%1.1f%%', shadow=True, startangle=140)\n\nplt.axis('equal')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Solution could be upsampling or under sampling, much likely it is to use downsampling and this is baseline so i'll keep it for the next one."},{"metadata":{"trusted":true},"cell_type":"code","source":"# show wample images per class\n\nlabels = ['Cassava Bacterial Blight', 'Cassava Brown Streak Disease', 'Cassava Green Mottle', 'Cassava Mosaic Disease', 'Healthy']\nlabel0 = train_csv[train_csv.label == 0]\nlabel1 = train_csv[train_csv.label == 1]\nlabel2 = train_csv[train_csv.label == 2]\nlabel3 = train_csv[train_csv.label == 3]\nlabel4 = train_csv[train_csv.label == 4]\nlabels_imgs = [label0, label1, label2, label3, label4]\nrandom_index = np.random.randint(0, 100, 3)\n\nfig, axes = plt.subplots(5, 3, figsize = (25, 25))\naxes = axes.ravel()\nindx = 0\n\nfor i, lab in enumerate(labels_imgs):\n    for j, rand_indx in enumerate(random_index):\n        img_path = home_dir + lab.iloc[rand_indx, [0]].values[0]\n        img = cv2.imread(img_path)\n        axes[j+indx].imshow(img)\n        axes[j+indx].set_title(labels[i])\n        axes[j+indx].axis('off')\n    indx = 3 + indx\nplt.subplots_adjust(hspace = 0.4);    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Configurations\n\nIMAGE_SIZE = [512, 512] # default size is 600,800\nEPOCHS = 15\nBATCH_SIZE = 32 * strategy.num_replicas_in_sync\nSEED = 42\nprint(\"Batch size used: \", BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# As TPUs require access to the GCS path\n\nGCS_DS_PATH = KaggleDatasets().get_gcs_path()\n\ndef seed_everything(seed=0):\n    np.random.seed(seed)\n    tf.random.set_seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    os.environ['TF_DETERMINISTIC_OPS'] = '1'\n \ndef format_path(s):\n    return GCS_DS_PATH + \"/train_images/\" +s\n\nseed_everything(SEED)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def decode_image(filename, label=None, image_size=IMAGE_SIZE):\n    bits = tf.io.read_file(filename)\n    image = tf.image.decode_jpeg(bits, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0\n    image = tf.image.resize(image, image_size)\n    return image, label\n    \ndef data_augment(image, label=None):\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_flip_up_down(image)\n    return image, label      ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_paths = train_csv.image_id.apply(format_path).values\ntrain_labels = train_csv.loc[:, 'label'].values\n\ntrain_images, valid_images, train_labels, valid_labels = train_test_split(train_paths, train_labels, test_size=0.15, random_state=SEED)\n\ntrain_dataset = (\ntf.data.Dataset\n.from_tensor_slices((train_images, train_labels))\n.map(decode_image, num_parallel_calls=AUTO)\n.cache()\n# add augs here\n.map(data_augment, num_parallel_calls=AUTO)\n.repeat()\n.shuffle(512)\n.batch(BATCH_SIZE)\n.prefetch(AUTO)\n)\n\nvalid_dataset = (\ntf.data.Dataset\n.from_tensor_slices((valid_images, valid_labels))\n.map(decode_image, num_parallel_calls=AUTO)\n.cache()\n.shuffle(512)\n.batch(BATCH_SIZE)\n.prefetch(AUTO)\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"with strategy.scope(): # load model on TPU\n    model = tf.keras.Sequential([\n        efn.EfficientNetB0(include_top=False, weights='noisy-student', input_shape=[IMAGE_SIZE[0], IMAGE_SIZE[1], 3]), \n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.Dense(128, activation='relu'),\n        tf.keras.layers.Dropout(0.2),\n        tf.keras.layers.Dense(64, activation='relu'),\n        tf.keras.layers.Dropout(0.2),\n        tf.keras.layers.Dense(5, activation='softmax')\n    ])\n    \nmodel.compile(optimizer='Adam',\n             loss='sparse_categorical_crossentropy',\n             metrics=['sparse_categorical_accuracy'])    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"STEPS_PER_EPOCH = train_labels.shape[0] // BATCH_SIZE\nCheckpoint=tf.keras.callbacks.ModelCheckpoint(f\"effnet_b0.h5\", verbose=1, \n                                              mode='min', save_best_only=True, monitor='val_loss') # make sure to save entire model \nhistory = model.fit(train_dataset,\n                    epochs=EPOCHS,\n                    validation_data=valid_dataset,\n                    steps_per_epoch = STEPS_PER_EPOCH,\n                    callbacks=[Checkpoint])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def display_training_curves(training, validation, title, subplot):\n    \"\"\"\n    Source: https://www.kaggle.com/mgornergoogle/getting-started-with-100-flowers-on-tpu\n    \"\"\"\n    if subplot%10==1: # set up the subplots on the first call\n        plt.subplots(figsize=(10,10), facecolor='#F0F0F0')\n        plt.tight_layout()\n    ax = plt.subplot(subplot)\n    ax.set_facecolor('#F8F8F8')\n    ax.plot(training)\n    ax.plot(validation)\n    ax.set_title('model '+ title)\n    ax.set_ylabel(title)\n    #ax.set_ylim(0.28,1.05)\n    ax.set_xlabel('epoch')\n    ax.legend(['train', 'valid.'])\nplt.rcParams.update({'font.size': 10})    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"display_training_curves(\n    history.history['loss'], \n    history.history['val_loss'], \n    'loss', 211)\ndisplay_training_curves(\n    history.history['sparse_categorical_accuracy'], \n    history.history['val_sparse_categorical_accuracy'], \n    'accuracy', 212)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"What can you do next?\n\n* Add Augumentations.\n* Tweak LR, use a different optimizer and a fancy LR Scheduler.\n* Address underfitting, Increase Efficientnet's Size.\n* Balance the class distributions, use focal loss, use more external dataset and try down sampling.\n* With larger models if overfitting try label smoothing, reduce LR and early stopping.\n* Try pretraining using different but relevant dataset.\n* Train diffirent models then make ensembles.\n* Try Psuedo Labelling."}],"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}