{"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\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Notebooks used as sources:\n\nhttps://www.kaggle.com/uysimty/keras-cnn-dog-or-cat-classification\n\nhttps://www.kaggle.com/bulentsiyah/dogs-vs-cats-classification-vgg16-fine-tuning"},{"metadata":{},"cell_type":"markdown","source":"### Libraries Import"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd \n\nfrom keras.preprocessing.image import ImageDataGenerator, load_img\nfrom keras.utils import to_categorical\nfrom keras.models import Sequential, Model\nfrom keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, Activation, BatchNormalization, GlobalMaxPooling2D\nfrom keras.applications import VGG16\nfrom keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau, Callback, LearningRateScheduler\nfrom keras.optimizers import RMSprop\nfrom keras import backend\n\nfrom sklearn.model_selection import train_test_split\n\nimport matplotlib.pyplot as plt\n\nimport random\nimport os\nimport zipfile","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Input Handling"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(os.listdir(\"/kaggle/input/dogs-vs-cats/\"))\n\nwith zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats/train.zip\",\"r\") as z:\n    z.extractall(\"/kaggle/working/dogs-vs-cats/\")\n    \n# with zipfile.ZipFile(\"/kaggle/input/dogs-vs-cats/test1.zip\",\"r\") as z:\n#     z.extractall(\"/kaggle/working/dogs-vs-cats/\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"filenames = os.listdir(\"/kaggle/working/dogs-vs-cats/train\")\n\ndf = pd.DataFrame()\n\ndf['filename'] = filenames\ndf['category'] = df['filename'].apply(lambda x: x.split('.')[0])\ndf['label'] = np.where(df['category'] == 'cat', 0, 1)\ndf.head(n=10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(df['category'].value_counts())\ndf['category'].value_counts().plot.bar()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Sample Image"},{"metadata":{"trusted":true},"cell_type":"code","source":"image = load_img(\"/kaggle/working/dogs-vs-cats/train/\" + random.choice(filenames))\nplt.imshow(image)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Prepare Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df, validate_df = train_test_split(df.drop(columns = 'label'), test_size=0.20, random_state=42)\ntrain_df = train_df.reset_index(drop=True)\nvalidate_df = validate_df.reset_index(drop=True)\nprint(train_df['category'].value_counts())\nprint(train_df.shape)\nprint('-'*60)\nprint(validate_df['category'].value_counts())\nprint(validate_df.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Read images from directory using Keras\n\nhttps://vijayabhaskar96.medium.com/tutorial-on-keras-flow-from-dataframe-1fd4493d237c\n\nhttps://vijayabhaskar96.medium.com/tutorial-on-keras-imagedatagenerator-with-flow-from-dataframe-8bd5776e45c1"},{"metadata":{"trusted":true},"cell_type":"code","source":"total_train = train_df.shape[0]\ntotal_validate = validate_df.shape[0]\nbatch_size=16\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    rescale = 1./255,\n    #rotation_range=15,\n    #zoom_range=0.2,\n    #height_shift_range=0.2,\n    #width_shift_range=0.2,\n    horizontal_flip=True\n)\ntrain_generator = train_datagen.flow_from_dataframe(\n    train_df, \n    \"/kaggle/working/dogs-vs-cats/train/\", \n    x_col='filename',\n    y_col='category',\n    target_size=(128,128),\n    class_mode='categorical',\n    batch_size=batch_size \n    #images served in each epoch\n)\n\nvalid_datagen = ImageDataGenerator(rescale = 1./255)\nvalid_generator = valid_datagen.flow_from_dataframe(\n    validate_df, \n    \"/kaggle/working/dogs-vs-cats/train/\", \n    x_col='filename',\n    y_col='category',\n    target_size=(128,128),\n    class_mode='categorical',\n    batch_size=batch_size \n    #images served in each epoch\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Plotting example images from generator\n\nhttps://stackoverflow.com/questions/59217031/plot-images-from-image-generator"},{"metadata":{"trusted":true},"cell_type":"code","source":"example_df = train_df.sample(n=1).reset_index(drop=True)\nexample_generator = ImageDataGenerator(\n    rescale = 1./255,\n    rotation_range=15,\n    zoom_range=0.2,\n    #height_shift_range=0.2,\n    #width_shift_range=0.2,\n    horizontal_flip=True,\n    vertical_flip=True\n).flow_from_dataframe(\n    example_df, \n    \"/kaggle/working/dogs-vs-cats/train/\", \n    x_col='filename',\n    y_col='category',\n    target_size=(128,128),\n    class_mode='categorical',\n    batch_size = 1\n)\n\nplt.figure(figsize=(12, 12))\nfor i in range(0, 16):\n    plt.subplot(4, 4, i+1)\n    x = example_generator.next()\n    image = x[0][0]\n    plt.imshow(image)\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"fit_generator(\n    generator, steps_per_epoch=None, epochs=1, verbose=1, callbacks=None,\n    validation_data=None, validation_steps=None, validation_freq=1,\n    class_weight=None, max_queue_size=10, workers=1, use_multiprocessing=False,\n    shuffle=True, initial_epoch=0\n)"},{"metadata":{"trusted":true},"cell_type":"code","source":"!nvidia-smi","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Model Building\n\nConvolutional Neural Networks work by extracting features maps from the image using filters/kernels.\nPooling layers are used for dimensionality reduction.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"model = Sequential()\n\nmodel.add(Conv2D(32, (3, 3), activation='relu', input_shape=(128, 128, 3)))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\nmodel.add(Conv2D(64, (3, 3), activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\nmodel.add(Conv2D(128, (3, 3), activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\nmodel.add(Flatten())\n#model.add(Dropout(0.25)) #Francois Chollet place drop out after flatten in his book Deep Learning with Python (Ch 5, Page 141)\nmodel.add(Dense(512, activation='relu'))\n#model.add(Dense(512, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(Dropout(0.25)) \nmodel.add(Dense(2, activation='softmax')) # 2 because we have cat and dog classes\n\nopt = RMSprop(learning_rate=0.01)\n\nmodel.compile(loss='categorical_crossentropy', optimizer=opt, metrics=['accuracy'])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Batch Normalization\n\nBatch Normalization layer normalizes its input. \nBatch normalization applies a transformation that maintains the mean output close to 0 and the output standard deviation close to 1. This allows each layer in the network to train more independently. \nDuring the training stage of networks, as the parameters of the preceding layers change, the distribution of inputs to the current layer changes accordingly, such that the current layer needs to constantly readjust to new distributions. This problem is especially severe for deep networks, because small changes in shallower hidden layers will be amplified as they propagate within the network, resulting in significant shift in deeper hidden layers. Therefore, the method of batch normalization is proposed to reduce these unwanted shifts to speed up training and to produce more reliable models.\n\n\nSources:\nhttps://analyticsindiamag.com/everything-you-should-know-about-dropouts-and-batchnormalization-in-cnn/\n\nhttps://en.wikipedia.org/wiki/Batch_normalization\n\nhttps://keras.io/api/layers/normalization_layers/batch_normalization/"},{"metadata":{},"cell_type":"markdown","source":"### Softmax\nTakes a vector of length k with real values. Returns a vector K of same length such that K[i] $\\in$ [0,1] and np.sum(K) = 1\n\n### Cross Entropy\n\nLoss Function: L(y, y') = - (y*log(y') + (1-y)*log(1-y'))\n\nif y = 1 ==> L(1, y') = -log(y') ==> y' must be as large as possible ==> y' -> 1\n\nif y = 0 ==> L(0, y') = -log(1-y') ==> 1-y' must be as large as possible ==> y' must be as small as possible ==> y' -> 0\n\nThe loss function computes the error for a single training example; the cost function is the average of the loss functions\nof the entire training set.\n\nCost Function: J = 1/m * Sum (L(y[i], y'[i])) \n\nFor more classes: Say you have 3 classes:\nLoss function = - [y1log(y1') + y2log(y2') + y3log(y3')]\nFor multiclass classification, due to one-hot encoding, we will have only one term active. So again the idea is to maximize output score for active class so it is closer to 1."},{"metadata":{},"cell_type":"markdown","source":"Non-trainable parameters:\n\nhttps://stackoverflow.com/questions/47312219/what-is-the-definition-of-a-non-trainable-parameter\n"},{"metadata":{},"cell_type":"markdown","source":"### Callbacks"},{"metadata":{"trusted":true},"cell_type":"code","source":"lr_0 = 0.01\nearlystop = EarlyStopping(patience=10)\n\nreduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1,\n                              patience=5, min_lr=0.001)\n\ncheckpoint_filepath = '/kaggle/working/catsdogsmodelweights.h5'\nmodel_checkpoint_callback = ModelCheckpoint(\n    filepath=checkpoint_filepath,\n    save_weights_only=True,\n    monitor='val_accuracy',\n    mode='max',\n    save_best_only=True)\n\n# def scheduler(epoch, lr):\n#     if epoch < 10:\n#         return lr\n#     else:\n#         #return lr * tf.math.exp(-0.1)\n#         return lr_0 * 0.6 ** epoch\n\n# lr_decay = tf.keras.callbacks.LearningRateScheduler(scheduler)\n\n# print the learning rate\nclass LearningRateMonitor(Callback):\n#end of each training epoch\n    def on_epoch_end(self, epoch, logs=None):\n    # print optimizer learning rate\n        optimizer = self.model.optimizer\n        print(\"\\nLearning rate: {}\".format(backend.get_value(model.optimizer.lr)))\n\nlrm = LearningRateMonitor()\n\ncallbacks = [earlystop, reduce_lr, lrm, model_checkpoint_callback]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"model.fit/fit_generator parameters:\n\n* batch_size\n* steps per epoch\n* validation_steps\n\nhttps://datascience.stackexchange.com/questions/29719/how-to-set-batch-size-steps-per-epoch-and-validation-steps"},{"metadata":{"trusted":true},"cell_type":"code","source":"if not os.path.isfile(checkpoint_filepath):\n    print('Pre-trained weights not found. Training from scratch.')\nelse:\n    model.load_weights(checkpoint_filepath)\n\n\nepochs = 50\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\nhistory = model.fit_generator(\n    generator = train_generator, \n    epochs=epochs,\n    validation_data=valid_generator,\n    validation_steps=total_validate//batch_size, #floor division\n    steps_per_epoch=total_train//batch_size,\n    callbacks = callbacks\n)\n#model.save('/kaggle/working/catsdogsmodel.h5')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"history.history","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Plotting Loss & Accuracy"},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 4))\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, epochs, 1))\nax1.set_yticks(np.arange(0, 1.1, 0.1))\nax1.set_ylim(0.0,1.0)\n\nax2.plot(history.history['accuracy'], color='b', label=\"Training accuracy\")\nax2.plot(history.history['val_accuracy'], color='r',label=\"Validation accuracy\")\nax2.set_xticks(np.arange(1, epochs, 1))\nax2.set_yticks(np.arange(0, 1.1, 0.1))\nax2.set_ylim(0.0,1.0)\n\nax1.legend(loc='best', shadow=True)\nax2.legend(loc='best', shadow=True)\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test_filenames = os.listdir(\"/kaggle/working/dogs-vs-cats/test1\")\n\n# test_df = pd.DataFrame()\n\n# test_df['filename'] = test_filenames\n# #test_df['category'] = test_df['filename'].apply(lambda x: x.split('.')[0])\n# #test_df['label'] = np.where(test_df['category'] == 'cat', 0, 1)\n# test_df.head(n=10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test_datagen = ImageDataGenerator(rescale = 1./255)\n# test_generator = test_datagen.flow_from_dataframe(\n#     test_df, \n#     \"/kaggle/working/dogs-vs-cats/test1/\", \n#     x_col='filename',\n#     y_col=None,\n#     target_size=(128,128),\n#     class_mode=None,\n#     batch_size=15, \n#     #images served in each epoch\n#     shuffle = False\n# )","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"https://stackoverflow.com/questions/45806669/keras-how-to-use-predict-generator-with-imagedatagenerator"},{"metadata":{"trusted":true},"cell_type":"code","source":"y_prob = model.predict_generator(valid_generator)\ny_classes = y_prob.argmax(axis=-1)\nprint(train_generator.class_indices)\nprint(y_prob[0])\nprint(y_classes[0])\n\nlabels_map = dict((v,k) for (k,v) in train_generator.class_indices.items())\nprint(labels_map)\n\nvalidate_df['pred_class'] = y_classes\nvalidate_df['pred_prob'] = y_prob[:,1]\nvalidate_df['pred_label'] = validate_df['pred_class'].replace(labels_map)\nvalidate_df.head(n=10)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Some Misclassified Examples"},{"metadata":{"trusted":true},"cell_type":"code","source":"#sample_test = validate_df.head(n=16)\nsample_test = validate_df[validate_df['category'] != validate_df['pred_label']].head(n=16).reset_index(drop=True)\nplt.figure(figsize=(16, 16))\nfor index, row in sample_test.iterrows():\n    filename = row['filename']\n    category = row['pred_label']\n    prob = float(row['pred_prob'])\n    img = load_img(\"/kaggle/working/dogs-vs-cats/train/\" + filename, target_size=(128,128))\n    plt.subplot(4, 4, index+1)\n    plt.imshow(img)\n    plt.xlabel(filename + ' (' + category + ':' + str(round(prob,2)) + ')' )\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Using Pre-trained Model: [VGG16](https://keras.io/api/applications/vgg/)\n\n![VGG16](https://miro.medium.com/max/470/1*3-TqqkRQ4rWLOMX-gvkYwA.png)"},{"metadata":{},"cell_type":"markdown","source":"ImageNet 1000 classes\n\nhttps://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a"},{"metadata":{"trusted":true},"cell_type":"code","source":"#include_top: whether to include the 3 fully-connected layers at the top of the network\npre_trained_model = VGG16(input_shape=(128,128,3), include_top=False, weights=\"imagenet\")\nprint(\"Number of layers:\", len(pre_trained_model.layers))\npre_trained_model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"We keep the initial layers as fixed, since they have already been trained and are good at extracting lower level features out of an image.\n\n> Transfer learning consists of taking features learned on one problem, and leveraging them on a new, similar problem. For instance, features from a model that has learned to identify racoons may be useful to kick-start a model meant to identify tanukis.\n> Transfer learning is usually done for tasks where your dataset has too little data to train a full-scale model from scratch.\n> The most common incarnation of transfer learning in the context of deep learning is the following worfklow:\n* Take layers from a previously trained model.\n* Freeze them, so as to avoid destroying any of the information they contain during future training rounds.\n* Add some new, trainable layers on top of the frozen layers. They will learn to turn the old features into predictions on a new dataset.\n* Train the new layers on your dataset.\n\n\nReferences:\n\nhttps://keras.io/guides/transfer_learning/"},{"metadata":{"trusted":true},"cell_type":"code","source":"# for layer in pre_trained_model.layers[:15]:\n#     layer.trainable = False\n\n# for layer in pre_trained_model.layers[15:]:\n#     layer.trainable = True\n\npre_trained_model.trainable = False","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Global Max Pooling\n\nhttps://stats.stackexchange.com/questions/257321/what-is-global-max-pooling-layer-and-what-is-its-advantage-over-maxpooling-layer\n\nAdding layers to the pre-trained model\n\nhttps://stackoverflow.com/questions/42475381/add-dropout-layers-between-pretrained-dense-layers-in-keras\n\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"last_layer = pre_trained_model.get_layer('block5_pool')\nlast_output = last_layer.output\n\n# Flatten the output layer to 1 dimension\nx = GlobalMaxPooling2D()(last_output)\n# Add a fully connected layer with 512 hidden units and ReLU activation\nx = Dense(512, activation='relu')(x)\n# Add a dropout rate of 0.25\nx = Dropout(0.25)(x)\n# Add a final sigmoid/softmax layer for classification\nx = Dense(2, activation='softmax')(x)\n\nvgg_model = Model(inputs=pre_trained_model.input, outputs=x)\n\nopt = RMSprop(learning_rate=0.01)\n\nvgg_model.compile(loss='categorical_crossentropy',\n              optimizer=opt,\n              metrics=['accuracy'])\n\nvgg_model.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Callbacks:**\n\nA callback is an object that can perform actions at various stages of training (e.g. at the start or end of an epoch, before or after a single batch, etc).\n\nhttps://keras.io/api/callbacks/"},{"metadata":{"trusted":true},"cell_type":"code","source":"earlystop = EarlyStopping(patience=10)\n\nreduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1,\n                              patience=5, min_lr=0.001)\n\ncheckpoint_filepath = '/kaggle/working/vgg16basedcatsdogs.h5'\nmodel_checkpoint_callback = ModelCheckpoint(\n    filepath=checkpoint_filepath,\n    save_weights_only=True,\n    monitor='val_accuracy',\n    mode='max',\n    save_best_only=True)\n\ncallbacks = [earlystop, model_checkpoint_callback, reduce_lr]\n\n# if not os.path.isfile(checkpoint_filepath):\n#     print('Pre-trained weights not found. Training from scratch.')\n# else:\n#     vgg_model.load_weights(checkpoint_filepath)\n\n\nepochs = 50\nvgg_history = vgg_model.fit_generator(\n    generator = train_generator, \n    epochs=epochs,\n    validation_data=valid_generator,\n    validation_steps=total_validate//batch_size, #floor division\n    steps_per_epoch=total_train//batch_size,\n    callbacks = callbacks)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"vgg_history.history","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 4))\nax1.plot(vgg_history.history['loss'], color='b', label=\"Training loss\")\nax1.plot(vgg_history.history['val_loss'], color='r', label=\"Validation loss\")\nax1.set_xticks(np.arange(1, epochs, 1))\nax1.set_yticks(np.arange(0, 1.1, 0.1))\nax1.set_ylim(0.0,1.0)\n\nax2.plot(vgg_history.history['accuracy'], color='b', label=\"Training accuracy\")\nax2.plot(vgg_history.history['val_accuracy'], color='r',label=\"Validation accuracy\")\nax2.set_xticks(np.arange(1, epochs, 1))\nax2.set_yticks(np.arange(0, 1.1, 0.1))\nax2.set_ylim(0.0,1.0)\n\nax1.legend(loc='best', shadow=True)\nax2.legend(loc='best', shadow=True)\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"y_prob = vgg_model.predict_generator(valid_generator)\ny_classes = y_prob.argmax(axis=-1)\nprint(train_generator.class_indices)\nprint(y_prob[0])\nprint(y_classes[0])\n\nlabels_map = dict((v,k) for (k,v) in train_generator.class_indices.items())\nprint(labels_map)\nvgg_df = validate_df[['filename','category']].copy()\nvgg_df['pred_class'] = y_classes\nvgg_df['pred_prob'] = y_prob[:,1]\nvgg_df['pred_label'] = vgg_df['pred_class'].replace(labels_map)\nvgg_df.head(n=10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample_test2 = vgg_df[vgg_df['filename'].isin(sample_test['filename'])].reset_index(drop = True)\nplt.figure(figsize=(16, 16))\nfor index, row in sample_test2.iterrows():\n    filename = row['filename']\n    category = row['pred_label']\n    prob = float(row['pred_prob'])\n    img = load_img(\"/kaggle/working/dogs-vs-cats/train/\" + filename, target_size=(128,128))\n    plt.subplot(4, 4, index+1)\n    plt.imshow(img)\n    plt.xlabel(filename + ' (' + category + ':' + str(round(prob,2)) + ')' )\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Delete training dataset before saving files"},{"metadata":{"trusted":true},"cell_type":"code","source":"!rm -r /kaggle/working/dogs-vs-cats","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}