{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"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 matplotlib.pyplot as plt # Data Plotting\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, shutil\nprint(os.listdir(\"../input\"))\n\nimport keras\nfrom keras import layers\nfrom keras import models\nfrom keras import optimizers\nfrom keras.preprocessing import image\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.applications import VGG16\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"original_dataset_directory = \"../input/train/train\"\n\nbase_dir = \"../cats_and_dogs_small\"\nos.mkdir(base_dir)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Directories for the training, validation and test splits\ntrain_dir = os.path.join(base_dir, \"train\")\nos.mkdir(train_dir)\n\nvalidation_dir = os.path.join(base_dir, \"validation\")\nos.mkdir(validation_dir)\n\ntest_dir = os.path.join(base_dir, \"test\")\nos.mkdir(test_dir)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Directory with training, valiation and test pictures (for both Cats and Dogs)\ntrain_cats_dir = os.path.join(train_dir, 'cats')\nos.mkdir(train_cats_dir)\n\ntrain_dogs_dir = os.path.join(train_dir, 'dogs')\nos.mkdir(train_dogs_dir)\n\nvalidation_cats_dir = os.path.join(validation_dir, 'cats')\nos.mkdir(validation_cats_dir)\n\nvalidation_dogs_dir = os.path.join(validation_dir, 'dogs')\nos.mkdir(validation_dogs_dir)\n\ntest_cats_dir = os.path.join(test_dir, 'cats')\nos.mkdir(test_cats_dir)\n\ntest_dogs_dir = os.path.join(test_dir, 'dogs')\nos.mkdir(test_dogs_dir)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Taking a sample from the original data set. Copying the first 1000 cat images to train_cats_dir\nfnames = ['cat.{}.jpg'.format(i) for i in range(1000)]\n\nfor fnames in fnames:\n    src = os.path.join(original_dataset_directory,fnames)\n    dst = os.path.join(train_cats_dir,fnames)\n    shutil.copyfile(src,dst)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Copying the next 500 images to validation_cats_dir\nfnames = ['cat.{}.jpg'.format(i) for i in range(1000, 1500)]\n\nfor fnames in fnames:\n    src = os.path.join(original_dataset_directory,fnames)\n    dst = os.path.join(validation_cats_dir,fnames)\n    shutil.copyfile(src,dst)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Copying the next 500 images to test_cats_dir\nfnames = ['cat.{}.jpg'.format(i) for i in range(1500, 2000)]\n\nfor fnames in fnames:\n    src = os.path.join(original_dataset_directory,fnames)\n    dst = os.path.join(test_cats_dir,fnames)\n    shutil.copyfile(src,dst)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Taking a sample from the original data set. Copying the first 1000 dog images to train_dogs_dir\nfnames = ['dog.{}.jpg'.format(i) for i in range(1000)]\n\nfor fnames in fnames:\n    src = os.path.join(original_dataset_directory,fnames)\n    dst = os.path.join(train_dogs_dir,fnames)\n    shutil.copyfile(src,dst)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Copying the next 500 images to validation_dogs_dir\nfnames = ['dog.{}.jpg'.format(i) for i in range(1000, 1500)]\n\nfor fnames in fnames:\n    src = os.path.join(original_dataset_directory,fnames)\n    dst = os.path.join(validation_dogs_dir,fnames)\n    shutil.copyfile(src,dst)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Copying the next 500 images to test_dogs_dir\nfnames = ['dog.{}.jpg'.format(i) for i in range(1500, 2000)]\n\nfor fnames in fnames:\n    src = os.path.join(original_dataset_directory,fnames)\n    dst = os.path.join(test_dogs_dir,fnames)\n    shutil.copyfile(src,dst)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# As a sanity check lets count how many pictures are there in each data set\nprint(\"Total training cat images\", len(os.listdir(\"../cats_and_dogs_small/train/cats\")))\nprint(\"Total training dog images\", len(os.listdir(\"../cats_and_dogs_small/train/dogs\")))\nprint(\"Total validation cat images\", len(os.listdir(\"../cats_and_dogs_small/validation/cats\")))\nprint(\"Total validation dog images\", len(os.listdir(\"../cats_and_dogs_small/validation/dogs\")))\nprint(\"Total test cat images\", len(os.listdir(\"../cats_and_dogs_small/test/cats\")))\nprint(\"Total test dog images\", len(os.listdir(\"../cats_and_dogs_small/test/dogs\")))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Creating the convnet model\nmodel = models.Sequential()\nmodel.add(layers.Conv2D(32,(3,3),activation = 'relu',\n                       input_shape = (150,150,3)))\nmodel.add(layers.MaxPooling2D((2,2)))\nmodel.add(layers.Conv2D(64,(3,3), activation = 'relu'))\nmodel.add(layers.MaxPooling2D((2,2)))\nmodel.add(layers.Conv2D(128,(3,3), activation = 'relu'))\nmodel.add(layers.MaxPooling2D((2,2)))\nmodel.add(layers.Conv2D(128,(3,3), activation = 'relu'))\nmodel.add(layers.MaxPooling2D((2,2)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dense(512, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(loss = 'binary_crossentropy',\n             optimizer = optimizers.RMSprop(lr=1e-4),\n             metrics=['acc'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Data Preprocessing\n\ntrain_datagen = ImageDataGenerator(rescale = 1./255)\ntest_datagen = ImageDataGenerator(rescale = 1./255)\n\ntrain_generator = train_datagen.flow_from_directory(\ntrain_dir,\ntarget_size = (150,150),\nbatch_size = 20,\nclass_mode = 'binary')\n\nvalidation_generator = test_datagen.flow_from_directory(\nvalidation_dir,\ntarget_size = (150,150),\nbatch_size = 20,\nclass_mode = 'binary')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Lets look at the output of one of these generators\n\nfor data_batch, lables_batch in train_generator:\n    print('data batch shape:', data_batch.shape)\n    print('lables batch shape;', lables_batch.shape)\n    break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Model Training begins here\n# Since we are using Data Generators, rather than static data sets, we would be using fit_generator to fit the data rather than traditional fit function\n\nhistory = model.fit_generator(\ntrain_generator,\nsteps_per_epoch=100,\nepochs = 30,\nvalidation_data=validation_generator,\nvalidation_steps = 50)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Saving the model post training\n\nmodel.save('cats_and_dogs_small_1.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Lets plot the loss and accuracy of the model over the training and validation data during training\n\nacc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(1, len(acc)+1)\n\nplt.plot(epochs, acc, 'bo', label = 'Training acc')\nplt.plot(epochs, val_acc, 'b', label = 'Validation acc')\nplt.title('Training and Validation Accuracy')\nplt.legend()\nplt.figure()\n\nplt.plot(epochs, loss, 'bo', label = 'Training loss')\nplt.plot(epochs, val_loss, 'b', label = 'Validation loss')\nplt.title('Training and Validation Accuracy')\nplt.legend()\nplt.figure()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* These plots are characteristic of overfitting \n* We see the training accuracy going up but the validation loss increasing\n* This is primarily happening because of the small size of the data set and lack of regularization within the model\n* So next step would be to do data augmentation and adding regularization to our model"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Lets take an example and see how does the image augmentation works\n\nfnames = [os.path.join(train_cats_dir, fnames) for fnames in os.listdir(train_cats_dir)]\n\ndatagen = ImageDataGenerator(\nrotation_range = 40,\nwidth_shift_range=0.2,\nheight_shift_range=0.2,\nshear_range=0.2,\nhorizontal_flip=True,\nfill_mode='nearest')\n\nimg_path = fnames[3]\nimg = image.load_img(img_path, target_size = (150,150))\n\nx = image.img_to_array(img)\nx = x.reshape((1,) + x.shape)\n\ni = 0\n\nfor batch in datagen.flow(x, batch_size = 1):\n    plt.figure(i)\n    imgplot = plt.imshow(image.array_to_img(batch[0]))\n    i += 1\n    if i % 4 == 0:\n        break\n\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* We have the code for data augmentation ready, now we need to rebuild our model by adding drop out regularization layer after the first flattening layer to prevent overfitting"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Re creating the model with added drop out layer\n\nmodel = models.Sequential()\nmodel.add(layers.Conv2D(32,(3,3),activation = 'relu',\n                       input_shape = (150,150,3)))\nmodel.add(layers.MaxPooling2D((2,2)))\nmodel.add(layers.Conv2D(64,(3,3), activation = 'relu'))\nmodel.add(layers.MaxPooling2D((2,2)))\nmodel.add(layers.Conv2D(128,(3,3), activation = 'relu'))\nmodel.add(layers.MaxPooling2D((2,2)))\nmodel.add(layers.Conv2D(128,(3,3), activation = 'relu'))\nmodel.add(layers.MaxPooling2D((2,2)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(512, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.compile(loss = 'binary_crossentropy',\n             optimizer = optimizers.RMSprop(lr=1e-4),\n             metrics = ['acc'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Lets train the network using data augmentation and dropout\n\ntrain_datagen = ImageDataGenerator(\nrescale = 1./255,\nrotation_range=40,\nwidth_shift_range=0.2,\nheight_shift_range=0.2,\nshear_range=0.2,\nzoom_range=0.2,\nhorizontal_flip=True)\n\ntest_datagen = ImageDataGenerator(rescale = 1./255) # Please note that the validation data set is not being augmented. Its just being rescaled\n\n# Passing the training directory to Image Data Generator constructor\ntrain_generator=train_datagen.flow_from_directory(\ntrain_dir,\ntarget_size = (150,150),\nbatch_size=32,\nclass_mode='binary')\n\n# Passing the test directory to its corresponding image pre processing constructor, just like the training data set\nvalidation_generator = test_datagen.flow_from_directory(\nvalidation_dir,\ntarget_size=(150,150),\nbatch_size=32,\nclass_mode='binary')\n\n# Fitting the model\nhistory = model.fit_generator(\ntrain_generator,\nsteps_per_epoch=100,\nepochs=100,\nvalidation_data = validation_generator,\nvalidation_steps = 50)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Saving the model post training\n\nmodel.save('cats_and_dogs_small_2.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plotting the results of the new network\n\nacc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(1, len(acc)+1)\n\nplt.plot(epochs, acc, 'bo', label = 'Training acc')\nplt.plot(epochs, val_acc, 'b', label = 'Validation acc')\nplt.title('Training and Validation Accuracy')\nplt.legend()\nplt.figure()\n\nplt.plot(epochs, loss, 'bo', label = 'Training loss')\nplt.plot(epochs, val_loss, 'b', label = 'Validation loss')\nplt.title('Training and Validation Accuracy')\nplt.legend()\nplt.figure()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* We have been able to bring down the overfitting, but the accuracy numbers are still not great\n* This is happening because of the small number of images in our training data set\n* Instead of building a network from scratch we can exploit Pre-Trained Networks to help us achieve better accuracy"},{"metadata":{},"cell_type":"markdown","source":"### Using Pre-Trained Networks: Feature Extraction"},{"metadata":{"trusted":true},"cell_type":"code","source":"# We will be using VGG16 network for feature extraction\n# Lets instantiate the VGG16 model\n\nconv_base = VGG16(weights = 'imagenet',\n                 include_top = False,\n                 input_shape=(150,150,3))\n\n# weights: It specifies the wieughts checkpoint from which to initialze the model\n# include_top: Specifies whether we need to inlcude the \"top\" densely connected layer or not\n# input_shape: Specifies the input shape which is required","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Click [https://neurohive.io/en/popular-networks/vgg16/](http://) <- to read more about VGG16 Network"},{"metadata":{},"cell_type":"markdown","source":"* There are two ways of using a pre-trained network:\n    1. Running the convolutional base over our dataset, recording its output to a Numpy array on disk and then using this data as an input to a standalone, densely connected classifier\n    2. Extending the model by adding a top layer and then training model\n* The first method is cheap in terms of computation since it doesnt require you to train the model from scratch. For the same reason we cannot take advantage of Data Augmentation\n* The second method involves training the network from scratch. This will help us exploit image augmentation, but for the same reason it will be computationally expensive"},{"metadata":{},"cell_type":"markdown","source":"### Feature Extraction without Data Augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Instantiating an ImageDataGenerator intance for recaling the images\ndatagen = ImageDataGenerator(rescale = 1./255)\nbatch_size = 20\n\ndef extract_features(directory, sample_count):\n    features = np.zeros(shape=(sample_count, 4, 4, 512))\n    labels = np.zeros(shape=(sample_count))\n    generator = datagen.flow_from_directory(\n    directory,\n    target_size=(150, 150),\n    batch_size=batch_size,\n    class_mode='binary')\n    i = 0\n    for inputs_batch, labels_batch in generator:\n        features_batch = conv_base.predict(inputs_batch)\n        features[i * batch_size : (i + 1) * batch_size] = features_batch\n        labels[i * batch_size : (i + 1) * batch_size] = labels_batch\n        i += 1\n        if i * batch_size >= sample_count:\n            break\n    return features, labels\n\n# Calling the extract features function on the training, validation and test directory\n\ntrain_features, train_labels = extract_features(train_dir, 2000)\nvalidation_features, validation_labels = extract_features(validation_dir, 1000)\ntest_features, test_labels = extract_features(test_dir, 1000)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Next we need to flatten the train_features, test_features and validation features so that they can be transferred to fully connected layer\n\ntrain_features = np.reshape(train_features,(2000, 4*4*512))\nvalidation_features = np.reshape(validation_features,(1000, 4*4*512))\ntest_features = np.reshape(test_features,(1000, 4*4*512))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Defining and training the densely connected classifier\n\nmodel = models.Sequential()\nmodel.add(layers.Dense(256,activation = 'relu', input_dim = 4*4*512))\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(1,activation = 'sigmoid'))\n\nmodel.compile(optimizer=optimizers.RMSprop(lr=2e-5),\nloss='binary_crossentropy',\nmetrics=['acc'])\n\n\nhistory = model.fit(train_features, train_labels,\n                   epochs = 30,\n                   batch_size = 20,\n                   validation_data = (validation_features, validation_labels))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Plotting the results of the new network\n\n# Plotting the results of the new network\n\nacc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(1, len(acc)+1)\n\nplt.plot(epochs, acc, 'bo', label = 'Training acc')\nplt.plot(epochs, val_acc, 'b', label = 'Validation acc')\nplt.title('Training and Validation Accuracy')\nplt.legend()\nplt.figure()\n\nplt.plot(epochs, loss, 'bo', label = 'Training loss')\nplt.plot(epochs, val_loss, 'b', label = 'Validation loss')\nplt.title('Training and Validation Accuracy')\nplt.legend()\nplt.figure()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* The accuracy has jumped up to 90% which is a big improvement"},{"metadata":{},"cell_type":"markdown","source":"### Feature Extraction with Data Augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras import models\nfrom keras import layers\n\nmodel = models.Sequential()\nmodel.add(conv_base)\nmodel.add(layers.Flatten())\nmodel.add(layers.Dense(256,activation='relu'))\nmodel.add(layers.Dense(1,activation='sigmoid'))\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Before we train the model its important to freeze the convolutional base\n* Freezing the convolutional base preserves the representations learnt by it so that you dont need to train the model from scratch  "},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"The number of trainable weights before freezing the convolutional layer = \",len(model.trainable_weights))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Freezing the conv base\nconv_base.trainable = False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"The number of trainable weights post freezing the convolutional layer\", len(model.trainable_weights))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# We can start training the model with the data augmentation which we used previously\n\ntrain_datagen = ImageDataGenerator(\nrescale = 1./255,\nrotation_range=40,\nheight_shift_range=0.2,\nwidth_shift_range=0.2,\nshear_range=0.2,\nzoom_range=0.2,\nhorizontal_flip=True,\nfill_mode='nearest')\n\ntest_datagen = ImageDataGenerator(\nrescale=1./255)\n\ntrain_generator = train_datagen.flow_from_directory(\ntrain_dir,\ntarget_size = (150,150),\nbatch_size=20,\nclass_mode = 'binary')\n\nvalidation_generator = test_datagen.flow_from_directory(\nvalidation_dir,\ntarget_size=(150,150),\nbatch_size=20,\nclass_mode='binary')\n\nmodel.compile(\nloss='binary_crossentropy',\noptimizer=optimizers.RMSprop(lr=2e-5),\nmetrics=['acc'])\n\nhistory = model.fit_generator(\ntrain_generator,\nsteps_per_epoch=100,\nepochs=30,\nvalidation_data=validation_generator,\nvalidation_steps=50)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\n# Plotting the results of the new network\n\nacc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(1, len(acc)+1)\n\nplt.plot(epochs, acc, 'bo', label = 'Training acc')\nplt.plot(epochs, val_acc, 'b', label = 'Validation acc')\nplt.title('Training and Validation Accuracy')\nplt.legend()\nplt.figure()\n\nplt.plot(epochs, loss, 'bo', label = 'Training loss')\nplt.plot(epochs, val_loss, 'b', label = 'Validation loss')\nplt.title('Training and Validation Accuracy')\nplt.legend()\nplt.figure()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Model Fine Tuning"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Freezing all layers upto a specific one \n\nconv_base.trainable = True\nset_trainable = False\n\nfor layer in conv_base.layers:\n    if layer.name == 'block5_conv1':\n        set_trainable = True\n    if set_trainable:\n        layer.trainable == True\n    else:\n        layer.trainable == False","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Recompiling the model\nmodel.compile(\nloss='binary_crossentropy',\noptimizer=optimizers.RMSprop(lr=1e-5),\nmetrics=['acc'])\n\nhistory = model.fit_generator(\ntrain_generator,\nepochs=100,\nsteps_per_epoch=100,\nvalidation_data=validation_generator,\nvalidation_steps=50)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Writing a smoothening function to smoothen the output plots\n\ndef smooth_curve(points, factor = 0.8):\n    smoothed_points = []\n    for point in points:\n        if smoothed_points:\n            previous_point = smoothed_points[-1]\n            smoothed_points.append(previous_point*factor + point*(1-factor))\n        else:\n            smoothed_points.append(point)\n    return smoothed_points","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(epochs,\nsmooth_curve(acc), 'bo', label='Smoothed training acc')\nplt.plot(epochs,\nsmooth_curve(val_acc), 'b', label='Smoothed validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.figure()\nplt.plot(epochs,\nsmooth_curve(loss), 'bo', label='Smoothed training loss')\nplt.plot(epochs,\nsmooth_curve(val_loss), 'b', label='Smoothed validation loss')\nplt.title('Training and validation loss')\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Testing the model on Test data\n\ntest_generator = test_datagen.flow_from_directory(\ntest_dir,\ntarget_size=(150, 150),\nbatch_size=20,\nclass_mode='binary')\ntest_loss, test_acc = model.evaluate_generator(test_generator, steps=50)\nprint('test acc:', test_acc)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}