{"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":21154,"databundleVersionId":1243559,"sourceType":"competition"}],"dockerImageVersionId":31090,"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":"2025-08-03T13:18:51.358379Z","iopub.execute_input":"2025-08-03T13:18:51.358630Z","iopub.status.idle":"2025-08-03T13:18:54.103094Z","shell.execute_reply.started":"2025-08-03T13:18:51.358606Z","shell.execute_reply":"2025-08-03T13:18:54.102362Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import math \nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom matplotlib import pyplot as plt\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense\nfrom tensorflow.keras.optimizers import SGD\nimport os\nimport glob\nfrom tensorflow.data.experimental import load\nimport warnings\nwarnings.filterwarnings('ignore')\nimport time\n\nstart_time = time.time()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:18:54.104648Z","iopub.execute_input":"2025-08-03T13:18:54.105011Z","iopub.status.idle":"2025-08-03T13:19:12.805048Z","shell.execute_reply.started":"2025-08-03T13:18:54.104986Z","shell.execute_reply":"2025-08-03T13:19:12.804458Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tf.keras.backend.clear_session()\n\nimage_size = [224,224]\n\ndef decode_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.image.resize(image, image_size, method = \"bilinear\")\n    image = tf.cast(image, tf.float32)\n    image = tf.keras.applications.resnet50.preprocess_input(image)\n    image = tf.reshape(image, [*image_size,3])\n    return image\n\ndef load_dataset(filenames, labeled=True):\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=tf.data.AUTOTUNE)\n    if labeled:\n        dataset = dataset.map(read_labeled_tfrec, num_parallel_calls=tf.data.AUTOTUNE)\n    else:\n        dataset = dataset.map(read_unlabeled_tfrec, num_parallel_calls=tf.data.AUTOTUNE)       \n    return dataset\n\ndef read_labeled_tfrec(input_example):\n    labeled_tfrec_format = { \n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"class\": tf.io.FixedLenFeature([], tf.int64)\n    }\n    input_example = tf.io.parse_single_example(input_example, labeled_tfrec_format)\n    image = decode_image(input_example[\"image\"])\n    label = tf.cast(input_example['class'], tf.int32)\n    return image, label\n\ndef read_unlabeled_tfrec(input_example):\n    unlabeled_tfrec_format = { \n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"id\": tf.io.FixedLenFeature([], tf.string)\n    }    \n    input_example = tf.io.parse_single_example(input_example, unlabeled_tfrec_format)\n    image = decode_image(input_example[\"image\"])\n    image_id = input_example['id']\n    return image, image_id","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:19:12.805745Z","iopub.execute_input":"2025-08-03T13:19:12.806161Z","iopub.status.idle":"2025-08-03T13:19:13.027681Z","shell.execute_reply.started":"2025-08-03T13:19:12.806144Z","shell.execute_reply":"2025-08-03T13:19:13.026802Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"folder = 'tfrecords-jpeg-224x224'\ntrain_files = tf.io.gfile.glob(f\"/kaggle/input/tpu-getting-started/{folder}/train/*.tfrec\")\nval_files = tf.io.gfile.glob(f\"/kaggle/input/tpu-getting-started/{folder}/val/*.tfrec\")\ntest_files = tf.io.gfile.glob(f\"/kaggle/input/tpu-getting-started/{folder}/test/*.tfrec\")\n\ntrain_dataset = load_dataset(train_files, labeled=True)\nvalidation_dataset = load_dataset(val_files, labeled=True)\ntest_dataset = load_dataset(test_files, labeled=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:19:13.028589Z","iopub.execute_input":"2025-08-03T13:19:13.028882Z","iopub.status.idle":"2025-08-03T13:19:14.922693Z","shell.execute_reply.started":"2025-08-03T13:19:13.028856Z","shell.execute_reply":"2025-08-03T13:19:14.921911Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def augment_image(image, label):\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_brightness(image, 0.12)  # Slightly increased from 0.1\n    image = tf.image.random_contrast(image, 0.88, 1.12)  # Slightly increased\n    return image, label\n\ntf.random.set_seed(42)\nshuffle_buffer = 2000 \n\ntrain_dataset = train_dataset.map(augment_image, num_parallel_calls=tf.data.AUTOTUNE)\ntrain_dataset = train_dataset.shuffle(shuffle_buffer, seed=42, reshuffle_each_iteration=False)\nvalidation_dataset = validation_dataset.shuffle(shuffle_buffer, seed=42, reshuffle_each_iteration=False)\n\nBATCH_SIZE = 32  \nAUTO = tf.data.AUTOTUNE\nNUM_CLASSES = 104\n\ntrain_dataset = train_dataset.batch(BATCH_SIZE).prefetch(AUTO)\nvalidation_dataset = validation_dataset.batch(BATCH_SIZE).prefetch(AUTO)\ntest_dataset = test_dataset.batch(BATCH_SIZE).prefetch(AUTO)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:19:14.924724Z","iopub.execute_input":"2025-08-03T13:19:14.924988Z","iopub.status.idle":"2025-08-03T13:19:16.791380Z","shell.execute_reply.started":"2025-08-03T13:19:14.924958Z","shell.execute_reply":"2025-08-03T13:19:16.790761Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_model():\n    base_model = tf.keras.applications.ResNet50(\n        include_top=False,\n        weights='imagenet',\n        input_shape=(224, 224, 3),\n        pooling=None\n    )\n    \n    base_model.trainable = True\n    fine_tune_at = int(0.8 * len(base_model.layers))\n    for layer in base_model.layers[:fine_tune_at]:\n        layer.trainable = False\n    \n    resnet_model = tf.keras.Sequential([\n        base_model,\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.BatchNormalization(),  # ONLY addition\n        tf.keras.layers.Dropout(0.5),\n        tf.keras.layers.Dense(512, activation='relu'),\n        tf.keras.layers.Dropout(0.3),\n        tf.keras.layers.Dense(NUM_CLASSES, activation='softmax')\n    ])\n    \n    return resnet_model","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:19:16.792056Z","iopub.execute_input":"2025-08-03T13:19:16.792237Z","iopub.status.idle":"2025-08-03T13:19:16.797730Z","shell.execute_reply.started":"2025-08-03T13:19:16.792222Z","shell.execute_reply":"2025-08-03T13:19:16.797223Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"resnet_model = create_model()\nresnet_model.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),\n    loss='sparse_categorical_crossentropy', \n    metrics=['accuracy']\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:19:16.798426Z","iopub.execute_input":"2025-08-03T13:19:16.798638Z","iopub.status.idle":"2025-08-03T13:19:19.576212Z","shell.execute_reply.started":"2025-08-03T13:19:16.798617Z","shell.execute_reply":"2025-08-03T13:19:19.575646Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"EPOCHS = 12  \n\ncallbacks = [\n    tf.keras.callbacks.EarlyStopping(\n        monitor='val_loss',\n        patience=3,\n        restore_best_weights=True\n    ),\n    tf.keras.callbacks.ReduceLROnPlateau(\n        monitor='val_loss',\n        factor=0.2,\n        patience=2,\n        min_lr=1e-6\n    )\n]\n\nhistory = resnet_model.fit(\n    train_dataset,\n    epochs=EPOCHS,\n    validation_data=validation_dataset,\n    callbacks=callbacks\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:19:19.576938Z","iopub.execute_input":"2025-08-03T13:19:19.577185Z","iopub.status.idle":"2025-08-03T13:33:32.322148Z","shell.execute_reply.started":"2025-08-03T13:19:19.577159Z","shell.execute_reply":"2025-08-03T13:33:32.321524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def plot_training_history(history):\n    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n    \n    ax1.plot(history.history['accuracy'], label='Training')\n    ax1.plot(history.history['val_accuracy'], label='Validation')\n    ax1.set_title('Improved ResNet Model Accuracy')\n    ax1.set_xlabel('Epoch')\n    ax1.set_ylabel('Accuracy')\n    ax1.legend()\n    \n    ax2.plot(history.history['loss'], label='Training')\n    ax2.plot(history.history['val_loss'], label='Validation')\n    ax2.set_title('Improved ResNet Model Loss')\n    ax2.set_xlabel('Epoch')\n    ax2.set_ylabel('Loss')\n    ax2.legend()\n    \n    plt.tight_layout()\n    plt.show()\n\nplot_training_history(history)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:33:32.322966Z","iopub.execute_input":"2025-08-03T13:33:32.323196Z","iopub.status.idle":"2025-08-03T13:33:32.941510Z","shell.execute_reply.started":"2025-08-03T13:33:32.323180Z","shell.execute_reply":"2025-08-03T13:33:32.940649Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_predictions_with_memory_safe_tta():\n    \n    image_ids = []\n    final_predictions = None\n    \n    # First pass: Original predictions\n    print(\"Pass 1/2: Original predictions\")\n    for batch_images, batch_image_names in test_dataset:\n        pred = resnet_model.predict(batch_images, verbose=0)\n        \n        if final_predictions is None:\n            final_predictions = pred\n        else:\n            final_predictions = np.concatenate([final_predictions, pred], axis=0)\n        \n        # Store image IDs only once\n        if len(image_ids) == 0:\n            batch_image_names = batch_image_names.numpy()\n            image_ids.extend([name.decode('utf-8') for name in batch_image_names])\n        elif len(image_ids) < len(final_predictions):\n            batch_image_names = batch_image_names.numpy()\n            image_ids.extend([name.decode('utf-8') for name in batch_image_names])\n    \n    # Second pass: Flipped predictions\n    print(\"Pass 2/2: Flipped predictions\")\n    flipped_predictions = None\n    \n    for batch_images, batch_image_names in test_dataset:\n        flipped_images = tf.image.flip_left_right(batch_images)\n        pred = resnet_model.predict(flipped_images, verbose=0)\n        \n        if flipped_predictions is None:\n            flipped_predictions = pred\n        else:\n            flipped_predictions = np.concatenate([flipped_predictions, pred], axis=0)\n    \n    # Average the two predictions\n    averaged_predictions = (final_predictions + flipped_predictions) / 2.0\n    pred_labels = np.argmax(averaged_predictions, axis=1)\n    \n    return image_ids, pred_labels\n\n# If TTA fails, fall back to original method\ndef get_predictions_fallback():\n    print(\"Using fallback prediction method...\")\n    image_ids = []\n    predictions = []\n    \n    for batch_images, batch_image_names in test_dataset:\n        pred = resnet_model.predict(batch_images, verbose=0)\n        pred_labels = tf.argmax(pred, axis=1)\n        \n        batch_image_names = batch_image_names.numpy()\n        pred_labels = pred_labels.numpy()\n        \n        image_ids.extend([name.decode('utf-8') for name in batch_image_names])\n        predictions.extend(pred_labels)\n    \n    return image_ids, predictions    ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:33:32.942429Z","iopub.execute_input":"2025-08-03T13:33:32.942770Z","iopub.status.idle":"2025-08-03T13:33:32.951212Z","shell.execute_reply.started":"2025-08-03T13:33:32.942742Z","shell.execute_reply":"2025-08-03T13:33:32.950523Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def create_submission():\n    try:\n        image_ids, predictions = get_predictions_with_memory_safe_tta()\n        print(\"TTA completed successfully!\")\n    except Exception as e:\n        print(f\"TTA failed with error: {e}\")\n        print(\"Falling back to single prediction...\")\n        image_ids, predictions = get_predictions_fallback()\n    \n    submission_df = pd.DataFrame({\n        'id': image_ids,\n        'label': predictions\n    })\n    \n    submission_df.to_csv('submission.csv', index=False)\n    print(f\"Submission created with {len(submission_df)} predictions\")\n\ncreate_submission()\n\nend_time = time.time()\nprint(\"Execution time: \", end_time - start_time, \"secs\")\n\n# Print final results\nif 'history' in locals():\n    best_val_acc = max(history.history['val_accuracy'])\n    print(f\"Best validation accuracy: {best_val_acc:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:33:32.951995Z","iopub.execute_input":"2025-08-03T13:33:32.952227Z","iopub.status.idle":"2025-08-03T13:34:57.920352Z","shell.execute_reply.started":"2025-08-03T13:33:32.952202Z","shell.execute_reply":"2025-08-03T13:34:57.919557Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save the trained model\nresnet_model.save('/kaggle/working/my_final_model.h5')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-03T13:39:39.435763Z","iopub.execute_input":"2025-08-03T13:39:39.436058Z","iopub.status.idle":"2025-08-03T13:39:40.092440Z","shell.execute_reply.started":"2025-08-03T13:39:39.436041Z","shell.execute_reply":"2025-08-03T13:39:40.091820Z"}},"outputs":[],"execution_count":null}]}