{"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":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":131587,"databundleVersionId":15786880}],"isInternetEnabled":false,"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        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-04-19T10:26:24.790944Z","iopub.execute_input":"2026-04-19T10:26:24.791217Z","iopub.status.idle":"2026-04-19T10:26:35.106708Z","shell.execute_reply.started":"2026-04-19T10:26:24.791184Z","shell.execute_reply":"2026-04-19T10:26:35.106087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================\n# CLEAN + STABLE SETUP (KAGGLE GPU)\n# =========================\n\nimport os\n\n# Disable XLA (fixes CUDA timer warnings & instability)\nos.environ[\"TF_XLA_FLAGS\"] = \"--tf_xla_enable_xla_devices=false\"\n\n# Hide TensorFlow C++ logs\nos.environ[\"TF_CPP_MIN_LOG_LEVEL\"] = \"3\"\n\n# =========================\n# IMPORTS\n# =========================\nimport warnings\nwarnings.filterwarnings('ignore')\n\nimport tensorflow as tf\nprint(tf.config.list_physical_devices('GPU'))\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\nimport numpy as np\nimport pandas as pd\nimport os\n\n# =========================\n# SILENCE TF LOGGING\n# =========================\ntf.get_logger().setLevel('ERROR')\ntf.config.optimizer.set_jit(False)\n\n# =========================\n# GPU CONFIG\n# =========================\ngpus = tf.config.list_physical_devices('GPU')\nprint(\"GPUs Available:\", gpus)\n\nif gpus:\n    for gpu in gpus:\n        tf.config.experimental.set_memory_growth(gpu, True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T10:26:35.108309Z","iopub.execute_input":"2026-04-19T10:26:35.108698Z","iopub.status.idle":"2026-04-19T10:27:00.622315Z","shell.execute_reply.started":"2026-04-19T10:26:35.108673Z","shell.execute_reply":"2026-04-19T10:27:00.621553Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================\n# CONFIG\n# =========================\nIMG_SIZE = (224, 224)\nBATCH_SIZE = 32\nEPOCHS = 15\n\nTRAIN_DIR = \"/kaggle/input/competitions/cs-460-muffin-vs-chihuahua-classification-challenge/train\"\nTEST_DIR = \"/kaggle/input/competitions/cs-460-muffin-vs-chihuahua-classification-challenge/kaggle_test_final\"\n\n# =========================\n# DATA GENERATOR (TRAIN + VALIDATION)\n# =========================\ndatagen = ImageDataGenerator(\n    rescale=1./255,\n    validation_split=0.2,\n\n    rotation_range=25,\n    width_shift_range=0.1,\n    height_shift_range=0.1,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n\ntrain_generator = 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)\n\nval_generator = 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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T10:27:00.623255Z","iopub.execute_input":"2026-04-19T10:27:00.623840Z","iopub.status.idle":"2026-04-19T10:27:01.605864Z","shell.execute_reply.started":"2026-04-19T10:27:00.623814Z","shell.execute_reply":"2026-04-19T10:27:01.605256Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.applications import MobileNetV2\nfrom tensorflow.keras import layers, models\nimport tensorflow as tf\n\n# Base pretrained model\nbase_model = MobileNetV2(\n    weights=None,\n    include_top=False,\n    input_shape=(224, 224, 3)\n)\n\n# Freeze base\nbase_model.trainable = False\n\n# Custom head\nx = base_model.output\nx = layers.GlobalAveragePooling2D()(x)\nx = layers.BatchNormalization()(x)\nx = layers.Dense(128, activation='relu')(x)\nx = layers.Dropout(0.5)(x)\n\noutput = layers.Dense(1, activation='sigmoid')(x)\n\n# Final model\nmodel = models.Model(inputs=base_model.input, outputs=output)\n\n# Compile\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(1e-4),\n    loss='binary_crossentropy',\n    metrics=['accuracy']\n)\n\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T10:27:01.606889Z","iopub.execute_input":"2026-04-19T10:27:01.607203Z","iopub.status.idle":"2026-04-19T10:27:04.223660Z","shell.execute_reply.started":"2026-04-19T10:27:01.607179Z","shell.execute_reply":"2026-04-19T10:27:04.223143Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Unfreeze last layers\nfor layer in base_model.layers[-30:]:\n    layer.trainable = True\n\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(1e-5),\n    loss='binary_crossentropy',\n    metrics=['accuracy']\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T10:27:04.224738Z","iopub.execute_input":"2026-04-19T10:27:04.225419Z","iopub.status.idle":"2026-04-19T10:27:04.233875Z","shell.execute_reply.started":"2026-04-19T10:27:04.225393Z","shell.execute_reply":"2026-04-19T10:27:04.233130Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================\n# TRAIN\n# =========================\nhistory = model.fit(\n    train_generator,\n    validation_data=val_generator,\n    epochs=EPOCHS,\n    verbose=1,\n    # callbacks=callbacks\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T10:27:04.234708Z","iopub.execute_input":"2026-04-19T10:27:04.235054Z","iopub.status.idle":"2026-04-19T10:44:34.590547Z","shell.execute_reply.started":"2026-04-19T10:27:04.235031Z","shell.execute_reply":"2026-04-19T10:44:34.589895Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================\n# PREPARE TEST DATA\n# =========================\ntest_files = os.listdir(TEST_DIR)\n\ntest_df = pd.DataFrame({\n    'filename': test_files\n})\n\n# =========================\n# TEST GENERATOR\n# =========================\ntest_datagen = ImageDataGenerator(rescale=1./255)\n\ntest_generator = test_datagen.flow_from_dataframe(\n    dataframe=test_df,\n    directory=TEST_DIR,\n    x_col='filename',\n    y_col=None,\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=None,\n    shuffle=False\n)\n\n# =========================\n# PREDICT\n# =========================\npredictions = model.predict(test_generator, verbose=0)\n\n# Convert predictions to labels\npred_labels = (predictions > 0.5).astype(int).reshape(-1)\n\n# Map numbers → class names\nlabel_map = {0: \"chihuahua\", 1: \"muffin\"}\npred_names = [label_map[x] for x in pred_labels]\n\n# Create submission\nsubmission = pd.DataFrame({\n    'ID': test_df['filename'],   # EXACT column name\n    'Label': pred_names          # STRING labels\n})\n\n# Save\nsubmission.to_csv(\"submission112.csv\", index=False)\n\nprint(\"✅ Submission fixed!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-19T10:44:34.593063Z","iopub.execute_input":"2026-04-19T10:44:34.593283Z","iopub.status.idle":"2026-04-19T10:45:02.972102Z","shell.execute_reply.started":"2026-04-19T10:44:34.593261Z","shell.execute_reply":"2026-04-19T10:45:02.971342Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"1️⃣ ResNet (Residual Network)\n💡 Idea:\n\n👉 Solve vanishing gradient problem\n\n🧠 Key concept:\n\n👉 Skip connections (shortcut links)\n\nInstead of:\n\ninput → layer → layer → output\n\nIt does:\n\ninput → layer → layer + input → output\n\n👉 This helps train very deep networks (50, 101 layers)\n\n✅ Pros:\nVery accurate\nStable training\nWidely used\n❌ Cons:\nHeavy (slow)\nLarge model size\n🧩 2️⃣ EfficientNet\n💡 Idea:\n\n👉 Smarter scaling\n\nInstead of just making network deeper, it balances:\n\ndepth (layers)\nwidth (neurons)\nresolution (image size)\n\n👉 Called compound scaling\n\n✅ Pros:\nVery high accuracy\nMore efficient than ResNet\nBetter performance per parameter\n❌ Cons:\nSlightly complex\nSometimes slower than MobileNet\n🧩 3️⃣ MobileNetV2 (what you used)\n💡 Idea:\n\n👉 Lightweight model for mobile devices\n\nUses:\n\ndepthwise separable convolutions\ninverted residual blocks\n✅ Pros:\nVery fast ⚡\nSmall size\nWorks on low hardware\n❌ Cons:\nSlightly less accurate than others\n⚔️ Direct comparison\nFeature\tMobileNetV2\tResNet\tEfficientNet\nGoal\tSpeed\tDepth\tEfficiency\nSize\tSmall\tLarge\tMedium\nAccuracy\tMedium\tHigh\tVery High\nSpeed\tFast ⚡\tSlow\tMedium\nBest for\tLow compute\tGeneral tasks\tBest performance\n🧠 How they are SIMILAR\n\nAll three:\n\n✅ Pretrained on ImageNet\n✅ Used with transfer learning\n✅ Plug into your code like:\nbase_model = ModelName(weights='imagenet')\n✅ Work for:\nbinary classification\nmulti-class classification\n⚠️ How they are DIFFERENT\n\n👉 The difference is in architecture design philosophy:\n\nResNet → deeper networks\nMobileNet → lightweight networks\nEfficientNet → balanced scaling\n🎯 What should YOU use?\n\nSince you're doing many datasets:\n\n👉 Use this rule:\n\n🚀 Fast training / low GPU → MobileNetV2\n🧠 Balanced → ResNet34 / ResNet50\n🏆 Best accuracy → EfficientNet\n🧠 Simple analogy\n\nThink of them like:\n\nMobileNet → 🛵 scooter (fast, light)\nResNet → 🚗 car (strong, reliable)\nEfficientNet → 🏎️ sports car (optimized performance)\n🔥 Final takeaway\n\n👉 They are NOT different types of models\n👉 They are different versions of the same idea (CNN)\n\nOnly:\n✔ structure\n✔ efficiency\n✔ performance","metadata":{}},{"cell_type":"markdown","source":"✅ 1. CHANGE MODEL (MobileNet → ResNet)\n❌ Your current line:\nfrom tensorflow.keras.applications import MobileNetV2\n✅ Replace with:\nfrom tensorflow.keras.applications import ResNet50\nfrom tensorflow.keras.applications.resnet50 import preprocess_input\n✅ 2. CHANGE DATA GENERATOR (VERY IMPORTANT)\n❌ Your current:\nrescale=1./255,\n✅ Replace with:\npreprocessing_function=preprocess_input,\n✔ Final datagen becomes:\ndatagen = ImageDataGenerator(\n    preprocessing_function=preprocess_input,\n    validation_split=0.2,\n\n    rotation_range=25,\n    width_shift_range=0.1,\n    height_shift_range=0.1,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n✅ 3. CHANGE BASE MODEL\n❌ Your current:\nbase_model = MobileNetV2(\n    weights='imagenet',\n✅ Replace with:\nbase_model = ResNet50(\n    weights='imagenet',\n    include_top=False,\n    input_shape=(224, 224, 3)\n)\n⚠️ 4. IMPORTANT (fix your Kaggle error)\n\nBecause of your earlier error:\n\n👉 Add this fallback:\n\ntry:\n    base_model = ResNet50(\n        weights='imagenet',\n        include_top=False,\n        input_shape=(224, 224, 3)\n    )\nexcept:\n    base_model = ResNet50(\n        weights=None,\n        include_top=False,\n        input_shape=(224, 224, 3)\n    )\n✅ 5. KEEP EVERYTHING ELSE SAME\n\n👉 DO NOT change:\n\nyour layers\ndropout\ncompile\nfit\ngenerators\n🔥 FINAL MINIMAL PATCH (copy this part only)\nfrom tensorflow.keras.applications import ResNet50\nfrom tensorflow.keras.applications.resnet50 import preprocess_input\n\ndatagen = ImageDataGenerator(\n    preprocessing_function=preprocess_input,\n    validation_split=0.2,\n    rotation_range=25,\n    width_shift_range=0.1,\n    height_shift_range=0.1,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n\ntry:\n    base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(224,224,3))\nexcept:\n    base_model = ResNet50(weights=None, include_top=False, input_shape=(224,224,3))\n🎯 That’s it\n\n👉 Only 3 things changed:\n\nModel → ResNet50\nPreprocessing → preprocess_input\nAdded fallback for download error\n👍 Result\n\n✔ Runs without error\n✔ Uses GPU\n✔ Same pipeline\n✔ Better accuracy than MobileNet","metadata":{}},{"cell_type":"markdown","source":"","metadata":{}}]}