{"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"},{"sourceId":10421266,"sourceType":"datasetVersion","datasetId":6459084}],"dockerImageVersionId":31193,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers, models, applications\nimport matplotlib.pyplot as plt\nimport warnings\nimport re\nimport random\nfrom sklearn.metrics import f1_score\nwarnings.filterwarnings('ignore')\n\nstrategy = tf.distribute.MirroredStrategy()\nAUTO = tf.data.experimental.AUTOTUNE\nSEED = 42\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)\n\nIMAGE_SIZE = [224, 224]\nBATCH_SIZE = 16 * strategy.num_replicas_in_sync\nNUM_CLASSES = 104\n\nBASE_PATH = \"/kaggle/input/tpu-getting-started\"\nGCS_PATH = f\"{BASE_PATH}/tfrecords-jpeg-{IMAGE_SIZE[0]}x{IMAGE_SIZE[1]}\"\n\nTRAINING_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/train/*.tfrec')\nVALIDATION_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/val/*.tfrec')\nTEST_FILENAMES = tf.io.gfile.glob(GCS_PATH + '/test/*.tfrec')\n\ndef decode_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0\n    image = tf.reshape(image, [*IMAGE_SIZE, 3])\n    return image\n\ndef read_labeled_tfrecord(example):\n    LABELED_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, LABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    label = tf.cast(example['class'], tf.int32)\n    return image, label\n\ndef read_unlabeled_tfrecord(example):\n    UNLABELED_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, UNLABELED_TFREC_FORMAT)\n    image = decode_image(example['image'])\n    idnum = example['id']\n    return image, idnum\n\ndef load_dataset(filenames, labeled=True, ordered=False):\n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False\n    \n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)\n    dataset = dataset.with_options(ignore_order)\n    \n    if labeled:\n        dataset = dataset.map(read_labeled_tfrecord, num_parallel_calls=AUTO)\n    else:\n        dataset = dataset.map(read_unlabeled_tfrecord, num_parallel_calls=AUTO)\n    \n    return dataset\n\ndef cutout_augment(img, sl=0.1, sh=0.2, rl=0.4):\n    if random.random() < 0.25:\n        return img\n    \n    h, w, c = IMAGE_SIZE[0], IMAGE_SIZE[1], 3\n    area = tf.cast(h * w, tf.float32)\n    \n    e_l = tf.cast(tf.round(tf.sqrt(area * sl * rl)), tf.int32)\n    e_h = tf.cast(tf.round(tf.sqrt(area * sh / rl)), tf.int32)\n    e_h = tf.minimum(e_h, h)\n    e_w = tf.minimum(e_h, w)\n    \n    erase_h = tf.random.uniform([], e_l, e_h, tf.int32)\n    erase_w = tf.random.uniform([], e_l, e_w, tf.int32)\n    \n    erase_mask = tf.zeros([erase_h, erase_w, c], tf.uint8)\n    \n    pad_h = h - erase_h\n    pad_w = w - erase_w\n    pad_top = tf.random.uniform([], 0, pad_h, tf.int32)\n    pad_left = tf.random.uniform([], 0, pad_w, tf.int32)\n    pad_bottom = pad_h - pad_top\n    pad_right = pad_w - pad_left\n    \n    erase_mask = tf.pad([erase_mask], \n                       [[0, 0], [pad_top, pad_bottom], [pad_left, pad_right], [0, 0]], \n                       constant_values=1)\n    erase_mask = tf.squeeze(erase_mask, axis=0)\n    \n    return tf.cast(tf.cast(img, tf.float32) * tf.cast(erase_mask, tf.float32), img.dtype)\n\ndef augment_image(image, label):\n    image = tf.image.random_flip_left_right(image)\n    image = cutout_augment(image)\n    return image, label\n\ndef get_validation_dataset(filenames=VALIDATION_FILENAMES, ordered=False):\n    dataset = load_dataset(filenames, labeled=True, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\ndef get_test_dataset(filenames=TEST_FILENAMES, ordered=False):\n    dataset = load_dataset(filenames, labeled=False, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\ndef count_data_items(filenames):\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in filenames]\n    return np.sum(n)\n\nNUM_VALIDATION_IMAGES = count_data_items(VALIDATION_FILENAMES)\nNUM_TEST_IMAGES = count_data_items(TEST_FILENAMES)\n\nVALIDATION_STEPS = -(-NUM_VALIDATION_IMAGES // BATCH_SIZE)\nTEST_STEPS = -(-NUM_TEST_IMAGES // BATCH_SIZE)\n\nprint(f\"Batch size: {BATCH_SIZE}\")\nprint(f\"Валидационных изображений: {NUM_VALIDATION_IMAGES}\")\nprint(f\"Тестовых изображений: {NUM_TEST_IMAGES}\")\n\ndef create_efficientnet_model():\n    with strategy.scope():\n        base_model = applications.EfficientNetB7(\n            input_shape=[*IMAGE_SIZE, 3],\n            weights='imagenet',\n            include_top=False\n        )\n        \n        model = models.Sequential([\n            base_model,\n            layers.GlobalAveragePooling2D(),\n            layers.Dense(NUM_CLASSES, activation='softmax')\n        ])\n        \n        model.compile(\n            optimizer='adam',\n            loss='sparse_categorical_crossentropy',\n            metrics=['accuracy']\n        )\n        \n        model.load_weights(\n            \"/kaggle/input/efficientnetb7-densenet201/EfficientNetB7_best.keras\",\n            skip_mismatch=True\n        )\n    \n    return model\n\ndef create_densenet_model():\n    with strategy.scope():\n        base_model = tf.keras.applications.DenseNet201(\n            input_shape=[*IMAGE_SIZE, 3],\n            weights='imagenet',\n            include_top=False\n        )\n        \n        model = models.Sequential([\n            base_model,\n            layers.GlobalAveragePooling2D(),\n            layers.Dense(NUM_CLASSES, activation='softmax')\n        ])\n        \n        model.compile(\n            optimizer='adam',\n            loss='sparse_categorical_crossentropy',\n            metrics=['accuracy']\n        )\n        \n        model.load_weights(\"/kaggle/input/efficientnetb7-densenet201/densenet201_best.keras\")\n    \n    return model\n\nmodel1 = create_efficientnet_model()\nmodel2 = create_densenet_model()\n\nval_dataset = get_validation_dataset(ordered=True)\nval_images_ds = val_dataset.map(lambda image, label: image)\nval_labels_ds = val_dataset.map(lambda image, label: label).unbatch()\nval_labels = next(iter(val_labels_ds.batch(NUM_VALIDATION_IMAGES))).numpy()\n\npreds1 = model1.predict(val_images_ds, verbose=2)\npreds2 = model2.predict(val_images_ds, verbose=2)\n\nalphas = np.linspace(0, 1, 100)\nscores = []\n\nfor alpha in alphas:\n    ensemble_preds = alpha * preds1 + (1 - alpha) * preds2\n    pred_labels = np.argmax(ensemble_preds, axis=1)\n    score = f1_score(val_labels, pred_labels, average='macro', labels=range(NUM_CLASSES))\n    scores.append(score)\n\nbest_alpha = alphas[np.argmax(scores)]\nbest_score = max(scores)\n\nprint(f\"Лучший alpha: {best_alpha:.3f}\")\nprint(f\"Лучший F1-score: {best_score:.4f}\")\n\ndef predict_tta(model, n_iter=5):\n    all_predictions = []\n    \n    for i in range(n_iter):\n        test_ds = get_test_dataset(ordered=True)\n        test_images_ds = test_ds.map(lambda image, idnum: image)\n        batch_preds = model.predict(test_images_ds, verbose=2)\n        all_predictions.append(batch_preds)\n    \n    return np.mean(all_predictions, axis=0)\n\ntest_preds1 = predict_tta(model1, n_iter=5)\ntest_preds2 = predict_tta(model2, n_iter=5)\n\nensemble_preds = best_alpha * test_preds1 + (1 - best_alpha) * test_preds2\ntest_predictions = np.argmax(ensemble_preds, axis=1)\n\ntest_ds = get_test_dataset(ordered=True)\ntest_ids_ds = test_ds.map(lambda image, idnum: idnum).unbatch()\ntest_ids = next(iter(test_ids_ds.batch(NUM_TEST_IMAGES))).numpy().astype('U')\n\nsubmission_df = pd.DataFrame({\n    'id': test_ids,\n    'label': test_predictions\n})\n\nsubmission_df.to_csv('submission.csv', index=False)\nprint(\"Submission файл сохранен\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T18:18:55.032393Z","iopub.execute_input":"2025-12-15T18:18:55.032738Z","iopub.status.idle":"2025-12-15T18:22:13.204086Z","shell.execute_reply.started":"2025-12-15T18:18:55.032713Z","shell.execute_reply":"2025-12-15T18:22:13.203285Z"}},"outputs":[],"execution_count":null}]}