{"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":"# Kaggle Dogs vs Cats\n\nApplying deep learning machine learning models on the Kaggle Dogs vs Cats dataset by comparing the performace between a model modified from [Keras tutorial](https://keras.io/examples/vision/image_classification_from_scratch/) and a transfer learning model built on VGG16.","metadata":{}},{"cell_type":"markdown","source":"<a id='toc'></a>\n<h2> Table of Contents</h2>\n<div class='alert alert-box alert-info'>\n    <ol>\n        <li><a href='#lib'> Import libraries </a></li>\n        <li><a href='#data'> Extracting data </a></li>\n        <li><a href='#ds'> Generating dataset </a></li>\n        <li><a href='#viz'> Visualise the data </a></li>\n        <li><a href='#aug'> Using image data augmentation </a></li>\n        <li><a href='#model'> Building the models </a></li>\n        <li><a href='#train'> Training the models </a></li>\n        <li><a href='#pred'> Predictions </a></li>        \n        <li><a href='#compare'> Comparison </a></li>\n        <li><a href='#ref'> References </a></li>\n    </ol>\n</div>","metadata":{}},{"cell_type":"markdown","source":"<a id='lib'></a>\n<h2> Import libraries </h2>\n","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport os\nfrom tqdm import tqdm\nfrom zipfile import ZipFile","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:06:10.200885Z","iopub.execute_input":"2022-03-29T15:06:10.201418Z","iopub.status.idle":"2022-03-29T15:06:10.800506Z","shell.execute_reply.started":"2022-03-29T15:06:10.201381Z","shell.execute_reply":"2022-03-29T15:06:10.799763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#from kaggle.api.kaggle_api_extended import KaggleApi","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:06.506706Z","iopub.execute_input":"2022-03-29T14:24:06.507247Z","iopub.status.idle":"2022-03-29T14:24:06.510439Z","shell.execute_reply.started":"2022-03-29T14:24:06.507215Z","shell.execute_reply":"2022-03-29T14:24:06.50976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import Sequential\nfrom tensorflow.keras import Input\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.preprocessing import image_dataset_from_directory\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\nfrom tensorflow.keras.callbacks import ModelCheckpoint\nfrom tensorflow.keras.applications import VGG16","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:06.583703Z","iopub.execute_input":"2022-03-29T14:24:06.584116Z","iopub.status.idle":"2022-03-29T14:24:11.700941Z","shell.execute_reply.started":"2022-03-29T14:24:06.584085Z","shell.execute_reply":"2022-03-29T14:24:11.700187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<a id='data'></a>\n<h2> Extracting data </h2>","metadata":{}},{"cell_type":"markdown","source":"We have 2 ways to access the data on Kaggle. \n\nIf we are running the notebook on Kaggle itself, we can use `os` library to extract the files. Otherwise if we are runnging the notebook on a local machine, we will have the access the data using Kaggle API to programatically download the dataset from Kaggle. \n\nThe instructions for getting Kaggle's API token can be found [here](https://www.kaggle.com/docs/api). Additionally, this excellent [article](https://python.plainenglish.io/how-to-use-the-kaggle-api-in-python-4d4c812c39c7) by <em>Python in Plain English</em> explains clearly how you can use the Kaggle API in Python.","metadata":{}},{"cell_type":"code","source":"run_on_kaggle = True","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:11.703974Z","iopub.execute_input":"2022-03-29T14:24:11.704524Z","iopub.status.idle":"2022-03-29T14:24:11.708351Z","shell.execute_reply.started":"2022-03-29T14:24:11.704482Z","shell.execute_reply":"2022-03-29T14:24:11.70743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if run_on_kaggle:\n    data_path = '../input/dogs-vs-cats'\n    work_path = '../work'\n    \n    with ZipFile(os.path.join(data_path, 'train.zip'), 'r') as z:\n        z.extractall(work_path)\n    with ZipFile(os.path.join(data_path, 'test1.zip'), 'r') as z:\n        z.extractall(work_path)\n    \nelse:\n    # initialise the API\n    kag = KaggleApi()\n    kag.authenticate()\n    \n    # downloading the files\n    comp_name = 'dogs-vs-cats'\n    dl_path = './'\n    kag.competition_download_files(competition=comp_name, path=dl_path)\n    \n    # unzip the files\n    with ZipFile('dogs-vs-cats.zip', 'r') as z:\n        z.extractall()\n    with ZipFile('train.zip', 'r') as z:\n        z.extractall()\n    with ZipFile('test1.zip', 'r') as z:\n        z.extractall()","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:11.710381Z","iopub.execute_input":"2022-03-29T14:24:11.710869Z","iopub.status.idle":"2022-03-29T14:24:29.154183Z","shell.execute_reply.started":"2022-03-29T14:24:11.710832Z","shell.execute_reply":"2022-03-29T14:24:29.152785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if run_on_kaggle:\n    train_path = os.path.join(work_path, 'train')\n    test_path = os.path.join(work_path, 'test1')\nelse:\n    train_path = './train'\n    test_path = './test1'","metadata":{"execution":{"iopub.status.busy":"2022-04-08T09:15:14.172593Z","iopub.execute_input":"2022-04-08T09:15:14.17339Z","iopub.status.idle":"2022-04-08T09:15:14.278698Z","shell.execute_reply.started":"2022-04-08T09:15:14.173291Z","shell.execute_reply":"2022-04-08T09:15:14.27698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3> Tidying up the data </h3>","metadata":{}},{"cell_type":"code","source":"train_df = pd.DataFrame({'image_name':os.listdir(train_path)})\ntrain_df['label'] =train_df['image_name'].apply(lambda x: x.split('.')[0])\ntrain_df","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:29.178282Z","iopub.execute_input":"2022-03-29T14:24:29.180257Z","iopub.status.idle":"2022-03-29T14:24:29.312459Z","shell.execute_reply.started":"2022-03-29T14:24:29.18022Z","shell.execute_reply":"2022-03-29T14:24:29.311623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We will move the training images into their respective folders, ie cat images to cat folders and dog images to dog folders. This will be done using `os.mkdir` (creating new folders) and `os.rename` (moving the files).","metadata":{}},{"cell_type":"code","source":"cat_path = os.path.join(train_path, 'cat')\nos.mkdir(cat_path)\ncat_df = train_df[train_df.label=='cat']\nfor n in tqdm(cat_df.image_name):\n    os.rename((os.path.join(train_path, n)), (os.path.join(cat_path, n)))","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:29.318366Z","iopub.execute_input":"2022-03-29T14:24:29.320865Z","iopub.status.idle":"2022-03-29T14:24:29.838109Z","shell.execute_reply.started":"2022-03-29T14:24:29.320827Z","shell.execute_reply":"2022-03-29T14:24:29.837397Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dog_path = os.path.join(train_path, 'dog')\nos.mkdir(dog_path)\ndog_df = train_df[train_df.label=='dog']\nfor n in tqdm(dog_df.image_name):\n    os.rename((os.path.join(train_path, n)), (os.path.join(dog_path, n)))","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:29.839269Z","iopub.execute_input":"2022-03-29T14:24:29.839987Z","iopub.status.idle":"2022-03-29T14:24:30.245466Z","shell.execute_reply.started":"2022-03-29T14:24:29.839949Z","shell.execute_reply":"2022-03-29T14:24:30.244691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<a id='ds'></a>\n<h2> Generating dataset </h2>\n\nWe will prepare tensorflow training and validation datasets using the \nKeras image data processing function [`image_dataset_from_directory`](https://keras.io/api/preprocessing/image/).","metadata":{}},{"cell_type":"code","source":"image_size = (128, 128)\nbatch_size = 32\nrand_seed = 42\nval_split = 0.2","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:30.247143Z","iopub.execute_input":"2022-03-29T14:24:30.247647Z","iopub.status.idle":"2022-03-29T14:24:30.252402Z","shell.execute_reply.started":"2022-03-29T14:24:30.247587Z","shell.execute_reply":"2022-03-29T14:24:30.251801Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_ds = image_dataset_from_directory(\n    directory=train_path,\n    class_names=['cat', 'dog'], \n    batch_size=batch_size,\n    image_size=image_size,\n    seed=rand_seed, \n    validation_split=val_split,\n    subset='training'\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:30.253635Z","iopub.execute_input":"2022-03-29T14:24:30.258195Z","iopub.status.idle":"2022-03-29T14:24:33.891058Z","shell.execute_reply.started":"2022-03-29T14:24:30.258126Z","shell.execute_reply":"2022-03-29T14:24:33.890334Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_ds = image_dataset_from_directory(\n    directory=train_path,\n    class_names=['cat', 'dog'],\n    batch_size=batch_size,\n    image_size=image_size,\n    seed=rand_seed,\n    validation_split=val_split,\n    subset='validation'\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:33.894063Z","iopub.execute_input":"2022-03-29T14:24:33.894799Z","iopub.status.idle":"2022-03-29T14:24:35.452412Z","shell.execute_reply.started":"2022-03-29T14:24:33.894758Z","shell.execute_reply":"2022-03-29T14:24:35.451686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<a id='viz'></a>\n<h2> Visualise the data </h2>\n\nTo visualise the images, we make use of the tensorflow datasets and the `dataset.take(n)` method. The method returns n batches of images and labels of batch size as defined. \n\nThe images are tensor objects which needs to be converted to numpy and cast to unsigned integers before using `axes.imshow`.\n\nThe labels are 0 for cat and 1 for dog. These can be controlled in the earlier `image_dataset_from_directory` function.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(10,10))\nfor images, labels in train_ds.take(1):\n    for i in range(16):\n        ax = plt.subplot(4, 4, i+1)\n        ax.imshow(images[i].numpy().astype('uint8'))\n        ax.set_title(int(labels[i]))\n        ax.axis('off')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:35.453645Z","iopub.execute_input":"2022-03-29T14:24:35.454046Z","iopub.status.idle":"2022-03-29T14:24:38.232422Z","shell.execute_reply.started":"2022-03-29T14:24:35.454008Z","shell.execute_reply":"2022-03-29T14:24:38.23156Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<a id='aug'></a>\n<h2> Visualising image augmentation </h2>\n\nWhen we don't have a large image dataset, it is a good practice to artifically introduce image diversity by adding some random yet realistic transformations to the training images. This helps expose our model to different aspects of the training data while minimising overfitting. \n\nWe have chosen to use random horizontal flipping, small random rotations, and small random zooms. Below shows the effects of these transformations when compared against the original image.","metadata":{}},{"cell_type":"code","source":"data_augmentation = Sequential(\n    [layers.RandomFlip('horizontal'),\n     layers.RandomRotation((-0.1, 0.1)),\n     layers.RandomZoom((-0.2, 0.2))\n    ]\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:38.233494Z","iopub.execute_input":"2022-03-29T14:24:38.233765Z","iopub.status.idle":"2022-03-29T14:24:38.29485Z","shell.execute_reply.started":"2022-03-29T14:24:38.23373Z","shell.execute_reply":"2022-03-29T14:24:38.29415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"I have set the `training` parameter of `data_augmentation` to True. Typically this will not be a problem if I'm running the notebook in sequence. But when I circle back to this code after building the model, the augmented images will not be shown as augmented anymore unless I have set `training` to True. \n\nThis has to do with the characteristic of the augmentation layer being active only during training and inactive during inference. Thanks to the [solution](https://stackoverflow.com/questions/71164259/tensorflow-augmentation-layers-not-working-after-importing-from-tf-keras-applica/71469695#71469695?newreg=fc8166485de44a8b8e70cac0f6f965c5) from stackoverflow that helped me with the debug.","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(10, 10))\nfor images, _ in train_ds.take(1):\n    ax = plt.subplot(441)\n    ax.imshow(images[0].numpy().astype('uint8'))\n    ax.set_title('original')\n    ax.axis('off')\n\n    fig = plt.figure(figsize=(10, 10))\n    for i in range(16):\n        augmented_image = data_augmentation(images[0], training=True) # training must be set to True\n        ax = plt.subplot(4, 4, i+1)\n        ax.imshow(augmented_image.numpy().astype('uint8'))\n        ax.axis('off')\n    fig.suptitle('Augmented images')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:38.296552Z","iopub.execute_input":"2022-03-29T14:24:38.297068Z","iopub.status.idle":"2022-03-29T14:24:42.006945Z","shell.execute_reply.started":"2022-03-29T14:24:38.297028Z","shell.execute_reply":"2022-03-29T14:24:42.006148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<a id='model'></a>\n<h2> Building the models </h2>\n\nWe will build 2 models for comparison. \n1. A base model modified from the Keras tutorial\n2. A transfer learning model based on VGG16","metadata":{}},{"cell_type":"markdown","source":"<h3> Base model </h3>","metadata":{}},{"cell_type":"code","source":"# Define augmentation layer\naugmentation_layer = Sequential(\n    [layers.RandomFlip('horizontal'),\n     layers.RandomRotation((-0.1, 0.1)),\n     layers.RandomZoom((-0.2, 0.2))\n    ]\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:42.008069Z","iopub.execute_input":"2022-03-29T14:24:42.008268Z","iopub.status.idle":"2022-03-29T14:24:42.029928Z","shell.execute_reply.started":"2022-03-29T14:24:42.008244Z","shell.execute_reply":"2022-03-29T14:24:42.029263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"A little information regarding batch normalisation. \n\nIt is a tecnique deisnged to automatically standardise the inputs to a layer in a deep learning neural network. The benefit being that it has the effect of dramatically accelerating the training process of a NN, and in some cases improving the performance of the model via a modest regularisation effect. \n\n<em>Reference: [BatchNormalization layer](https://keras.io/api/layers/normalization_layers/batch_normalization/) and [How to Accelerate Learning of DNN with Batch Normalisation](https://machinelearningmastery.com/how-to-accelerate-learning-of-deep-neural-networks-with-batch-normalization/) </em>","metadata":{}},{"cell_type":"code","source":"basemodel = Sequential()\nbasemodel.add(Input(shape=image_size+(3,)))\nbasemodel.add(augmentation_layer)\nbasemodel.add(layers.Rescaling(1.0/255))\n\nfor size in [32, 64]:\n    basemodel.add(layers.Conv2D(size, 3, padding='same', activation='relu'))\n    basemodel.add(layers.BatchNormalization())\n    basemodel.add(layers.MaxPooling2D(pool_size=2))\n    basemodel.add(layers.Dropout(0.2))\n\nfor size in [128, 256, 512, 728]:\n    basemodel.add(layers.SeparableConv2D(size, 3, padding='same', activation='relu'))\n    basemodel.add(layers.BatchNormalization())\n    basemodel.add(layers.SeparableConv2D(size, 3, padding='same', activation='relu'))\n    basemodel.add(layers.BatchNormalization())\n    basemodel.add(layers.MaxPooling2D(pool_size=2))\n    basemodel.add(layers.Dropout(0.2))\n    \n# output layer\nbasemodel.add(layers.Flatten())\nbasemodel.add(layers.Dense(512, activation='relu'))\n#basemodel.add(Dense(2, activation='softmax'))\nbasemodel.add(layers.Dense(1, activation='sigmoid'))","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:42.031193Z","iopub.execute_input":"2022-03-29T14:24:42.031511Z","iopub.status.idle":"2022-03-29T14:24:43.620807Z","shell.execute_reply.started":"2022-03-29T14:24:42.031474Z","shell.execute_reply":"2022-03-29T14:24:43.620087Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"basemodel.summary()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-29T14:24:43.622186Z","iopub.execute_input":"2022-03-29T14:24:43.622412Z","iopub.status.idle":"2022-03-29T14:24:43.646652Z","shell.execute_reply.started":"2022-03-29T14:24:43.62238Z","shell.execute_reply":"2022-03-29T14:24:43.64597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<h3> Transfer learning model </h3>\n\nTo implement transfer learning model with VGG16","metadata":{}},{"cell_type":"code","source":"vgg16layer = VGG16(\n    weights='imagenet', \n    include_top=False, \n)\nvgg16layer.trainable = False","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:43.647641Z","iopub.execute_input":"2022-03-29T14:24:43.647862Z","iopub.status.idle":"2022-03-29T14:24:46.578396Z","shell.execute_reply.started":"2022-03-29T14:24:43.64783Z","shell.execute_reply":"2022-03-29T14:24:46.577668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"vgg16model = keras.Sequential()\nvgg16model.add(Input(shape=image_size+(3,)))\nvgg16model.add(augmentation_layer)\nvgg16model.add(layers.Rescaling(1.0/255))\nvgg16model.add(vgg16layer)\n\nvgg16model.add(layers.Flatten())\nvgg16model.add(layers.Dense(512, activation='relu'))\n#basemodel.add(Dense(2, activation='softmax'))\nvgg16model.add(layers.Dense(1, activation='sigmoid'))","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:46.579528Z","iopub.execute_input":"2022-03-29T14:24:46.579804Z","iopub.status.idle":"2022-03-29T14:24:46.760985Z","shell.execute_reply.started":"2022-03-29T14:24:46.579769Z","shell.execute_reply":"2022-03-29T14:24:46.76029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"vgg16model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:46.762512Z","iopub.execute_input":"2022-03-29T14:24:46.762762Z","iopub.status.idle":"2022-03-29T14:24:46.770828Z","shell.execute_reply.started":"2022-03-29T14:24:46.76273Z","shell.execute_reply":"2022-03-29T14:24:46.770139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<a id='train'></a>\n<h2> Train the model </h2>","metadata":{}},{"cell_type":"code","source":"if run_on_kaggle:\n    epochs = 50\nelse:\n    epochs = 1","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:46.772081Z","iopub.execute_input":"2022-03-29T14:24:46.772536Z","iopub.status.idle":"2022-03-29T14:24:46.778421Z","shell.execute_reply.started":"2022-03-29T14:24:46.772496Z","shell.execute_reply":"2022-03-29T14:24:46.777534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"early_stop = EarlyStopping(patience=10)\n\nlr_reduction = ReduceLROnPlateau(\n    monitor='val_accuracy',\n    patience=2,\n    verbose=1,\n    factor=0.5,\n    min_lr=0.00001\n)\n\nmodel_chkpt = ModelCheckpoint('save_at_{epoch}.h5')\n\ncallbacks = [\n    early_stop,\n    lr_reduction,\n    model_chkpt\n]","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:46.779738Z","iopub.execute_input":"2022-03-29T14:24:46.780259Z","iopub.status.idle":"2022-03-29T14:24:46.787813Z","shell.execute_reply.started":"2022-03-29T14:24:46.780222Z","shell.execute_reply":"2022-03-29T14:24:46.787035Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<b> Training base model </b>","metadata":{}},{"cell_type":"code","source":"basemodel.compile(\n    optimizer='adam',\n    loss='binary_crossentropy',\n    metrics=['accuracy']\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:24:46.788859Z","iopub.execute_input":"2022-03-29T14:24:46.789382Z","iopub.status.idle":"2022-03-29T14:24:46.805461Z","shell.execute_reply.started":"2022-03-29T14:24:46.789344Z","shell.execute_reply":"2022-03-29T14:24:46.804807Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_hist = basemodel.fit(\n    train_ds, epochs=epochs, callbacks=callbacks, validation_data=val_ds\n)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-29T14:24:46.806785Z","iopub.execute_input":"2022-03-29T14:24:46.807556Z","iopub.status.idle":"2022-03-29T14:44:39.389126Z","shell.execute_reply.started":"2022-03-29T14:24:46.807519Z","shell.execute_reply":"2022-03-29T14:44:39.388351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<b> Training transfer learning model </b>","metadata":{}},{"cell_type":"code","source":"vgg16model.compile(\n    optimizer='adam',\n    loss='binary_crossentropy',\n    metrics=['accuracy']\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:44:39.390433Z","iopub.execute_input":"2022-03-29T14:44:39.390834Z","iopub.status.idle":"2022-03-29T14:44:39.401119Z","shell.execute_reply.started":"2022-03-29T14:44:39.390798Z","shell.execute_reply":"2022-03-29T14:44:39.400463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"vgg16_hist = vgg16model.fit(\n    train_ds, epochs=epochs, callbacks=callbacks, validation_data=val_ds\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T14:44:39.402281Z","iopub.execute_input":"2022-03-29T14:44:39.403749Z","iopub.status.idle":"2022-03-29T15:01:32.580062Z","shell.execute_reply.started":"2022-03-29T14:44:39.403711Z","shell.execute_reply":"2022-03-29T15:01:32.579155Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"basemodel_df = pd.DataFrame.from_dict(base_hist.history)\nprint(basemodel_df.head())\nprint(basemodel_df.tail())","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:11:18.33988Z","iopub.execute_input":"2022-03-29T15:11:18.340136Z","iopub.status.idle":"2022-03-29T15:11:18.351823Z","shell.execute_reply.started":"2022-03-29T15:11:18.340109Z","shell.execute_reply":"2022-03-29T15:11:18.350946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"vgg16model_df = pd.DataFrame.from_dict(vgg16_hist.history)\nprint(vgg16model_df.head())\nprint(vgg16model_df.tail())","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:11:35.889525Z","iopub.execute_input":"2022-03-29T15:11:35.890134Z","iopub.status.idle":"2022-03-29T15:11:35.901481Z","shell.execute_reply.started":"2022-03-29T15:11:35.89009Z","shell.execute_reply":"2022-03-29T15:11:35.900772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(10, 10))\nplt.subplot(221)\nsns.lineplot(x=basemodel_df.index, y='loss', data=basemodel_df, label='loss')\nsns.lineplot(x=basemodel_df.index, y='val_loss', data=basemodel_df, label='val loss')\nplt.title('loss and val loss of base model')\n\nplt.subplot(222)\nsns.lineplot(x=vgg16model_df.index, y='loss', data=vgg16model_df, label='loss')\nsns.lineplot(x=vgg16model_df.index, y='val_loss', data=vgg16model_df, label ='val loss')\nplt.title('loss and val loss of trf learning model')\n\n\nplt.subplot(223)\nsns.lineplot(x=basemodel_df.index, y='accuracy', data=basemodel_df, label='acc')\nsns.lineplot(x=basemodel_df.index, y='val_accuracy', data=basemodel_df, label='val acc')\nplt.title('acc and val acc of base model')\n\nplt.subplot(224)\nsns.lineplot(x=vgg16model_df.index, y='accuracy', data=vgg16model_df, label='acc')\nsns.lineplot(x=vgg16model_df.index, y='val_accuracy', data=vgg16model_df, label='val acc')\nplt.title('acc and val acc of trf learning model')\n\nplt.tight_layout()\nplt.show()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-29T15:15:09.88129Z","iopub.execute_input":"2022-03-29T15:15:09.881549Z","iopub.status.idle":"2022-03-29T15:15:10.655046Z","shell.execute_reply.started":"2022-03-29T15:15:09.881521Z","shell.execute_reply":"2022-03-29T15:15:10.654435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<a id='pred'></a>\n<h2> Predictions </h2>","metadata":{}},{"cell_type":"code","source":"img_num = str(np.random.randint(1, 12501))\nsample_img = os.path.join(test_path, img_num+'.jpg')\n\nimg = keras.preprocessing.image.load_img(\n    sample_img, target_size=image_size\n)\nimg_array = keras.preprocessing.image.img_to_array(img)\nimg_array = tf.expand_dims(img_array, 0)  # Create batch axis\n\npredictions = basemodel.predict(img_array)\nscore = predictions[0]\nplt.imshow(img_array[0].numpy().astype('uint8'))\nplt.axis('off')\nplt.show()\nprint(\n    \"This image is %.2f percent cat and %.2f percent dog.\"\n    % (100 * (1 - score), 100 * score)\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:13:10.279918Z","iopub.execute_input":"2022-03-29T15:13:10.280188Z","iopub.status.idle":"2022-03-29T15:13:10.743389Z","shell.execute_reply.started":"2022-03-29T15:13:10.280159Z","shell.execute_reply":"2022-03-29T15:13:10.742774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_ds = image_dataset_from_directory(\n    test_path,\n    label_mode=None,\n    image_size=image_size,\n    shuffle=False\n)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:13:18.461572Z","iopub.execute_input":"2022-03-29T15:13:18.462282Z","iopub.status.idle":"2022-03-29T15:13:18.851989Z","shell.execute_reply.started":"2022-03-29T15:13:18.462244Z","shell.execute_reply":"2022-03-29T15:13:18.851271Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_filenames = [f.split('/')[-1] for f in test_ds.file_paths]\n#test_filenames = [int(f.split('\\\\')[-1].split('.')[0]) for f in test_ds.file_paths]\n#test_filenames = [int(f.split('.')[0]) for f in test_filenames]\n#test_filenames","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:18:04.206083Z","iopub.execute_input":"2022-03-29T15:18:04.206359Z","iopub.status.idle":"2022-03-29T15:18:04.21414Z","shell.execute_reply.started":"2022-03-29T15:18:04.206329Z","shell.execute_reply":"2022-03-29T15:18:04.213357Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_pred = basemodel.predict(test_ds)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:18:42.682711Z","iopub.execute_input":"2022-03-29T15:18:42.683466Z","iopub.status.idle":"2022-03-29T15:18:53.823034Z","shell.execute_reply.started":"2022-03-29T15:18:42.683426Z","shell.execute_reply":"2022-03-29T15:18:53.82219Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"vgg16_pred = vgg16model.predict(test_ds)","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:19:04.513192Z","iopub.execute_input":"2022-03-29T15:19:04.513439Z","iopub.status.idle":"2022-03-29T15:19:14.748932Z","shell.execute_reply.started":"2022-03-29T15:19:04.513406Z","shell.execute_reply":"2022-03-29T15:19:14.748182Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_pred","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:19:14.75376Z","iopub.execute_input":"2022-03-29T15:19:14.756022Z","iopub.status.idle":"2022-03-29T15:19:14.765931Z","shell.execute_reply.started":"2022-03-29T15:19:14.755955Z","shell.execute_reply":"2022-03-29T15:19:14.765249Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_df = pd.DataFrame(\n    {'filename':test_filenames,\n     'base_score':base_pred.reshape(1, -1)[0],\n     'vgg16_score':vgg16_pred.reshape(1, -1)[0]\n    }\n)\n\npred_df['base_prediction'] = (pred_df['base_score'] >= 0.5).astype('int')\npred_df['vgg16_prediction'] = (pred_df['vgg16_score'] >= 0.5).astype('int')\n\npred_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:20:20.930239Z","iopub.execute_input":"2022-03-29T15:20:20.930701Z","iopub.status.idle":"2022-03-29T15:20:20.948148Z","shell.execute_reply.started":"2022-03-29T15:20:20.930668Z","shell.execute_reply":"2022-03-29T15:20:20.94746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"[Back to top](#toc)","metadata":{}},{"cell_type":"markdown","source":"<a id='compare'></a>\n<h2> Comparison </h2>","metadata":{}},{"cell_type":"code","source":"n = 16\n\nsample_img_df = pred_df.sample(n)\nplt.figure(figsize=(10, 10))\nfor i in range(n):\n    plt.subplot(4, 4, i+1)\n    sample_img = os.path.join(test_path, sample_img_df.iloc[i].filename)\n    img = image.load_img(\n        sample_img, target_size=image_size\n    )\n    plt.imshow(img)\n    plt.title(f'base pred:{sample_img_df.iloc[i].base_prediction}\\n vgg16 pred:{sample_img_df.iloc[i].vgg16_prediction}'\n    )\n    plt.axis('off')\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:23:58.776052Z","iopub.execute_input":"2022-03-29T15:23:58.776304Z","iopub.status.idle":"2022-03-29T15:23:59.634892Z","shell.execute_reply.started":"2022-03-29T15:23:58.776275Z","shell.execute_reply":"2022-03-29T15:23:59.634261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_df['diff'] = pred_df['base_prediction'] != pred_df['vgg16_prediction']\ndiff_df = pred_df[pred_df['diff'] == True]","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:28:03.572045Z","iopub.execute_input":"2022-03-29T15:28:03.572315Z","iopub.status.idle":"2022-03-29T15:28:03.57905Z","shell.execute_reply.started":"2022-03-29T15:28:03.572286Z","shell.execute_reply":"2022-03-29T15:28:03.578391Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n = 16\n\nsample_img_df = diff_df.sample(n)\nplt.figure(figsize=(10, 10))\nfor i in range(n):\n    plt.subplot(4, 4, i+1)\n    sample_img = os.path.join(test_path, sample_img_df.iloc[i].filename)\n    img = image.load_img(\n        sample_img, target_size=image_size\n    )\n    plt.imshow(img)\n    plt.title(f'base pred:{sample_img_df.iloc[i].base_prediction}\\n vgg16 pred:{sample_img_df.iloc[i].vgg16_prediction}'\n    )\n    plt.axis('off')\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-29T15:28:07.217414Z","iopub.execute_input":"2022-03-29T15:28:07.217698Z","iopub.status.idle":"2022-03-29T15:28:08.427353Z","shell.execute_reply.started":"2022-03-29T15:28:07.217666Z","shell.execute_reply":"2022-03-29T15:28:08.426507Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<a id='ref'></a>\n<h2> References </h2>\n<ol>\n    <li><a href='https://keras.io/examples/vision/image_classification_from_scratch/'> Image classification from scratch </a></li>\n    <li><a href='https://www.kaggle.com/docs/api'> Kaggle Public API </a></li>\n    <li><a href='https://python.plainenglish.io/how-to-use-the-kaggle-api-in-python-4d4c812c39c7'> How to Use Kaggle API in Python </a></li>\n    <li><a href='https://www.kaggle.com/code/uysimty/keras-cnn-dog-or-cat-classification/notebook'> Keras CNN Dog or Cat Classification by <em>UYSIM</em> </a></li>\n    <li><a href='https://towardsdatascience.com/transfer-learning-with-vgg16-and-keras-50ea161580b4'> Transfer Learning with VGG16 and Keras </a></li>    \n    <li><a href='https://towardsdatascience.com/a-basic-introduction-to-separable-convolutions-b99ec3102728'> A Basic Introduction to Separable Convolutions </a></li>\n\n</ol>\n\n\n[Back to top](#toc)","metadata":{}}]}