{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Introduction\n\n*This is my first time using keras* (with tensorflow backend) hands-on to practice DL. I am using a video from youtube to guide myself and created this notebook as a memo and note to myself.\n\nYou can find the video playlist [here](https://www.youtube.com/watch?v=wQ8BIBpya2k&list=PLQVvvaa0QuDfhTox0AjmQ6tvTgMBZBEXN&index=2&t=0s).\n\n- Being a newbie at DL, this is very much a very very basic model without any augmentations done. The validation scores and accuracy will be pretty horrible.\n\n- Having said that, this kernel will be helpful in giving the most BASIC BASELINE model to improve upon, so it can be used to practice DL and other improvement methods like tranfer learning, using data generators, data augmentation etc.\n\n- **I have deleted the unzipped files at the end, so that after the predictions are made, you can easily see your output .csv, or else it'll be filled with cat and dog images which were unzipped on output directory.**\n\n- Incase, you are not able to get rid of cat and dog images, you'll find your csv in the output folder in \"Data\" section to right, in the editable kernel.","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nimport os\nimport cv2\n\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Unzipping the data onto Kaggle itself\nThe following code will unzip the image data. Although they will show up as normal test and train with \".zip\", you should be able to use os and walkthrough inside the zip files to access each image after this step without any warnings.","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-output":true},"cell_type":"code","source":"!unzip ../input/dogs-vs-cats-redux-kernels-edition/train.zip -d train\n!unzip ../input/dogs-vs-cats-redux-kernels-edition/test.zip -d test","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"TRAIN_DIR = '../working/train/train/'\nTEST_DIR = '../working/test/test/'\n\ntrain_images_filepaths = [TRAIN_DIR + last_file_name for last_file_name in os.listdir(TRAIN_DIR)]\ntest_images_filepaths = [TEST_DIR + last_file_name for last_file_name in os.listdir(TEST_DIR)]\n\nprint(\"Done\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We have training data containing both cat as well as dog image. Let us make a list of cat and dog images from the train data and store them separately.\n\nGetting the dogs and cats data sorted from the training dataset using list comprehension will do the trick for now.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dogs_filepaths = [TRAIN_DIR+ dog_file_name for dog_file_name in os.listdir(TRAIN_DIR) if 'dog' in dog_file_name]\ntrain_cats_filepaths = [TRAIN_DIR+ cat_file_name for cat_file_name in os.listdir(TRAIN_DIR) if 'cat' in cat_file_name]\n\nprint(\"Done\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Seeing a sample image\n\nEach entry in the `train_dogs` list is a file path to one individual image of dog in jpg format.\nWe will be converting each of this photo into an array so that each individual image can be represented as an array.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#Seeing a \"color\" image\ntest_img_file_path = train_dogs_filepaths[0]\nimg_array = cv2.imread(test_img_file_path,cv2.IMREAD_COLOR) #The last parameter can be switched with cv2.IMREAD_GRAYSCALE too\nplt.imshow(img_array)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Unhide the output to see how the image looks like in array form\nprint(img_array)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(img_array.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The 3 at the end signifies that the image has 3 channels, each for\n* red\n* green\n* blue\n\nIncase of grayscale images, there is no need for such three channels. Below is a quick implementation of it,","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"img_array_gray = cv2.imread(test_img_file_path,cv2.IMREAD_GRAYSCALE)\n\nplt.imshow(img_array_gray, cmap = \"gray\")\nplt.show()\n\nprint(img_array_gray.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Resizing the photos\n\nEach image in the file needn't be the same in it's dimensions. A snapshot of the images as given below.\n\nNOTE : In the snapshot, the filenames don't match with that of Kaggle's data. Kaggle has each image filename with 'dog' or 'cat' mentioned in it (only for train data). This dataset used in the YT tutorial is downloaded from microsoft store, which has both the cats and dog files separated into two respective folders.\n\n![Dog Snapshot](https://i.imgur.com/0NiPett.jpg)\n\nHence, we will set a global image size, which will serve as a global dimesnion standard for all the images.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"ROW_DIMENSION = 60\nCOLUMN_DIMENSION = 60\nCHANNELS = 3 #For greyscale images put it to 1; put it to 3 if you want color image data\n\nnew_array = cv2.resize(img_array_gray,(ROW_DIMENSION,COLUMN_DIMENSION)) #A squarish compression on it's width will take place\nplt.imshow(new_array,cmap = 'gray')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prep train and test images\n\nNow, we need to prep all the images in the datasets, ie, assigning them with the same global dimensions and other configurations so they stay uniform. \n\nWe will also add a read_converted_img function that will take an image array as argument and display it back in the converted format, incase we want to see any image in future.\n\n`prep_img` does exactly the same, except it returns the modified resized array.\n\n![](http://)We will return preped_data which will contain all the modified image arrays while the original filepaths linking to the original image files remain unchanged inside `train_dogs` and `train_cats`","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def read_converted_img(to_read_img_array):\n    plt.imshow(to_read_img_array,cmap = 'gray')\n    plt.show()\n    \ndef prep_img(single_image_path):\n    img_array_to_resize = cv2.imread(single_image_path,cv2.IMREAD_COLOR)\n    resized = cv2.resize(img_array_to_resize,(ROW_DIMENSION,COLUMN_DIMENSION),interpolation = cv2.INTER_CUBIC)\n    return resized\n\ndef prep_data(list_of_image_paths):\n    \n    size = len(list_of_image_paths)\n    \n    #preped_data = np.ndarray((size, ROW_DIMENSION, COLUMN_DIMENSION,CHANNELS), dtype=np.uint8)\n    preped_data = []\n    \n    '''\n    for i in range(size):\n        list_of_image_paths[i] = prep_img(list_of_image_paths)\n    '''\n    \n    for i, image_file_path in enumerate(list_of_image_paths):\n        '''\n        image = prep_img(image_file_path)\n        #preped_data[i] = image.T\n        preped_data.append(image)\n        '''\n        preped_data.append(cv2.resize(cv2.imread(image_file_path), (ROW_DIMENSION,COLUMN_DIMENSION), interpolation=cv2.INTER_CUBIC))\n        \n        if(i%1000==0):\n            print(\"Processed\",i,\"of\",size)\n        \n        #print(image.shape)\n        #print(preped_data.shape)\n        \n    return preped_data","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"The two variables, `train_data` and `test_data` will be used for storing the modified prep data generated from `train_images` and `test_images` ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"PREPING TRAINING SET\")\ntrain_data = prep_data(train_images_filepaths)\nprint(\"\\nPREPING TEST SET\")\ntest_data = prep_data(test_images_filepaths)\nprint(\"\\nDone\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Since train_data is a list, let us convert it into a numpy array. I will name it X_train for convenience.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train = np.array(train_data)\n\nprint(X_train.shape)\n#print(train_data.shape)\n#print(test_data.shape)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let us try visualising a photo from the converted training set. We'll use the `read_converted_img` method we defined above for this.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"read_converted_img(X_train[0])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preparing Y_train\n\nUnlike the MNIST dataset, which has a separate column `label` depicting the outcome, we have no such column in this case. However, in the filepath names, each file in train.zip folder has 'dog' or 'cat' being written in it's filename.\n\nThe same is not true for testing images for obvious reasons. You can confirm this with the code below.\n\nLet's start making the `y_train`!","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_images_filepaths[:3])\nprint(\"\\n\")\nprint(test_images_filepaths[:3])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Preparing y_train\n\ny_train = []\n\nfor path_name in train_images_filepaths:\n    if('dog' in path_name):\n        y_train.append(1)\n    else:\n        y_train.append(0)\n\nprint(\"Percentage of dogs is\",sum(y_train)/len(y_train))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We have equal number of cats and dog photos to train from. This is good.\nLet's convert this list to a numpy array too.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"y_train = np.array(y_train)\ny_train.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Choosing a model\n","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow import keras\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Flatten, Conv2D, Dropout\n\nprint(\"Import Successful\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dvc_classifier = Sequential()\n\ndvc_classifier.add(Conv2D(32,kernel_size = (3,3),\n                         activation = 'relu',\n                         input_shape = (ROW_DIMENSION,COLUMN_DIMENSION,3)))\n\ndvc_classifier.add(Conv2D(32,kernel_size = (3,3),\n                        activation = 'relu'))\n\ndvc_classifier.add(Conv2D(64,kernel_size = (3,3),\n                        activation = 'relu'))\n\ndvc_classifier.add(Flatten())\n\ndvc_classifier.add(Dense(128,activation = 'relu'))\n\ndvc_classifier.add(Dropout(0.5))\n\ndvc_classifier.add(Dense(1,activation = 'sigmoid'))\n\ndvc_classifier.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Syntax Observations : Important for absolute Begineers\n\n- **NOTE** : We passed a dense layer of size 1 at the end as this is a binary classification problem and one prediction is enough to find the other prediction. \nEg, if a picture is 80% likely to not be a cat, it is 80% likely to be a dog.\n\nThis is not the case with MNIST dataset that is tasked with recognising the digits. The digits can be any one of the 10 types, and binary classification isn't a viable option.\n\nThis is highlighted by the shape of our target arrays or the `y_train`\n\nThe shape of `y_train` in most tutorials for Digit Recognition such as [this one](https://www.kaggle.com/poonaml/deep-neural-network-keras-way), has shape of `y_train` as [num_of_testcases,classifiaction_categories] or simply. [num_of_testcases,10]\n\nIn this case, `y_train` is of shape (25000,)\n\nSimply put, in MNIST Digit Recognition, a number 8 would have it's `y_train` row as\n[0,0,0,0,0,0,0,0,1,0]\n\nIn this excercise, if a picture is cat, it's `y_train` is given as\n[0]\n\n- **NOTE 2** : If you decide to use same syntax as MNIST digit prediction, you need to show a cat image in it's y_train representation as [1,0] where 0th index is for Cats and 1th index is for Dogs.\n\nDoing so also allows you to use the 'softmax' activation function at the last Dense Layer.\nThe respective code changes to\n\n`dvc_classifier.add(Dense(num_of_classes,activation = 'softmax'))`\nwhere num_of_classes = 2","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"Compile the model.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"dvc_classifier.compile(loss = keras.losses.binary_crossentropy,\n                      optimizer = 'adam',\n                      metrics = ['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Fit the model.\nSince train_data has no need of splitting into X_train and y_train (due to there being no labels in train_data), we can safely conclude `X_train` would be = `train_data`.\nFor readability, we'll copy the elements of it anyway in a new varible `X_train` and use it for fitting.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"dvc_classifier.fit(X_train,y_train,\n               batch_size = 128,\n               epochs = 3,\n               validation_split = 0.2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Trying to save a model\nmodel_json = dvc_classifier.to_json()\nwith open(\"model.json\", \"w\") as json_file:\n    json_file.write(model_json)\n# serialize weights to HDF5\ndvc_classifier.save_weights(\"model.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.models import model_from_json\n\n# load json and create model\njson_file = open('model.json', 'r')\nloaded_model_json = json_file.read()\njson_file.close()\nloaded_model = model_from_json(loaded_model_json)\n# load weights into new model\nloaded_model.load_weights(\"model.h5\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"loaded_model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"arr_test = np.array(test_data)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"prediction_probabilities = dvc_classifier.predict(arr_test, verbose=0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Let us visualize some of the predictions the model made.","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"for i in range(5,11):\n    if prediction_probabilities[i, 0] >= 0.5: \n        print('I am {:.2%} sure this is a Dog'.format(prediction_probabilities[i][0]))\n    else: \n        print('I am {:.2%} sure this is a Cat'.format(1-prediction_probabilities[i][0]))\n        \n    plt.imshow(arr_test[i])\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Generating output","execution_count":null},{"metadata":{},"cell_type":"markdown","source":"We will first remove the zipped files, as they fill up the output section and we are able to see no .csv file.\nWe later make the .csv file 'submissions'","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#Deletig the folders containing unzipped data so output section is free of pictures\n\nimport sys\nimport shutil\n\n# Get directory name\nmydir = \"/kaggle/working\"\n\ntry:\n    shutil.rmtree(mydir)\nexcept OSError as e:\n    print(\"Error: %s - %s.\" % (e.filename, e.strerror))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pred_vals = [float(probability) for probability in prediction_probabilities ]\n\nsubmissions = pd.DataFrame({\"id\": list(range(1,len(prediction_probabilities)+1)),\n                         \"label\": pred_vals})\n\nsubmissions.to_csv(\"dogvcat_1.csv\", index=False, header=True)\n\nprint(\"Time to submit the baseline model!\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Improve upon the model from here\n\nTODO","execution_count":null},{"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}