{"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":"# **I. Show original data folder and path**","metadata":{}},{"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","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-05-16T14:57:05.108089Z","iopub.execute_input":"2022-05-16T14:57:05.108665Z","iopub.status.idle":"2022-05-16T14:57:05.146846Z","shell.execute_reply.started":"2022-05-16T14:57:05.108573Z","shell.execute_reply":"2022-05-16T14:57:05.146077Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **II. Set up data directory**","metadata":{}},{"cell_type":"markdown","source":"## **1. Unzip train folder to directory .**","metadata":{}},{"cell_type":"code","source":"!unzip ../input/dogs-vs-cats/train.zip -d .","metadata":{"_kg_hide-input":false,"scrolled":true,"execution":{"iopub.status.busy":"2022-05-16T14:57:08.784917Z","iopub.execute_input":"2022-05-16T14:57:08.785451Z","iopub.status.idle":"2022-05-16T14:57:20.879608Z","shell.execute_reply.started":"2022-05-16T14:57:08.785417Z","shell.execute_reply":"2022-05-16T14:57:20.878644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **2. Split train folder to dog and cat folders**","metadata":{}},{"cell_type":"code","source":"%mkdir ./train/cat\n%mkdir ./train/dog\n%mkdir ./test\n%mkdir ./test/cat\n%mkdir ./test/dog\n%mkdir ./test/cat/data\n%mkdir ./test/dog/data","metadata":{"execution":{"iopub.status.busy":"2022-05-16T14:57:37.884588Z","iopub.execute_input":"2022-05-16T14:57:37.884863Z","iopub.status.idle":"2022-05-16T14:57:42.550757Z","shell.execute_reply.started":"2022-05-16T14:57:37.884831Z","shell.execute_reply":"2022-05-16T14:57:42.549767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nfrom os import listdir\nfrom os.path import isfile, join\nimport shutil\n\n#split data in train folder to cat and dog folders\nmypath = './train'\n\nonlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]\n\nfor file in onlyfiles:\n    if \"cat\" in file: \n        shutil.move(f\"{mypath}/{file}\", f\"{mypath}/cat/{file}\")\n    if \"dog\" in file:\n        shutil.move(f\"{mypath}/{file}\", f\"{mypath}/dog/{file}\")\n        \n#move images from ./train/cat to ./test/data/cat\nmypath = './train/cat'\ndem = 0\n\nonlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]\n\nfor file in onlyfiles:\n    dem += 1\n    if dem <= 6250: shutil.move(f\"{mypath}/{file}\", f\"./test/cat/data/{file}\")\n    else: break\n    \n#move images from ./train/dog to ./test/data/dog\nmypath = './train/dog'\ndem = 0\n\nonlyfiles = [f for f in listdir(mypath) if isfile(join(mypath, f))]\n\nfor file in onlyfiles:\n    dem += 1\n    if dem <= 6250: shutil.move(f\"{mypath}/{file}\", f\"./test/dog/data/{file}\")\n    else: break","metadata":{"execution":{"iopub.status.busy":"2022-05-16T14:57:47.547981Z","iopub.execute_input":"2022-05-16T14:57:47.548252Z","iopub.status.idle":"2022-05-16T14:57:48.684442Z","shell.execute_reply.started":"2022-05-16T14:57:47.548219Z","shell.execute_reply":"2022-05-16T14:57:48.683752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**This is visualization of file tree after setup**\n\n```\n.\n|__ train:\n    |______ cats: [cat.0.jpg, cat.1.jpg ...]\n    |______ dogs: [dog.0.jpg, dog.1.jpg ...]\n|__ test:\n    |______ cats: \n            |____ data: [cat.0.jpg, cat.1.jpg ...]\n    |______ dogs: \n            |____ data: [dog.0.jpg, dog.1.jpg ...]\n```","metadata":{}},{"cell_type":"markdown","source":"# **III. Import neccessary library**","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\n\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Conv2D, Flatten, Dropout, Activation, MaxPooling2D, BatchNormalization\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.optimizers import SGD\nfrom tensorflow.keras.applications.vgg16 import VGG16\nfrom tensorflow.keras.models import Model\n\nimport os\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport random\nimport math\nimport pandas as pd\n\n# Variables for pre-processing and training.\nbatch_size = 128\nepochs = 20\nIMG_HEIGHT = 224\nIMG_WIDTH = 224","metadata":{"execution":{"iopub.status.busy":"2022-05-16T14:57:55.52082Z","iopub.execute_input":"2022-05-16T14:57:55.521202Z","iopub.status.idle":"2022-05-16T14:58:01.078288Z","shell.execute_reply.started":"2022-05-16T14:57:55.521168Z","shell.execute_reply":"2022-05-16T14:58:01.077493Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **IV. Initially set up data and model**","metadata":{}},{"cell_type":"markdown","source":"## **1. Create image generators for train image set and validation image set**","metadata":{}},{"cell_type":"markdown","source":"* We split images in train folder. 75% for training and 25% fot validation.\n* Both train data generator and valid data generator have rescale 1./255 so Saturate problems can be reduced.\n* Image Data Augmentation: Image data augmentation is a technique that can be used to artificially expand the size of a training dataset by creating modified versions of images in the dataset. Example: Rotate image, Zoom Image, Brightness, ...","metadata":{}},{"cell_type":"code","source":"validation_generator = ImageDataGenerator(rescale=1./255, validation_split=0.25)\ntrain_generator = ImageDataGenerator(rescale=1./255, rotation_range=15, width_shift_range=0.1, height_shift_range=0.1, brightness_range=(0.7, 1.3), shear_range=10.0, zoom_range=0.2, horizontal_flip=True, validation_split=0.25)\ntrain_data_gen = train_generator.flow_from_directory(directory=\"train\", target_size=(IMG_HEIGHT, IMG_WIDTH), batch_size=batch_size, shuffle=True, class_mode='binary', subset=\"training\")\nval_data_gen = validation_generator.flow_from_directory(directory=\"train\", target_size=(IMG_HEIGHT, IMG_WIDTH), batch_size=batch_size, shuffle=True, class_mode='binary', subset=\"validation\")","metadata":{"execution":{"iopub.status.busy":"2022-05-16T14:58:36.858517Z","iopub.execute_input":"2022-05-16T14:58:36.858854Z","iopub.status.idle":"2022-05-16T14:58:37.523334Z","shell.execute_reply.started":"2022-05-16T14:58:36.85882Z","shell.execute_reply":"2022-05-16T14:58:37.522113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Plot image function**","metadata":{}},{"cell_type":"code","source":"#Plot image function\ndef plotImages(images_arr):\n    fig = plt.figure(figsize=(3, 3 * len(images_arr)))\n    dem = 0\n    for img in images_arr:\n        dem += 1\n        fig.add_subplot(len(images_arr), 1, dem)\n        plt.imshow(img)\n    plt.show()","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-05-16T14:58:40.405252Z","iopub.execute_input":"2022-05-16T14:58:40.405641Z","iopub.status.idle":"2022-05-16T14:58:40.411989Z","shell.execute_reply.started":"2022-05-16T14:58:40.405605Z","shell.execute_reply":"2022-05-16T14:58:40.411298Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### **Test rotated image form**","metadata":{}},{"cell_type":"code","source":"augmented_images = [train_data_gen[0][0][0] for i in range(5)]\n\nplotImages(augmented_images)\n\naugmented_images = [val_data_gen[0][0][0] for i in range(5)]\n\nplotImages(augmented_images)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-05-16T14:39:21.931535Z","iopub.execute_input":"2022-05-16T14:39:21.931808Z","iopub.status.idle":"2022-05-16T14:39:32.798699Z","shell.execute_reply.started":"2022-05-16T14:39:21.931777Z","shell.execute_reply":"2022-05-16T14:39:32.798019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **2. Make a model**","metadata":{}},{"cell_type":"markdown","source":"We use convolutional neural network model because it's good for computer vision problems. Tryout multiple models:","metadata":{}},{"cell_type":"markdown","source":"**First, we try a model with three VGG blocks. The final accuracy of model is 64%**\n* Activation Function or Transfer Function is the way to get output out of node. We use Relu because it can solve the saturate problems.\n* In the last layer, we use activation = 'sigmoid' for classifing ouput.","metadata":{}},{"cell_type":"code","source":"#Three Block VGG Model: 64%\nmodel = Sequential([\n    #Block 1\n    Conv2D(32, (3, 3), activation='relu', input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),\n    MaxPooling2D(2, 2),\n    #Block 2\n    Conv2D(64, (3, 3), activation='relu'),\n    MaxPooling2D(2, 2),\n    #Block 3\n    Conv2D(128, (3, 3), activation='relu'),\n    MaxPooling2D(2,2),\n    #Flatten and Dense layer\n    Flatten(),\n    Dense(128, activation='relu'),\n    Dense(1, activation='sigmoid')\n])\n\nmodel.compile(optimizer=SGD(lr=0.001, momentum=0.9), loss='binary_crossentropy', metrics=['accuracy'])\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T13:54:30.67149Z","iopub.execute_input":"2022-05-16T13:54:30.671749Z","iopub.status.idle":"2022-05-16T13:54:30.73827Z","shell.execute_reply.started":"2022-05-16T13:54:30.67172Z","shell.execute_reply":"2022-05-16T13:54:30.737609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Second, we try a model with three VGG blocks and dropout but the accuracy of model drop to 61%**\n* Dropout: regulization method to prevent overfitting","metadata":{}},{"cell_type":"code","source":"#Three Block VGG Model + Dropout: 61%\nmodel = Sequential([\n    #Block 1\n    Conv2D(32, (3, 3), activation='relu', input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)),\n    MaxPooling2D(2, 2),\n    #Block 2\n    Conv2D(64, (3, 3), activation='relu'),\n    MaxPooling2D(2, 2),\n    #Block 3\n    Conv2D(128, (3, 3), activation='relu'),\n    MaxPooling2D(2,2),\n    #Dropout, Dense and Flatten layers\n    Dropout(0.2),\n    Flatten(),\n    Dense(128, activation='relu'),\n    Dropout(0.5),\n    Dense(1, activation='sigmoid')\n])\n\nmodel.compile(optimizer=SGD(lr=0.001, momentum=0.9), loss='binary_crossentropy', metrics=['accuracy'])\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T13:54:10.472546Z","iopub.execute_input":"2022-05-16T13:54:10.472817Z","iopub.status.idle":"2022-05-16T13:54:10.7718Z","shell.execute_reply.started":"2022-05-16T13:54:10.472789Z","shell.execute_reply":"2022-05-16T13:54:10.77045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Finally, we modify already existing VGG16 model to apply to our problem. The accuracy jump to 90%**\n* VGG16 is a convolutional neural network trained on a subset of the ImageNet dataset, a collection of over 14 million images belonging to 22,000 categories. Because its pre-trained model, we don't need to train again","metadata":{}},{"cell_type":"code","source":"# VGG16 model 90%\n\n# load VGG16 base model\n# Include_top is set to False, in order to exclude the model's fully-connected layers.\nconv_base = VGG16(include_top=False, input_shape=(IMG_HEIGHT, IMG_WIDTH, 3))\n\n# because vgg16 is pre-trained model, no need to train again \nfor layer in conv_base.layers:\n    layer.trainable = False\n    \n# add flatten and dense layer\noutput = conv_base.output\noutput = Flatten()(output)\noutput = Dense(128, activation='relu')(output)\noutput = Dense(1, activation='sigmoid')(output)\n\n# define new model\nmodel = Model(inputs=conv_base.inputs, outputs=output)\n\n# compile model\nmodel.compile(optimizer=SGD(lr=0.001, momentum=0.9), loss='binary_crossentropy', metrics=['accuracy'])\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T15:16:34.434112Z","iopub.execute_input":"2022-05-16T15:16:34.434371Z","iopub.status.idle":"2022-05-16T15:16:34.742102Z","shell.execute_reply.started":"2022-05-16T15:16:34.434342Z","shell.execute_reply":"2022-05-16T15:16:34.741392Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **V. Train model**","metadata":{}},{"cell_type":"code","source":"#Use model.fit to train model\nhistory = model.fit(x=train_data_gen, steps_per_epoch=16, epochs=epochs, validation_data=val_data_gen, validation_steps=16, verbose=1)","metadata":{"execution":{"iopub.status.busy":"2022-05-16T15:16:40.594717Z","iopub.execute_input":"2022-05-16T15:16:40.594994Z","iopub.status.idle":"2022-05-16T15:40:05.704841Z","shell.execute_reply.started":"2022-05-16T15:16:40.594966Z","shell.execute_reply":"2022-05-16T15:40:05.703765Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Need visualization to prevent problems like overfitting**","metadata":{}},{"cell_type":"code","source":"#visualize the accuracy and loss of the model.\naccuracy = history.history['accuracy']\nval_accuracy = history.history['val_accuracy']\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nplt.figure(figsize=(10, 10))\n\nplt.subplot(2, 1, 1)\nplt.plot(range(epochs), accuracy, label='Training Accuracy')\nplt.plot(range(epochs), val_accuracy, label='Validation Accuracy')\nplt.legend(loc='lower right')\nplt.title('Accuracy Performance')\n\nplt.subplot(2, 1, 2)\nplt.plot(range(epochs), loss, label='Training Loss')\nplt.plot(range(epochs), val_loss, label='Validation Loss')\nplt.legend(loc='lower left')\nplt.title('Loss Performance')\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-05-16T15:40:44.916327Z","iopub.execute_input":"2022-05-16T15:40:44.916597Z","iopub.status.idle":"2022-05-16T15:40:45.251329Z","shell.execute_reply.started":"2022-05-16T15:40:44.916566Z","shell.execute_reply":"2022-05-16T15:40:45.250651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **VI. Test model**","metadata":{}},{"cell_type":"markdown","source":"## **1. Create test data generator**","metadata":{}},{"cell_type":"code","source":"#create test image generator\ntest_generator = ImageDataGenerator(rescale=1./255)\ntest_dog_gen = test_generator.flow_from_directory(directory = \"test/dog\", target_size=(IMG_HEIGHT, IMG_WIDTH), batch_size=batch_size, shuffle=False, class_mode='binary')\ntest_cat_gen = test_generator.flow_from_directory(directory = \"test/cat\", target_size=(IMG_HEIGHT, IMG_WIDTH), batch_size=batch_size, shuffle=False, class_mode='binary')","metadata":{"execution":{"iopub.status.busy":"2022-05-16T15:40:52.511675Z","iopub.execute_input":"2022-05-16T15:40:52.512327Z","iopub.status.idle":"2022-05-16T15:40:52.947322Z","shell.execute_reply.started":"2022-05-16T15:40:52.51228Z","shell.execute_reply":"2022-05-16T15:40:52.946469Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **2. Random pick 1 image from test folder and print the prediction**","metadata":{}},{"cell_type":"code","source":"#random cat or dog\ntype_num = random.randint(1, 2)\n#1 for cat\n#2 for dog\n\n#get random image\nimg_num = random.randint(1, 6250)\nx_num = math.floor(img_num / batch_size)\ny_num = img_num % batch_size\n\nif type_num == 1: sample_test_images, _ = test_cat_gen[x_num]\nelse: sample_test_images, _ = test_dog_gen[x_num]\nplotImages([sample_test_images[y_num]])\n\n#print prediction\noutput = model.predict(np.array([sample_test_images[y_num]]))\nx = output[0][0]\nif (x > 0.5): print(\"dog\")\nelse: print(\"cat\")","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-05-16T01:47:30.894544Z","iopub.execute_input":"2022-05-16T01:47:30.895442Z","iopub.status.idle":"2022-05-16T01:47:32.069536Z","shell.execute_reply.started":"2022-05-16T01:47:30.895402Z","shell.execute_reply":"2022-05-16T01:47:32.068701Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## **3. Model performance**","metadata":{}},{"cell_type":"code","source":"dog_predictions = model.predict(test_dog_gen)\ncat_predictions = model.predict(test_cat_gen)\nsum1 = sum(1 if dog > 0.5 else 0 for dog in dog_predictions)\nsum2 = sum(1 if cat <= 0.5 else 0 for cat in cat_predictions)\nprint(f\"Your model correctly identified {round((sum1 + sum2)/12500, 2) * 100}% of the images\")","metadata":{"execution":{"iopub.status.busy":"2022-05-16T15:40:57.323174Z","iopub.execute_input":"2022-05-16T15:40:57.32369Z","iopub.status.idle":"2022-05-16T15:41:56.753728Z","shell.execute_reply.started":"2022-05-16T15:40:57.323653Z","shell.execute_reply":"2022-05-16T15:41:56.752936Z"},"trusted":true},"execution_count":null,"outputs":[]}]}