{"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":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Imports\nimport math, os\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping\nfrom tensorflow.keras.applications import ResNet50\nfrom tensorflow.keras.applications.resnet50 import preprocess_input\nimport matplotlib.pyplot as plt\nfrom kaggle_datasets import KaggleDatasets\n\n# Ignore the warning\nimport warnings\nwarnings.filterwarnings('ignore')\n\nprint(\"TensorFlow version:\", tf.__version__)\n\n# --- TPU / GPU / CPU Setup ---\nAUTO = tf.data.AUTOTUNE\n\ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()\n    print('Running on TPU ', tpu.master())\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.TPUStrategy(tpu)\nelse:\n    strategy = tf.distribute.get_strategy()\n\n# Set effective batch size based on number of replicas\nBATCH_SIZE = 32 * strategy.num_replicas_in_sync\nprint(\"Effective batch size:\", BATCH_SIZE)\n\n# --- Dataset Paths and Configuration ---\ntrain_path = '/kaggle/input/tpu-getting-started/tfrecords-jpeg-224x224/train'\nval_path   = '/kaggle/input/tpu-getting-started/tfrecords-jpeg-224x224/val'\ntest_path  = '/kaggle/input/tpu-getting-started/tfrecords-jpeg-224x224/test'\n\nIMAGE_SIZE = [224, 224]\n\nTRAINING_FILENAMES = tf.io.gfile.glob(os.path.join(train_path, '*.tfrec'))\nVALIDATION_FILENAMES = tf.io.gfile.glob(os.path.join(val_path, '*.tfrec'))\nTEST_FILENAMES = tf.io.gfile.glob(os.path.join(test_path, '*.tfrec'))\n\n# --- Data Augmentation ---\ndata_augmentation = keras.Sequential([\n    layers.RandomFlip(\"horizontal\"),\n    layers.RandomRotation(0.1),\n    layers.RandomZoom(0.1),\n    layers.RandomContrast(0.1)\n])\n\n# --- Data Loading and Preprocessing Functions ---\ndef read_tfrecord(example, augment=False):\n    TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"class\": tf.io.FixedLenFeature([], tf.int64),\n    }\n    example = tf.io.parse_single_example(example, TFREC_FORMAT)\n    image = tf.image.decode_jpeg(example[\"image\"], channels=3)\n    image = tf.image.resize(image, IMAGE_SIZE)\n    if augment:\n        image = data_augmentation(image)\n    image = preprocess_input(image)\n    label = tf.cast(example[\"class\"], tf.int32)\n    return image, label\n\ndef read_tfrecord_test(example):\n    TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"id\": tf.io.FixedLenFeature([], tf.string),\n    }\n    example = tf.io.parse_single_example(example, TFREC_FORMAT)\n    image = tf.image.decode_jpeg(example[\"image\"], channels=3)\n    image = tf.image.resize(image, IMAGE_SIZE)\n    image = preprocess_input(image)\n    return image, example[\"id\"]\n\ndef load_dataset(filenames, shuffle=True, augment=False):\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)\n    dataset = dataset.map(lambda x: read_tfrecord(x, augment), num_parallel_calls=AUTO)\n    if shuffle:\n        dataset = dataset.shuffle(2048)\n    dataset = dataset.repeat()\n    dataset = dataset.batch(BATCH_SIZE, drop_remainder=True)\n    dataset = dataset.prefetch(AUTO)\n    options = tf.data.Options()\n    options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA\n    dataset = dataset.with_options(options)\n    return dataset\n\ndef load_test_dataset(filenames):\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)\n    dataset = dataset.map(read_tfrecord_test, num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO)\n    options = tf.data.Options()\n    options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA\n    dataset = dataset.with_options(options)\n    return dataset\n\n# --- Dataset Creation and Sizing ---\ntrain_ds = load_dataset(TRAINING_FILENAMES, shuffle=True, augment=True)\nval_ds   = load_dataset(VALIDATION_FILENAMES, shuffle=False)\ntest_ds  = load_test_dataset(TEST_FILENAMES)\n\ndef count_data_items(filenames):\n    n = [int(os.path.basename(x).split('-')[2].split('.')[0]) for x in filenames]\n    return np.sum(n)\n\nnum_train_images = count_data_items(TRAINING_FILENAMES)\nnum_val_images   = count_data_items(VALIDATION_FILENAMES)\n\nSTEPS_PER_EPOCH = math.ceil(num_train_images / BATCH_SIZE)\nVALIDATION_STEPS = math.ceil(num_val_images / BATCH_SIZE)\n\nprint(\"num_train_images:\", num_train_images)\nprint(\"num_val_images:\", num_val_images)\nprint(\"STEPS_PER_EPOCH:\", STEPS_PER_EPOCH)\nprint(\"VALIDATION_STEPS:\", VALIDATION_STEPS)\n\n# --- Model Building and Compilation ---\nNUM_CLASSES = 104\n\nwith strategy.scope():\n    base_model = ResNet50(weights='imagenet', include_top=False, input_shape=(*IMAGE_SIZE, 3))\n    base_model.trainable = False\n    x = layers.GlobalAveragePooling2D()(base_model.output)\n    x = layers.Dropout(0.3)(x)\n    output = layers.Dense(NUM_CLASSES, activation='softmax')(x)\n    model = keras.Model(inputs=base_model.input, outputs=output)\n\n    model.compile(\n        optimizer=keras.optimizers.Adam(learning_rate=1e-3),\n        loss='sparse_categorical_crossentropy',\n        metrics=['sparse_categorical_accuracy']\n    )\n\n# --- Callbacks ---\ncheckpoint = ModelCheckpoint(\n    'best_model.h5',\n    monitor='val_sparse_categorical_accuracy',\n    save_best_only=True,\n    mode='max',\n    verbose=1\n)\n\nearlystop = EarlyStopping(\n    monitor='val_sparse_categorical_accuracy',\n    patience=3,\n    mode='max',\n    verbose=1,\n    restore_best_weights=True\n)\n\n# --- Training ---\nEPOCHS = 10\nhistory = model.fit(\n    train_ds,\n    validation_data=val_ds,\n    epochs=EPOCHS,\n    steps_per_epoch=STEPS_PER_EPOCH,\n    validation_steps=VALIDATION_STEPS,\n    callbacks=[checkpoint, earlystop],\n    verbose=1\n)\n\n# Fine-tuning\nwith strategy.scope():\n    base_model.trainable = True\n    fine_tune_at = 140\n    for layer in base_model.layers[:fine_tune_at]:\n        layer.trainable = False\n\n    model.compile(\n        optimizer=keras.optimizers.Adam(learning_rate=1e-5),\n        loss='sparse_categorical_crossentropy',\n        metrics=['sparse_categorical_accuracy']\n    )\n\nhistory_finetune = model.fit(\n    train_ds,\n    validation_data=val_ds,\n    epochs=5,\n    steps_per_epoch=STEPS_PER_EPOCH,\n    validation_steps=VALIDATION_STEPS,\n    callbacks=[checkpoint, earlystop],\n    verbose=1\n)\n\n# --- Predictions and Submission ---\ndef load_test_images_only(filenames):\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)\n    dataset = dataset.map(lambda x: read_tfrecord_test(x)[0], num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO)\n    options = tf.data.Options()\n    options.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA\n    dataset = dataset.with_options(options)\n    return dataset\n\ndef load_test_ids_only(filenames):\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)\n    dataset = dataset.map(lambda x: read_tfrecord_test(x)[1], num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE)\n    return dataset\n\ntest_ds_images = load_test_images_only(TEST_FILENAMES)\ntest_ds_ids = load_test_ids_only(TEST_FILENAMES)\n\npreds = model.predict(test_ds_images)\nlabels = preds.argmax(axis=-1)\n\ntest_ids = []\nfor ids in test_ds_ids:\n    test_ids.extend([id_.numpy().decode('utf-8') for id_ in ids])\n\nval_acc = history.history['val_sparse_categorical_accuracy'][-1]\nprint(\"Validation accuracy after head training:\", val_acc)\n\nval_acc_finetune = history_finetune.history['val_sparse_categorical_accuracy'][-1]\nprint(\"Validation accuracy after fine-tuning:\", val_acc_finetune)\n\nsubmission = pd.DataFrame({'id': test_ids, 'label': labels})\nprint(submission.head())\nprint(\"Number of rows:\", len(submission))\nsubmission.to_csv('submission.csv', index=False)\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-09-23T19:56:57.981681Z","iopub.execute_input":"2025-09-23T19:56:57.982448Z","iopub.status.idle":"2025-09-23T20:21:37.838361Z","shell.execute_reply.started":"2025-09-23T19:56:57.982426Z","shell.execute_reply":"2025-09-23T20:21:37.837587Z"}},"outputs":[],"execution_count":null}]}