{"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":"# ===========================\n# Basic Libraries\n# ===========================\nimport os\nimport random\nfrom shutil import copyfile\n\nimport numpy as np\nimport pandas as pd\n\n# ===========================\n# Data Visualization\n# ===========================\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom matplotlib.image import imread\nfrom PIL import Image\n\n# ===========================\n# Scikit-learn\n# ===========================\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import (\n    classification_report,\n    confusion_matrix,\n    ConfusionMatrixDisplay\n)\n\n# ===========================\n# TensorFlow / Keras\n# ===========================\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import (\n    Conv2D,\n    MaxPooling2D,\n    Flatten,\n    Dense,\n    Dropout,\n    BatchNormalization\n)\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:25:11.994847Z","iopub.execute_input":"2026-07-17T14:25:11.995213Z","iopub.status.idle":"2026-07-17T14:25:12.001046Z","shell.execute_reply.started":"2026-07-17T14:25:11.995185Z","shell.execute_reply":"2026-07-17T14:25:12.000218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Dataset paths\ntrain_zip = \"/kaggle/input/competitions/dogs-vs-cats/train.zip\"\ntest_zip = \"/kaggle/input/competitions/dogs-vs-cats/test1.zip\"\n\nextract_path = \"/kaggle/working/\"\n\nimport zipfile\n\n# Extract training images\nwith zipfile.ZipFile(train_zip, \"r\") as zip_ref:\n    zip_ref.extractall(extract_path)\n\n# Extract test images\nwith zipfile.ZipFile(test_zip, \"r\") as zip_ref:\n    zip_ref.extractall(extract_path)\n\nprint(\"✅ Dataset extracted successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:25:55.3274Z","iopub.execute_input":"2026-07-17T14:25:55.327711Z","iopub.status.idle":"2026-07-17T14:26:05.222785Z","shell.execute_reply.started":"2026-07-17T14:25:55.327685Z","shell.execute_reply":"2026-07-17T14:26:05.222047Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Path to extracted training images\nimage_dir = \"/kaggle/working/train\"\n\n# Get all image filenames\nfilenames = os.listdir(image_dir)\n\n# Extract labels (cat/dog) from filenames\nlabels = [filename.split(\".\")[0] for filename in filenames]\n\n# Create DataFrame\ndata = pd.DataFrame({\n    \"filename\": filenames,\n    \"label\": labels\n})\n\n# Display first 5 rows\ndata.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:26:44.749982Z","iopub.execute_input":"2026-07-17T14:26:44.750435Z","iopub.status.idle":"2026-07-17T14:26:44.798138Z","shell.execute_reply.started":"2026-07-17T14:26:44.750409Z","shell.execute_reply":"2026-07-17T14:26:44.797271Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Train, Validation and Test Split\n# ===========================\n\n# Use labels for stratified splitting\nlabels = data[\"label\"]\n\n# 80% Train | 20% Temp\ntrain_df, temp_df = train_test_split(\n    data,\n    test_size=0.20,\n    stratify=labels,\n    random_state=42\n)\n\n# Split the remaining 20% equally\ntemp_labels = temp_df[\"label\"]\n\ntest_df, val_df = train_test_split(\n    temp_df,\n    test_size=0.50,\n    stratify=temp_labels,\n    random_state=42\n)\n\nprint(f\"Training Images   : {train_df.shape[0]}\")\nprint(f\"Testing Images    : {test_df.shape[0]}\")\nprint(f\"Validation Images : {val_df.shape[0]}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:27:36.725657Z","iopub.execute_input":"2026-07-17T14:27:36.726279Z","iopub.status.idle":"2026-07-17T14:27:36.78022Z","shell.execute_reply.started":"2026-07-17T14:27:36.726249Z","shell.execute_reply":"2026-07-17T14:27:36.779357Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Class Distribution\n# ===========================\n\nfig, axes = plt.subplots(1, 3, figsize=(18, 5))\n\n# Training Set\nsns.countplot(\n    data=train_df,\n    x=\"label\",\n    hue=\"label\",\n    palette=\"icefire\",\n    legend=False,\n    ax=axes[0]\n)\naxes[0].set_title(\"Training Set\")\naxes[0].set_xlabel(\"Class\")\naxes[0].set_ylabel(\"Count\")\n\n# Validation Set\nsns.countplot(\n    data=val_df,\n    x=\"label\",\n    hue=\"label\",\n    palette=\"icefire\",\n    legend=False,\n    ax=axes[1]\n)\naxes[1].set_title(\"Validation Set\")\naxes[1].set_xlabel(\"Class\")\naxes[1].set_ylabel(\"Count\")\n\n# Test Set\nsns.countplot(\n    data=test_df,\n    x=\"label\",\n    hue=\"label\",\n    palette=\"icefire\",\n    legend=False,\n    ax=axes[2]\n)\naxes[2].set_title(\"Test Set\")\naxes[2].set_xlabel(\"Class\")\naxes[2].set_ylabel(\"Count\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:29:00.659208Z","iopub.execute_input":"2026-07-17T14:29:00.659682Z","iopub.status.idle":"2026-07-17T14:29:01.168709Z","shell.execute_reply.started":"2026-07-17T14:29:00.659653Z","shell.execute_reply":"2026-07-17T14:29:01.167974Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Create Train / Validation / Test Directories\n# ===========================\n\nimport os\nimport shutil\n\ndataset_path = \"/kaggle/working/dataset\"\n\nfolders = [\n    \"train/cats\",\n    \"train/dogs\",\n    \"validation/cats\",\n    \"validation/dogs\",\n    \"test/cats\",\n    \"test/dogs\"\n]\n\nfor folder in folders:\n    os.makedirs(os.path.join(dataset_path, folder), exist_ok=True)\n\n\n# ===========================\n# Copy Images\n# ===========================\n\nsource_path = \"/kaggle/working/train\"\n\ndef copy_images(df, split):\n    for _, row in df.iterrows():\n        filename = row[\"filename\"]\n        label = row[\"label\"]\n\n        if label == \"cat\":\n            destination = os.path.join(dataset_path, split, \"cats\", filename)\n        else:\n            destination = os.path.join(dataset_path, split, \"dogs\", filename)\n\n        shutil.copy(\n            os.path.join(source_path, filename),\n            destination\n        )\n\ncopy_images(train_df, \"train\")\ncopy_images(val_df, \"validation\")\ncopy_images(test_df, \"test\")\n\n\n# ===========================\n# Verify Dataset\n# ===========================\n\nprint(\"Training Cats      :\", len(os.listdir(dataset_path + \"/train/cats\")))\nprint(\"Training Dogs      :\", len(os.listdir(dataset_path + \"/train/dogs\")))\n\nprint(\"Validation Cats    :\", len(os.listdir(dataset_path + \"/validation/cats\")))\nprint(\"Validation Dogs    :\", len(os.listdir(dataset_path + \"/validation/dogs\")))\n\nprint(\"Testing Cats       :\", len(os.listdir(dataset_path + \"/test/cats\")))\nprint(\"Testing Dogs       :\", len(os.listdir(dataset_path + \"/test/dogs\")))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:29:56.093663Z","iopub.execute_input":"2026-07-17T14:29:56.09432Z","iopub.status.idle":"2026-07-17T14:30:00.844306Z","shell.execute_reply.started":"2026-07-17T14:29:56.09429Z","shell.execute_reply":"2026-07-17T14:30:00.843474Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Image Parameters\n# ===========================\n\nIMAGE_SIZE = 128\nIMAGE_CHANNELS = 3\nBATCH_SIZE = 32","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:31:11.39791Z","iopub.execute_input":"2026-07-17T14:31:11.398395Z","iopub.status.idle":"2026-07-17T14:31:11.402143Z","shell.execute_reply.started":"2026-07-17T14:31:11.398367Z","shell.execute_reply":"2026-07-17T14:31:11.401284Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Image Data Generators\n# ===========================\n\ntrain_datagen = ImageDataGenerator(\n    rescale=1.0 / 255,\n    rotation_range=15,\n    width_shift_range=0.10,\n    height_shift_range=0.10,\n    shear_range=0.10,\n    zoom_range=0.20,\n    horizontal_flip=True,\n    fill_mode=\"nearest\"\n)\n\nvalidation_datagen = ImageDataGenerator(\n    rescale=1.0 / 255\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:31:47.674668Z","iopub.execute_input":"2026-07-17T14:31:47.675387Z","iopub.status.idle":"2026-07-17T14:31:47.680806Z","shell.execute_reply.started":"2026-07-17T14:31:47.675358Z","shell.execute_reply":"2026-07-17T14:31:47.680136Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Data Generators\n# ===========================\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    dataframe=train_df,\n    directory=\"/kaggle/working/train\",\n    x_col=\"filename\",\n    y_col=\"label\",\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode=\"binary\",\n    shuffle=True\n)\n\nval_generator = validation_datagen.flow_from_dataframe(\n    dataframe=val_df,\n    directory=\"/kaggle/working/train\",\n    x_col=\"filename\",\n    y_col=\"label\",\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode=\"binary\",\n    shuffle=False\n)\n\ntest_generator = validation_datagen.flow_from_dataframe(\n    dataframe=test_df,\n    directory=\"/kaggle/working/train\",\n    x_col=\"filename\",\n    y_col=\"label\",\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode=\"binary\",\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:32:23.020817Z","iopub.execute_input":"2026-07-17T14:32:23.02155Z","iopub.status.idle":"2026-07-17T14:32:23.223519Z","shell.execute_reply.started":"2026-07-17T14:32:23.021516Z","shell.execute_reply":"2026-07-17T14:32:23.222965Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_gen = train_datagen.flow_from_directory(\n    \"/kaggle/working/dataset/train/\",\n    class_mode=\"binary\",\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=BATCH_SIZE,\n)\n\nval_gen = validation_datagen.flow_from_directory(\n    \"/kaggle/working/dataset/validation/\",\n    class_mode=\"binary\",\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=BATCH_SIZE,\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:35:46.208768Z","iopub.execute_input":"2026-07-17T14:35:46.20916Z","iopub.status.idle":"2026-07-17T14:35:46.398483Z","shell.execute_reply.started":"2026-07-17T14:35:46.209132Z","shell.execute_reply":"2026-07-17T14:35:46.397869Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# CNN Model\n# ===========================\n\nmodel = Sequential()\n\n# Input Layer\nmodel.add(Conv2D(32, (3, 3), activation=\"relu\",\n                 input_shape=(IMAGE_SIZE, IMAGE_SIZE, IMAGE_CHANNELS)))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\n# Block 1\nmodel.add(Conv2D(64, (3, 3), activation=\"relu\"))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\n# Block 2\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# Block 3\nmodel.add(Conv2D(256, (3, 3), activation=\"relu\"))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\nmodel.add(Dropout(0.25))\n\n# Fully Connected Layer\nmodel.add(Flatten())\nmodel.add(Dense(512, activation=\"relu\"))\nmodel.add(BatchNormalization())\nmodel.add(Dropout(0.50))\n\n# Output Layer\nmodel.add(Dense(1, activation=\"sigmoid\"))\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:40:36.396032Z","iopub.execute_input":"2026-07-17T14:40:36.396733Z","iopub.status.idle":"2026-07-17T14:40:36.612221Z","shell.execute_reply.started":"2026-07-17T14:40:36.396701Z","shell.execute_reply":"2026-07-17T14:40:36.61158Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Callbacks\n# ===========================\n\nlearning_rate_reduction = ReduceLROnPlateau(\n    monitor=\"val_accuracy\",\n    patience=2,\n    factor=0.5,\n    min_lr=1e-5,\n    verbose=1\n)\n\nearly_stopping = EarlyStopping(\n    monitor=\"val_loss\",\n    patience=3,\n    restore_best_weights=True,\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:40:45.043921Z","iopub.execute_input":"2026-07-17T14:40:45.044335Z","iopub.status.idle":"2026-07-17T14:40:45.048666Z","shell.execute_reply.started":"2026-07-17T14:40:45.044307Z","shell.execute_reply":"2026-07-17T14:40:45.047662Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(\n    optimizer=\"adam\",\n    loss=\"binary_crossentropy\",\n    metrics=[\"accuracy\"]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:41:12.33919Z","iopub.execute_input":"2026-07-17T14:41:12.339756Z","iopub.status.idle":"2026-07-17T14:41:12.347683Z","shell.execute_reply.started":"2026-07-17T14:41:12.339728Z","shell.execute_reply":"2026-07-17T14:41:12.346975Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Train the CNN Model\n# ===========================\n\nhistory = model.fit(\n    train_gen,\n    validation_data=val_gen,\n    epochs=10,\n    callbacks=[\n        early_stopping,\n        learning_rate_reduction\n    ]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T14:43:00.82645Z","iopub.execute_input":"2026-07-17T14:43:00.827258Z","iopub.status.idle":"2026-07-17T14:58:39.991946Z","shell.execute_reply.started":"2026-07-17T14:43:00.827226Z","shell.execute_reply":"2026-07-17T14:58:39.991324Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Model Evaluation\n# ===========================\n\n# Evaluate on Training Set\ntrain_loss, train_acc = model.evaluate(\n    train_gen,\n    verbose=0\n)\n\nprint(f\"Training Accuracy : {train_acc*100:.2f}%\")\nprint(f\"Training Loss     : {train_loss:.4f}\")\n\nprint(\"-\" * 40)\n\n# Evaluate on Validation Set\nval_loss, val_acc = model.evaluate(\n    val_gen,\n    verbose=0\n)\n\nprint(f\"Validation Accuracy : {val_acc*100:.2f}%\")\nprint(f\"Validation Loss     : {val_loss:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:05:47.416581Z","iopub.execute_input":"2026-07-17T15:05:47.417001Z","iopub.status.idle":"2026-07-17T15:07:18.683892Z","shell.execute_reply.started":"2026-07-17T15:05:47.41697Z","shell.execute_reply":"2026-07-17T15:07:18.682875Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Save the Trained Model\n# ===========================\n\nmodel.save(\"cats_vs_dogs_classifier.keras\")\n\nprint(\"✅ Model saved successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:15:07.778012Z","iopub.execute_input":"2026-07-17T15:15:07.77848Z","iopub.status.idle":"2026-07-17T15:15:08.078885Z","shell.execute_reply.started":"2026-07-17T15:15:07.77845Z","shell.execute_reply":"2026-07-17T15:15:08.078149Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nprint(os.listdir(\"/kaggle/working/dataset\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:15:53.768191Z","iopub.execute_input":"2026-07-17T15:15:53.768891Z","iopub.status.idle":"2026-07-17T15:15:53.772764Z","shell.execute_reply.started":"2026-07-17T15:15:53.768864Z","shell.execute_reply":"2026-07-17T15:15:53.772037Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_gen = validation_datagen.flow_from_directory(\n    \"/kaggle/working/dataset/test/\",\n    target_size=(IMAGE_SIZE, IMAGE_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode=\"binary\",\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:16:00.694407Z","iopub.execute_input":"2026-07-17T15:16:00.694818Z","iopub.status.idle":"2026-07-17T15:16:00.725628Z","shell.execute_reply.started":"2026-07-17T15:16:00.694789Z","shell.execute_reply":"2026-07-17T15:16:00.724988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Test Set Prediction\n# ===========================\n\n# Predict probabilities\npredictions = model.predict(test_gen, verbose=0)\n\n# Convert probabilities to 0 (cat) and 1 (dog)\ny_pred = (predictions > 0.5).astype(int).flatten()\n\n# True labels\ny_true = test_gen.classes\n\n# Evaluate on test set\ntest_loss, test_acc = model.evaluate(test_gen, verbose=0)\n\nprint(f\"Testing Accuracy : {test_acc*100:.2f}%\")\nprint(f\"Testing Loss     : {test_loss:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:16:44.621998Z","iopub.execute_input":"2026-07-17T15:16:44.622944Z","iopub.status.idle":"2026-07-17T15:16:52.109174Z","shell.execute_reply.started":"2026-07-17T15:16:44.622904Z","shell.execute_reply":"2026-07-17T15:16:52.108353Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Classification Report\n# ===========================\n\nclass_names = [\"Cat\", \"Dog\"]\n\nprint(\n    classification_report(\n        y_true,\n        y_pred,\n        target_names=class_names\n    )\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:17:26.443918Z","iopub.execute_input":"2026-07-17T15:17:26.444337Z","iopub.status.idle":"2026-07-17T15:17:26.45983Z","shell.execute_reply.started":"2026-07-17T15:17:26.444306Z","shell.execute_reply":"2026-07-17T15:17:26.459198Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Confusion Matrix\n# ===========================\n\ncm = confusion_matrix(y_true, y_pred)\n\nplt.figure(figsize=(7, 5), dpi=200)\n\nsns.heatmap(\n    cm,\n    annot=True,\n    fmt=\"d\",\n    cmap=\"Blues\",\n    cbar=False,\n    xticklabels=[\"Cat\", \"Dog\"],\n    yticklabels=[\"Cat\", \"Dog\"]\n)\n\nplt.title(\"Confusion Matrix\", fontsize=14)\nplt.xlabel(\"Predicted Label\")\nplt.ylabel(\"True Label\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:18:17.595212Z","iopub.execute_input":"2026-07-17T15:18:17.596023Z","iopub.status.idle":"2026-07-17T15:18:17.743656Z","shell.execute_reply.started":"2026-07-17T15:18:17.595992Z","shell.execute_reply":"2026-07-17T15:18:17.742801Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = pd.DataFrame({\n    \"id\": range(1, len(predicted_labels) + 1),\n    \"label\": predicted_labels\n})\n\nsubmission.to_csv(\"submission.csv\", index=False)\n\nprint(\"✅ submission.csv created successfully!\")\nsubmission.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:20:30.899368Z","iopub.execute_input":"2026-07-17T15:20:30.899782Z","iopub.status.idle":"2026-07-17T15:20:30.924101Z","shell.execute_reply.started":"2026-07-17T15:20:30.899753Z","shell.execute_reply":"2026-07-17T15:20:30.923316Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(os.listdir(\"/kaggle/input/competitions\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:20:37.38368Z","iopub.execute_input":"2026-07-17T15:20:37.384162Z","iopub.status.idle":"2026-07-17T15:20:37.390342Z","shell.execute_reply.started":"2026-07-17T15:20:37.38413Z","shell.execute_reply":"2026-07-17T15:20:37.389487Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ===========================\n# Display Sample Predictions\n# ===========================\n\nfig, axes = plt.subplots(1, 10, figsize=(20, 4))\n\nfor i in range(10):\n    image_path = os.path.join(test_dir, test_df.iloc[i][\"filename\"])\n    image = Image.open(image_path)\n\n    axes[i].imshow(image)\n    axes[i].set_title(test_df.iloc[i][\"label\"].capitalize())\n    axes[i].axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-07-17T15:21:35.840364Z","iopub.execute_input":"2026-07-17T15:21:35.840804Z","iopub.status.idle":"2026-07-17T15:21:36.442978Z","shell.execute_reply.started":"2026-07-17T15:21:35.840775Z","shell.execute_reply":"2026-07-17T15:21:36.442022Z"}},"outputs":[],"execution_count":null}]}