{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":5441,"databundleVersionId":38425,"sourceType":"competition"}],"dockerImageVersionId":31011,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":" 1. Libraries\nWe begin by importing essential libraries for data handling, visualization, image processing, and deep learning. TensorFlow and Keras provide the framework for building and training the CNN using MobileNetV2 as the base model.","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"code","source":"import os, zipfile, shutil\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.applications import MobileNetV2\nfrom tensorflow.keras.applications.mobilenet_v2 import preprocess_input\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Dropout\nfrom tensorflow.keras.optimizers import Adam\nimport matplotlib.image as mpimg\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:04:25.797039Z","iopub.execute_input":"2025-04-22T21:04:25.797321Z","iopub.status.idle":"2025-04-22T21:04:39.918366Z","shell.execute_reply.started":"2025-04-22T21:04:25.797300Z","shell.execute_reply":"2025-04-22T21:04:39.917795Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"📂 2. Dataset Extraction\nThe training and test datasets are extracted from the provided zipped files. The structure is reorganized to match Keras' expected input format — separating cat and dog images into respective folders.\n\n","metadata":{}},{"cell_type":"code","source":"with zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/train')\n\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/test')\n\nshutil.copy('/kaggle/input/dogs-vs-cats-redux-kernels-edition/sample_submission.csv', '/kaggle/working/sample_submission.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:05:17.541383Z","iopub.execute_input":"2025-04-22T21:05:17.542207Z","iopub.status.idle":"2025-04-22T21:05:31.261506Z","shell.execute_reply.started":"2025-04-22T21:05:17.542181Z","shell.execute_reply":"2025-04-22T21:05:31.260810Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"🧹 3. Organizing Training Data\nKeras' flow_from_directory expects a folder structure like /class_name/images. Therefore, we scan the filenames (which are formatted like cat.123.jpg or dog.456.jpg) and move each image to its respective class folder.","metadata":{}},{"cell_type":"code","source":"base_dir = '/kaggle/working/dataset'\ntrain_dir = os.path.join(base_dir, 'train')\nos.makedirs(train_dir + '/cats', exist_ok=True)\nos.makedirs(train_dir + '/dogs', exist_ok=True)\n\nfor file in os.listdir('/kaggle/working/train/train'):\n    src = f'/kaggle/working/train/train/{file}'\n    dst = f'{train_dir}/cats/{file}' if 'cat' in file else f'{train_dir}/dogs/{file}'\n    shutil.move(src, dst)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:05:53.933183Z","iopub.execute_input":"2025-04-22T21:05:53.933472Z","iopub.status.idle":"2025-04-22T21:05:54.599554Z","shell.execute_reply.started":"2025-04-22T21:05:53.933447Z","shell.execute_reply":"2025-04-22T21:05:54.598757Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":" 3.5 Exploratory Data Analysis (EDA)\nTo understand the dataset better:\n\nClass Balance: We confirmed an approximately equal number of cat and dog images (~12,500 each).\n\nSample Images: We visually inspected 5 random images from each class to verify label correctness and image quality.\n\nConclusion: The dataset is well-balanced and appropriate for training a binary classifier.\n\n","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport random\n\n# Define directories for plotting\ncat_dir = os.path.join(train_dir, 'cats')\ndog_dir = os.path.join(train_dir, 'dogs')\n\ndef plot_samples(image_dir, title, num_samples=5):\n    images = random.sample(os.listdir(image_dir), num_samples)\n    plt.figure(figsize=(15, 5))\n    for i, img_file in enumerate(images):\n        img_path = os.path.join(image_dir, img_file)\n        img = mpimg.imread(img_path)\n        plt.subplot(1, num_samples, i + 1)\n        plt.imshow(img)\n        plt.axis('off')\n        plt.title(f\"{title} {i+1}\")\n    plt.suptitle(f\"Sample {title} Images\", fontsize=16)\n    plt.show()\n\n# Show samples\nplot_samples(cat_dir, 'Cat')\nplot_samples(dog_dir, 'Dog')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:07:24.250717Z","iopub.execute_input":"2025-04-22T21:07:24.251252Z","iopub.status.idle":"2025-04-22T21:07:25.192905Z","shell.execute_reply.started":"2025-04-22T21:07:24.251227Z","shell.execute_reply":"2025-04-22T21:07:25.192063Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"4. Data Generators\nImage data generators are used for efficient preprocessing and on-the-fly augmentation. We:\n\nResize images to 160×160 pixels (MobileNetV2 default).\n\nNormalize inputs using preprocess_input.\n\nSplit data: 80% training, 20% validation.\n\nApply random horizontal flips for better generalization.","metadata":{}},{"cell_type":"code","source":"# %%\nimg_size = 160\nbatch_size = 16\n\ntrain_datagen = ImageDataGenerator(\n    preprocessing_function=preprocess_input,\n    validation_split=0.2,\n    horizontal_flip=True\n)\n\ntrain_generator = train_datagen.flow_from_directory(\n    train_dir,\n    target_size=(img_size, img_size),\n    batch_size=batch_size,\n    class_mode='binary',\n    subset='training'\n)\n\nval_generator = train_datagen.flow_from_directory(\n    train_dir,\n    target_size=(img_size, img_size),\n    batch_size=batch_size,\n    class_mode='binary',\n    subset='validation'\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:09:41.353237Z","iopub.execute_input":"2025-04-22T21:09:41.353874Z","iopub.status.idle":"2025-04-22T21:09:41.595606Z","shell.execute_reply.started":"2025-04-22T21:09:41.353848Z","shell.execute_reply":"2025-04-22T21:09:41.595073Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":" 5. Model: MobileNetV2\nWe use transfer learning with MobileNetV2:\n\nBase model: Pre-trained on ImageNet.\n\nFrozen layers: Only the top classifier is trained.\n\nTop layers: A global average pooling, dropout for regularization, and a single sigmoid-activated neuron for binary classification.\n\nThis allows for quick and efficient training while leveraging powerful pre-learned features.\n\n📈 6. Training the Model\nThe model is trained for 3 epochs using:\n\nLoss Function: Binary Crossentropy\n\nOptimizer: Adam (learning rate = 1e-4)\n\nMetrics: Accuracy\n\nTraining is done using the augmented and normalized data generators.","metadata":{}},{"cell_type":"code","source":"# %%\nbase_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(img_size, img_size, 3))\nbase_model.trainable = False\n\nx = base_model.output\nx = GlobalAveragePooling2D()(x)\nx = Dropout(0.4)(x)\npreds = Dense(1, activation='sigmoid')(x)\n\nmodel = Model(inputs=base_model.input, outputs=preds)\nmodel.compile(optimizer=Adam(1e-4), loss='binary_crossentropy', metrics=['accuracy'])\n\n# %% [markdown]\n# ## 7. Model Training\n# Train the model for a few epochs using the training and validation generators.\n\n# %%\nmodel.fit(train_generator, validation_data=val_generator, epochs=3)\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:10:46.759528Z","iopub.execute_input":"2025-04-22T21:10:46.760124Z","iopub.status.idle":"2025-04-22T21:13:16.122096Z","shell.execute_reply.started":"2025-04-22T21:10:46.760101Z","shell.execute_reply":"2025-04-22T21:13:16.121272Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"🔍 7. Predictions on Test Data\nTest images are loaded and preprocessed in the same way as the training data. We maintain order (sorted by filename) and disable shuffling to ensure predictions align with submission format.\n\nThe model outputs probabilities which represent how likely an image is of class “dog”.","metadata":{}},{"cell_type":"code","source":"# Prepare test data, generate predictions using the trained model.\n\n# %%\ntest_dir = '/kaggle/working/test/test'\ntest_df = pd.DataFrame({\n    'filename': sorted(os.listdir(test_dir), key=lambda x: int(x.split('.')[0]))\n})\ntest_df['filepath'] = test_df['filename'].apply(lambda x: os.path.join(test_dir, x))\n\ntest_datagen = ImageDataGenerator(preprocessing_function=preprocess_input)\n\ntest_gen = test_datagen.flow_from_dataframe(\n    test_df,\n    x_col='filepath',\n    y_col=None,\n    class_mode=None,\n    target_size=(img_size, img_size),\n    batch_size=batch_size,\n    shuffle=False\n)\n\npredictions = model.predict(test_gen, verbose=1).flatten()\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:14:48.136706Z","iopub.execute_input":"2025-04-22T21:14:48.137484Z","iopub.status.idle":"2025-04-22T21:15:14.447571Z","shell.execute_reply.started":"2025-04-22T21:14:48.137458Z","shell.execute_reply":"2025-04-22T21:15:14.446713Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Convert predictions to class labels: 0 for cat, 1 for dog\npredicted_classes = (predictions > 0.5).astype(int)\n\n# Map numeric labels to text\nlabel_map = {0: 'Cat', 1: 'Dog'}\n\n# Display a few test images with predicted labels\ndef show_predictions(test_df, predicted_classes, num_images=10):\n    plt.figure(figsize=(20, 5))\n    indices = np.random.choice(len(test_df), num_images, replace=False)\n    \n    for i, idx in enumerate(indices):\n        img_path = test_df.iloc[idx]['filepath']\n        img = mpimg.imread(img_path)\n        plt.subplot(1, num_images, i+1)\n        plt.imshow(img)\n        plt.axis('off')\n        pred_label = label_map[predicted_classes[idx]]\n        plt.title(pred_label)\n    plt.suptitle(\"Predicted Labels on Test Images\", fontsize=18)\n    plt.show()\n\nshow_predictions(test_df, predicted_classes, num_images=10)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:17:55.597632Z","iopub.execute_input":"2025-04-22T21:17:55.598370Z","iopub.status.idle":"2025-04-22T21:17:56.194890Z","shell.execute_reply.started":"2025-04-22T21:17:55.598343Z","shell.execute_reply":"2025-04-22T21:17:56.194187Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"📝 8. Submission File\nPredictions are stored in the label column of the submission DataFrame, and written to a CSV file titled:","metadata":{}},{"cell_type":"code","source":"# %%\nsubmission = pd.read_csv('/kaggle/working/sample_submission.csv')\nsubmission['label'] = predictions\nsubmission.to_csv('/kaggle/working/MSBA.SessionX.SwapnilSharma.csv', index=False)\n\n# Display a few predictions\nprint(\"✅ Lightweight submission saved.\")\nprint(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-22T21:16:27.725934Z","iopub.execute_input":"2025-04-22T21:16:27.726616Z","iopub.status.idle":"2025-04-22T21:16:27.769841Z","shell.execute_reply.started":"2025-04-22T21:16:27.726589Z","shell.execute_reply":"2025-04-22T21:16:27.769083Z"}},"outputs":[],"execution_count":null}]}