{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":129474,"databundleVersionId":15526883,"sourceType":"competition"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-02-01T12:20:42.317344Z","iopub.execute_input":"2026-02-01T12:20:42.317932Z","iopub.status.idle":"2026-02-01T12:20:50.746055Z","shell.execute_reply.started":"2026-02-01T12:20:42.317898Z","shell.execute_reply":"2026-02-01T12:20:50.745324Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport glob\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow.keras.applications import MobileNetV2\nfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Dropout\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# --- 1. ROBUST PATH DETECTION ---\n# Kaggle datasets are in \"../input\". We search for the \"train\" folder dynamically.\nprint(\"Searching for dataset...\")\npossible_roots = glob.glob(\"../input/**/train\", recursive=True)\n\nif not possible_roots:\n    # Fallback: check if user uploaded data directly to working dir (rare but possible)\n    if os.path.exists(\"Dataset/train\"):\n        TRAIN_DIR = \"Dataset/train\"\n        TEST_DIR = \"Dataset/test\"\n    else:\n        raise FileNotFoundError(\"Could not find a 'train' directory in ../input/ or Dataset/. Please check dataset mapping.\")\nelse:\n    # Use the first valid train path found in ../input\n    TRAIN_DIR = possible_roots[0]\n    # Assuming \"test\" is a sibling of \"train\" (standard Kaggle structure)\n    TEST_DIR = TRAIN_DIR.replace(\"train\", \"test\")\n\nprint(f\"FOUND TRAIN DIR: {TRAIN_DIR}\")\nprint(f\"FOUND TEST DIR:  {TEST_DIR}\")\n\n# --- 2. CONFIGURATION ---\nIMG_SIZE = (224, 224)\nBATCH_SIZE = 32\nEPOCHS = 10\n\n# --- 3. DATA PREPARATION ---\ntrain_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=20,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest',\n    validation_split=0.2\n)\n\nprint(\"Loading Training Data...\")\ntrain_gen = train_datagen.flow_from_directory(\n    TRAIN_DIR,\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode='binary',\n    subset='training',\n    shuffle=True\n)\n\nval_gen = train_datagen.flow_from_directory(\n    TRAIN_DIR,\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode='binary',\n    subset='validation',\n    shuffle=False\n)\n\n# --- 4. MODEL BUILDING (Transfer Learning) ---\nbase_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(224, 224, 3))\nbase_model.trainable = False\n\nx = base_model.output\nx = GlobalAveragePooling2D()(x)\nx = Dropout(0.3)(x)\nx = Dense(128, activation='relu')(x)\npredictions = Dense(1, activation='sigmoid')(x)\n\nmodel = Model(inputs=base_model.inputs, outputs=predictions)\nmodel.compile(optimizer=Adam(learning_rate=0.0001), loss='binary_crossentropy', metrics=['accuracy'])\n\n# --- 5. TRAINING ---\nhistory = model.fit(train_gen, epochs=EPOCHS, validation_data=val_gen, verbose=1)\n\n# --- 6. PREDICTION & SUBMISSION ---\nprint(\"Generating Predictions...\")\n\n# Robust Test File Loading\n# 1. Try finding files in the TEST_DIR\ntest_file_paths = sorted(glob.glob(os.path.join(TEST_DIR, '*.jpg')))\n\n# 2. If TEST_DIR was guessed wrong or empty, try searching broadly for test images\nif not test_file_paths:\n    print(f\"Warning: No images found in {TEST_DIR}. Searching recursively...\")\n    test_file_paths = sorted(glob.glob(\"../input/**/test/*.jpg\", recursive=True))\n\nif not test_file_paths:\n    raise FileNotFoundError(\"Could not find any .jpg files for testing.\")\n\nprint(f\"Found {len(test_file_paths)} test images.\")\n\n# Create a DataFrame for the generator\ntest_filenames = [os.path.basename(p) for p in test_file_paths]\ntest_df = pd.DataFrame({'filename': test_filenames, 'filepath': test_file_paths})\n\ntest_datagen = ImageDataGenerator(rescale=1./255)\ntest_gen = test_datagen.flow_from_dataframe(\n    dataframe=test_df,\n    x_col='filepath', # Read directly from path to be safe\n    y_col=None,\n    class_mode=None,\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    shuffle=False\n)\n\npreds = model.predict(test_gen, verbose=1)\n\n# --- 7. POST-PROCESSING (Invert Logic) ---\n# Keras Default: 0='with_mask', 1='without_mask' (Alphabetical)\n# Competition:   0='without_mask', 1='with_mask'\n\nfinal_preds = []\nfor p in preds:\n    if p > 0.5: \n        # Model predicted 1 (without_mask) -> Competition requires 0\n        final_preds.append(0)\n    else:\n        # Model predicted 0 (with_mask) -> Competition requires 1\n        final_preds.append(1)\n\n# Create final submission\nsubmission = pd.DataFrame({'filename': test_df['filename'], 'label': final_preds})\nsubmission.to_csv('submission.csv', index=False)\n\nprint(\"SUCCESS: submission.csv generated.\")\nprint(submission.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-01T12:23:27.951028Z","iopub.execute_input":"2026-02-01T12:23:27.951929Z","iopub.status.idle":"2026-02-01T12:41:12.708826Z","shell.execute_reply.started":"2026-02-01T12:23:27.951889Z","shell.execute_reply":"2026-02-01T12:41:12.708173Z"}},"outputs":[],"execution_count":null}]}