{"cells":[{"metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","trusted":false},"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 in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport numpy as np\nimport random\nimport matplotlib.pyplot as plt\nfrom keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array\nfrom keras.utils import to_categorical\nfrom sklearn.model_selection import train_test_split\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ee477f9706b466fc950518a160aec3bdad9fd505"},"cell_type":"markdown","source":"# Prepare Traning Data"},{"metadata":{"_uuid":"9c716fb93c18c2e542cba2dda964464cc916cdd3","trusted":false},"cell_type":"code","source":"filenames = os.listdir(\"../input/train/train\")\ncategories = []\nfor filename in filenames:\n    category = filename.split('.')[0]\n    if category == 'dog':\n        categories.append(1)\n    else:\n        categories.append(0)\n        \n        \ndf = pd.DataFrame({'filename':filenames,\n                  'category':categories})\n\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9526d21917cc07b2a184a078e80ad6c8c6f47f2a","trusted":false},"cell_type":"code","source":"filenames = os.listdir(\"../input/train/train\")\nsample = random.choice(filenames)\nimage = load_img(\"../input/train/train/\"+sample)\nplt.imshow(image)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"efef71584c059c40d0e1610266d7e02b497a2fd0","trusted":false},"cell_type":"code","source":"df['category'].value_counts().plot.bar()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"312f430bcd7c893d401844f1c1462f918d30eac9","trusted":false},"cell_type":"code","source":"train_df, validation_df = train_test_split(df,test_size = 0.20, random_state = 42)\n\ntrain_df = train_df.reset_index(drop=True)\nvalidation_df = validation_df.reset_index(drop=True)\n\ntotal_train = train_df.shape[0]\ntotal_validate = validation_df.shape[0]\nbatch_size=15","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a6b178eea04588b056ab91e57ab499dfb43e5615"},"cell_type":"markdown","source":"## Build the classifier model\n* Build a CNN.CNN has mostly four fucntions:\n    * Convolution: Add the first layer which is a convolutional layer. Set the number of filters as 32, the shape of each filter as 3x3 and the input shape and the type of image as 50,50,3 i.e. the input is of a 50x50 RGB image and the activation function as relu.\n    * Pooling: Add a pooling layer to reduce the total number of nodes for the upcoming layers. It takes a 2x2 matrix thus giving minimum pixel loss and a precise region where the features are located.\n    * Flatten : Flattens the pooled images.\n    * Dense : add a fully connected layer to feed the images to the output layer. Set the number of nodes as 256, as its a common practice to use a power of 2 and a rectifier function asthe activation function, relu.\n\n* Define the output layer. Set number of units to 1 as this is a binary classifier and sigmoid as the activation function\n* Compile the model. Set adam as the optimizer and binary_crossentropy as the loss fucntion, as this is a binary classifier."},{"metadata":{"_uuid":"8c4349accb97e3e1bb3f8f7c11ea01cc2c6ade3d","trusted":false},"cell_type":"code","source":"from keras.models import Sequential,model_from_json\nfrom keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, Activation, BatchNormalization","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d3418bb01aeebc8ff7630bd6b15c19e4d5774c44","trusted":false},"cell_type":"code","source":"image_width = 50\nimage_height = 50\nimage_size = (image_width, image_height)\nimage_channel = 3 # RGB color","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9d8bd4d1488de4dc85d9b8c73d4c0ec1c9b30a1c","trusted":false},"cell_type":"code","source":"classifier1 = Sequential()\nclassifier1.add(Conv2D(32,(3,3),input_shape = (image_width,image_height,image_channel),activation = 'relu'))\nclassifier1.add(BatchNormalization())\nclassifier1.add(MaxPooling2D(pool_size = (2,2)))\n                \nclassifier1.add(Conv2D(64,(3,3),activation = 'relu'))\nclassifier1.add(BatchNormalization())\nclassifier1.add(MaxPooling2D(pool_size = (2,2)))\n                \nclassifier1.add(Flatten())\nclassifier1.add(Dense(256,activation = 'relu'))\nclassifier1.add(Dense(units = 1, activation = 'sigmoid'))\nclassifier1.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"64ce8e235dd39a2905a099169dfbe84d4150531b","trusted":false},"cell_type":"code","source":"classifier1.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"67cd573551bb6ddeeacae7dd85a55639dc03e960"},"cell_type":"markdown","source":""},{"metadata":{"_uuid":"6c0ac09000d2bdfbdf0e87f239a1aa8aae0220f7"},"cell_type":"markdown","source":"## Fitting the CNN to the images\n* Improve the dataset using the ImageDataGenerator method which generate batches of tensor image data with real-time data augmentation. \n    * rescale: rescaling factor. If None or 0, no rescaling is applied, otherwise the data is multiplied by the value provided.\n    * shear_range: Shear Intensity\n    * zoom_range: Range for random zoom.\n    * horizontal_flip: Randomly flip inputs horizontally if true.\n* Define the training and test datasets using the flow_from_directory which takes the path to a directory, and generates batches of augmented/normalized data.\n    * directory: path to the target directory. It should contain one subdirectory per class.\n    * target_size: The dimensions to which all images found will be resized.\n    * class_mode: one of \"categorical\", \"binary\", \"sparse\", \"input\" or None. Determines the type of label arrays that are returned\n    * batch_size: size of the batches of data"},{"metadata":{"_uuid":"76adebcc143a13b8a8a3325a30f24ab43402e626","trusted":false},"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    rotation_range=15,\n    rescale=1./255,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    width_shift_range=0.1,\n    height_shift_range=0.1\n)\n\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    train_df, \n    \"../input/train/train/\", \n    x_col='filename',\n    y_col='category',\n    target_size=image_size,\n    class_mode='binary',\n    batch_size=batch_size\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"afb92e74455d39d14c071aea6887d74fede24884"},"cell_type":"markdown","source":"## Validation Image Generator"},{"metadata":{"_uuid":"8ae7920b655cfee1dc38176c7b8cf0c2d5744918","trusted":false},"cell_type":"code","source":"validation_datagen = ImageDataGenerator(rescale=1./255)\nvalidation_generator = validation_datagen.flow_from_dataframe(\n    validation_df, \n    \"../input/train/train/\", \n    x_col='filename',\n    y_col='category',\n    target_size=image_size,\n    class_mode='binary',\n    batch_size=batch_size\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b3638abb03404cf1606ee11bf681283468a70f64"},"cell_type":"markdown","source":"## Explore the dataset\n* Print a preprocessed image from the dataset"},{"metadata":{"_uuid":"6b13da1932ef2bd453037870b2e4a22e51ab4d93","trusted":false},"cell_type":"code","source":"x , y  = train_generator.next()\nfor i in range(0,1):\n    random_image = x[i]\n    plt.imshow(random_image)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0fc7040da42b359fe75e5a7e0b06e2790e73ea09"},"cell_type":"markdown","source":"## Define an earlystopping callback\n* Import EarlyStopping - method to stop training when a monitored quantity has stopped improving.\n* Define a callback.Set monitor as val_acc, patience as 5 and mode as max so that if val_acc does not improve over 5 epochs, terminate the training process."},{"metadata":{"_uuid":"a5bcebbea9b156137096455c6d0d4ae2c555d3a0","trusted":false},"cell_type":"code","source":"from keras.callbacks import EarlyStopping, ReduceLROnPlateau\n\nearlystop = EarlyStopping(patience=10)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0dab5f05fcdb196adca0d5e3fae7267933c9e010","trusted":false},"cell_type":"code","source":"learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', \n                                            patience=2, \n                                            verbose=1, \n                                            factor=0.5, \n                                            min_lr=0.00001)\n\ncallbacks = [earlystop, learning_rate_reduction]","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cda4ba714a216119b8d263fe14410d9d7aaa662a"},"cell_type":"markdown","source":"## Fit the model\n* Invoke the fit_generator to fits the model on data generated batch-by-batch by a Python generator.\n    * steps_per_epoch’ holds the number of training images, i.e 8000\n    * A single epoch is a single step in training a neural network,set it at 25.\n    * callbacks: List of callbacks to apply during training.\n    * validation_data: test data\n    * validation_steps: Total number of steps (batches of samples) to yield from  validation_data generator before stopping at the end of every epoch. It should typically be equal to the number of samples of your validation dataset divided by the batch size."},{"metadata":{"_uuid":"6115f60ce9f517d986e45c4afdde89b82303e1ef","trusted":false},"cell_type":"code","source":"history = classifier1.fit_generator(\n    train_generator, \n    epochs= 25,\n    validation_data=validation_generator,\n    validation_steps=total_validate//batch_size,\n    steps_per_epoch=total_train//batch_size,\n    callbacks=callbacks\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f8ab37b5e658fcac0818fa6370f1995cf25f753f"},"cell_type":"markdown","source":"# Save Model"},{"metadata":{"_uuid":"e5ee70c799e4bd93c206955973e697141be5730d","trusted":false},"cell_type":"code","source":"model_json = classifier1.to_json()\n!mkdir Saved_models\nwith open(\"Saved_models/cnn_base_model.json\",\"w\") as json_file:\n    json_file.write(model_json)\n    \nclassifier1.save_weights(\"Saved_models/cnn_base_model.h5\")\nprint(\"Saved model to disk\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"66c4b18b517231db800032c932af43c6e883c91c"},"cell_type":"markdown","source":"## Evaluate the model\n* Load model from disk.\n* Preprocess and feed a random input image to the model for prediction.\n* Test the accuracy and loss using the evaluate_generator method."},{"metadata":{"_uuid":"430bee44aaeac69dd14787ebb98e42b4fc19f1da","trusted":false},"cell_type":"code","source":"json_file = open('Saved_models/cnn_base_model.json', 'r')\n\nloaded_classifier_json = json_file.read()\n\njson_file.close()\n\nloaded_classifier = model_from_json(loaded_classifier_json)\n\nloaded_classifier.load_weights(\"Saved_models/cnn_base_model.h5\")\nprint(\"Loaded model from disk\")\n\nloaded_classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"cd8642fa6b7c450b93369879a1fa49c62b727288"},"cell_type":"markdown","source":"# Virtualize Training and loss"},{"metadata":{"_uuid":"3e0f751dce78e96c56de21ba1d9723cb928b7997","trusted":false},"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12))\nax1.plot(history.history['loss'], color='b', label=\"Training loss\")\nax1.plot(history.history['val_loss'], color='r', label=\"validation loss\")\nax1.set_xticks(np.arange(1, 25, 1))\nax1.set_yticks(np.arange(0, 1, 0.1))\n\nax2.plot(history.history['acc'], color='b', label=\"Training accuracy\")\nax2.plot(history.history['val_acc'], color='r',label=\"Validation accuracy\")\nax2.set_xticks(np.arange(1, 25, 1))\n\nlegend = plt.legend(loc='best', shadow=True)\nplt.tight_layout()\nplt.show()\n\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ce6f425259ff95103fd8183c3419252443584e52","trusted":false},"cell_type":"code","source":"test_image = load_img('../input/test1/test1/1.jpg', target_size = (50, 50))\nplt.imshow(test_image)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"335f229657f47feb72b73bb28dfd59c6717d71f7","trusted":false},"cell_type":"code","source":"test_image = img_to_array(test_image)\ntest_image = np.expand_dims(test_image, axis = 0)\nresult = loaded_classifier.predict(test_image)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"424fa242f948d451abf810039048a152a14a2965","trusted":false},"cell_type":"code","source":"if result[0][0] == 1:\n    prediction = 'This is a dog'\nelse:\n    prediction = 'This is a cat'\n\nprint (prediction)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"339ccf3cf354e1c325060473c03b002a9effa7de"},"cell_type":"markdown","source":"# Prepare Testing Data"},{"metadata":{"_uuid":"508d46a96f81f23584670251608bfd799d7cb9d3","trusted":false},"cell_type":"code","source":"test_filenames = os.listdir(\"../input/test1/test1\")\ntest_df = pd.DataFrame({\n    'filename': test_filenames\n})\nnb_samples = test_df.shape[0]\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6db94b120b974dfd878ba13985f7b95af75b2f8a"},"cell_type":"markdown","source":"# Create Testing Data Generator"},{"metadata":{"_uuid":"8cc012e99c2cb4dd3a8c4db1f32fd3b50051563b","trusted":false},"cell_type":"code","source":"test_gen = ImageDataGenerator(rescale=1./255)\ntest_generator = test_gen.flow_from_dataframe(\n    test_df, \n    \"../input/test1/test1/\", \n    x_col='filename',\n    y_col=None,\n    class_mode=None,\n    target_size=image_size,\n    batch_size=batch_size,\n    shuffle=False\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f04481bb961f2f21f2078f7a9ee41dc06186b623"},"cell_type":"markdown","source":"# Prediction"},{"metadata":{"_uuid":"dff63ff0bbded07b11e765c6050ce1d6f4a2473d","trusted":false},"cell_type":"code","source":"predict = loaded_classifier.predict_generator(test_generator, steps=np.ceil(nb_samples/batch_size))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5011d8f98e35fe234f8cc9635f0d1c916efc470d"},"cell_type":"markdown","source":"\nAs predicted of binary classification result return probability that image likely to be a dog. So we will have threshold 0.5 which mean if predicted value more than 50% it is a dog and under 50% will be a cat.\n"},{"metadata":{"_uuid":"4601e1109532f892717363ab583aeff73a902d46","trusted":false},"cell_type":"code","source":"threshold = 0.5\ntest_df['probability'] = predict\ntest_df['category'] = np.where(test_df['probability'] > threshold, 1,0)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"61c1892f4ec3ebf26c3b2e00b820031a925d9856","trusted":false},"cell_type":"code","source":"test_df['category'].value_counts().plot.bar()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"edea9037bb3be0e873076cfd543a6b5ad98d38c0","trusted":false},"cell_type":"code","source":"sample_test = test_df.head(18)\nsample_test.head()\nplt.figure(figsize=(12, 24))\nfor index, row in sample_test.iterrows():\n    filename = row['filename']\n    category = row['category']\n    probability = row['probability']\n    img = load_img(\"../input/test1/test1/\"+filename, target_size=image_size)\n    plt.subplot(6, 3, index+1)\n    plt.imshow(img)\n    plt.xlabel(filename + '(' + \"{}\".format(category) + ')' '(' + \"{}\".format(round(probability, 2)) + ')')\nplt.tight_layout()\nplt.show()\n","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"34f764958ebbe11d06b43f37515afc9ba0a64ab6","trusted":false},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.6.8"}},"nbformat":4,"nbformat_minor":1}