{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nimport random\nimport os\nimport zipfile\nfrom PIL import Image\nimport seaborn as sns\nimport shutil\nimport cv2\n\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\n\nfrom keras.models import Sequential,Model\nfrom keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, BatchNormalization,Input,GlobalAveragePooling2D\nfrom sklearn.metrics import confusion_matrix , classification_report, ConfusionMatrixDisplay\nfrom keras.callbacks import (ModelCheckpoint, LearningRateScheduler,\n                             EarlyStopping, ReduceLROnPlateau)\nfrom tensorflow.keras.optimizers import Adam\nfrom keras.regularizers import l2\nfrom tensorflow.keras.applications.resnet50 import ResNet50\nfrom tensorflow.keras.applications.resnet50 import preprocess_input\nfrom sklearn.model_selection import train_test_split\n\n\nprint(os.listdir(\"../input\"))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-09-21T16:40:20.048448Z","iopub.execute_input":"2024-09-21T16:40:20.048867Z","iopub.status.idle":"2024-09-21T16:40:31.881865Z","shell.execute_reply.started":"2024-09-21T16:40:20.048828Z","shell.execute_reply":"2024-09-21T16:40:31.880829Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Unzip and Load The Data ","metadata":{}},{"cell_type":"code","source":"# Set the path for the input directory where the zip files are located\ninput_path = '/kaggle/input/dogs-vs-cats'\n\n# Define the paths for the train and test zip files\ntrain_zip = os.path.join(input_path, 'train.zip')\ntest_zip = os.path.join(input_path, 'test1.zip')\n\n# Set the output paths where the unzipped data will be extracted\noutput_train_path = '/kaggle/working/train'\noutput_test_path = '/kaggle/working/test'\n\n# Unzip the training data to the specified output path\nwith zipfile.ZipFile(train_zip, 'r') as zip_ref:\n    zip_ref.extractall(output_train_path)\n    print(\"Unzipping training data complete.\")\n\n# Unzip the test data to the specified output path\nwith zipfile.ZipFile(test_zip, 'r') as zip_ref:\n    zip_ref.extractall(output_test_path)\n    print(\"Unzipping testing data complete.\")\n","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:40:31.883870Z","iopub.execute_input":"2024-09-21T16:40:31.884922Z","iopub.status.idle":"2024-09-21T16:40:46.505668Z","shell.execute_reply.started":"2024-09-21T16:40:31.884870Z","shell.execute_reply":"2024-09-21T16:40:46.504695Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data_path='/kaggle/working/train/train'\ntest_data_path='/kaggle/working/test/test1'\n\ntrain_images=os.listdir(train_data_path)\ntest_images=os.listdir(test_data_path)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:40:46.506901Z","iopub.execute_input":"2024-09-21T16:40:46.507283Z","iopub.status.idle":"2024-09-21T16:40:46.534927Z","shell.execute_reply.started":"2024-09-21T16:40:46.507240Z","shell.execute_reply":"2024-09-21T16:40:46.533984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Get the images into DataFrame","metadata":{}},{"cell_type":"code","source":"image_name=[]\ncategory=[]\ncode=[]\nsize=[]\naspect_ratio=[]\n\nfor image in train_images:\n    image_name.append(image)\n    cate=image.split('.')[0]\n    category.append(cate)\n    code.append(1) if cate=='dog'  else code.append(0)\n    \n    img_path=os.path.join(train_data_path,image)    \n    # Read the image to get its size (height, width)\n    img=cv2.imread(img_path)\n    size.append((img.shape[0],img.shape[1]))\n    # Calculate and append the aspect ratio (height/width) of the image\n    aspect_ratio.append(img.shape[0]/img.shape[1])\n\ntrain_df=pd.DataFrame({'Image_Name':image_name,'Category':category,'Code':code,\"Size\":size,'Aspect_ratio':aspect_ratio})\ntrain_df","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:40:15.581862Z","iopub.execute_input":"2024-09-21T17:40:15.582259Z","iopub.status.idle":"2024-09-21T17:40:34.688863Z","shell.execute_reply.started":"2024-09-21T17:40:15.582221Z","shell.execute_reply":"2024-09-21T17:40:34.687726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define a function to display the first 9 images from a DataFrame \ndef display_first_9(path,df):\n    plt.figure(figsize=[30,30])\n    for i in range(9):\n        plt.subplot(3,3,i+1)\n        img_path=os.path.join(path,df['Image_Name'].iloc[i])\n        plt.title(df['Image_Name'][i])\n        img=Image.open(img_path)\n        plt.imshow(img)\n        plt.axis('off')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:16.753992Z","iopub.execute_input":"2024-09-21T16:41:16.754443Z","iopub.status.idle":"2024-09-21T16:41:16.761685Z","shell.execute_reply.started":"2024-09-21T16:41:16.754399Z","shell.execute_reply":"2024-09-21T16:41:16.760333Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sorted=train_df.sort_values(by='Aspect_ratio',ascending=False)\ndisplay_first_9(train_data_path,df_sorted)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:16.763258Z","iopub.execute_input":"2024-09-21T16:41:16.763678Z","iopub.status.idle":"2024-09-21T16:41:18.825127Z","shell.execute_reply.started":"2024-09-21T16:41:16.763633Z","shell.execute_reply":"2024-09-21T16:41:18.823651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sorted=train_df.sort_values(by='Aspect_ratio',ascending=True)\ndisplay_first_9(train_data_path,df_sorted)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:18.826624Z","iopub.execute_input":"2024-09-21T16:41:18.827002Z","iopub.status.idle":"2024-09-21T16:41:20.513777Z","shell.execute_reply.started":"2024-09-21T16:41:18.826963Z","shell.execute_reply":"2024-09-21T16:41:20.512339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"now we can find that there are 3 image that dosen't belong to out data and they might have come from scraping some websites","metadata":{}},{"cell_type":"code","source":"df_sorted.drop(df_sorted.index[:3],inplace=True)\ntrain_df=df_sorted","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:20.515032Z","iopub.execute_input":"2024-09-21T16:41:20.515361Z","iopub.status.idle":"2024-09-21T16:41:20.525791Z","shell.execute_reply.started":"2024-09-21T16:41:20.515328Z","shell.execute_reply":"2024-09-21T16:41:20.524711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Check Aagin\ndisplay_first_9(train_data_path,train_df)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:20.529885Z","iopub.execute_input":"2024-09-21T16:41:20.530287Z","iopub.status.idle":"2024-09-21T16:41:22.261773Z","shell.execute_reply.started":"2024-09-21T16:41:20.530233Z","shell.execute_reply":"2024-09-21T16:41:22.260429Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ax=sns.countplot(data=train_df,x='Category',palette='viridis')\nax.bar_label(ax.containers[0])\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:22.263223Z","iopub.execute_input":"2024-09-21T16:41:22.263665Z","iopub.status.idle":"2024-09-21T16:41:22.445623Z","shell.execute_reply.started":"2024-09-21T16:41:22.263622Z","shell.execute_reply":"2024-09-21T16:41:22.444512Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Split the training data into training, test, and validation sets \nThis is done to evaluate the model and understand its performance.\n","metadata":{}},{"cell_type":"code","source":"# First split: 80% training and 20% temporary (validation + test)\ntrain_df, temp_df = train_test_split(train_df, test_size=0.2, random_state=42, stratify=train_df['Category'])\n\n# Second split: 50% of temp_df for validation and 50% for test (10% of original data each)\nval_df, test_df = train_test_split(temp_df, test_size=0.5, random_state=42, stratify=temp_df['Category'])","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:40:53.409370Z","iopub.execute_input":"2024-09-21T17:40:53.409801Z","iopub.status.idle":"2024-09-21T17:40:53.470955Z","shell.execute_reply.started":"2024-09-21T17:40:53.409761Z","shell.execute_reply":"2024-09-21T17:40:53.470124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set the style of the figure\n# Options: \"whitegrid\", \"darkgrid\", \"white\", \"dark\", \"ticks\"\nsns.set_style(\"whitegrid\")  \nplt.figure(figsize=(30, 10))   \n\n# Training Data Count Plot\nplt.subplot(1, 3, 1)\nax = sns.countplot(data=train_df, x='Category', palette='viridis')   \nax.bar_label(ax.containers[0], fontsize=14)   \nplt.title('Training Data Distribution', fontsize=18)\nplt.xlabel('Category', fontsize=14)\nplt.ylabel('Count', fontsize=14)\n\n# Test Data Count Plot\nplt.subplot(1, 3, 2)\nax = sns.countplot(data=test_df, x='Category', palette='viridis')\nax.bar_label(ax.containers[0], fontsize=14)\nplt.title('Test Data Distribution', fontsize=18)\nplt.xlabel('Category', fontsize=14)\nplt.ylabel('Count', fontsize=14)\n\n# Validation Data Count Plot\nplt.subplot(1, 3, 3)\nax = sns.countplot(data=val_df, x='Category', palette='viridis')\nax.bar_label(ax.containers[0], fontsize=14)\nplt.title('Validation Data Distribution', fontsize=18)\nplt.xlabel('Category', fontsize=14)\nplt.ylabel('Count', fontsize=14)\n\nplt.tight_layout()  \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:22.519583Z","iopub.execute_input":"2024-09-21T16:41:22.519933Z","iopub.status.idle":"2024-09-21T16:41:23.455345Z","shell.execute_reply.started":"2024-09-21T16:41:22.519899Z","shell.execute_reply":"2024-09-21T16:41:23.454350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df.sort_values(by='Size',ascending=False)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:41:00.049188Z","iopub.execute_input":"2024-09-21T17:41:00.050070Z","iopub.status.idle":"2024-09-21T17:41:00.103118Z","shell.execute_reply.started":"2024-09-21T17:41:00.050027Z","shell.execute_reply":"2024-09-21T17:41:00.102170Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Image Data Generator","metadata":{}},{"cell_type":"code","source":"image_size=(224,224)\nimage_channels=3\nimage_shape=(image_size[0],image_size[1],3)\nbatch_size = 32\nepochs = 5","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:23.511360Z","iopub.execute_input":"2024-09-21T16:41:23.511795Z","iopub.status.idle":"2024-09-21T16:41:23.517667Z","shell.execute_reply.started":"2024-09-21T16:41:23.511748Z","shell.execute_reply":"2024-09-21T16:41:23.516580Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Data augmentation (like flipping, shifting, zooming, etc.) is typically applied only to the training set to introduce variability and prevent overfitting.\n\nFor validation and test sets, you generally avoid augmentations, as they are used to evaluate the model's performance on unmodified images.","metadata":{}},{"cell_type":"code","source":"train_data_gen = ImageDataGenerator(preprocessing_function=preprocess_input,\n                                    horizontal_flip=True,\n                                    zoom_range=0.2,\n                                    width_shift_range=0.3,\n                                    height_shift_range=0.3,\n                                    rotation_range=0.3,\n                                    shear_range=0.2,\n                                    fill_mode='nearest')\n\ntrain_generator = train_data_gen.flow_from_dataframe(\n                                    dataframe=train_df,          # Your training DataFrame\n                                    directory=train_data_path,   # Path to training data\n                                    x_col='Image_Name',\n                                    y_col='Category',\n                                    batch_size=batch_size, \n                                    shuffle=True,\n                                    class_mode=\"binary\",\n                                    target_size=image_size)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:41:05.002244Z","iopub.execute_input":"2024-09-21T17:41:05.003115Z","iopub.status.idle":"2024-09-21T17:41:05.254832Z","shell.execute_reply.started":"2024-09-21T17:41:05.003073Z","shell.execute_reply":"2024-09-21T17:41:05.253880Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_data_gen = ImageDataGenerator(preprocessing_function=preprocess_input)\n\nval_generator = val_data_gen.flow_from_dataframe(\n                                    dataframe=val_df,            # Your validation DataFrame\n                                    directory=train_data_path,   # Path to validation data  \n                                    x_col='Image_Name',\n                                    y_col='Category',\n                                    batch_size=batch_size, \n                                    shuffle=False,\n                                    class_mode=\"binary\",\n                                    target_size=image_size)\n\n\ntest_generator = val_data_gen.flow_from_dataframe(\n                                    dataframe=test_df,            # Your validation DataFrame\n                                    directory=train_data_path,   # Path to validation data  \n                                    x_col='Image_Name',\n                                    y_col='Category',\n                                    batch_size=batch_size, \n                                    shuffle=False,\n                                    class_mode=\"binary\",\n                                    target_size=image_size)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:46:29.484722Z","iopub.execute_input":"2024-09-21T17:46:29.485520Z","iopub.status.idle":"2024-09-21T17:46:29.567979Z","shell.execute_reply.started":"2024-09-21T17:46:29.485480Z","shell.execute_reply":"2024-09-21T17:46:29.567023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"You can still apply the preprocessing_function=preprocess_input to your validation and test data because it ensures consistency with how the model was trained.","metadata":{}},{"cell_type":"markdown","source":"# Show Sample From Train Data after augmentation\nCalling next(train_generator) retrieves the next batch of data from this generator. Each batch is a tuple containing two elements:\n\n* images: A NumPy array of shape (batch_size, height, width, channels), representing the batch of images.\n* labels: A NumPy array of shape (batch_size, ) or (batch_size, num_classes), representing the labels for these images. The exact shape depends on the class_mode parameter (e.g., 'binary', 'categorical').","metadata":{}},{"cell_type":"code","source":"sample_batch=next(train_generator)\nimages,labels=sample_batch","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:23.873238Z","iopub.execute_input":"2024-09-21T16:41:23.873607Z","iopub.status.idle":"2024-09-21T16:41:24.245563Z","shell.execute_reply.started":"2024-09-21T16:41:23.873572Z","shell.execute_reply":"2024-09-21T16:41:24.244558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# this is what the resnet expect \nplt.figure(figsize=(15,15))\nfor i in range(batch_size):\n    plt.subplot(8,4,i+1)\n    plt.imshow(images[i])\n    label_index = np.argmax(labels[i])\n    label='Cat' if label_index ==0 else 'Dog'\n    plt.title(label)\n    plt.axis('off')\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:24.246792Z","iopub.execute_input":"2024-09-21T16:41:24.247104Z","iopub.status.idle":"2024-09-21T16:41:29.582299Z","shell.execute_reply.started":"2024-09-21T16:41:24.247072Z","shell.execute_reply":"2024-09-21T16:41:29.581317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ReseNet","metadata":{}},{"cell_type":"code","source":"ResNet=ResNet50(weights='imagenet',include_top=False,input_shape=(image_size[0],image_size[1],3))","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:29.583672Z","iopub.execute_input":"2024-09-21T16:41:29.584096Z","iopub.status.idle":"2024-09-21T16:41:32.338790Z","shell.execute_reply.started":"2024-09-21T16:41:29.584049Z","shell.execute_reply":"2024-09-21T16:41:32.337893Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ResNet.summary()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:32.340320Z","iopub.execute_input":"2024-09-21T16:41:32.340815Z","iopub.status.idle":"2024-09-21T16:41:32.587310Z","shell.execute_reply.started":"2024-09-21T16:41:32.340772Z","shell.execute_reply":"2024-09-21T16:41:32.586343Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Get the output from the pre-trained ResNet model\nresnet_output = ResNet.output\n\n# Apply Global Average Pooling to reduce the dimensionality of the feature maps\ngb = GlobalAveragePooling2D()(resnet_output)\n\n# Add a Dropout layer to help prevent overfitting during training\ndrop = Dropout(0.5)(gb)\n\n# Add a fully connected Dense layer with 1024 units and ReLU activation\n# Apply L2 regularization to prevent overfitting\ndense = Dense(1024, activation='relu', kernel_regularizer=l2(5e-4))(drop)\n\n# Add another Dropout layer after the Dense layer\ndrop = Dropout(0.5)(dense)\n\n# Create the output layer with 1 unit (binary classification: dog or cat) using sigmoid activation\npredictions = Dense(1, activation='sigmoid')(drop)\n\n# Define the model with the specified inputs (ResNet input) and outputs (predictions)\nmodel = Model(inputs=ResNet.input, outputs=predictions)\n\n# Display the model summary to show the architecture\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:32.588432Z","iopub.execute_input":"2024-09-21T16:41:32.588756Z","iopub.status.idle":"2024-09-21T16:41:32.871609Z","shell.execute_reply.started":"2024-09-21T16:41:32.588717Z","shell.execute_reply":"2024-09-21T16:41:32.870684Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model Callbacks¶\nSet up some general callbacks for all instances of training. These are:\n\n- checkpoints: save weights of model for best scores while training\n- reduce learning rate: if training gains hit a plateau, try lowering learning rate\n- early stopping: if no gain for several epochs in row, stop\n\nNot all of these are really needed for this simple example, but I left them here since I find them useful to have around when generally training longer iterations.","metadata":{}},{"cell_type":"code","source":"checkpoint = ModelCheckpoint('../working/Resnet50_best.weights.h5', monitor='val_loss', verbose=1, \n                             save_best_only=True, mode='min', save_weights_only=True)\n\nreduceLROnPlat = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=3,\n                                   verbose=1, mode='auto', epsilon=0.0001)\n\nearly = EarlyStopping(monitor=\"val_loss\", mode=\"min\", patience=5)\n\ncallbacks_list = [checkpoint, reduceLROnPlat, early]","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:32.872953Z","iopub.execute_input":"2024-09-21T16:41:32.873272Z","iopub.status.idle":"2024-09-21T16:41:32.879451Z","shell.execute_reply.started":"2024-09-21T16:41:32.873239Z","shell.execute_reply":"2024-09-21T16:41:32.878380Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#the total number of images we have:\ntrain_size = len(train_generator.filenames)\n#train_steps is how many steps per epoch Keras runs the genrator. One step is batch_size*images\ntrain_steps = train_size/batch_size\n#use 2* number of images to get more augmentations in. some do, some dont. up to you\ntrain_steps = int(2*train_steps)\n\n#same for the validation set\nvalid_size = len(val_generator.filenames)\nvalid_steps = valid_size/batch_size\nvalid_steps = int(2*valid_steps) \n\n#same for the test set\ntest_size = len(test_generator.filenames)\ntest_steps = test_size/batch_size\ntest_steps = int(2*test_steps) ","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:32.880803Z","iopub.execute_input":"2024-09-21T16:41:32.881139Z","iopub.status.idle":"2024-09-21T16:41:32.887894Z","shell.execute_reply.started":"2024-09-21T16:41:32.881099Z","shell.execute_reply":"2024-09-21T16:41:32.886902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Step 1: Freeze the ResNet layers\nfor layer in ResNet.layers:\n    layer.trainable = False\n\n# Step 2: Compile the model with frozen layers\nmodel.compile(optimizer=Adam(learning_rate=0.001), loss='binary_crossentropy', metrics=['accuracy'])\n\n# Step 3: Train the model with frozen ResNet layers\nhistory=model.fit(\n    train_generator,\n    steps_per_epoch=train_steps,\n    epochs=epochs,\n    validation_data=val_generator,\n    validation_steps=valid_steps,\n    callbacks=callbacks_list,\n    verbose=1\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-21T16:41:32.888966Z","iopub.execute_input":"2024-09-21T16:41:32.889258Z","iopub.status.idle":"2024-09-21T17:01:56.645683Z","shell.execute_reply.started":"2024-09-21T16:41:32.889227Z","shell.execute_reply":"2024-09-21T17:01:56.644742Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Step 4: Unfreeze the ResNet layers for fine-tuning\nfor layer in ResNet.layers:\n    layer.trainable = True\n\n# Step 5: Re-compile the model after unfreezing the layers (with potentially a lower learning rate)\nmodel.compile(optimizer=Adam(learning_rate=0.0001), loss='binary_crossentropy', metrics=['accuracy'])\n\n# Step 6: Train the model again with the unfrozen ResNet layers (fine-tuning)\nnew_history=model.fit(\n    train_generator,\n    steps_per_epoch=train_steps,\n    epochs=epochs,\n    validation_data=val_generator,\n    validation_steps=valid_steps,\n    callbacks=callbacks_list,\n    verbose=1\n)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:01:56.647022Z","iopub.execute_input":"2024-09-21T17:01:56.647836Z","iopub.status.idle":"2024-09-21T17:23:34.374424Z","shell.execute_reply.started":"2024-09-21T17:01:56.647800Z","shell.execute_reply":"2024-09-21T17:23:34.373568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history.history['loss'] += new_history.history['loss']\nhistory.history['val_loss'] += new_history.history['val_loss']\nhistory.history['accuracy'] += new_history.history['accuracy']\nhistory.history['val_accuracy'] += new_history.history['val_accuracy']","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:23:34.381833Z","iopub.execute_input":"2024-09-21T17:23:34.382154Z","iopub.status.idle":"2024-09-21T17:23:34.387652Z","shell.execute_reply.started":"2024-09-21T17:23:34.382120Z","shell.execute_reply":"2024-09-21T17:23:34.386482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history.history.keys()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:23:34.388868Z","iopub.execute_input":"2024-09-21T17:23:34.389194Z","iopub.status.idle":"2024-09-21T17:23:34.399684Z","shell.execute_reply.started":"2024-09-21T17:23:34.389159Z","shell.execute_reply":"2024-09-21T17:23:34.398722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss=history.history['loss']\nval_loss=history.history['val_loss']\nacc=history.history['accuracy']\nval_acc=history.history['val_accuracy']\n\n# Find the epoch with the minimum validation loss (best performance in terms of loss)\nindex_loss = np.argmin(val_loss)\n# Find the epoch with the maximum validation accuracy (best performance in terms of accuracy)\nindex_acc = np.argmax(val_acc)\n\n# Get the lowest validation loss value at the best epoch\nval_lowest = val_loss[index_loss]\n# Get the highest validation accuracy value at the best epoch\nval_highest = val_acc[index_acc]\n\n# Create a list of epoch numbers, starting from 1, for plotting purposes\nepochs=[i+1 for i in range(len(acc))]\n\n# Create labels for plotting the best epoch in terms of loss and accuracy\nloss_label = f'Best Epoch = {str(index_loss + 1)}'\nacc_label = f'Best Epoch = {str(index_acc + 1)}'","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:23:34.400887Z","iopub.execute_input":"2024-09-21T17:23:34.401218Z","iopub.status.idle":"2024-09-21T17:23:34.408448Z","shell.execute_reply.started":"2024-09-21T17:23:34.401176Z","shell.execute_reply":"2024-09-21T17:23:34.407572Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Set the style of the plot using 'fivethirtyeight' for a cleaner look\nplt.style.use('fivethirtyeight')\nplt.figure(figsize=(15,8))\n\n# Create the first subplot (1 row, 2 columns, this is the first plot)\nplt.subplot(1,2,1)\n# Plot training loss across epochs\nplt.plot(epochs, loss, 'r', label='Training Loss')\n# Plot validation loss across epochs\nplt.plot(epochs, val_loss, 'g', label='Validation Loss')\n# Highlight the point with the lowest validation loss with a blue dot\nplt.scatter((index_loss+1), val_lowest, label=loss_label, s=150, c='b')\n# Set the title, x-axis label, and y-axis label for the loss plot\nplt.title('Training vs Validation (Loss)')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\n# Show the legend to differentiate between training and validation curves\nplt.legend()\n\n# Create the second subplot (2nd plot of the 1 row, 2 column layout)\nplt.subplot(1,2,2)\n# Plot training accuracy across epochs\nplt.plot(epochs, acc, 'r', label='Training Accuracy')\n# Plot validation accuracy across epochs\nplt.plot(epochs, val_acc, 'g', label='Validation Accuracy')\n# Highlight the point with the highest validation accuracy with a blue dot\nplt.scatter((index_acc+1), val_highest, label=acc_label, s=150, c='b')\n# Set the title, x-axis label, and y-axis label for the accuracy plot\nplt.title('Training vs Validation (Accuracy)')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\n# Show the legend to differentiate between training and validation curves\nplt.legend()\n\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:23:34.409644Z","iopub.execute_input":"2024-09-21T17:23:34.409957Z","iopub.status.idle":"2024-09-21T17:23:35.322175Z","shell.execute_reply.started":"2024-09-21T17:23:34.409922Z","shell.execute_reply":"2024-09-21T17:23:35.321232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history.history","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:23:35.323390Z","iopub.execute_input":"2024-09-21T17:23:35.323798Z","iopub.status.idle":"2024-09-21T17:23:35.331277Z","shell.execute_reply.started":"2024-09-21T17:23:35.323755Z","shell.execute_reply":"2024-09-21T17:23:35.330306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Exclude learning_rate if it's of a different length\nhistory_dict = {k: v for k, v in history.history.items() if len(v) == len(history.history['accuracy'])}\n    \n# Create DataFrame\ndf_history = pd.DataFrame(history_dict)\ndf_history","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:23:35.332663Z","iopub.execute_input":"2024-09-21T17:23:35.333313Z","iopub.status.idle":"2024-09-21T17:23:35.348034Z","shell.execute_reply.started":"2024-09-21T17:23:35.333270Z","shell.execute_reply":"2024-09-21T17:23:35.347098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Let's look at the models biggest mistakes\nMaybe we can learn something from the ones where it makes the largest misclassifications.\n\nRe-run predictions on the whole validation set to make sure that we are working with the latest model predictions\n- This can be especially useful if you've made adjustments to the model or hyperparameters and want to validate the changes.\n\nCollect probability of cat/dog\n- this allows you to not only see the predicted label (which could be binary, i.e., cat or dog) but also the model's confidence in that prediction:\n\nResetting the generator\n- The `valid_generator.reset()` is resetting the validation data generator, ensuring that the generator starts from the beginning of the validation set.","metadata":{}},{"cell_type":"markdown","source":"`np_img[np.newaxis]`: Adds a new axis to the image to make it compatible with the model’s expected input shape (batch size, height, width, channels).","metadata":{}},{"cell_type":"code","source":"val_generator.reset()\ndf_valid = pd.DataFrame()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:28:45.972533Z","iopub.execute_input":"2024-09-21T17:28:45.973021Z","iopub.status.idle":"2024-09-21T17:28:45.978282Z","shell.execute_reply.started":"2024-09-21T17:28:45.972983Z","shell.execute_reply":"2024-09-21T17:28:45.977263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# os.path.join(dir1,dir2)==(f'{dir1}/{dir2}')\n# plt.imread('')==np.array(Image.open(''))","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:28:46.881181Z","iopub.execute_input":"2024-09-21T17:28:46.881795Z","iopub.status.idle":"2024-09-21T17:28:46.885671Z","shell.execute_reply.started":"2024-09-21T17:28:46.881756Z","shell.execute_reply":"2024-09-21T17:28:46.884711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Initialize lists to store differences, predictions, categories, and labels\ndiffs = []\npredictions = []\ncat_or_dog = []\nlabels = []\n\n# Iterate through each filename in the validation generator\nfor file in val_generator.filenames:\n    # Create the full image path\n    img_path = os.path.join(train_data_path, file)\n    img = Image.open(img_path)\n    # Resize the image to the specified dimensions\n    img = img.resize((image_size[0], image_size[1]))\n    # Convert the image to a NumPy array\n    img = np.array(img)\n    \n    # Determine the reference label based on the filename\n    if 'cat' == file.split('.')[0]:\n        ref = 0  \n        cat_or_dog.append('cat')   \n    else:\n        ref = 1   \n        cat_or_dog.append('dog')   \n    \n    labels.append(ref)\n    pred = model.predict(preprocess_input(img[np.newaxis]))\n    predictions.append(pred)\n    diffs.append(np.abs(pred[0][0] - ref))","metadata":{"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_valid[\"filename\"] = val_generator.filenames\ndf_valid[\"cat_or_dog\"] = cat_or_dog\ndf_valid[\"label\"] = labels\ndf_valid[\"diff\"] = diffs\ndf_valid[\"prediction\"] = predictions","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:34:03.034317Z","iopub.execute_input":"2024-09-21T17:34:03.035055Z","iopub.status.idle":"2024-09-21T17:34:03.043194Z","shell.execute_reply.started":"2024-09-21T17:34:03.035017Z","shell.execute_reply":"2024-09-21T17:34:03.042250Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sorted_diffs=df_valid.sort_values(by='diff',ascending=False)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:34:03.466438Z","iopub.execute_input":"2024-09-21T17:34:03.466802Z","iopub.status.idle":"2024-09-21T17:34:03.473051Z","shell.execute_reply.started":"2024-09-21T17:34:03.466767Z","shell.execute_reply":"2024-09-21T17:34:03.471898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":" ## Plot the top N misclassifications","metadata":{}},{"cell_type":"code","source":"def plot_top_N(N, sorted_df):\n    from math import ceil\n    # Initialize index for subplot tracking\n    i = 0\n    rows = int(ceil(N / 3))  # Calculate number of rows needed\n    height = rows * 10  # Determine plot height based on rows\n    plt.figure(figsize=[30, height])  # Set figure size (width fixed, height scales)\n\n    # Iterate over each row in the sorted DataFrame\n    for index, row in sorted_df.iterrows():\n        # Create subplot for the current image\n        plt.subplot(rows, 3, i + 1)\n        \n        # Extract data from the DataFrame row\n        file_name = row[\"filename\"]\n        category = row[\"cat_or_dog\"]  # True label as string ('cat' or 'dog')\n        true_label = row[\"label\"]  # True label as 0 or 1\n        diffs = row[\"diff\"]  # Difference between prediction and actual\n        predictions = row[\"prediction\"]  # Predicted probability\n\n        # Determine predicted label based on model prediction\n        pred_label = 1 if predictions[0][0] > 0.5 else 0  # 1 = dog, 0 = cat\n        predicted_category = 'dog' if pred_label == 1 else 'cat'  # Predicted category as string\n        \n        # Open and display image\n        img = Image.open(f\"{train_data_path}/{file_name}\")\n        plt.imshow(img)\n\n        # Set title with model prediction and difference\n        plt.title(f'It is a {category}, model predicted as {predicted_category} with {predictions[0][0]:.2f}, error {diffs:.2f}')\n\n        i += 1  \n        img.close()  # Close image to free memory\n\n        if i >= N:  # Stop when the top N images are plotted\n            break","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:39:14.082985Z","iopub.execute_input":"2024-09-21T17:39:14.083369Z","iopub.status.idle":"2024-09-21T17:39:14.092831Z","shell.execute_reply.started":"2024-09-21T17:39:14.083332Z","shell.execute_reply":"2024-09-21T17:39:14.091725Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_top_N(10,sorted_diffs)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:39:14.382783Z","iopub.execute_input":"2024-09-21T17:39:14.383159Z","iopub.status.idle":"2024-09-21T17:39:20.925033Z","shell.execute_reply.started":"2024-09-21T17:39:14.383121Z","shell.execute_reply":"2024-09-21T17:39:20.923292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Evalute the model","metadata":{}},{"cell_type":"code","source":"nb_samples=len(test_generator.filenames)\nnb_samples","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:46:48.406327Z","iopub.execute_input":"2024-09-21T17:46:48.406747Z","iopub.status.idle":"2024-09-21T17:46:48.413408Z","shell.execute_reply.started":"2024-09-21T17:46:48.406708Z","shell.execute_reply":"2024-09-21T17:46:48.412274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predict=model.predict(test_generator,steps=int(np.ceil(nb_samples/batch_size)))\ntest_df['Predication']=(predict > .5).astype(int)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:49:10.637785Z","iopub.execute_input":"2024-09-21T17:49:10.638193Z","iopub.status.idle":"2024-09-21T17:49:17.037466Z","shell.execute_reply.started":"2024-09-21T17:49:10.638157Z","shell.execute_reply":"2024-09-21T17:49:17.036689Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:48:14.777614Z","iopub.execute_input":"2024-09-21T17:48:14.778663Z","iopub.status.idle":"2024-09-21T17:48:14.796624Z","shell.execute_reply.started":"2024-09-21T17:48:14.778617Z","shell.execute_reply":"2024-09-21T17:48:14.795613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(val_generator.class_indices)\nprint(val_generator.class_indices.items())","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:48:26.146420Z","iopub.execute_input":"2024-09-21T17:48:26.147273Z","iopub.status.idle":"2024-09-21T17:48:26.152104Z","shell.execute_reply.started":"2024-09-21T17:48:26.147230Z","shell.execute_reply":"2024-09-21T17:48:26.151123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels=dict((v,k) for k,v in val_generator.class_indices.items())\nlabels","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:48:30.675607Z","iopub.execute_input":"2024-09-21T17:48:30.676399Z","iopub.status.idle":"2024-09-21T17:48:30.683197Z","shell.execute_reply.started":"2024-09-21T17:48:30.676360Z","shell.execute_reply":"2024-09-21T17:48:30.682100Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model misclassification","metadata":{}},{"cell_type":"code","source":"test_df[test_df['Code']!=test_df['Predication']]","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:51:15.983626Z","iopub.execute_input":"2024-09-21T17:51:15.984006Z","iopub.status.idle":"2024-09-21T17:51:16.012195Z","shell.execute_reply.started":"2024-09-21T17:51:15.983971Z","shell.execute_reply":"2024-09-21T17:51:16.011094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_loss, train_accuracy = model.evaluate(train_generator, steps=int(np.ceil(len(train_generator.filenames) / batch_size)))\ntest_loss, test_accuracy = model.evaluate(test_generator, steps=int(np.ceil(len(test_generator.filenames) / batch_size)))\nval_loss, val_accuracy = model.evaluate(val_generator, steps=int(np.ceil(len(val_generator.filenames) / batch_size)))","metadata":{"execution":{"iopub.status.busy":"2024-09-21T17:53:16.580446Z","iopub.execute_input":"2024-09-21T17:53:16.581441Z","iopub.status.idle":"2024-09-21T17:57:18.611151Z","shell.execute_reply.started":"2024-09-21T17:53:16.581397Z","shell.execute_reply":"2024-09-21T17:57:18.610227Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predictions","metadata":{}},{"cell_type":"code","source":"image_name=[]\nsize=[]\naspect_ratio=[]\n\nfor image in test_images:\n    image_name.append(image)\n    img_path=os.path.join(test_data_path,image)    \n    \n    # Read the image to get its size (height, width)\n    img=cv2.imread(img_path)\n    size.append((img.shape[0],img.shape[1]))\n    # Calculate and append the aspect ratio (height/width) of the image\n    aspect_ratio.append(img.shape[0]/img.shape[1])    \n\ntest_df=pd.DataFrame({'Image_Name':image_name})\ntest_df","metadata":{"execution":{"iopub.status.busy":"2024-09-21T18:01:56.174488Z","iopub.execute_input":"2024-09-21T18:01:56.175161Z","iopub.status.idle":"2024-09-21T18:02:05.910016Z","shell.execute_reply.started":"2024-09-21T18:01:56.175121Z","shell.execute_reply":"2024-09-21T18:02:05.908965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data_gen = ImageDataGenerator(preprocessing_function=preprocess_input)\ntest_generator = test_data_gen.flow_from_dataframe(\n                                    dataframe=test_df,          # Your test DataFrame\n                                    directory=test_data_path,   # Path to test data\n                                    x_col='Image_Name',\n                                    y_col=None,   \n                                    batch_size=batch_size, \n                                    shuffle=False,\n                                    class_mode=None,            # Set to None since there are no labels\n                                    target_size=image_size)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T18:02:05.912162Z","iopub.execute_input":"2024-09-21T18:02:05.912626Z","iopub.status.idle":"2024-09-21T18:02:06.052921Z","shell.execute_reply.started":"2024-09-21T18:02:05.912578Z","shell.execute_reply":"2024-09-21T18:02:06.052031Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred=model.predict(test_generator,steps=int(np.ceil(len(test_generator.filenames))))","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['Predication']=(pred>.5).astype(int)","metadata":{"execution":{"iopub.status.busy":"2024-09-21T18:02:41.765043Z","iopub.execute_input":"2024-09-21T18:02:41.765569Z","iopub.status.idle":"2024-09-21T18:02:41.770912Z","shell.execute_reply.started":"2024-09-21T18:02:41.765514Z","shell.execute_reply":"2024-09-21T18:02:41.769837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df['Category']=test_df['Predication'].map({0:'cat',1:'dog'})\ntest_df","metadata":{"execution":{"iopub.status.busy":"2024-09-21T18:05:46.954823Z","iopub.execute_input":"2024-09-21T18:05:46.956056Z","iopub.status.idle":"2024-09-21T18:05:46.970295Z","shell.execute_reply.started":"2024-09-21T18:05:46.956001Z","shell.execute_reply":"2024-09-21T18:05:46.969167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# See predicted result\n","metadata":{}},{"cell_type":"code","source":"sample_test = test_df.sample(n=9).reset_index()\nsample_test.head()\nplt.figure(figsize=(12, 12))\nfor index, row in sample_test.iterrows():\n    plt.subplot(3, 3, index+1)\n    filename = row['Image_Name']\n    category = row['Category']\n    img = Image.open(f'{test_data_path}/{filename}')\n    plt.imshow(img)\n    plt.title(f'Image {filename} Predicated as {category}',fontsize=12)\n    plt.axis('off')\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2024-09-21T18:11:14.633025Z","iopub.execute_input":"2024-09-21T18:11:14.633421Z","iopub.status.idle":"2024-09-21T18:11:16.936566Z","shell.execute_reply.started":"2024-09-21T18:11:14.633381Z","shell.execute_reply":"2024-09-21T18:11:16.935578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"test_df","metadata":{"execution":{"iopub.status.busy":"2024-09-21T18:19:28.937393Z","iopub.execute_input":"2024-09-21T18:19:28.937814Z","iopub.status.idle":"2024-09-21T18:19:28.949632Z","shell.execute_reply.started":"2024-09-21T18:19:28.937776Z","shell.execute_reply":"2024-09-21T18:19:28.948584Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Creating the submission DataFrame\nsubmission_df = test_df.copy()\nsubmission_df['id'] = submission_df['Image_Name'].str.split('.').str[0]\nsubmission_df['label'] = submission_df['Predication']\nsubmission_df.drop(['Image_Name', 'Category', 'Predication'], axis=1, inplace=True)\n\n# Saving the DataFrame to a CSV file\nsubmission_df.to_csv('submission.csv', index=False)\n\n# Plotting the count of labels\nplt.figure(figsize=(10,5))\nsns.countplot(x='label', data=submission_df)\nplt.title(\"Label distribution in Test data\")\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2024-09-21T18:19:56.517331Z","iopub.execute_input":"2024-09-21T18:19:56.517761Z","iopub.status.idle":"2024-09-21T18:19:56.780616Z","shell.execute_reply.started":"2024-09-21T18:19:56.517722Z","shell.execute_reply":"2024-09-21T18:19:56.779408Z"},"trusted":true},"execution_count":null,"outputs":[]}]}