{"cells":[{"metadata":{"_uuid":"e7294aa19de486962a6a629e6f6779594f9606b5"},"cell_type":"markdown","source":"# Hello everyone"},{"metadata":{"_uuid":"2bdbc0c66f7f5b32ad2c4b0d7e4040da984a368b"},"cell_type":"markdown","source":"This is my first attempt to build a CNN from scratch. Untill now I am just doing models from 'from keras.dataset import ...', so I hope it works fine (and works as you see at the end and I am very happy with the results)\n\nI will describe as clearly as possible for you if you're a beginner and for myself because I probably gonna use this notebook as my future guides as well. So I want you to understand clearly what I am doing\n\nAt the end of the page I'm gonna put some notes just for justify some stuffs I know that can be written in another way or why I'm importing x library since y library can do the same.\n\nSo lets begin ..."},{"metadata":{"trusted":true,"_uuid":"9bd51c6e4b5d495536de1536009b2ce1dd935752"},"cell_type":"code","source":"import keras\nfrom keras.preprocessing import image\nfrom glob import glob\nimport cv2, os\nimport numpy as np\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9cf78d302cf733f81345d8b9b9ea89b1f2ee5ebb"},"cell_type":"markdown","source":"Note that even it is a jupyter notebook file I not: using %matplotlib inline\n    \nThe reason is just because it is easier to run if I download it as .py\n\nI am using the kaggle's notebook path for the train folder and we don't need the test for this project. We gonna create and train our network for those images and thats all.\n\nI write ROW and COL in uppercase because this is the way I learn and used to write my codes with Keras so it is a way to differentiate things that are more important or belong to Keras parte from the most part of code but in this case, we need these variables to resize our image."},{"metadata":{"trusted":true,"_uuid":"92b70b2e560692c00818ca49c29635638ca34f05"},"cell_type":"code","source":"path = '../input/train/'\n\nROW, COL = 96, 96","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"45d97ab7e0e5820b198f860a6a71f6aa7bc787ad"},"cell_type":"code","source":"dogs, cats = [], []\ny_dogs, y_cats = [], []","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b372d64b53c7c9dec495f402a0cfcd66c6719df6"},"cell_type":"markdown","source":"# Data pre processing"},{"metadata":{"_uuid":"cf7156f7ff26088af316f2a1d793be31a859ae46"},"cell_type":"markdown","source":"Ok. I am like to separate Cats from Dogs (because they tend to fight each other - just kidding). To be honest I don't think you need to do this but I think it is a better way to understand what I am doing and best if you someday need to use this way for a further projects.\n\ny_dogs and y_cats are my labels.\n\nThe code bellow are just a definition and selfexplanatory but lets see\n\nI am getting all 'dog' images. In this case there are just .jpg in this folder so it is unnecessary to write things like 'dog*.jpg' and for each dog image (dog_img) I am creating a variable for save all transformations I am going to do.\n\nRead an image then change its color to gray because there are more variables that differentiate a dog from a cat. Resize this image for an OK size (I've tested it and 50x50px still nice but lets use 96x96px) and then convert it into array. If you don't convert it's ok but to read and proccess images as images itself is slower than to proccess them as arrays"},{"metadata":{"trusted":true,"_uuid":"ea7823cb5f4a1b7d7cc862f23c23532900b15927"},"cell_type":"code","source":"def load_dogs():\n    print('Loading all dog images\\n')\n    dog_path = os.path.join(path, 'dog*')\n    for dog_img in glob(dog_path):\n        dog = cv2.imread(dog_img)\n        dog = cv2.cvtColor(dog, cv2.COLOR_BGR2GRAY)\n        dog = cv2.resize(dog, (ROW, COL))\n        dog = image.img_to_array(dog)\n        dogs.append(dog)\n    print('All dog images loaded')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"10ebd4ded48e6c067c8d840b6b9900833f149e5e"},"cell_type":"code","source":"def load_cats():\n    print('Loading all cat images\\n')\n    cat_path = os.path.join(path, 'cat*')\n    for cat_img in glob(cat_path):\n        cat = cv2.imread(cat_img)\n        cat = cv2.cvtColor(cat, cv2.COLOR_BGR2GRAY)\n        cat = cv2.resize(cat, (ROW, COL))\n        cat = image.img_to_array(cat)\n        cats.append(cat)\n    print('All cat images loaded')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4dd9a243e8063d66619868a544c6f98e07ebe6ff"},"cell_type":"code","source":"load_dogs()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f24f7637ff6d89587839408e7ca3484cf4aa14fb"},"cell_type":"code","source":"print('#################################')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c289ed34e2d8002d237e10764f25e8473f7811b8"},"cell_type":"code","source":"load_cats()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"704f4809e924f58b2077025b41b85302dd38e317"},"cell_type":"code","source":"print('Lenght of our dogs array: {}\\nLenght of our cats array: {}'.format(len(dogs),len(cats)))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"baff59f34d9b18a9fddea997f435de5391303fae"},"cell_type":"markdown","source":"Everything is ok. We need exactly 12,500 for cats and 12,500 for dogs"},{"metadata":{"trusted":true,"_uuid":"4d167a2fdc54a3ec6f4bce8dc0ccac947e538301"},"cell_type":"code","source":"classes = ['dog', 'cat']","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"54b188d8263088e8b18770910b5b982ab936c5a8"},"cell_type":"markdown","source":"Acctually it is another step that you can skip (with propper changes with code bellow) but to make it more clearly I am gonna make it explicity that our classes are 'dog' and 'cat'.\n\nAnd bellow I am just want to see if our code store everything correctly. You know. Sometimes it is easier to work with arrays but are you sure that those numbers means what you whant to they supposed to mean?"},{"metadata":{"trusted":true,"_uuid":"c440fd4a620a0263847353eb232e67397af59996"},"cell_type":"code","source":"import random","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b1e1330c56f0a529c04e444be145ffbb97ad1672"},"cell_type":"code","source":"plt.figure(figsize=(12,8))\n\nfor i in range(5):\n    plt.subplot(1, 5, i+1)\n    img = image.array_to_img(random.choice(dogs))\n    plt.imshow(img)\n    \n    plt.axis('off')\n    plt.title('Suposed to be a {}'.format(classes[0]))\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a4d48a2405414d811b035a085ef83a4d972f5bd9"},"cell_type":"code","source":"plt.figure(figsize=(12,8))\n\nfor i in range(5):\n    plt.subplot(1, 5, i+1)\n    img = image.array_to_img(random.choice(cats))\n    plt.imshow(img)\n    \n    plt.axis('off')\n    plt.title('Suposed to be a {}'.format(classes[1]))\n    \nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"e39a3c632f20855a3177da48ff2c06193bed6757"},"cell_type":"markdown","source":"Nice. They mean what I want to.\n\nBut my computer doesn't understand what dogs and cats are but it knew very well what a 0 and 1 means.\n\nLets give these labels 1 for dogs and 0 for cats, as Kaggle inform."},{"metadata":{"trusted":true,"_uuid":"d0cd2776b0c998b4b9a4c05a9602835ae97c1f37"},"cell_type":"code","source":"y_dogs = [1 for item in enumerate(dogs)]\ny_cats = [0 for item in enumerate(cats)]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b16987d6f0e8aff7a9be147846900d39d6a8cc10"},"cell_type":"code","source":"print('Len of dogs labels: {}\\nLen of cats labels: {}'.format(len(y_dogs), len(y_cats)))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fe032fd7c5ed3bc26ee5d170354140f135f111b7"},"cell_type":"markdown","source":"# Almost done for data preparation"},{"metadata":{"_uuid":"bac1bbd73ce7add374433b1cee4a7f6b05dfbf22"},"cell_type":"markdown","source":"What I am going to do is to write an X file for our trainning just like the convetion. Put all my values into one array and them I am going to normalize my X just to fit values between 0 and 1 and for this reason I need to specify that my X is a float type\n\nFor my y vales or my labels I am just writing them as one array also because we need to use like this to make what is called: One-hot encoding."},{"metadata":{"trusted":true,"_uuid":"bd631fb989ecc54f08c8de0c7764d6134cba70e6"},"cell_type":"code","source":"dogs = np.asarray(dogs).astype('float32')\ncats = np.asarray(cats).astype('float32')\ny_dogs = np.asarray(y_dogs).astype('int32')\ny_cats = np.asarray(y_cats).astype('int32')\ndogs /= 255\ncats /= 255","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ba2e190b68a5c57d6f340c77bd54ba8de49c52d3"},"cell_type":"code","source":"X = np.concatenate((dogs,cats), axis=0)\ny = np.concatenate((y_dogs, y_cats), axis=0)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"458d090cd22b666ef02fcc7594e84a4e5947244a"},"cell_type":"markdown","source":"# Start our CNN model"},{"metadata":{"trusted":true,"_uuid":"ca53881cb4d45a89fb162e53d7e9cb1552b1dece"},"cell_type":"code","source":"from keras.models import Sequential\nfrom keras.layers.convolutional import Conv2D, MaxPooling2D\nfrom keras.layers.core import Dense, Flatten, Dropout, Activation\nfrom keras.optimizers import Adam\nfrom keras.utils import np_utils\nfrom keras.callbacks import ModelCheckpoint\nfrom keras.models import save_model, load_model","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"085ca9796c863370379402118d2a85b79e776c08"},"cell_type":"markdown","source":"Now I am just setting my network from what is called Convolution Neural Network. Those variables are not arbitrary and you can change for and from your necessity but the composition for being a CNN still remmaing:\n\nConvolutional -> Convolutional -> MaxPooling -> Convolutional -> Convolutional -> MaxPooling\n\nAs I said those variables are not arbitrary but I am happy with my results. I'm not gonna explain everything. The harder part is over with our data pre processing.\n\nNow I suggest you to learn more about networks because it worth. Even myself still very beginner.\n\nWe gonna run this network for 100 epochs and I think it is enought to get a great result.\n\nOne more thing. I am changing my y again, passing my labels to a matrice that can be 0 or 1, deppending on what my model learn and for this I said that I have 2 classes getting from the lenght of my classes variable which in my opinion is a great way to inform to your model how manny classes you have."},{"metadata":{"trusted":true,"_uuid":"e1ee179e632492c0fab00d36df234b50abdfe95a"},"cell_type":"code","source":"IMG_CHANNEL = 1\nBATCH_SIZE = 128\nN_EPOCH = 100\nVERBOSE = 2\nVALIDAION_SPLIT = .2\nOPTIM = Adam()\nN_CLASSES = len(classes)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5c4e337be38e5e4ffc6bffcd93cb9496381a81b0"},"cell_type":"code","source":"y = np_utils.to_categorical(y, N_CLASSES)\nprint('One-Hot Encoding done')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"992953a8547ff95173a2ac863c7a36cc46e3a2ed"},"cell_type":"code","source":"model = Sequential([\n    Conv2D(32, (3,3), padding='same', input_shape=(ROW, COL, IMG_CHANNEL), activation='relu'),\n    Conv2D(32, (3,3), padding='same', activation='relu'),\n    MaxPooling2D(pool_size=(2,2)),\n    Dropout(.25),\n    Conv2D(64, (3,3), padding='same', activation='relu'),\n    Conv2D(64, (3,3), padding='same', activation='relu'),\n    MaxPooling2D(pool_size=(2,2)),\n    Dropout(.25),\n    Flatten(),\n    Dense(512, activation='relu'),\n    Dropout(.5),\n    Dense(N_CLASSES, activation='softmax')\n])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"44e85a4f3787900eaebaea77cedcf2924e6a49e8"},"cell_type":"code","source":"print('The model was created by following config:')\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ad27b89cdf5e22ff515236c1df93a3290b140209"},"cell_type":"code","source":"model.compile(loss='categorical_crossentropy', optimizer=OPTIM, metrics=['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"47fc7946db29b8bdf2d19adf0012a68f6c4a8ab2"},"cell_type":"code","source":"checkpoint = ModelCheckpoint('model_checkpoint/dogs_vs_cats_redux_checkpoint.h5')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"604fbf9c6eb82a547c373f15d8d1138ec5befb70"},"cell_type":"markdown","source":"Everything setted up so ..."},{"metadata":{"_uuid":"7d3fe95ac121a0b084287d4f275fba32b9dc62ae"},"cell_type":"markdown","source":"# Lets run our model"},{"metadata":{"trusted":true,"_uuid":"b0d7f3ae1af087f5d23885159be6bd7913cd8fcd"},"cell_type":"code","source":"print('#################################')\nprint('########### RUNNING #############')\nmodel.fit(X, y, batch_size=BATCH_SIZE, epochs=N_EPOCH, validation_split=VALIDAION_SPLIT, verbose=VERBOSE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e70aaaccb29b357ddadbccab04142231b885c93a","scrolled":true},"cell_type":"code","source":"print('############ SCORE ##############')\nscores = model.evaluate(X, y, verbose=2)\nprint('MODEL ACCURACY\\n{}: {}%'.format(model.metrics_names[1], scores[1]*100))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cc48917e7bea421b1941906f6a0cc712cad340a8"},"cell_type":"markdown","source":"That is it.\n\nEverything I done here was based on what I've read and learn from the book: Deep Learning with Keras by Antonio Gulli and Sujit Pal\n\nAnd material collected from internet, specially sentdex and rmotr\n\nThank you"}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}