{"cells":[{"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 5GB 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":"## Loading the dataset\nThe dataset is given in a zip file. So to use this at first we have to **unzip** the zip files.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import zipfile\nimport os\nimport shutil","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"# Removing files that are allready unzippped\nfor folder in os.listdir(\"/kaggle/working/\"):\n    if folder != \"__notebook_source__.ipynb\":\n        shutil.rmtree(\"/kaggle/working/\"+folder)\n\n# Unzip train data\nwith zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats/train.zip\") as zip_ref:\n    zip_ref.extractall(\"/kaggle/working/train\")\n\n# Unzip test data\nwith zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats/test1.zip\") as zip_ref:\n    zip_ref.extractall(\"/kaggle/working/test\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Seperate cats and dogs images in train data","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"TRAIN_DIR = \"/kaggle/working/train/\"\nTEST_DIR = \"/kaggle/working/test/\"\n\n# Creating separate folder for cat and dog images\n# Using try catch so that if the folder is already created, then it won't throw any error\ntry:\n    os.mkdir(TRAIN_DIR + \"cat\")\n    os.mkdir(TRAIN_DIR + \"dog\")\nexcept os.error:\n    pass\n\n# Seperating training data\nfor image in os.listdir(TRAIN_DIR + \"train\"):\n    source = TRAIN_DIR + \"train/\" + image\n    destination = TRAIN_DIR + image.split(\".\")[0]\n    shutil.move(source, destination)\n\n# Test data can't be sepearated, so putting them in one folder\nfor image in os.listdir(TEST_DIR + \"test1\"):\n    source = TEST_DIR + \"test1/\" + image\n    destination = TEST_DIR\n    shutil.move(source, destination)\n\n# Removing the empty folders\nos.rmdir(TRAIN_DIR + \"train\")\nos.rmdir(TEST_DIR + \"test1\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Exploring the dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"DOG_DIR = \"/kaggle/working/train/dog/\"\nCAT_DIR = \"/kaggle/working/train/cat/\"\n\nTEST_FILES = os.listdir(TEST_DIR)\nCAT_FILES = os.listdir(CAT_DIR)\nDOG_FILES = os.listdir(DOG_DIR)\n\nTEST_DATA_SIZE = len(TEST_FILES)\nDOG_DATA_SIZE = len(DOG_FILES)\nCAT_DATA_SIZE = len(CAT_FILES)\n\nprint(f\"There are {DOG_DATA_SIZE} dog, {CAT_DATA_SIZE} cat and {TEST_DATA_SIZE} test images.\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Showing some images from the dataset","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport random","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Getting random indexes\ncat1, cat2, dog1, dog2 = [random.randint(0, CAT_DATA_SIZE-1) for i in range(4)]\n\n# Showing the images on a subplot\nfigure, axes = plt.subplots(nrows = 2, ncols = 2, figsize=(8,8))\n\naxes[0, 0].imshow(mpimg.imread(CAT_DIR + CAT_FILES[cat1]))\naxes[0, 1].imshow(mpimg.imread(CAT_DIR + CAT_FILES[cat2]))\naxes[1, 0].imshow(mpimg.imread(DOG_DIR + DOG_FILES[dog1]))\naxes[1, 1].imshow(mpimg.imread(DOG_DIR + DOG_FILES[dog2]))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Time to create the model\nThis time I'm going to create my model from scratch usign only CNN and MaxPool.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.layers import Conv2D, MaxPool2D, Flatten, Dense, Input\nfrom tensorflow.keras.models import Sequential","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = Sequential([\n    Input((150, 150, 3)),\n    Conv2D(16, 3, activation=\"relu\"),\n    MaxPool2D(2, 2),\n    Conv2D(32, 3, activation=\"relu\"),\n    MaxPool2D(2, 2),\n    Conv2D(64, 3, activation=\"relu\"),\n    MaxPool2D(2, 2),\n    Flatten(),\n    Dense(512, activation=\"relu\"),\n    Dense(1, activation=\"sigmoid\")\n])\n\nmodel.compile(optimizer=\"adam\", loss=\"binary_crossentropy\", metrics=[\"accuracy\"])\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"My model has only 3 Conv2D layers followed by MaxPool2D layers. And 2 Dense layer on top of that.","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Loading and Augmenting images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 32\ntrain_datagen = ImageDataGenerator(rescale=1./255,\n                                   validation_split=0.2,\n                                   rotation_range=45,\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\ntrain_gen = train_datagen.flow_from_directory(TRAIN_DIR,\n                                              target_size=(150, 150),\n                                              batch_size=BATCH_SIZE,\n                                              class_mode=\"binary\",\n                                              subset=\"training\")\n\nvalidation_gen = train_datagen.flow_from_directory(TRAIN_DIR,\n                                                   target_size=(150, 150),\n                                                   batch_size=BATCH_SIZE,\n                                                   class_mode=\"binary\",\n                                                   subset=\"validation\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Train the model on augmented images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"history = model.fit(train_gen,\n                    epochs=10,\n                    steps_per_epoch=train_gen.samples // BATCH_SIZE,\n                    validation_data=validation_gen,\n                    validation_steps=validation_gen.samples // BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let's see how our model performed","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plotting loss and accuracy\nfig, axes = plt.subplots(nrows=1, ncols=2, figsize=(12, 3))\naxes[0].plot(history.history[\"loss\"], label=\"Loss\")\naxes[0].plot(history.history[\"val_loss\"], label=\"Val Loss\")\naxes[1].plot(history.history[\"accuracy\"], label=\"Accuracy\")\naxes[1].plot(history.history[\"val_accuracy\"], label=\"Val Accuracy\")\naxes[0].legend()\naxes[1].legend()\nfig.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Well, atleast it isn't overfitted. 😛","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"## Getting the test files ready to predict","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import pandas as pd","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.DataFrame({'filename': TEST_FILES})\n\ntest_datagen = ImageDataGenerator(rescale=1./255)\ntest_gen = test_datagen.flow_from_dataframe(test_df,\n                                            TEST_DIR,\n                                            x_col=\"filename\",\n                                            y_col=None,\n                                            class_mode=None,\n                                            target_size=(150, 150),\n                                            shuffle=False,\n                                            batch_size=BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Predict","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"predict = model.predict(test_gen, steps=np.ceil(test_df.shape[0] / BATCH_SIZE))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"As I've used softmax for binary classification, this will predict a float value (0 to 1) for every test image.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"output = (predict >= 0.5).astype(int)\n# As output was a 2D array, I had to squeeze it\noutput = np.squeeze(output).tolist()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"I took 1 if the prediction is greater or equal to 0.5, else I took 0.\nHere 1 means it's a dog, and 0 means it's a cat.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating the label map for categories\nlabel_map = dict((v, k) for k, v in train_gen.class_indices.items())\nCATEGORY = [label_map[i] for i in output]\n\nTEST_ID = []\nfor file in TEST_FILES:\n    TEST_ID.append(file.split('.')[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating the dataframe for submission\nsubmission_df = pd.DataFrame({\n    \"id\": TEST_ID,\n    \"label\": CATEGORY\n})\n\nsubmission_df.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}