{"cells":[{"metadata":{},"cell_type":"markdown","source":"This is my first kaggle competition using FastAI\n\n**Note** This notebook is incomplete with loads of comments & test code. I am just trying to play around and learn. If there are better way to do things then please comment below. \n\nv3: using Keras and EfficientNet as a model - public LB pending\n\nv2: used resnet50 with 12 epochs -- public LB 0.103 score - no difference, need to change the image model \n\nv1: used resnet50 with default params and 3 epochs -- public LB 0.103 score"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Import libraries "},{"metadata":{"trusted":true},"cell_type":"code","source":"import os, warnings\nimport json\nimport glob\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom matplotlib import gridspec\nimport numpy as np\nimport tensorflow as tf\nimport tensorflow_hub as hub\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# Set Matplotlib defaults\nplt.rc('figure', autolayout=True)\nplt.rc('axes', labelweight='bold', labelsize='large',\n       titleweight='bold', titlesize=18, titlepad=10)\nplt.rc('image', cmap='magma')\nwarnings.filterwarnings(\"ignore\") # to clean up output cells\n\n# import fastai; \n# from fastai.vision.all import *\n# from fastai.vision.learner import cnn_learner, create_head, create_body, num_features_model, default_split, has_pool_type, apply_init, load_learner\n\n# %config IPCompleter.greedy=True\n\n# fastai.__version__\n\nprint(\"Libraries loaded...\")\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load the files\n\nLoad the json"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"BASE_DIR = \"../input/cassava-leaf-disease-classification/\"\n\n# read the json file with disease infection \nwith open(os.path.join(BASE_DIR, \"label_num_to_disease_map.json\")) as file:\n    map_classes = json.loads(file.read())\n    \nprint(json.dumps(map_classes, indent=4))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load the train dataset via csv"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train = pd.read_csv(os.path.join(BASE_DIR, \"train.csv\"))\n\ndf_train[\"class_name\"] = df_train[\"label\"].astype(str).map(map_classes)\ndf_train[\"label\"] = df_train[\"label\"].astype(str)\n\ndf_train","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train.groupby(df_train.label).count()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_img = (os.path.join(BASE_DIR, \"train_images\"))\ntest_img = (os.path.join(BASE_DIR, \"test_images\"))\n#img_path = '../input/cassava-leaf-disease-classification/train_images/'\ntrain_img, test_img\n# img_files = get_image_files(img)\n# img_files","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Using Keras and EfficientNet "},{"metadata":{"trusted":true},"cell_type":"code","source":"imageDataGenerator = ImageDataGenerator(rescale=1/255.,\n                                        rotation_range=45,\n                                        horizontal_flip=True,\n                                        vertical_flip=True,\n                                        zoom_range=0.2,\n                                        shear_range=10,\n                                        validation_split=0.2,\n                                       )\n\ntrain_set = imageDataGenerator.flow_from_dataframe(dataframe=df_train,\n                                                    directory=train_img,\n                                                    x_col=\"image_id\",\n                                                    y_col=\"label\",\n                                                    target_size=(100, 100),\n                                                    batch_size=32,\n                                                    class_mode=\"sparse\",\n                                                    subset='training',\n                                                    shuffle=True,\n                                                    seed=42\n                                                )\n\n                                       \nval_set = imageDataGenerator.flow_from_dataframe(dataframe=df_train,\n                                                    directory=train_img,\n                                                    x_col=\"image_id\",\n                                                    y_col=\"label\",\n                                                    target_size=(100, 100),\n                                                    batch_size=32,\n                                                    class_mode=\"sparse\",\n                                                    subset='validation',\n                                                    shuffle=True,\n                                                    seed=42\n                                                )\n\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prepare the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.layers import Dense, InputLayer, Dropout\nfrom tensorflow.keras.optimizers import Adam\n\n# MODULE_HANDLE = \"https://tfhub.dev/tensorflow/efficientnet/b4/feature-vector/1\"\n# MODULE_HANDLE = tf.keras.applications.EfficientNetB4(include_top=True, weights='imagenet', input_tensor=None,input_shape=None)\n\n# IMAGE_SIZE = (380, 380)\n\n# loss_func = tf.keras.losses.SparseCategoricalCrossentropy()\n\n# model = tf.keras.Sequential([\n#     InputLayer(input_shape=IMAGE_SIZE + (3,)),\n#     hub.KerasLayer(MODULE_HANDLE, trainable=False),\n#     Dense(512, activation='relu'),\n#     Dropout(0.33),\n#     Dense(256, activation='relu'),\n#     Dropout(0.33),\n#     Dense(128, activation='relu'),\n#     Dropout(0.33),\n#     Dense(5, activation='softmax')\n# ])\n\n# model.compile(optimizer=Adam(), loss=loss_func, metrics=['acc'])\n# # model.compile(optimizer=Adam(), loss='categorical_crossentropy', metrics=['acc'])\n\n# model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.layers import Dense, InputLayer, Dropout\nfrom tensorflow.keras.optimizers import Adam\n\nMODULE_HANDLE = \"https://tfhub.dev/tensorflow/efficientnet/b4/feature-vector/1\"\n\nIMAGE_SIZE = (380, 380)\n\nloss_func = tf.keras.losses.SparseCategoricalCrossentropy()\n\nmodel = tf.keras.Sequential([\n    InputLayer(input_shape=IMAGE_SIZE + (3,)),\n    hub.KerasLayer(MODULE_HANDLE, trainable=False),\n    Dense(512, activation='relu'),\n    Dropout(0.33),\n    Dense(256, activation='relu'),\n    Dropout(0.33),\n    Dense(128, activation='relu'),\n    Dropout(0.33),\n    Dense(5, activation='softmax')\n])\n\nmodel.compile(optimizer=Adam(), loss=loss_func, metrics=['acc'])\n# model.compile(optimizer=Adam(), loss='categorical_crossentropy', metrics=['acc'])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Now lets train the model "},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.callbacks import ModelCheckpoint\ncheckpoint_filepath = 'model.h5'\nmc = tf.keras.callbacks.ModelCheckpoint(checkpoint_filepath, verbose=1, \n                                        save_weights_only=True, monitor='val_loss', \n                                        mode='auto', save_best_only=True)\n\nhistory = model.fit(train_set, epochs=30, verbose=1, callbacks=[mc], validation_data=val_set)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Check training and validation loss"},{"metadata":{"trusted":true},"cell_type":"code","source":"history.history","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history_df =  pd.DataFrame(history.history) #history.history\n\nfig, (ax1, ax2) = plt.subplots(2, 1, sharex='col', figsize=(20, 14))\n\nax1.plot(history_df['loss'], label='Train loss')\nax1.plot(history_df['val_loss'], label='Validation loss')\nax1.legend(loc='best')\nax1.set_title('Loss')\n\nax2.plot(history_df['acc'], label='Train accuracy')\nax2.plot(history_df['val_acc'], label='Validation accuracy')\nax2.legend(loc='best')\nax2.set_title('Accuracy')\n\nplt.xlabel('Epochs')\n#sns.despine()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Lets predict and save the results to the file"},{"metadata":{"trusted":true},"cell_type":"code","source":"# model.save('./best_model.h5')\n# #model.save('/kaggle/input/efficientnetleaf/best_model.h5') ../input/efficientnetleaf/model_new.h5\n# print('Model saved!')\nmodel.save_weights('./model_weight.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Inference over the dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"myModel = tf.keras.models.load_model('../input/efficientnetleaf/model_new.h5',custom_objects={'KerasLayer':hub.KerasLayer})\nprint(\"Model loaded\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"myModel.summary()\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import cv2 \ntest_img_path = \"../input/cassava-leaf-disease-classification/test_images/2216849948.jpg\"\n\nimg = cv2.imread(test_img_path)\nresized_img = cv2.resize(img, (255, 255)).reshape(-1, 255, 255, 3)/255\n\nplt.figure(figsize=(8,4))\nplt.title(\"TEST IMAGE\")\nplt.imshow(resized_img[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"imageDataGenerator = ImageDataGenerator(rescale=1/255.)\ntest_gen = imageDataGenerator.flow_from_directory('../input/cassava-leaf-disease-classification/test_images/',classes=['0', '1', '2', '3','4'], target_size=(380, 380),\n                                                  class_mode=None, batch_size=32, shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# File submission to Kaggle"},{"metadata":{"trusted":true},"cell_type":"code","source":"IMG_SIZE = 320\n\n\nmydict = {\"image_id\":[], 'label':[]}\n\nfor img in glob.glob(\"../input/cassava-leaf-disease-classification/test_images/*.jpg\"):\n        test_filename = os.path.basename(img)\n        print(img)\n        img = tf.keras.preprocessing.image.load_img(img)\n        img = tf.keras.preprocessing.image.img_to_array(img)\n        img = tf.keras.preprocessing.image.smart_resize(img, (IMG_SIZE, IMG_SIZE))\n        img = tf.reshape(img, (-1, IMG_SIZE, IMG_SIZE, 3))\n        probabilities = myModel.predict(img/255)\n        #mydict.append(np.argmax(prediction))\n        predictions = np.argmax(probabilities, axis=-1)\n        mydict[\"image_id\"].append(test_filename)\n        mydict[\"label\"].append(predictions[0])\n    \ndf = pd.DataFrame(mydict)\ndf.to_csv('submission.csv', index=False)\n!head submission.csv\nprint(\"File submitted\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# FastAI method"},{"metadata":{"trusted":true,"pixiedust":{"displayParams":{}}},"cell_type":"code","source":"#dls = ImageDataLoaders.from_df(df=df_train, path=train_img, seed=16, item_tfms=Resize(460), batch_tfms=aug_transforms(size=224))\n# learn = cnn_learner(dls, resnet50, metrics=accuracy) \n# learn.fit_one_cycle(3, 3e-3)\n# learn.unfreeze()\n# learn.fit_one_cycle(12, lr_max=slice(1e-6,1e-4))\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# learn.model_dir = \"/kaggle/working\"\n# learn.lr_find()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#learn.recorder.plot_loss()\n#Learn.model_dir = \"/kaggle/working\"\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Fine tuning\n\nLets fine tune the model so that intead of accepting ramdom weight we apply specific weights for our model"},{"metadata":{},"cell_type":"markdown","source":"# Export the model \n\nwe should export the model to use the competition as our \"Internet\" needs to be off"},{"metadata":{"trusted":true},"cell_type":"code","source":"# interp = ClassificationInterpretation.from_learner(learn)\n# interp.plot_confusion_matrix(figsize=(12,12), dpi=60)\n\n# learn.export('/kaggle/working/model.pkl')\n# print(\"Model exported\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Making predictions "},{"metadata":{"trusted":true},"cell_type":"code","source":"\n# learn_inf = load_learner(\"/kaggle/input/cassavaleafmodel/model.pkl\")\n# print(\"Model loaded\")\n\n# mydict = {\"image_id\":[], 'label':[]}\n# for img in glob.glob(\"../input/cassava-leaf-disease-classification/test_images/*.jpg\"):\n#         test_filename = os.path.basename(img)\n#         probabilities = learn_inf.predict(img)\n#         predictions = np.argmax(probabilities, axis=-1)\n#         #print(test_filename, predictions)\n#         mydict[\"image_id\"].append(test_filename)\n#         mydict[\"label\"].append(predictions)\n    \n\n\n# df = pd.DataFrame(mydict)\n# df.to_csv('submission.csv', index=False)\n# !head submission.csv","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Attempt 2: EfficientNet and custom weights using FastAI\n\nlets see if we can use EfficientNet & FastAI to get a better result\n\n1. Install Ross Wightman repository to download efficeientNet model (instlal timm)\n2. Use custom weights to use with FASAI\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"# def create_timm_body(arch:str, pretrained=True, cut=None):\n#   model = create_model(arch, pretrained=pretrained)\n#   if cut is None:\n#     ll = list(enumerate(model.children()))\n#     cut = next(i for i,o in reversed(ll) if has_pool_type(o))\n#   if isinstance(cut, int): return nn.Sequential(*list(model.children())[:cut])\n#   elif callable(cut): return cut(model)\n#   else: raise NameError(\"cut must be either integer or function\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# net = create_model('efficientnet_b3a', pretrained=True)\n# net","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n# body = create_timm_body('efficientnet_b3a', pretrained=True)\n# len(body)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# body","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# nf = num_features_model(nn.Sequential(*body.children())) * (2); nf","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# train_img = (os.path.join(BASE_DIR, \"train_images\"))\n# print(train_img)\n# dls = ImageDataLoaders.from_df(df=df_train, path=train_img, seed=16, item_tfms=Resize(460), batch_tfms=aug_transforms(size=224))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# dls.show_batch(max_n=9,figsize=(8,9))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# head = create_head(nf, dls.c)\n# head","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# model = nn.Sequential(body, head)\n# apply_init(model[1], nn.init.kaiming_normal_)\n# len(model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# learn = Learner(dls, model,loss_func=LabelSmoothingCrossEntropy(), metrics=accuracy)\n# learn.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# learn.model_dir = \"/kaggle/working\"\n# learn.lr_find()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# learn.fit_one_cycle(20, slice(3e-2)) # 0.78 accuracy","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# learn.save('stage_1')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# learn.unfreeze()\n# learn.lr_find()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#learn.fit_one_cycle(5, 1e-4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#learn.save('model_2')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#learn.export('/kaggle/working/model.pkl')\n#print(\"Model exported\")\n#learn_inf = load_learner(\"/kaggle/input/efficientnetleaf/model.pkl\")\n#print(\"Model loaded\")\n\n# mydict = {\"image_id\":[], 'label':[]}\n# for img in glob.glob(\"../input/cassava-leaf-disease-classification/test_images/*.jpg\"):\n#         test_filename = os.path.basename(img)\n#         probabilities = learn_inf.predict(img)\n#         predictions = np.argmax(probabilities, axis=-1)\n#         #print(test_filename, predictions)\n#         mydict[\"image_id\"].append(test_filename)\n#         mydict[\"label\"].append(predictions)\n    \n\n\n# df = pd.DataFrame(mydict)\n# df.to_csv('submission.csv', index=False)\n# !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}