{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames[:20]:\n        print(os.path.join(dirname, filename))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:36:54.622174Z","iopub.execute_input":"2026-09-26T16:36:54.622492Z","iopub.status.idle":"2026-09-26T16:36:54.63549Z","shell.execute_reply.started":"2026-09-26T16:36:54.62246Z","shell.execute_reply":"2026-09-26T16:36:54.634425Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import zipfile\n\nwith zipfile.ZipFile('/kaggle/input/competitions/dogs-vs-cats-redux-kernels-edition/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/')\n\nprint(\"Done extracting!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:38:58.750493Z","iopub.execute_input":"2026-09-26T16:38:58.751018Z","iopub.status.idle":"2026-09-26T16:39:16.964841Z","shell.execute_reply.started":"2026-09-26T16:38:58.750955Z","shell.execute_reply":"2026-09-26T16:39:16.963886Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nprint(os.listdir('/kaggle/working/train')[:10])\nprint(\"Total images:\", len(os.listdir('/kaggle/working/train')))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:40:03.372066Z","iopub.execute_input":"2026-09-26T16:40:03.372399Z","iopub.status.idle":"2026-09-26T16:40:03.413693Z","shell.execute_reply.started":"2026-09-26T16:40:03.372371Z","shell.execute_reply":"2026-09-26T16:40:03.41191Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport cv2\nimport os\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.preprocessing import StandardScaler\nfrom sklearn.metrics import (accuracy_score, precision_score, recall_score, \n                              f1_score, confusion_matrix, classification_report)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:42:48.770021Z","iopub.execute_input":"2026-09-26T16:42:48.770919Z","iopub.status.idle":"2026-09-26T16:42:51.101686Z","shell.execute_reply.started":"2026-09-26T16:42:48.770883Z","shell.execute_reply":"2026-09-26T16:42:51.100746Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_dir = '/kaggle/working/train'\nimg_size = 64   # resize all images to 64x64 pixels\n\ndata = []\nlabels = []\n\n# Load 1000 cat images\ncount = 0\nfor filename in os.listdir(img_dir):\n    if filename.startswith('cat') and count < 1000:\n        img_path = os.path.join(img_dir, filename)\n        img = cv2.imread(img_path)\n        img = cv2.resize(img, (img_size, img_size))\n        data.append(img)\n        labels.append(0)   # 0 = cat\n        count += 1\n\n# Load 1000 dog images\ncount = 0\nfor filename in os.listdir(img_dir):\n    if filename.startswith('dog') and count < 1000:\n        img_path = os.path.join(img_dir, filename)\n        img = cv2.imread(img_path)\n        img = cv2.resize(img, (img_size, img_size))\n        data.append(img)\n        labels.append(1)   # 1 = dog\n        count += 1\n\nprint(\"Total images loaded:\", len(data))\nprint(\"Total labels:\", len(labels))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:43:28.283168Z","iopub.execute_input":"2026-09-26T16:43:28.283707Z","iopub.status.idle":"2026-09-26T16:43:30.250373Z","shell.execute_reply.started":"2026-09-26T16:43:28.283672Z","shell.execute_reply":"2026-09-26T16:43:30.249242Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Convert lists to numpy arrays\nX = np.array(data)\ny = np.array(labels)\n\nprint(\"Shape of X before flattening:\", X.shape)\n\n# Flatten each image: (64, 64, 3) -> single row of 12288 numbers\nX = X.reshape(X.shape[0], -1)\n\nprint(\"Shape of X after flattening:\", X.shape)\n\n# Normalize pixel values (0-255 -> 0-1)\nX = X / 255.0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:45:00.93937Z","iopub.execute_input":"2026-09-26T16:45:00.939795Z","iopub.status.idle":"2026-09-26T16:45:01.055388Z","shell.execute_reply.started":"2026-09-26T16:45:00.939764Z","shell.execute_reply":"2026-09-26T16:45:01.053774Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train, X_test, y_train, y_test = train_test_split(\n    X, y, test_size=0.2, random_state=42, stratify=y\n)\n\nprint(\"Training samples:\", X_train.shape[0])\nprint(\"Testing samples:\", X_test.shape[0])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:45:57.071308Z","iopub.execute_input":"2026-09-26T16:45:57.071669Z","iopub.status.idle":"2026-09-26T16:45:57.165466Z","shell.execute_reply.started":"2026-09-26T16:45:57.071641Z","shell.execute_reply":"2026-09-26T16:45:57.164307Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = LogisticRegression(max_iter=1000)\nmodel.fit(X_train, y_train)\n\nprint(\"Model training complete!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:48:14.460226Z","iopub.execute_input":"2026-09-26T16:48:14.460589Z","iopub.status.idle":"2026-09-26T16:48:31.916894Z","shell.execute_reply.started":"2026-09-26T16:48:14.460559Z","shell.execute_reply":"2026-09-26T16:48:31.916169Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y_pred = model.predict(X_test)\ny_prob = model.predict_proba(X_test)[:, 1]\n\nprint(\"Predictions done!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:50:28.208556Z","iopub.execute_input":"2026-09-26T16:50:28.208901Z","iopub.status.idle":"2026-09-26T16:50:28.228058Z","shell.execute_reply.started":"2026-09-26T16:50:28.208872Z","shell.execute_reply":"2026-09-26T16:50:28.226757Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Accuracy:\", accuracy_score(y_test, y_pred))\nprint(\"Precision:\", precision_score(y_test, y_pred))\nprint(\"Recall:\", recall_score(y_test, y_pred))\nprint(\"F1 Score:\", f1_score(y_test, y_pred))\nprint(\"\\nClassification Report:\\n\", classification_report(y_test, y_pred))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:51:14.918912Z","iopub.execute_input":"2026-09-26T16:51:14.919251Z","iopub.status.idle":"2026-09-26T16:51:14.946717Z","shell.execute_reply.started":"2026-09-26T16:51:14.919223Z","shell.execute_reply":"2026-09-26T16:51:14.945755Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cm = confusion_matrix(y_test, y_pred)\n\nplt.figure(figsize=(6,5))\nsns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n            xticklabels=['Cat','Dog'],\n            yticklabels=['Cat','Dog'])\nplt.xlabel('Predicted')\nplt.ylabel('Actual')\nplt.title('Confusion Matrix - Cats vs Dogs Classification')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T16:54:05.027808Z","iopub.execute_input":"2026-09-26T16:54:05.028679Z","iopub.status.idle":"2026-09-26T16:54:05.339962Z","shell.execute_reply.started":"2026-09-26T16:54:05.028633Z","shell.execute_reply":"2026-09-26T16:54:05.337867Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.linear_model import SGDClassifier\n\n# Use SGDClassifier with log_loss to simulate epoch-based training\nsgd_model = SGDClassifier(loss='log_loss', max_iter=1, warm_start=True, random_state=42)\n\ntrain_acc = []\nval_acc = []\nepochs = 30\n\nfor epoch in range(epochs):\n    sgd_model.fit(X_train, y_train)\n    train_acc.append(sgd_model.score(X_train, y_train))\n    val_acc.append(sgd_model.score(X_test, y_test))\n\nplt.figure(figsize=(8,5))\nplt.plot(range(1, epochs+1), train_acc, label='Training Accuracy')\nplt.plot(range(1, epochs+1), val_acc, label='Validation Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.title('Training vs Validation Accuracy')\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:02:56.549213Z","iopub.execute_input":"2026-09-26T17:02:56.550455Z","iopub.status.idle":"2026-09-26T17:03:01.1294Z","shell.execute_reply.started":"2026-09-26T17:02:56.550379Z","shell.execute_reply":"2026-09-26T17:03:01.128254Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Re-plot and save Confusion Matrix\nplt.figure(figsize=(6,5))\nsns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n            xticklabels=['Cat','Dog'], yticklabels=['Cat','Dog'])\nplt.xlabel('Predicted')\nplt.ylabel('Actual')\nplt.title('Confusion Matrix - Cats vs Dogs Classification')\nplt.savefig('/kaggle/working/confusion_matrix.png', bbox_inches='tight')\nplt.show()\n\n# Re-plot and save Training/Validation graph\nplt.figure(figsize=(8,5))\nplt.plot(range(1, epochs+1), train_acc, label='Training Accuracy')\nplt.plot(range(1, epochs+1), val_acc, label='Validation Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.title('Training vs Validation Accuracy')\nplt.legend()\nplt.savefig('/kaggle/working/training_validation.png', bbox_inches='tight')\nplt.show()\n\nprint(\"Graphs saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:09:11.426599Z","iopub.execute_input":"2026-09-26T17:09:11.427817Z","iopub.status.idle":"2026-09-26T17:09:12.035177Z","shell.execute_reply.started":"2026-09-26T17:09:11.427777Z","shell.execute_reply":"2026-09-26T17:09:12.034149Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Input\nimport numpy as np","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:14:50.057179Z","iopub.execute_input":"2026-09-26T17:14:50.058121Z","iopub.status.idle":"2026-09-26T17:15:09.363034Z","shell.execute_reply.started":"2026-09-26T17:14:50.058082Z","shell.execute_reply":"2026-09-26T17:15:09.36215Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Recall: earlier we flattened images into rows of 12288 numbers for Logistic Regression.\n# CNN needs the original image shape back: (num_images, 64, 64, 3)\n\nX_train_img = X_train.reshape(-1, 64, 64, 3)\nX_test_img = X_test.reshape(-1, 64, 64, 3)\n\nprint(X_train_img.shape, X_test_img.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:16:47.385529Z","iopub.execute_input":"2026-09-26T17:16:47.386755Z","iopub.status.idle":"2026-09-26T17:16:47.395077Z","shell.execute_reply.started":"2026-09-26T17:16:47.386625Z","shell.execute_reply":"2026-09-26T17:16:47.393761Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"input_layer = Input(shape=(64, 64, 3))\nx = Conv2D(32, (3,3), activation='relu', padding='same', name='conv_layer')(input_layer)\nx = MaxPooling2D((2,2))(x)\nx = Flatten()(x)\nx = Dense(64, activation='relu')(x)\noutput_layer = Dense(1, activation='sigmoid')(x)\n\ncnn_model = Model(inputs=input_layer, outputs=output_layer)\ncnn_model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])\ncnn_model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:18:08.018077Z","iopub.execute_input":"2026-09-26T17:18:08.018635Z","iopub.status.idle":"2026-09-26T17:18:08.168935Z","shell.execute_reply.started":"2026-09-26T17:18:08.018598Z","shell.execute_reply":"2026-09-26T17:18:08.16785Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.layers import GlobalAveragePooling2D\nfrom tensorflow.keras.optimizers import Adam\n\ninput_layer = Input(shape=(64, 64, 3))\nx = Conv2D(32, (3,3), activation='relu', padding='same', name='conv_layer')(input_layer)\nx = MaxPooling2D((2,2))(x)\nx = Conv2D(64, (3,3), activation='relu', padding='same')(x)\nx = MaxPooling2D((2,2))(x)\nx = GlobalAveragePooling2D()(x)\nx = Dense(32, activation='relu')(x)\noutput_layer = Dense(1, activation='sigmoid')(x)\n\ncnn_model = Model(inputs=input_layer, outputs=output_layer)\ncnn_model.compile(optimizer=Adam(learning_rate=0.0005), loss='binary_crossentropy', metrics=['accuracy'])\ncnn_model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:31:52.145446Z","iopub.execute_input":"2026-09-26T17:31:52.14593Z","iopub.status.idle":"2026-09-26T17:31:52.227539Z","shell.execute_reply.started":"2026-09-26T17:31:52.145896Z","shell.execute_reply":"2026-09-26T17:31:52.226548Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = cnn_model.fit(\n    X_train_img, y_train,\n    validation_data=(X_test_img, y_test),\n    epochs=10,\n    batch_size=32\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:22:18.728138Z","iopub.execute_input":"2026-09-26T17:22:18.728522Z","iopub.status.idle":"2026-09-26T17:22:49.09079Z","shell.execute_reply.started":"2026-09-26T17:22:18.728489Z","shell.execute_reply":"2026-09-26T17:22:49.089411Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = cnn_model.fit(\n    X_train_img, y_train,\n    validation_data=(X_test_img, y_test),\n    epochs=15,\n    batch_size=32\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:32:46.386551Z","iopub.execute_input":"2026-09-26T17:32:46.38686Z","iopub.status.idle":"2026-09-26T17:34:02.461938Z","shell.execute_reply.started":"2026-09-26T17:32:46.386837Z","shell.execute_reply":"2026-09-26T17:34:02.460682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.cm as cm\n\ndef get_gradcam_heatmap(model, img_array, layer_name='conv_layer'):\n    grad_model = Model(inputs=model.input, \n                        outputs=[model.get_layer(layer_name).output, model.output])\n    \n    with tf.GradientTape() as tape:\n        conv_outputs, predictions = grad_model(img_array)\n        loss = predictions[:, 0]\n    \n    grads = tape.gradient(loss, conv_outputs)\n    pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))\n    \n    conv_outputs = conv_outputs[0]\n    heatmap = conv_outputs @ pooled_grads[..., tf.newaxis]\n    heatmap = tf.squeeze(heatmap)\n    heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)\n    \n    return heatmap.numpy()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:35:27.06918Z","iopub.execute_input":"2026-09-26T17:35:27.070294Z","iopub.status.idle":"2026-09-26T17:35:27.077974Z","shell.execute_reply.started":"2026-09-26T17:35:27.070255Z","shell.execute_reply":"2026-09-26T17:35:27.076833Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\n\nimg_index = 0\nimg_array = np.expand_dims(X_test_img[img_index], axis=0)\n\nheatmap = get_gradcam_heatmap(cnn_model, img_array)\n\nheatmap_resized = cv2.resize(heatmap, (64, 64))\nheatmap_colored = cm.jet(heatmap_resized)[:, :, :3]\n\noriginal_img = X_test_img[img_index]\noverlayed_img = 0.6 * original_img + 0.4 * heatmap_colored\n\nplt.figure(figsize=(10,4))\nplt.subplot(1,3,1)\nplt.imshow(original_img)\nplt.title('Original Image')\nplt.axis('off')\n\nplt.subplot(1,3,2)\nplt.imshow(heatmap_resized, cmap='jet')\nplt.title('Grad-CAM Heatmap')\nplt.axis('off')\n\nplt.subplot(1,3,3)\nplt.imshow(overlayed_img)\nplt.title('Overlay')\nplt.axis('off')\n\nplt.savefig('/kaggle/working/gradcam_example.png', bbox_inches='tight')\nplt.show()\n\nactual_label = 'Dog' if y_test[img_index] == 1 else 'Cat'\nprint(\"Actual label:\", actual_label)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:36:14.213004Z","iopub.execute_input":"2026-09-26T17:36:14.213352Z","iopub.status.idle":"2026-09-26T17:36:14.641896Z","shell.execute_reply.started":"2026-09-26T17:36:14.213305Z","shell.execute_reply":"2026-09-26T17:36:14.640876Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Show Grad-CAM for 3 different test images\nsample_indices = [0, 5, 10]  # you can change these numbers\n\nfor idx in sample_indices:\n    img_array = np.expand_dims(X_test_img[idx], axis=0)\n    heatmap = get_gradcam_heatmap(cnn_model, img_array)\n    heatmap_resized = cv2.resize(heatmap, (64, 64))\n    heatmap_colored = cm.jet(heatmap_resized)[:, :, :3]\n    overlayed_img = 0.6 * X_test_img[idx] + 0.4 * heatmap_colored\n    \n    predicted_prob = cnn_model.predict(img_array, verbose=0)[0][0]\n    predicted_label = 'Dog' if predicted_prob > 0.5 else 'Cat'\n    actual_label = 'Dog' if y_test[idx] == 1 else 'Cat'\n    \n    plt.figure(figsize=(10,4))\n    plt.subplot(1,3,1)\n    plt.imshow(X_test_img[idx])\n    plt.title('Original')\n    plt.axis('off')\n    \n    plt.subplot(1,3,2)\n    plt.imshow(heatmap_resized, cmap='jet')\n    plt.title('Grad-CAM')\n    plt.axis('off')\n    \n    plt.subplot(1,3,3)\n    plt.imshow(overlayed_img)\n    plt.title('Overlay')\n    plt.axis('off')\n    \n    plt.suptitle(f'Actual: {actual_label} | Predicted: {predicted_label}')\n    plt.savefig(f'/kaggle/working/gradcam_example_{idx}.png', bbox_inches='tight')\n    plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-09-26T17:38:46.173711Z","iopub.execute_input":"2026-09-26T17:38:46.174633Z","iopub.status.idle":"2026-09-26T17:38:47.591647Z","shell.execute_reply.started":"2026-09-26T17:38:46.174579Z","shell.execute_reply":"2026-09-26T17:38:47.590567Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}