{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.18"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":21154,"databundleVersionId":1243559,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true},"papermill":{"default_parameters":{},"duration":479.051753,"end_time":"2025-10-05T10:15:26.815502","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2025-10-05T10:07:27.763749","version":"2.6.0"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os, time, warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom matplotlib import pyplot as plt\n\nSEED = 43\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)\n\nIMAGE_SIZE = (224, 224)\nNUM_CLASSES = 104\nBATCH_SIZE = 28\nEPOCHS = 1\nFOLDER = \"tfrecords-jpeg-224x224\"\n\nBASE_PATH = \"/kaggle/input/tpu-getting-started\"\n\nTRAIN_FILES = tf.io.gfile.glob(f\"{BASE_PATH}/{FOLDER}/train/*.tfrec\")\nVAL_FILES   = tf.io.gfile.glob(f\"{BASE_PATH}/{FOLDER}/val/*.tfrec\")\nTEST_FILES  = tf.io.gfile.glob(f\"{BASE_PATH}/{FOLDER}/test/*.tfrec\")\n\nassert len(TRAIN_FILES) > 0, \"train/*.tfrec NotebookAdd Data\"\nassert len(VAL_FILES)   > 0, \"val/*.tfrec \"\nassert len(TEST_FILES)  > 0, \"test/*.tfrec \"\n\nAUTO = tf.data.AUTOTUNE\nstart_time = time.time()\n\ndef decode_image(image_bytes: tf.Tensor) -> tf.Tensor:\n    \"\"\"JPEG -> float32 (0..255), resize\"\"\"\n    image = tf.image.decode_jpeg(image_bytes, channels=3)\n    image = tf.image.resize(image, IMAGE_SIZE, method=\"bilinear\")\n    image = tf.cast(image, tf.float32)\n    return tf.reshape(image, [*IMAGE_SIZE, 3])\n\ndef preprocess_for_resnet(image: tf.Tensor) -> tf.Tensor:\n    \"\"\"ResNet50 BGR; 0..255\"\"\"\n    return tf.keras.applications.resnet50.preprocess_input(image)\n\ndef read_labeled_tfrec(example: tf.Tensor):\n    feature_spec = {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"class\": tf.io.FixedLenFeature([], tf.int64),\n    }\n    ex = tf.io.parse_single_example(example, feature_spec)\n    image = decode_image(ex[\"image\"])\n    label = tf.cast(ex[\"class\"], tf.int32)\n    return image, label\n\ndef read_unlabeled_tfrec(example: tf.Tensor):\n    feature_spec = {\n        \"image\": tf.io.FixedLenFeature([], tf.string),\n        \"id\": tf.io.FixedLenFeature([], tf.string),\n    }\n    ex = tf.io.parse_single_example(example, feature_spec)\n    image = decode_image(ex[\"image\"])\n    image_id = ex[\"id\"]\n    return image, image_id\n\ndef load_dataset(filenames, labeled=True):\n    ds = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)\n    if labeled:\n        ds = ds.map(read_labeled_tfrec, num_parallel_calls=AUTO)\n    else:\n        ds = ds.map(read_unlabeled_tfrec, num_parallel_calls=AUTO)\n    return ds\n\ndef augment_image(image, label):\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_brightness(image, 0.12)\n    image = tf.image.random_contrast(image, 0.88, 1.12)\n    return image, label\n\ndef to_model_space(image, label):\n    image = preprocess_for_resnet(image)\n    return image, label\n\ntrain_ds = load_dataset(TRAIN_FILES, labeled=True)\nval_ds   = load_dataset(VAL_FILES, labeled=True)\ntest_ds  = load_dataset(TEST_FILES, labeled=False)\n\nSHUFFLE_BUFFER = 2000\ntrain_ds = (train_ds\n            .map(augment_image, num_parallel_calls=AUTO)\n            .map(to_model_space, num_parallel_calls=AUTO)\n            .shuffle(SHUFFLE_BUFFER, seed=SEED, reshuffle_each_iteration=False)\n            .batch(BATCH_SIZE)\n            .prefetch(AUTO))\n\nval_ds = (val_ds\n          .map(to_model_space, num_parallel_calls=AUTO)\n          .batch(BATCH_SIZE)\n          .prefetch(AUTO))\n\ntest_ds = (test_ds\n           .map(lambda x, id_: (preprocess_for_resnet(x), id_), num_parallel_calls=AUTO)\n           .batch(BATCH_SIZE)\n           .prefetch(AUTO))\n\noptions_data = tf.data.Options()\noptions_data.experimental_distribute.auto_shard_policy = tf.data.experimental.AutoShardPolicy.DATA\nval_ds  = val_ds.with_options(options_data)\ntest_ds = test_ds.with_options(options_data)\n\nstrategy = None\ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()\n    strategy = tf.distribute.TPUStrategy(tpu)\nexcept Exception:\n    pass\n\ndef build_model():\n    base = tf.keras.applications.ResNet50(\n        include_top=False,\n        weights=\"imagenet\",\n        input_shape=(*IMAGE_SIZE, 3),\n        pooling=None\n    )\n    base.trainable = True\n    fine_tune_at = int(0.8 * len(base.layers))\n    for layer in base.layers[:fine_tune_at]:\n        layer.trainable = False\n\n    model = tf.keras.Sequential([\n        base,\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.BatchNormalization(),\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    return model\n\ncompile_kwargs = dict(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),\n    loss=\"sparse_categorical_crossentropy\",\n    metrics=[\"accuracy\"],\n    jit_compile=False,\n)\n\nif strategy:\n    with strategy.scope():\n        model = build_model()\n        model.compile(**compile_kwargs)\nelse:\n    model = build_model()\n    model.compile(**compile_kwargs)\n\ncallbacks = [\n    tf.keras.callbacks.EarlyStopping(\n        monitor=\"val_loss\", patience=3, restore_best_weights=True\n    ),\n    tf.keras.callbacks.ReduceLROnPlateau(\n        monitor=\"val_loss\", factor=0.2, patience=2, min_lr=1e-6\n    ),\n]\n\ndef count_items(files):\n    n = 0\n    for f in files:\n        n += int(f.split(\"-\")[-1].split(\".\")[0])\n    return n\n\ntrain_count = count_items(TRAIN_FILES)\nval_count   = count_items(VAL_FILES)\nsteps_per_epoch  = max(1, train_count // BATCH_SIZE)\nvalidation_steps = max(1, val_count   // BATCH_SIZE)\n\nhistory = model.fit(\n    train_ds,\n    epochs=EPOCHS,\n    validation_data=val_ds,\n    steps_per_epoch=steps_per_epoch,\n    validation_steps=validation_steps,\n    callbacks=callbacks,\n    verbose=1\n)\n\ndef plot_history(h):\n    fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n    ax1.plot(h.history[\"accuracy\"], label=\"train\")\n    ax1.plot(h.history[\"val_accuracy\"], label=\"valid\")\n    ax1.set_title(\"Accuracy\"); ax1.legend()\n    ax2.plot(h.history[\"loss\"], label=\"train\")\n    ax2.plot(h.history[\"val_loss\"], label=\"valid\")\n    ax2.set_title(\"Loss\"); ax2.legend()\n    plt.tight_layout(); plt.show()\n\nplot_history(history)\n\ndef predict_with_tta(test_dataset):\n    preds_orig = model.predict(test_dataset, verbose=0)\n    test_ds_flip = test_dataset.map(\n        lambda x, id_: (tf.image.flip_left_right(x), id_), num_parallel_calls=AUTO\n    ).with_options(options_data)\n    preds_flip = model.predict(test_ds_flip, verbose=0)\n\n    image_ids = []\n    for _, ids in test_dataset.unbatch().batch(1024):\n        image_ids.extend([i.decode(\"utf-8\") for i in ids.numpy().tolist()])\n\n    preds = (preds_orig + preds_flip) / 2.0\n    labels = preds.argmax(axis=1)\n    return image_ids, labels\n\ndef predict_fallback(test_dataset):\n    image_ids, labels = [], []\n    for imgs, ids in test_dataset:\n        p = model.predict(imgs, verbose=0)\n        l = p.argmax(axis=1)\n        ids = ids.numpy().tolist()\n        image_ids.extend([i.decode(\"utf-8\") for i in ids])\n        labels.extend(l)\n    return image_ids, labels\n\ndef make_submission():\n    try:\n        ids, labels = predict_with_tta(test_ds)\n    except Exception as e:\n        ids, labels = predict_fallback(test_ds)\n    sub = pd.DataFrame({\"id\": ids, \"label\": labels})\n    sub.to_csv(\"submission.csv\", index=False)\n    return sub\n\nsub = make_submission()\n\nbest_val_acc = float(np.max(history.history[\"val_accuracy\"]))\nelapsed = time.time() - start_time\n\nmodel.save(\"/kaggle/working/best_model.h5\")","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":468.2405,"end_time":"2025-10-05T10:15:18.873908","exception":false,"start_time":"2025-10-05T10:07:30.633408","status":"completed"},"tags":[],"trusted":true},"outputs":[],"execution_count":null}]}