{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Cats vs Dogs Classifier with Deep CNN"},{"metadata":{},"cell_type":"markdown","source":"Source: https://machinelearningmastery.com/how-to-develop-a-convolutional-neural-network-to-classify-photos-of-dogs-and-cats/"},{"metadata":{},"cell_type":"markdown","source":"## Dogs vs. Cats Dataset Preparation"},{"metadata":{"trusted":true},"cell_type":"code","source":"# plot dog photos from the dogs vs cats dataset\nfrom matplotlib import pyplot\nfrom matplotlib.image import imread\n# define location of dataset\nfolder = '/kaggle/input/dogs-vs-cats/train/train/'\ndef plot_images(class_name, count):\n    # plot first few images\n    for i in range(count):\n        # define subplot\n        pyplot.subplot(330 + 1 + i)\n        # define filename\n        filename = folder + class_name + '.' + str(i) + '.jpg'\n        # load image pixels\n        image = imread(filename)\n        # plot raw pixel data\n        pyplot.imshow(image)\n    # show the figure\n    pyplot.show()\n\nplot_images('cat', 9)\nplot_images('dog', 9)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Split dataset into test and train groups"},{"metadata":{"trusted":true},"cell_type":"code","source":"# organize dataset into a useful structure\nfrom os import makedirs\nfrom os import listdir\nfrom shutil import copyfile\nfrom random import seed\nfrom random import random\n# create directories\ndataset_home = 'dataset_dogs_vs_cats/'\nsubdirs = ['train/', 'test/']\nfor subdir in subdirs:\n\t# create label subdirectories\n\tlabeldirs = ['dogs/', 'cats/']\n\tfor labldir in labeldirs:\n\t\tnewdir = dataset_home + subdir + labldir\n\t\tmakedirs(newdir, exist_ok=True)\n# seed random number generator\nseed(1)\n# define ratio of pictures to use for validation\nval_ratio = 0.25\n# copy training dataset images into subdirectories\nsrc_directory = '/kaggle/input/dogs-vs-cats/train/train/'\nfor file in listdir(src_directory):\n\tsrc = src_directory + '/' + file\n\tdst_dir = 'train/'\n\tif random() < val_ratio:\n\t\tdst_dir = 'test/'\n\tif file.startswith('cat'):\n\t\tdst = dataset_home + dst_dir + 'cats/'  + file\n\t\tcopyfile(src, dst)\n\telif file.startswith('dog'):\n\t\tdst = dataset_home + dst_dir + 'dogs/'  + file\n\t\tcopyfile(src, dst)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Develop CNN Models"},{"metadata":{"trusted":true},"cell_type":"code","source":"# baseline model for the dogs vs cats dataset\nimport sys\nfrom matplotlib import pyplot\nfrom keras.utils import to_categorical\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D\nfrom keras.layers import MaxPooling2D\nfrom keras.layers import Dense\nfrom keras.layers import Flatten\nfrom keras.optimizers import SGD\nfrom keras.preprocessing.image import ImageDataGenerator\n\n# plot diagnostic learning curves\ndef summarize_diagnostics(model_name, history):\n\t# plot loss\n\tpyplot.subplot(211)\n\tpyplot.title('Cross Entropy Loss')\n\tpyplot.plot(history.history['loss'], color='blue', label='train')\n\tpyplot.plot(history.history['val_loss'], color='orange', label='test')\n\t# plot accuracy\n\tpyplot.subplot(212)\n\tpyplot.title('Classification Accuracy')\n\tpyplot.plot(history.history['acc'], color='blue', label='train')\n\tpyplot.plot(history.history['val_acc'], color='orange', label='test')\n\tpyplot.show()\n\t# save plot to file\n\tpyplot.savefig(model_name + '_plot.png')\n\tpyplot.close()\n\n# run the test harness for evaluating a model\ndef run_test_harness(model_name, model):\n\t# create data generator\n\tdatagen = ImageDataGenerator(rescale=1.0/255.0)\n\t# prepare iterators\n\ttrain_it = datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n\t\tclass_mode='binary', batch_size=64, target_size=(200, 200))\n\ttest_it = datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n\t\tclass_mode='binary', batch_size=64, target_size=(200, 200))\n\t# fit model\n\thistory = model.fit_generator(train_it, steps_per_epoch=len(train_it),\n\t\tvalidation_data=test_it, validation_steps=len(test_it), epochs=20, verbose=0)\n\t# evaluate model\n\t_, acc = model.evaluate_generator(test_it, steps=len(test_it), verbose=0)\n\tprint('> %.3f' % (acc * 100.0))\n\t# learning curves\n\tsummarize_diagnostics(model_name, history)\n\t# save model\n\tmodel.save(model_name + '.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### One Block VGG Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# define cnn model\ndef define_vgg1_model():\n\tmodel = Sequential()\n\tmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Flatten())\n\tmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n\tmodel.add(Dense(1, activation='sigmoid'))\n\t# compile model\n\topt = SGD(lr=0.001, momentum=0.9)\n\tmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n\treturn model\n\n# entry point, run the test harness\nmodel_vgg1 = define_vgg1_model()\nrun_test_harness('vgg1', model_vgg1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Two Blocks VGG Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# define cnn model\ndef define_vgg2_model():\n\tmodel = Sequential()\n\tmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Flatten())\n\tmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n\tmodel.add(Dense(1, activation='sigmoid'))\n\t# compile model\n\topt = SGD(lr=0.001, momentum=0.9)\n\tmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n\treturn model\n\n# entry point, run the test harness\nmodel_vgg2 = define_vgg2_model()\nrun_test_harness('vgg2', model_vgg2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Three Blocks VGG Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# define cnn model\ndef define_vgg3_model():\n\tmodel = Sequential()\n\tmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Flatten())\n\tmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n\tmodel.add(Dense(1, activation='sigmoid'))\n\t# compile model\n\topt = SGD(lr=0.001, momentum=0.9)\n\tmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n\treturn model\n\n# entry point, run the test harness\nmodel_vgg3 = define_vgg3_model()\nrun_test_harness('vgg3', model_vgg3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Develop Model Improvements"},{"metadata":{},"cell_type":"markdown","source":"### Dropout Regularization\n\nDropout works by probabilistically removing, or “dropping out,” inputs to a layer, which may be input variables in the data sample or activations from a previous layer. It has the effect of simulating a large number of networks with very different network structures and, in turn, making nodes in the network generally more robust to the inputs."},{"metadata":{"trusted":true},"cell_type":"code","source":"# define VGG3 Block cnn model with Dropout\ndef define_dropout_model():\n\tmodel = Sequential()\n\tmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Dropout(0.2))\n\tmodel.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Dropout(0.2))\n\tmodel.add(Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Dropout(0.2))\n\tmodel.add(Flatten())\n\tmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n\tmodel.add(Dropout(0.5))\n\tmodel.add(Dense(1, activation='sigmoid'))\n\t# compile model\n\topt = SGD(lr=0.001, momentum=0.9)\n\tmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n\treturn model\n\n# entry point, run the test harness\nmodel_vgg3_dropout = define_dropout_model()\nrun_test_harness('vgg3_dropout', model_vgg3_dropout)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Image Data Augmentation\n\nImage 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. The augmentation techniques can create variations of the images that can improve the ability of the fit models to generalize what they have learned to new images."},{"metadata":{"trusted":true},"cell_type":"code","source":"# run the test harness for evaluating a model\ndef run_augmented_img_test_harness(model_name, model):\n\t# create data generators\n\ttrain_datagen = ImageDataGenerator(rescale=1.0/255.0,\n\t\twidth_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True)\n\ttest_datagen = ImageDataGenerator(rescale=1.0/255.0)\n\t# prepare iterators\n\ttrain_it = train_datagen.flow_from_directory('dataset_dogs_vs_cats/train/',\n\t\tclass_mode='binary', batch_size=64, target_size=(200, 200))\n\ttest_it = test_datagen.flow_from_directory('dataset_dogs_vs_cats/test/',\n\t\tclass_mode='binary', batch_size=64, target_size=(200, 200))\n\t# fit model\n\thistory = model.fit_generator(train_it, steps_per_epoch=len(train_it),\n\t\tvalidation_data=test_it, validation_steps=len(test_it), epochs=50, verbose=0)\n\t# evaluate model\n\t_, acc = model.evaluate_generator(test_it, steps=len(test_it), verbose=0)\n\tprint('> %.3f' % (acc * 100.0))\n\t# learning curves\n\tsummarize_diagnostics(model_name, history)\n\t# save model\n\tmodel.save(model_name + '.h5')\n\n# entry point, run the test harness\nrun_augmented_img_test_harness('vgg3_augmented', model_vgg3)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Explore Transfer Learning"},{"metadata":{},"cell_type":"markdown","source":"### Keras pre-trained VGG16 model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# define cnn model\ndef define_vgg16_model():\n\t# load model\n\tmodel = VGG16(include_top=False, input_shape=(224, 224, 3))\n\t# mark loaded layers as not trainable\n\tfor layer in model.layers:\n\t\tlayer.trainable = False\n\t# add new classifier layers\n\tflat1 = Flatten()(model.layers[-1].output)\n\tclass1 = Dense(128, activation='relu', kernel_initializer='he_uniform')(flat1)\n\toutput = Dense(1, activation='sigmoid')(class1)\n\t# define new model\n\tmodel = Model(inputs=model.inputs, outputs=output)\n\t# compile model\n\topt = SGD(lr=0.001, momentum=0.9)\n\tmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n\treturn model\n\n# entry point, run the test harness\nmodel_vgg16 = define_vgg16_model()\nrun_test_harness('vgg16', model_vgg16)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Finalize the Model and Make Predictions"},{"metadata":{},"cell_type":"markdown","source":"### Predict image"},{"metadata":{"trusted":true},"cell_type":"code","source":"# make a prediction for a new image.\nfrom keras.preprocessing.image import load_img\nfrom keras.preprocessing.image import img_to_array\nfrom keras.models import load_model\n\n# load and prepare the image\ndef load_image(filename):\n\t# load the image\n\timg = load_img(filename, target_size=(224, 224))\n\t# convert to array\n\timg = img_to_array(img)\n\t# reshape into a single sample with 3 channels\n\timg = img.reshape(1, 224, 224, 3)\n\t# center pixel data\n\timg = img.astype('float32')\n\timg = img - [123.68, 116.779, 103.939]\n\treturn img\n\n# load an image and predict the class\ndef run_example(model_name, image_path):\n\t# load the image\n\timg = load_image(image_path)\n\t# load model\n\tmodel = load_model(model_name + '.h5')\n\t# predict the class\n\tresult = model.predict(img)\n\tprint(result[0])\n\n# entry point, run the example\nfile_path = '/kaggle/input/sample_image/sample_image.jpg'\nprint('VGG1')\nrun_example('vgg1', file_path)\nprint('VGG2')\nrun_example('vgg2', file_path)\nprint('VGG3')\nrun_example('vgg3', file_path)\nprint('VGG3 + Dropout')\nrun_example('vgg3_dropout', file_path)\nprint('VGG3 + Augmented')\nrun_example('vgg3_augmented', file_path)\nprint('VGG16')\nrun_example('vgg16', file_path)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"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.7.4"}},"nbformat":4,"nbformat_minor":1}