{"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":"# Name : Aditya Pradip Kulkarni.\n# Date : December-18,2022.\n\n\n### Project : Image classification using CNN\n\nThe problem : \n\n    - Predict whether the given image is of cat or dog from large image dataset.\n\nAlgorithm used to solve the problem :\n\n    - We are going to train a Convolutional Neural Networks(CNN) to predict whether the image is of cat or dog by training the algorithm with dataset consisting of images of cats and dogs. Later test data will be used to predict whether the image choosen is of cat or dog.\n\nWhy CNN?\n    ### Convolutional Neural Networks\n\n    - In CNN, we have filters (which are tiny 3x3 matrices) which \"convolve\" an image to get a transformed matrix. We won't worry about the theory and filters here. All you need to know, that filters transform the image to a new matrix. This matrix is made smaller by a method called Pooling. These two operations create one Convolution Layer, and several such Layers create a CNN. This order isn't mandatory, as we'll see later.\n\nLibrary :\n - Keras","metadata":{}},{"cell_type":"markdown","source":"## Workflow\n\n1. **Gather the data i.e image dataset**.\n\n2. **Explore the images.**\n\n3. **Create a data loader**.\n\n4. **Define the CNN model**.\n\n5. **Training the model.**\n\n6. **Capturing the predictions and labelling the predictions whether cat or dog (1 = dog, 0 = cat).**","metadata":{}},{"cell_type":"markdown","source":"**Required - Libraries**","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img\nfrom tensorflow.keras.utils import plot_model\nfrom tensorflow.keras.utils import to_categorical\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\nimport random\nimport os\nfrom PIL import Image\nimport glob","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-12-19T02:38:00.065206Z","iopub.execute_input":"2022-12-19T02:38:00.065970Z","iopub.status.idle":"2022-12-19T02:38:05.674750Z","shell.execute_reply.started":"2022-12-19T02:38:00.065867Z","shell.execute_reply":"2022-12-19T02:38:05.673639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls ../input/dogs-vs-cats/\n\n# the images are in a zip file in this folder","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:05.679988Z","iopub.execute_input":"2022-12-19T02:38:05.680710Z","iopub.status.idle":"2022-12-19T02:38:06.718079Z","shell.execute_reply.started":"2022-12-19T02:38:05.680664Z","shell.execute_reply":"2022-12-19T02:38:06.716879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 1. Gather the data i.e image dataset.\n\nExtract the images from the zip file. Now there are two folders: train/ and test1/","metadata":{}},{"cell_type":"code","source":"import zipfile\n\nwith zipfile.ZipFile(\"../input/dogs-vs-cats/train.zip\",\"r\") as z:\n    z.extractall(\".\")\n    \nwith zipfile.ZipFile(\"../input/dogs-vs-cats/test1.zip\",\"r\") as z:\n    z.extractall(\".\")\n!ls /kaggle/working/","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:06.720037Z","iopub.execute_input":"2022-12-19T02:38:06.720407Z","iopub.status.idle":"2022-12-19T02:38:25.291607Z","shell.execute_reply.started":"2022-12-19T02:38:06.720374Z","shell.execute_reply":"2022-12-19T02:38:25.289967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# List some random files in the train.zip file.\nglob.glob(\"/kaggle/working/train/*.jpg\")[:5]","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:25.298952Z","iopub.execute_input":"2022-12-19T02:38:25.299446Z","iopub.status.idle":"2022-12-19T02:38:25.486182Z","shell.execute_reply.started":"2022-12-19T02:38:25.299398Z","shell.execute_reply":"2022-12-19T02:38:25.478485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We are collecting each filename, and the corresponding label in a pandas dataframe (needed later)","metadata":{}},{"cell_type":"code","source":"train_files = glob.glob(\"/kaggle/working/train/*.jpg\")\ntrain_labels = [i.strip('/kaggle/working/train/')[:3] for i in train_files]\ntrain_df = pd.DataFrame({'filename': train_files, 'class': train_labels})\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:25.487914Z","iopub.execute_input":"2022-12-19T02:38:25.488619Z","iopub.status.idle":"2022-12-19T02:38:25.646137Z","shell.execute_reply.started":"2022-12-19T02:38:25.488581Z","shell.execute_reply":"2022-12-19T02:38:25.645213Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Explore the images.\n\nExplore 4 random images.","metadata":{"execution":{"iopub.status.busy":"2022-12-15T17:51:39.824303Z","iopub.execute_input":"2022-12-15T17:51:39.825266Z","iopub.status.idle":"2022-12-15T17:51:39.835381Z","shell.execute_reply.started":"2022-12-15T17:51:39.825228Z","shell.execute_reply":"2022-12-15T17:51:39.834084Z"}}},{"cell_type":"code","source":"fig, axs = plt.subplots(2, 2, figsize=(10,10))\naxs = axs.ravel()\nfor i in range(0,4):\n    idx = random.choice(train_df.index)\n    axs[i].imshow(Image.open(train_df['filename'][idx]))\n    axs[i].set_title(train_df['class'][idx])","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:25.650163Z","iopub.execute_input":"2022-12-19T02:38:25.652631Z","iopub.status.idle":"2022-12-19T02:38:26.722590Z","shell.execute_reply.started":"2022-12-19T02:38:25.652594Z","shell.execute_reply":"2022-12-19T02:38:26.720264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**2.1 Observations** : \n\n* The data quality is good.\n\n* The dimensions of the images are not constant, they vary a lot. This will be a problem for the CNN- it expects images of a fixed size! The data loader will be helpful in this case.\n","metadata":{}},{"cell_type":"markdown","source":"## 3. Create a data loader.\n\n*Dataloaders takes care of the following things :*\n\n* 1. Resizing, \n* 2. Batching.\n* 3. Label Encoding.\n* 4. Data Augmentation.\n* 5. Validation Split.\n\n*Steps required to create the data loader:*\n\n* 1. Define a `ImageDataGenerator` instance, and specify the augmentation strategies.\n* 2. Create a generator from this instance by specifying the image file paths and labels.\n\nSend this generator to the model for training.","metadata":{}},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    rotation_range=5,\n    rescale=1./255,\n    horizontal_flip=True,\n    shear_range=0.2,\n    zoom_range=0.2,\n    validation_split=0.2)\n\n# create a image data generator object. \n\n# Specify the image size to which each image will be resized to\nimg_height, img_width = 224, 224\nbatch_size = 64","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:26.726405Z","iopub.execute_input":"2022-12-19T02:38:26.727244Z","iopub.status.idle":"2022-12-19T02:38:26.756202Z","shell.execute_reply.started":"2022-12-19T02:38:26.727195Z","shell.execute_reply":"2022-12-19T02:38:26.742258Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_generator = train_datagen.flow_from_dataframe(\n    train_df,\n    target_size=(img_height, img_width),\n    batch_size=batch_size,\n    class_mode='categorical',\n    subset='training') # set as training data\n\nvalidation_generator = train_datagen.flow_from_dataframe(\n    train_df, # same directory as training data\n    target_size=(img_height, img_width),\n    batch_size=batch_size,\n    class_mode='categorical',\n    subset='validation') # set as validation data\n\nprint(\"Class Indices:\", train_generator.class_indices)","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:26.757822Z","iopub.execute_input":"2022-12-19T02:38:26.763477Z","iopub.status.idle":"2022-12-19T02:38:27.558389Z","shell.execute_reply.started":"2022-12-19T02:38:26.763429Z","shell.execute_reply":"2022-12-19T02:38:27.556924Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4. Define the CNN Model\n\nDefine a series of Convolution Layers, and each convolution layer consists of a convolution operation followed by a max pool layer.\n\nTwo Convolution operations followed by one max pool, or three, or an average pool- that's the neat part of neural networks.\n\n### Working\n\nAs more Conv Layers are applied, will get a transformed matrix of somesize x somesize. Flatten the final matrix to a single vector of size somesize-times-2 x 1. Then pass it through more neural network neurons to get a single neuron at the end. This neuron's output is constrained between 0 and 1. This is the final probability! If it's greater than 0.5, the prediction is 1, if not, it's 0.\n\n### Model Hyperparameters\n\n* Conv layers\n* Selecting the optimizer\n* The learning rate, \n* The loss function, \n* The number of filters.","metadata":{}},{"cell_type":"code","source":"from keras.models import Sequential\nfrom keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, Activation, BatchNormalization\n\nmodel = Sequential()\n\nmodel.add(Conv2D(32, (3, 3), activation='relu', \n                 input_shape=(img_width, img_height, 3)))\n# 32 layer will contain 32 filters of size 3x3 being learnt\nmodel.add(BatchNormalization())\n# batchnorm is a useful layer that helps in convergence\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n# maxpooling will reduce the size of the image\nmodel.add(Dropout(0.25))\n# dropout is used for regularization, ensuring that model doesn't overfit\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\n# convolutional block is complete.\n\n# flatten the matrix to get a single array\nmodel.add(Flatten())\n# adding a dense hidden layer of neurons\nmodel.add(Dense(512, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(Dropout(0.5))\n# finally the output layer with neurons=number of classes and softmax activation\nmodel.add(Dense(2, activation='softmax')) # 2 because we have cat and dog classes","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:27.559738Z","iopub.execute_input":"2022-12-19T02:38:27.560718Z","iopub.status.idle":"2022-12-19T02:38:31.089265Z","shell.execute_reply.started":"2022-12-19T02:38:27.560680Z","shell.execute_reply":"2022-12-19T02:38:31.088264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model visualization : ","metadata":{}},{"cell_type":"code","source":"plot_model(model, show_shapes=True, show_layer_names=False, dpi=60)","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:31.090653Z","iopub.execute_input":"2022-12-19T02:38:31.091355Z","iopub.status.idle":"2022-12-19T02:38:31.993019Z","shell.execute_reply.started":"2022-12-19T02:38:31.091314Z","shell.execute_reply":"2022-12-19T02:38:31.991785Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# compiled the model and defined a loss, optimizer, and metrics to track.\nmodel.compile(loss='categorical_crossentropy', \n              optimizer='adam', \n              metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:31.996421Z","iopub.execute_input":"2022-12-19T02:38:31.997333Z","iopub.status.idle":"2022-12-19T02:38:32.016914Z","shell.execute_reply.started":"2022-12-19T02:38:31.997297Z","shell.execute_reply":"2022-12-19T02:38:32.016017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs=10\nhistory = model.fit(\n    train_generator, \n    epochs=epochs,\n    validation_data=validation_generator,\n)","metadata":{"execution":{"iopub.status.busy":"2022-12-19T02:38:32.018271Z","iopub.execute_input":"2022-12-19T02:38:32.018649Z","iopub.status.idle":"2022-12-19T03:33:38.606450Z","shell.execute_reply.started":"2022-12-19T02:38:32.018608Z","shell.execute_reply":"2022-12-19T03:33:38.605424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_loss(history):\n    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(6, 6))\n    ax1.plot(history.history['loss'], color='b', label=\"Training loss\")\n    ax1.plot(history.history['val_loss'], color='r', label=\"validation loss\")\n    ax1.set_xticks(np.arange(1, epochs, 1))\n\n    ax2.plot(history.history['accuracy'], color='b', label=\"Training accuracy\")\n    ax2.plot(history.history['val_accuracy'], color='r',label=\"Validation accuracy\")\n    ax2.set_xticks(np.arange(1, epochs, 1))\n\n    legend = plt.legend(loc='best', shadow=True)\n    plt.tight_layout()\n    plt.show()\nplot_loss(history)","metadata":{"execution":{"iopub.status.busy":"2022-12-19T03:33:38.609577Z","iopub.execute_input":"2022-12-19T03:33:38.609881Z","iopub.status.idle":"2022-12-19T03:33:38.939829Z","shell.execute_reply.started":"2022-12-19T03:33:38.609853Z","shell.execute_reply":"2022-12-19T03:33:38.938961Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 6. Capture the Predictions\n","metadata":{}},{"cell_type":"code","source":"test_files = glob.glob('/kaggle/working/test1/*.jpg')\ntest_df = pd.DataFrame({'filename': test_files})\ntest_gen = ImageDataGenerator(rescale=1./255)\ntest_generator = test_gen.flow_from_dataframe(\n    test_df, \n    x_col='filename',\n    y_col=None,\n    class_mode=None,\n    target_size=(img_height, img_width),\n    batch_size=batch_size,\n    shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2022-12-19T03:33:38.941218Z","iopub.execute_input":"2022-12-19T03:33:38.942201Z","iopub.status.idle":"2022-12-19T03:33:39.070865Z","shell.execute_reply.started":"2022-12-19T03:33:38.942166Z","shell.execute_reply":"2022-12-19T03:33:39.069857Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def visualize_predictions(test_generator, model):\n    plt.figure(figsize=(12, 12))\n    for i in range(0, 15):\n        plt.subplot(5, 3, i+1)\n        for X_batch in test_generator:\n            prediction = model.predict(X_batch)[0]\n            image = X_batch[0]\n            plt.imshow(image)\n            plt.title('cat' if np.argmax(prediction)==0 else \"dog\")\n            break\n    plt.tight_layout()\n    plt.show()\nvisualize_predictions(test_generator, model)","metadata":{"execution":{"iopub.status.busy":"2022-12-19T03:33:39.072305Z","iopub.execute_input":"2022-12-19T03:33:39.072661Z","iopub.status.idle":"2022-12-19T03:33:45.931367Z","shell.execute_reply.started":"2022-12-19T03:33:39.072626Z","shell.execute_reply":"2022-12-19T03:33:45.930306Z"},"trusted":true},"execution_count":null,"outputs":[]}]}