{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<center><h1><font color='#000FFF'>  Classification of images containing a dog or cat</font></h1><center>\n<center><i>by Arailym Seisenbekkyzy<i><center>","metadata":{"execution":{"iopub.status.busy":"2022-05-17T03:10:10.71367Z","iopub.execute_input":"2022-05-17T03:10:10.714037Z","iopub.status.idle":"2022-05-17T03:10:10.72131Z","shell.execute_reply.started":"2022-05-17T03:10:10.714005Z","shell.execute_reply":"2022-05-17T03:10:10.719894Z"}}},{"cell_type":"markdown","source":"# Introduction\n\nIn this assignment, I will write a neural network to classify whether images contain either a dog or a cat. Link to: https://www.kaggle.com/competitions/dogs-vs-cats/data","metadata":{}},{"cell_type":"markdown","source":"## Import all the packages that will need.","metadata":{}},{"cell_type":"code","source":"# import packages\nimport os\nimport zipfile\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import ConfusionMatrixDisplay\nimport zipfile\nimport glob\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n%matplotlib inline\nfrom tensorflow.keras import layers\nfrom tensorflow.keras import models\nfrom tensorflow.keras import regularizers\nfrom tensorflow.keras import optimizers\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-05-29T15:14:19.482036Z","iopub.execute_input":"2022-05-29T15:14:19.482938Z","iopub.status.idle":"2022-05-29T15:14:25.741193Z","shell.execute_reply.started":"2022-05-29T15:14:19.482819Z","shell.execute_reply":"2022-05-29T15:14:25.740420Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load your data and explore it.","metadata":{}},{"cell_type":"code","source":"# load  dataset\n\nzip_file = glob.glob('/kaggle/input/dogs-vs-cats/*.zip')  #return any files with .zip extension\nprint(zip_file)\n\n#extract file into a temp folder\ndef extract_zip(file):\n    with zipfile.ZipFile(file,\"r\") as zip_ref:\n        zip_ref.extractall(\"temp\")\n        \n#extract both train and test1 zip\nfor files in zip_file:\n    extract_zip(files)\n\nprint(len(os.listdir('/kaggle/working/temp/train')), \"training data\")\nprint(len(os.listdir('/kaggle/working/temp/test1')), \"test data\")\nos.listdir(\"temp\")","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:25.742866Z","iopub.execute_input":"2022-05-29T15:14:25.743120Z","iopub.status.idle":"2022-05-29T15:14:42.967487Z","shell.execute_reply.started":"2022-05-29T15:14:25.743085Z","shell.execute_reply":"2022-05-29T15:14:42.966746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Since in the future I will be converting our data to a **Dataframe**, we will create a target variable responsible for the picture class: **cat** and **dog**","metadata":{}},{"cell_type":"code","source":"# explore\n\n'''\ncreate a target variable responsible for the picture class:\ncat and dog, because then I convert data to a Dataframe\n'''\n\npath = '/kaggle/working/temp/train/'\nfilenames = os.listdir(path)\nfilenames[:5]\n\nlabel = []\nfor filename in filenames:\n    if filename.split('.')[0] =='cat': # cat = 1\n        label.append('1')\n    else:\n        label.append('0') # dog = 0\n        \ndf = pd.DataFrame({\n                   'name':filenames,\n                   'label':label\n                 })\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:42.968806Z","iopub.execute_input":"2022-05-29T15:14:42.969452Z","iopub.status.idle":"2022-05-29T15:14:43.016630Z","shell.execute_reply.started":"2022-05-29T15:14:42.969412Z","shell.execute_reply":"2022-05-29T15:14:43.015739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#histogram to check whether the label is correct sorted all the photos into classes\n\nprint(df['label'].value_counts())\nsns.countplot(data=df, x=df['label']);","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:43.018712Z","iopub.execute_input":"2022-05-29T15:14:43.019046Z","iopub.status.idle":"2022-05-29T15:14:43.248731Z","shell.execute_reply.started":"2022-05-29T15:14:43.019009Z","shell.execute_reply":"2022-05-29T15:14:43.248049Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We have an equal number of cat and dog classes\n* cat = 1\n*dog = 0\n\nLet's extract a couple of images from the data:","metadata":{}},{"cell_type":"code","source":"load_img(path+'cat.10001.jpg')","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:43.250070Z","iopub.execute_input":"2022-05-29T15:14:43.250566Z","iopub.status.idle":"2022-05-29T15:14:43.345230Z","shell.execute_reply.started":"2022-05-29T15:14:43.250525Z","shell.execute_reply":"2022-05-29T15:14:43.344527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Describe chosen model and its architecture: Base model","metadata":{}},{"cell_type":"markdown","source":"#### Basic architecture of **CNN**","metadata":{}},{"cell_type":"markdown","source":"Convolutional Neural Network (CNN) has been the to-go neural network architecture when dealing with images. From Yann LeCunn's LeNet in 1990s predicting digits on the popular MNIST data, to Alexnet impressive performance on ImageNet, the area of CNN has evolved tremendously.\n","metadata":{}},{"cell_type":"markdown","source":"In this section, we will try to implement a CNN architecture from scratch, using the Keras library. We will be using just 5 epochs for all our training\n\nIn this model, we use 5 consecutive blocks from ***Conv2D*** and ***MaxPooling2d*** with different filtering depths.\nSince we have a classification task, after 5 blocks we will transform our data into a 1D tensor and apply Dense Layers.\nThe last ***dense layer*** should have 1 layer and ***activation=\"sigmoid\"*** since we have a binary classification task\ninput_shape set ***(256, 256, 3)*** as a base for further use of the generator without resizing the image","metadata":{}},{"cell_type":"code","source":"model = models.Sequential()\nmodel.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(256, 256, 3)))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\n\nmodel.add(layers.Flatten())\nmodel.add(layers.Dense(512, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))\n\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:43.346343Z","iopub.execute_input":"2022-05-29T15:14:43.347106Z","iopub.status.idle":"2022-05-29T15:14:46.140659Z","shell.execute_reply.started":"2022-05-29T15:14:43.347074Z","shell.execute_reply":"2022-05-29T15:14:46.139899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#optimizer='Adam' as the most basic and recommended\n#loss='binary_crossentropy' since we have a binary classification\n#metrics='acc' since we have the same number of classes and accuracy is a suitable metric\n\nmodel.compile(optimizer='Adam', loss='binary_crossentropy', metrics='acc')","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:46.142163Z","iopub.execute_input":"2022-05-29T15:14:46.142447Z","iopub.status.idle":"2022-05-29T15:14:46.158149Z","shell.execute_reply.started":"2022-05-29T15:14:46.142411Z","shell.execute_reply":"2022-05-29T15:14:46.157263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Describe how you will divide data for training, validation, and testing.","metadata":{}},{"cell_type":"markdown","source":"Splitting data into train, test, valid\nWe will use proportions train:test:valid - ***8:1:1***\n- On the ***train*** sample, we will train our model\n- On the ***validation*** sample, we will check the ability of our model to generalize to unknown data\n- On the ***test*** sample, we will make the final prediction","metadata":{}},{"cell_type":"code","source":"# split the data in a ratio of 8:1:1 and with the same ratio of classes\n\ntrain, test_val = train_test_split(df, test_size=0.2, stratify=df['label'], random_state=17)\ntest, val = train_test_split(test_val, test_size=0.5,  stratify=test_val['label'], random_state=17)\n\nprint('train size:', train.shape[0],\n      '\\nvalidation size:', val.shape[0],\n      '\\ntest size:', test.shape[0],     \n     )\nprint('train labels:\\n',train['label'].value_counts(),\n      '\\n\\nvalidataion labels:\\n',val['label'].value_counts(),\n      '\\n\\ntest labels:\\n',test['label'].value_counts(),\n      sep='')","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:46.160005Z","iopub.execute_input":"2022-05-29T15:14:46.160354Z","iopub.status.idle":"2022-05-29T15:14:46.220696Z","shell.execute_reply.started":"2022-05-29T15:14:46.160316Z","shell.execute_reply":"2022-05-29T15:14:46.219888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Describe your evaluation metrics.","metadata":{}},{"cell_type":"markdown","source":"Apply an ImageDataGenerator to our data to make it look like an input_shape for our model.\n\nNeural networks need to receive scaled data as input, for this we apply rescale=1./255\n\nIn this case, the image size is not specified, because flow_from_dataframe creates target_size=(256, 256).\n\nAugmentation is the process of generating artificial images using rotations, mirroring, shifts and many other different methods based on existing ones.","metadata":{}},{"cell_type":"code","source":"# use and apply augmentation\n\n# batch_size=32\n# train_size(20000)/batch_size(32)=625\n# larger the batch_size value, the less time it takes to train one epoch and the more epochs are needed to get good results\ntrain_gen = ImageDataGenerator(rescale=1./255)\ntrain_data = train_gen.flow_from_dataframe(train,\n                                           directory=path,\n                                           x_col='name',\n                                           y_col='label',\n                                           class_mode='binary',\n                                           seed=17                                          \n                                          )\n\nval_gen = ImageDataGenerator(rescale=1./255)\nval_data = val_gen.flow_from_dataframe(val,\n                                       directory=path,\n                                       x_col='name',\n                                       y_col='label',\n                                       class_mode='binary',\n                                       seed=17  \n                                      )","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:46.222172Z","iopub.execute_input":"2022-05-29T15:14:46.222466Z","iopub.status.idle":"2022-05-29T15:14:46.602601Z","shell.execute_reply.started":"2022-05-29T15:14:46.222429Z","shell.execute_reply":"2022-05-29T15:14:46.601057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train model.","metadata":{}},{"cell_type":"code","source":"history = model.fit(train_data,\n                    validation_data = val_data,\n                    epochs=30\n                   )\n\nloss = history.history['loss']\nval_loss = history.history['val_loss']\n\nplt.figure(figsize=(15,8))\nplt.plot(loss, label='Train loss')\nplt.plot(val_loss,'--', label='Val loss')\nplt.title('Training and validation loss')\nplt.xticks(np.arange(0,10))\nplt.yticks(np.arange(0, 0.7, 0.05));\nplt.grid()\nplt.legend();\n\n","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:14:46.605482Z","iopub.execute_input":"2022-05-29T15:14:46.605804Z","iopub.status.idle":"2022-05-29T15:57:47.994057Z","shell.execute_reply.started":"2022-05-29T15:14:46.605770Z","shell.execute_reply":"2022-05-29T15:57:47.993248Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We see the problem of overfitting, since after the 5th epoch, val loss stopped decreasing, but went up.","metadata":{}},{"cell_type":"markdown","source":"# Data Preprocessing : Augmentation","metadata":{}},{"cell_type":"markdown","source":"Augmentation is the process of generating artificial images using rotations, mirroring, shifts and other methods based on existing data.","metadata":{}},{"cell_type":"code","source":"# Data Preprocessing : Augmentation\naug_gen = ImageDataGenerator(rescale = 1./255,\n                               shear_range = 0.2,\n                               zoom_range = 0.2,\n                               rotation_range=40,\n                               width_shift_range=0.2,\n                               height_shift_range=0.2,\n                               horizontal_flip=True,\n                               fill_mode='nearest'\n                              )\n\nimg_cat = load_img(path+'cat.10001.jpg')\nimg_dog = load_img(path+'dog.1280.jpg')\n\nimg_cat_arr = image.img_to_array(img_cat)\nimg_cat_arr = img_cat_arr.reshape((1,)+img_cat_arr.shape)\n\nimg_dog_arr = image.img_to_array(img_dog)\nimg_dog_arr = img_dog_arr.reshape((1,)+ img_dog_arr.shape)\n\naug_images_cat = aug_gen.flow(img_cat_arr, batch_size=1)\naug_images_dog = aug_gen.flow(img_dog_arr, batch_size=1)\n\nplt.figure(figsize=(15,8))\nplt.subplot(141)\nplt.imshow(img_cat)\nplt.title(\"original\")\ni=2\nfor batch in aug_images_cat:\n    plt.subplot(14*10+i)\n    plt.imshow(image.array_to_img(batch[0]))\n    plt.title(\"augmented\")\n    i += 1\n    if i % 5 == 0:\n        break","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:57:47.995515Z","iopub.execute_input":"2022-05-29T15:57:47.995931Z","iopub.status.idle":"2022-05-29T15:57:48.720833Z","shell.execute_reply.started":"2022-05-29T15:57:47.995891Z","shell.execute_reply":"2022-05-29T15:57:48.720057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15,8))\nplt.subplot(141)\nplt.imshow(img_dog)\nplt.title(\"original\")\ni=2\nfor batch in aug_images_dog:\n    plt.subplot(14*10+i)\n    plt.imshow(image.array_to_img(batch[0]))\n    plt.title(\"augmented\")\n    i += 1\n    if i % 5 == 0:\n        break","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:57:48.722285Z","iopub.execute_input":"2022-05-29T15:57:48.722609Z","iopub.status.idle":"2022-05-29T15:57:49.520864Z","shell.execute_reply.started":"2022-05-29T15:57:48.722569Z","shell.execute_reply":"2022-05-29T15:57:49.520107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Apply augmentation to our train data.\nIt is important to apply augmentation only to train data, not to val and test. We need to provide our model with a large sample of images so that it can learn to recognize patterns in images.","metadata":{}},{"cell_type":"code","source":"train_data = aug_gen.flow_from_dataframe(train,\n                                         directory=path,\n                                         x_col='name',\n                                         y_col='label',\n                                         class_mode='binary',\n                                         target_size=(224,224),\n                                         seed=17\n                                        )\n\nval_data = val_gen.flow_from_dataframe(val,\n                                       directory=path,\n                                       x_col='name',\n                                       y_col='label',\n                                       class_mode='binary',\n                                       target_size=(224,224),\n                                       seed=17  \n                                      )","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:57:49.522305Z","iopub.execute_input":"2022-05-29T15:57:49.522536Z","iopub.status.idle":"2022-05-29T15:57:49.751149Z","shell.execute_reply.started":"2022-05-29T15:57:49.522503Z","shell.execute_reply":"2022-05-29T15:57:49.750381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Evaluate model.","metadata":{}},{"cell_type":"markdown","source":"**Base model:**","metadata":{"execution":{"iopub.status.busy":"2022-05-18T10:21:58.033088Z","iopub.execute_input":"2022-05-18T10:21:58.034644Z","iopub.status.idle":"2022-05-18T10:21:58.04268Z","shell.execute_reply.started":"2022-05-18T10:21:58.034589Z","shell.execute_reply":"2022-05-18T10:21:58.04125Z"}}},{"cell_type":"code","source":"# howbase model looked\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:57:49.752299Z","iopub.execute_input":"2022-05-29T15:57:49.752548Z","iopub.status.idle":"2022-05-29T15:57:49.763059Z","shell.execute_reply.started":"2022-05-29T15:57:49.752513Z","shell.execute_reply":"2022-05-29T15:57:49.762358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"It is important to understand that a strong fight against an overfitting problem can turn into an underfitting problem.\n\nPerhaps the augmentation is already enough to solve the problem of overfitting our model, but I want to add some more examples of hyperparameter regularization","metadata":{}},{"cell_type":"code","source":"best_model = models.Sequential()\n\nbest_model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)))\nbest_model.add(layers.MaxPooling2D((2, 2)))\n\nbest_model.add(layers.Conv2D(64, (3, 3), activation='relu'))\nbest_model.add(layers.MaxPooling2D((2, 2)))\n\nbest_model.add(layers.Conv2D(64, (3, 3), activation='relu'))\nbest_model.add(layers.MaxPooling2D((2, 2)))\n\nbest_model.add(layers.Conv2D(128, (3, 3), activation='relu'))\nbest_model.add(layers.MaxPooling2D((2, 2)))\n\nbest_model.add(layers.Conv2D(128, (3, 3), activation='relu'))\nbest_model.add(layers.MaxPooling2D((2, 2)))\n\nbest_model.add(layers.Flatten())\nbest_model.add(layers.Dense(512, activation='relu', kernel_regularizer=regularizers.l2(0.001)))\nbest_model.add(layers.Dropout(0.2))\nbest_model.add(layers.Dense(1, activation='sigmoid'))","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:57:49.765089Z","iopub.execute_input":"2022-05-29T15:57:49.765289Z","iopub.status.idle":"2022-05-29T15:57:49.850125Z","shell.execute_reply.started":"2022-05-29T15:57:49.765265Z","shell.execute_reply":"2022-05-29T15:57:49.849376Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"best_model.summary()","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:57:49.851538Z","iopub.execute_input":"2022-05-29T15:57:49.851785Z","iopub.status.idle":"2022-05-29T15:57:49.860985Z","shell.execute_reply.started":"2022-05-29T15:57:49.851749Z","shell.execute_reply":"2022-05-29T15:57:49.860291Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Try to directly set the learning_rate to the optimizer, take a value slightly less than the default.\n\nThus, we guarantee that our optimizer will not get stuck in the local minimum of the function, however, for this we reduce the learning rate","metadata":{}},{"cell_type":"code","source":"best_model.compile(optimizer=optimizers.Adam(learning_rate=5e-4), loss='binary_crossentropy', metrics='acc')","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:57:49.862921Z","iopub.execute_input":"2022-05-29T15:57:49.863263Z","iopub.status.idle":"2022-05-29T15:57:49.871886Z","shell.execute_reply.started":"2022-05-29T15:57:49.863231Z","shell.execute_reply":"2022-05-29T15:57:49.871252Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Tuned model training","metadata":{}},{"cell_type":"markdown","source":"Increase the number of **epochs to 60**, most likely the model will need many more epochs than in the previous version\n\nAlso add **callbacks** that will stop training if **val_loss** has not changed more than **0.001** over the past **5 epochs**","metadata":{}},{"cell_type":"code","source":"# increase the number of epochs to 60\n\nhistory_2 = best_model.fit(train_data,\n                           validation_data = val_data,\n                           epochs=60,\n                           callbacks=[EarlyStopping(monitor='val_acc', min_delta=0.001, patience=5, verbose=1)]\n                          )","metadata":{"execution":{"iopub.status.busy":"2022-05-29T15:57:49.873883Z","iopub.execute_input":"2022-05-29T15:57:49.875310Z","iopub.status.idle":"2022-05-29T17:20:02.408724Z","shell.execute_reply.started":"2022-05-29T15:57:49.875273Z","shell.execute_reply":"2022-05-29T17:20:02.407879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Our network stopped after 19 epochs as the callback fired.\n\nPerhaps after a few epochs, val_acc would begin to grow, but this accuracy suits me, since this notebook was not written to find the best results, but to work out and understand working with CNN in Keras.\n","metadata":{}},{"cell_type":"code","source":"# accuracy plot\nloss = history_2.history['acc']\nval_loss = history_2.history['val_acc']\n\nplt.figure(figsize=(15,8))\nplt.plot(loss, label='Train acc')\nplt.plot(val_loss,'--', label='Val acc')\nplt.title('Training and validation accuracy')\nplt.yticks(np.arange(0.5, 1, 0.05))\nplt.xticks(np.arange(0, 26))\nplt.grid()\nplt.legend();","metadata":{"execution":{"iopub.status.busy":"2022-05-29T17:20:02.410306Z","iopub.execute_input":"2022-05-29T17:20:02.410570Z","iopub.status.idle":"2022-05-29T17:20:02.717188Z","shell.execute_reply.started":"2022-05-29T17:20:02.410534Z","shell.execute_reply":"2022-05-29T17:20:02.716493Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Compared to our first model, we really got rid of the **overfitting** problem. Now our metrics on the chart grow in proportion to each other","metadata":{}},{"cell_type":"code","source":"# save the model and apply it to the test data\nbest_model.save('best_model_cat_vs_dog.h5')","metadata":{"execution":{"iopub.status.busy":"2022-05-29T17:20:02.718352Z","iopub.execute_input":"2022-05-29T17:20:02.718931Z","iopub.status.idle":"2022-05-29T17:20:02.794207Z","shell.execute_reply.started":"2022-05-29T17:20:02.718890Z","shell.execute_reply":"2022-05-29T17:20:02.793454Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Result on test data","metadata":{}},{"cell_type":"code","source":"test_data = val_gen.flow_from_dataframe(test,\n                                        directory=path,\n                                        x_col='name',\n                                        y_col='label',\n                                        class_mode='binary',\n                                        target_size=(224,224),\n                                        shuffle=False,\n                                        seed=17  \n                                       )\ntest_pred = best_model.predict(test_data)\npred_label = test_pred > 0.5\ntrue_label = test_data.classes\nConfusionMatrixDisplay(confusion_matrix(true_label, pred_label), display_labels=test_data.class_indices).plot();","metadata":{"execution":{"iopub.status.busy":"2022-05-29T17:20:02.795386Z","iopub.execute_input":"2022-05-29T17:20:02.795647Z","iopub.status.idle":"2022-05-29T17:20:10.873324Z","shell.execute_reply.started":"2022-05-29T17:20:02.795613Z","shell.execute_reply":"2022-05-29T17:20:10.872560Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"best_model.evaluate(test_data)","metadata":{"execution":{"iopub.status.busy":"2022-05-29T17:20:10.874489Z","iopub.execute_input":"2022-05-29T17:20:10.875041Z","iopub.status.idle":"2022-05-29T17:20:21.260900Z","shell.execute_reply.started":"2022-05-29T17:20:10.874998Z","shell.execute_reply":"2022-05-29T17:20:21.260112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**92% on test data**\n\nIt is possible that the model could be trained for high accuracy results, however, the purpose of this notebook was to learn how to work with **Keras** and **CNN**","metadata":{}}]}