{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","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"}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport shutil\nimport random\nimport numpy as np\nimport pandas as pd\nimport matplotlib.image as mpimg\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.utils import image_dataset_from_directory\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, BatchNormalization, Dropout\nfrom tensorflow.keras.regularizers import L2\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:10.003801Z","iopub.execute_input":"2025-10-24T15:41:10.004408Z","iopub.status.idle":"2025-10-24T15:41:23.161046Z","shell.execute_reply.started":"2025-10-24T15:41:10.004385Z","shell.execute_reply":"2025-10-24T15:41:23.160254Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if not os.path.exists(\"/kaggle/working/train\"):\n    !unzip -q /kaggle/input/dogs-vs-cats/train.zip","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T16:12:06.689964Z","iopub.status.idle":"2025-10-24T16:12:06.690262Z","shell.execute_reply.started":"2025-10-24T16:12:06.690106Z","shell.execute_reply":"2025-10-24T16:12:06.690119Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_path = '/kaggle/working/train'\nlen(os.listdir(train_path))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:34.062677Z","iopub.execute_input":"2025-10-24T15:41:34.063397Z","iopub.status.idle":"2025-10-24T15:41:34.084142Z","shell.execute_reply.started":"2025-10-24T15:41:34.063372Z","shell.execute_reply":"2025-10-24T15:41:34.08358Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"os.listdir(train_path)[:10]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:34.08551Z","iopub.execute_input":"2025-10-24T15:41:34.085966Z","iopub.status.idle":"2025-10-24T15:41:34.258793Z","shell.execute_reply.started":"2025-10-24T15:41:34.085949Z","shell.execute_reply":"2025-10-24T15:41:34.2582Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"try:\n    parent_dir = '/kaggle/working/cats-v-dogs'\n    os.makedirs(parent_dir, exist_ok=True)\n\n    subdirs = ['training/cats', 'training/dogs', 'validation/cats', 'validation/dogs']\n    for subdir in subdirs:\n        os.makedirs(os.path.join(parent_dir, subdir), exist_ok=True)\n\nexcept OSError as e:\n    print(f\"Error: {e}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:34.259352Z","iopub.execute_input":"2025-10-24T15:41:34.259562Z","iopub.status.idle":"2025-10-24T15:41:34.264343Z","shell.execute_reply.started":"2025-10-24T15:41:34.259525Z","shell.execute_reply":"2025-10-24T15:41:34.263778Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"src_dir = train_path\n\ncats_train_dir = '/kaggle/working/cats-v-dogs/training/cats'\ncats_valid_dir = '/kaggle/working/cats-v-dogs/validation/cats'\n\ndogs_train_dir = '/kaggle/working/cats-v-dogs/training/dogs'\ndogs_valid_dir = '/kaggle/working/cats-v-dogs/validation/dogs'\n\n# List of cats names in all training images\ncats =[img for img in os.listdir(src_dir) if img[:3] == 'cat']\n\n# List of dogs names in all training images\ndogs =[img for img in os.listdir(src_dir) if img[:3] == 'dog']\n\n# Take 10% of training images for validation    \nnp.random.seed(100)\ncats_valid_sample = random.sample(cats, int(0.1*len(cats))) \ndogs_valid_sample = random.sample(dogs, int(0.1*len(dogs)))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:34.265043Z","iopub.execute_input":"2025-10-24T15:41:34.265234Z","iopub.status.idle":"2025-10-24T15:41:34.304264Z","shell.execute_reply.started":"2025-10-24T15:41:34.26522Z","shell.execute_reply":"2025-10-24T15:41:34.303572Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for img in os.listdir(src_dir):\n    src_img = os.path.join(src_dir, img)\n\n    if img[:3] == 'cat':\n        if img in cats_valid_sample:\n            dest_img = os.path.join(cats_valid_dir, img)\n        else:\n            dest_img = os.path.join(cats_train_dir, img)\n\n    elif img[:3] == 'dog':\n        if img in dogs_valid_sample:\n            dest_img = os.path.join(dogs_valid_dir, img)\n        else:\n            dest_img = os.path.join(dogs_train_dir, img)\n    if not os.path.exists(dest_img):\n        shutil.copyfile(src_img, dest_img)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:34.305023Z","iopub.execute_input":"2025-10-24T15:41:34.305262Z","iopub.status.idle":"2025-10-24T15:41:37.544936Z","shell.execute_reply.started":"2025-10-24T15:41:34.305242Z","shell.execute_reply":"2025-10-24T15:41:37.544355Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print('No. of ALL cats : ', len(cats))\nprint('No. of cats for training: ', len(os.listdir(cats_train_dir)))\nprint('No. of cats for validation: ', len(os.listdir(cats_valid_dir)))\n\nprint('\\nNo. of ALL dogs : ', len(dogs))\nprint('No. of dogs for training: ', len(os.listdir(dogs_train_dir)))\nprint('No. of dogs for validation: ', len(os.listdir(dogs_valid_dir)))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:37.545704Z","iopub.execute_input":"2025-10-24T15:41:37.545972Z","iopub.status.idle":"2025-10-24T15:41:37.562313Z","shell.execute_reply.started":"2025-10-24T15:41:37.545949Z","shell.execute_reply":"2025-10-24T15:41:37.561668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models, Sequential\n\n# Dataset paths\ntrain_dir = '/kaggle/working/cats-v-dogs/training'\nvalid_dir = '/kaggle/working/cats-v-dogs/validation'\n\n# Load datasets (non-deprecated)\ntrain_ds = image_dataset_from_directory(\n    train_dir,\n    image_size=(150, 150),\n    batch_size=32,\n    label_mode='binary',\n    shuffle=True,\n    seed=100\n)\n\nvalid_ds = image_dataset_from_directory(\n    valid_dir,\n    image_size=(150, 150),\n    batch_size=32,\n    label_mode='binary',\n    shuffle=False\n)\n\n# Normalize pixel values\ntrain_ds = train_ds.map(lambda x, y: (tf.cast(x, tf.float32) / 255.0, y))\nvalid_ds = valid_ds.map(lambda x, y: (tf.cast(x, tf.float32) / 255.0, y))\n\n# Optimize input pipeline\nAUTOTUNE = tf.data.AUTOTUNE\ntrain_ds = train_ds.cache().shuffle(1000).prefetch(AUTOTUNE)\nvalid_ds = valid_ds.cache().prefetch(AUTOTUNE)\n\nprint(\"✅ Dataset ready\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:37.563065Z","iopub.execute_input":"2025-10-24T15:41:37.563656Z","iopub.status.idle":"2025-10-24T15:41:40.870479Z","shell.execute_reply.started":"2025-10-24T15:41:37.563639Z","shell.execute_reply":"2025-10-24T15:41:40.869846Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🧠 Efficient Data Pipeline in TensorFlow\n\nTraining a deep learning model involves **two main jobs happening simultaneously**:\n\n- **🧩 CPU (Data Loader)** — Reads images, decodes, resizes, and prepares batches.  \n- **⚡ GPU (Trainer)** — Runs forward and backward propagation.\n\n\n## 🚨 The Problem\n\nIf the **CPU finishes preparing the next batch after** the **GPU finishes training the current one**,  \n👉 the **GPU sits idle**, waiting for data.\n\nThis causes **training slowdowns** and **wastes compute time** ⏳.\n\n---\n\n## ⚙️ TensorFlow’s Solution: Data Pipeline Optimization\n\nTensorFlow’s `cache()`, `shuffle()`, and `prefetch()` fix this by keeping the CPU and GPU **working in parallel**.\n\n### 🔹 1️⃣ `cache()`\n\n- Stores the dataset (or a portion of it) **in memory after the first read**.\n- Removes the need to repeatedly read from disk (which is slow).  \n- Makes **subsequent epochs faster**.  \n- You can cache:\n  - **In memory** (for small datasets)\n  - **To a local file** (for large datasets)\n\n\n### 🔹 2️⃣ `shuffle(1000)`\n\n- Randomizes the order of samples.  \n- Keeps training **dynamic** — model sees data in a different order each epoch.  \n- `1000` → buffer size (TensorFlow keeps 1000 samples in memory and randomly picks from them).  \n- Helps **prevent overfitting** and **pattern memorization**.\n\n\n### 🔹 3️⃣ `prefetch(AUTOTUNE)`\n\n- Prepares the **next batch while the current one is training**.  \n- Overlaps **CPU data preparation** with **GPU training**.  \n- `AUTOTUNE` automatically picks the **optimal buffer size** based on your hardware.  \n\n✅ Keeps GPU **busy 100% of the time** — no waiting for data!\n\n\n","metadata":{}},{"cell_type":"code","source":"# Create model\nmodel = Sequential([\n    Conv2D(filters = 32, kernel_size = (3,3),\n           strides=(1, 1), padding=\"valid\",\n           activation='relu', input_shape=(150, 150, 3)),\n    MaxPooling2D(2, 2),\n    \n    Conv2D(64, (3,3), activation='relu'),\n    MaxPooling2D(2, 2),\n    \n    Conv2D(128, (3,3), activation='relu'),\n    MaxPooling2D(2, 2),\n    \n    Flatten(),\n    Dense(128, activation='relu'),\n    Dense(1, activation='sigmoid')\n])\n\n# Compile model\nmodel.compile(\n    optimizer='adamax',\n    loss='binary_crossentropy',\n    metrics=['accuracy']\n)\n\nmodel.summary()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:40.872889Z","iopub.execute_input":"2025-10-24T15:41:40.87315Z","iopub.status.idle":"2025-10-24T15:41:41.630869Z","shell.execute_reply.started":"2025-10-24T15:41:40.873133Z","shell.execute_reply":"2025-10-24T15:41:41.630303Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\n\ncheckpoint_path = '/kaggle/working/cats_dogs_cnn.keras'\ncallbacks = [\n    EarlyStopping(patience=3, restore_best_weights=True, monitor='val_accuracy'),\n    ModelCheckpoint(checkpoint_path, save_best_only=True, monitor='val_accuracy')\n]\n\nhistory = model.fit(\n    train_ds,\n    validation_data=valid_ds,\n    epochs=15,\n    callbacks=callbacks,\n    verbose=1\n)\n\nprint(\"✅ Training complete, best model saved at:\", checkpoint_path)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:41:41.631492Z","iopub.execute_input":"2025-10-24T15:41:41.631829Z","iopub.status.idle":"2025-10-24T15:44:32.722282Z","shell.execute_reply.started":"2025-10-24T15:41:41.631811Z","shell.execute_reply":"2025-10-24T15:44:32.721701Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Evaluate\nloss, acc = model.evaluate(valid_ds, verbose=0)\nprint(f\"✅ Validation accuracy: {acc:.3f} | loss: {loss:.3f}\")\n\n# Plot training curves\nplt.plot(history.history['accuracy'], label='train_acc')\nplt.plot(history.history['val_accuracy'], label='val_acc')\nplt.title('Training vs Validation Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:44:32.723096Z","iopub.execute_input":"2025-10-24T15:44:32.723365Z","iopub.status.idle":"2025-10-24T15:44:33.416801Z","shell.execute_reply.started":"2025-10-24T15:44:32.723341Z","shell.execute_reply":"2025-10-24T15:44:33.416107Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Augmentation layers (GPU-friendly)\nfrom tensorflow.keras.layers import RandomFlip, RandomRotation, RandomZoom\n\ndata_augmentation = Sequential([\n    RandomFlip(\"horizontal\"),\n    RandomRotation(0.1),\n    RandomZoom(0.1),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:44:33.417563Z","iopub.execute_input":"2025-10-24T15:44:33.417849Z","iopub.status.idle":"2025-10-24T15:44:33.43086Z","shell.execute_reply.started":"2025-10-24T15:44:33.41783Z","shell.execute_reply":"2025-10-24T15:44:33.430309Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Check Image augmentation layers [Here](https://keras.io/api/layers/preprocessing_layers/image_augmentation/)","metadata":{}},{"cell_type":"code","source":"# Model with augmentation + normalization up front\nmodel = Sequential([\n    data_augmentation,\n\n    Conv2D(32, (3,3), activation='relu', input_shape=(150, 150, 3)),\n    BatchNormalization(),\n    MaxPooling2D(2, 2),\n\n    Conv2D(64, (3,3), activation='relu'),\n    BatchNormalization(),\n    MaxPooling2D(2, 2),\n\n    Conv2D(128, (3,3), activation='relu'),\n    BatchNormalization(),\n    MaxPooling2D(2, 2),\n    Dropout(0.3),   # remove it and retry\n\n    Flatten(),\n    Dense(128, activation='relu'),\n    BatchNormalization(),\n    Dropout(0.5), \n    Dense(1, activation='sigmoid')\n])\n\n# Compile model\nmodel.compile(\n    optimizer='adamax',\n    loss='binary_crossentropy',\n    metrics=['accuracy']\n)\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:44:33.431425Z","iopub.execute_input":"2025-10-24T15:44:33.431689Z","iopub.status.idle":"2025-10-24T15:44:33.470806Z","shell.execute_reply.started":"2025-10-24T15:44:33.431672Z","shell.execute_reply":"2025-10-24T15:44:33.470291Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\n\n# Where to save the best model\ncheckpoint_path = \"/kaggle/working/cats_dogs_best.keras\"\n\n# Define callbacks\ncallbacks = [\n    EarlyStopping(\n        monitor='val_loss',      # stop when validation loss stops improving\n        patience=5,              # wait 5 epochs before stopping\n        restore_best_weights=True\n    ),\n    ModelCheckpoint(\n        filepath=checkpoint_path,\n        monitor='val_accuracy',  # save best model by val_accuracy\n        save_best_only=True,\n        verbose=1\n    ),\n    ReduceLROnPlateau(\n        monitor='val_loss',\n        factor=0.5,              # reduce LR by half on plateau\n        patience=2,              # after 2 stagnant epochs\n        verbose=1,\n        min_lr=1e-6\n    )\n]\n\n# Train the model\nhistory = model.fit(\n    train_ds,\n    validation_data=valid_ds,\n    epochs=15,   # increase it and retry\n    callbacks=callbacks,\n    verbose=1\n)\n\nprint(f\"✅ Training complete — best model saved to: {checkpoint_path}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:44:33.471502Z","iopub.execute_input":"2025-10-24T15:44:33.472215Z","iopub.status.idle":"2025-10-24T15:55:07.534112Z","shell.execute_reply.started":"2025-10-24T15:44:33.472198Z","shell.execute_reply":"2025-10-24T15:55:07.533444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport matplotlib.pyplot as plt\n\nhistory_df = pd.DataFrame(history.history)\n\nplt.figure(figsize=(10,4))\nplt.subplot(1,2,1)\nplt.plot(history_df[\"loss\"], label=\"Train Loss\")\nplt.plot(history_df[\"val_loss\"], label=\"Val Loss\")\nplt.legend(); plt.title(\"Loss\")\n\nplt.subplot(1,2,2)\nplt.plot(history_df[\"accuracy\"], label=\"Train Acc\")\nplt.plot(history_df[\"val_accuracy\"], label=\"Val Acc\")\nplt.legend(); plt.title(\"Accuracy\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:55:07.534896Z","iopub.execute_input":"2025-10-24T15:55:07.535203Z","iopub.status.idle":"2025-10-24T15:55:07.822976Z","shell.execute_reply.started":"2025-10-24T15:55:07.535185Z","shell.execute_reply":"2025-10-24T15:55:07.822323Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\nfrom tensorflow.keras.applications import EfficientNetB0\nfrom tensorflow.keras.applications.efficientnet import preprocess_input\n\nIMG_SIZE = 224\nBATCH_SIZE = 32\nSEED = 100\nAUTOTUNE = tf.data.AUTOTUNE\n\n# 1) Datasets (NO manual /255 here; let preprocess_input handle it)\ntrain_ds = tf.keras.utils.image_dataset_from_directory(\n    '/kaggle/working/cats-v-dogs/training',\n    image_size=(IMG_SIZE, IMG_SIZE),\n    batch_size=BATCH_SIZE,\n    label_mode='binary',\n    shuffle=True,\n    seed=SEED\n)\nvalid_ds = tf.keras.utils.image_dataset_from_directory(\n    '/kaggle/working/cats-v-dogs/validation',\n    image_size=(IMG_SIZE, IMG_SIZE),\n    batch_size=BATCH_SIZE,\n    label_mode='binary',\n    shuffle=False\n)\n\n# Prefetch for speed\ntrain_ds = train_ds.cache().shuffle(1000, seed=SEED).prefetch(AUTOTUNE)\nvalid_ds = valid_ds.cache().prefetch(AUTOTUNE)\n\n# 2) Augmentation block\ndata_augmentation = keras.Sequential([\n    layers.RandomFlip(\"horizontal\"),\n    layers.RandomRotation(0.1),\n    layers.RandomZoom(0.1),\n], name=\"augmentation\")\n\n# 3) Build model (feature extractor)\nbase = EfficientNetB0(include_top=False, weights=\"imagenet\", input_shape=(IMG_SIZE, IMG_SIZE, 3))\nbase.trainable = False  # freeze backbone initially\n\ninputs = keras.Input(shape=(IMG_SIZE, IMG_SIZE, 3))\nx = data_augmentation(inputs)\nx = preprocess_input(x)              # <- use app-specific preprocessing\nx = base(x, training=False)\nx = layers.GlobalAveragePooling2D()(x)\nx = layers.Dropout(0.3)(x)\noutputs = layers.Dense(1, activation=\"sigmoid\")(x)\nmodel = keras.Model(inputs, outputs)\n\nmodel.compile(optimizer=keras.optimizers.Adam(1e-3),\n              loss=\"binary_crossentropy\",\n              metrics=[\"accuracy\", keras.metrics.AUC(name=\"auc\")])\n\nmodel.summary()\n\n# 4) Train (frozen)\ncheckpoint_path = \"/kaggle/working/cats_dogs_effb0_best.keras\"\ncallbacks = [\n    EarlyStopping(monitor=\"val_loss\", patience=4, restore_best_weights=True),\n    ModelCheckpoint(checkpoint_path, monitor=\"val_accuracy\", save_best_only=True, verbose=1),\n    ReduceLROnPlateau(monitor=\"val_loss\", factor=0.5, patience=2, min_lr=1e-6, verbose=1),\n]\n\nhistory = model.fit(train_ds, validation_data=valid_ds, epochs=10, callbacks=callbacks, verbose=1)\n\n# 5) Fine-tune (unfreeze top blocks)\nbase.trainable = True\nfor layer in base.layers[:-40]:  # keep most layers frozen; tune last ~40\n    layer.trainable = False\n\nmodel.compile(optimizer=keras.optimizers.Adam(1e-4),\n              loss=\"binary_crossentropy\",\n              metrics=[\"accuracy\", keras.metrics.AUC(name=\"auc\")])\n\nprint(\"#### Fine Tuning Started ####\")\nhistory_ft = model.fit(train_ds, validation_data=valid_ds, epochs=10, callbacks=callbacks, verbose=1)\n\nval_loss, val_acc, val_auc = model.evaluate(valid_ds, verbose=0)\nprint(f\"✅ EfficientNetB0 — val_acc: {val_acc:.3f}, val_auc: {val_auc:.3f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T15:55:07.823781Z","iopub.execute_input":"2025-10-24T15:55:07.824027Z","iopub.status.idle":"2025-10-24T16:11:21.842385Z","shell.execute_reply.started":"2025-10-24T15:55:07.824005Z","shell.execute_reply":"2025-10-24T16:11:21.841589Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Evaluate on validation set\nval_loss, val_acc, val_auc = model.evaluate(valid_ds, verbose=1)\n\nprint(f\"📊 Validation Results:\")\nprint(f\"   Loss      : {val_loss:.4f}\")\nprint(f\"   Accuracy  : {val_acc:.4f}\")\nprint(f\"   AUC Score : {val_auc:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T16:11:21.843315Z","iopub.execute_input":"2025-10-24T16:11:21.843598Z","iopub.status.idle":"2025-10-24T16:11:27.415321Z","shell.execute_reply.started":"2025-10-24T16:11:21.843575Z","shell.execute_reply":"2025-10-24T16:11:27.414757Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"! unzip -q /kaggle/input/dogs-vs-cats/test1.zip\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T16:11:27.416095Z","iopub.execute_input":"2025-10-24T16:11:27.416338Z","iopub.status.idle":"2025-10-24T16:11:34.972628Z","shell.execute_reply.started":"2025-10-24T16:11:27.416321Z","shell.execute_reply":"2025-10-24T16:11:34.97179Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nfrom tensorflow.keras.preprocessing import image\n\ndef convert_imgs_to_tensors(img_folder, target_size=(150, 150), verbose=True):\n    \"\"\"\n    Converts all images in a folder into a single NumPy tensor suitable for model prediction.\n    \n    Args:\n        img_folder (str): Path to folder containing images.\n        target_size (tuple): (width, height) to resize images to.\n        verbose (bool): Print progress information.\n\n    Returns:\n        np.ndarray: 4D tensor (N, height, width, 3) ready for model.predict()\n        list: filenames in the same order as tensors\n    \"\"\"\n    images = []\n    valid_files = []\n\n    img_list = sorted(os.listdir(img_folder))\n    total = len(img_list)\n    for i, img_name in enumerate(img_list, 1):\n        try:\n            img_path = os.path.join(img_folder, img_name)\n            img_obj = image.load_img(img_path, target_size=target_size)\n            img_arr = image.img_to_array(img_obj)\n            img_arr = np.expand_dims(img_arr, axis=0) / 255.0  # normalize once\n            images.append(img_arr)\n            valid_files.append(img_name)\n\n            if verbose and i % 500 == 0:\n                print(f\"Processed {i}/{total} images...\")\n\n        except Exception as e:\n            print(f\"⚠️ Skipped {img_name}: {e}\")\n\n    if not images:\n        raise ValueError(f\"No valid images found in {img_folder}\")\n\n    images_tensor = np.vstack(images)\n    if verbose:\n        print(f\"✅ Converted {len(images_tensor)} images into tensor of shape {images_tensor.shape}\")\n\n    return images_tensor, valid_files\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T16:11:34.973774Z","iopub.execute_input":"2025-10-24T16:11:34.974058Z","iopub.status.idle":"2025-10-24T16:11:34.982855Z","shell.execute_reply.started":"2025-10-24T16:11:34.974022Z","shell.execute_reply":"2025-10-24T16:11:34.98214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_dir = '/kaggle/working/test1'\n\ntest_images_tensor, test_filenames = convert_imgs_to_tensors(test_dir)\n\n# Predict\npredictions = model.predict(test_images_tensor)\npred_labels = (predictions > 0.5).astype(int)\n\n# Combine into a DataFrame\nimport pandas as pd\ntest_df = pd.DataFrame({\n    \"id\": [name.split('.')[0] for name in test_filenames],\n    \"label\": pred_labels.flatten()\n})\n\ntest_df.to_csv('/kaggle/working/my_transfer_preds.csv', index=False)\nprint(test_df.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T16:11:34.983563Z","iopub.execute_input":"2025-10-24T16:11:34.983787Z","iopub.status.idle":"2025-10-24T16:12:06.681852Z","shell.execute_reply.started":"2025-10-24T16:11:34.983765Z","shell.execute_reply":"2025-10-24T16:12:06.679408Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport random\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport os\n\n# Number of samples to visualize\nn_samples = 100\n\n# Random indices from the loaded test tensors\nindices = random.sample(range(len(test_filenames)), n_samples)\n\nplt.figure(figsize=(16, 16))\nfor i, idx in enumerate(indices, 1):\n    img_name = test_filenames[idx]\n    img_path = os.path.join(test_dir, img_name)\n\n    # Get prediction (already preprocessed tensor)\n    pred_prob = model.predict(np.expand_dims(test_images_tensor[idx], axis=0), verbose=0)[0][0]\n    label = 'Dog' if pred_prob > 0.50 else 'Cat'\n\n    # Plot image\n    plt.subplot(10, 10, i)\n    plt.imshow(mpimg.imread(img_path))\n    plt.title(f\"{label}\\n({pred_prob:.2f})\", fontsize=8)\n    plt.axis('off')\n\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-24T18:12:22.148756Z","iopub.execute_input":"2025-10-24T18:12:22.149295Z","iopub.status.idle":"2025-10-24T18:12:22.230558Z","shell.execute_reply.started":"2025-10-24T18:12:22.149274Z","shell.execute_reply":"2025-10-24T18:12:22.229555Z"}},"outputs":[],"execution_count":null}]}