{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport re\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\n\nprint(\"TensorFlow:\", tf.__version__)\n\n# 检查 GPU\ngpus = tf.config.list_physical_devices(\"GPU\")\nprint(\"GPUs:\", gpus)\n\nif len(gpus) > 1:\n    strategy = tf.distribute.MirroredStrategy()\nelse:\n    strategy = tf.distribute.get_strategy()\n\nprint(\"Replicas:\", strategy.num_replicas_in_sync)\n\nAUTO = tf.data.experimental.AUTOTUNE\nIMAGE_SIZE = [224, 224]\nBATCH_SIZE = 32 * strategy.num_replicas_in_sync\nNUM_CLASSES = 104\n\nDATA_PATH = \"/kaggle/input/competitions/tpu-getting-started/tfrecords-jpeg-224x224\"\n\nTRAINING_FILENAMES = tf.io.gfile.glob(DATA_PATH + \"/train/*.tfrec\")\nVALIDATION_FILENAMES = tf.io.gfile.glob(DATA_PATH + \"/val/*.tfrec\")\nTEST_FILENAMES = tf.io.gfile.glob(DATA_PATH + \"/test/*.tfrec\")\n\nprint(\"Train files:\", len(TRAINING_FILENAMES))\nprint(\"Val files:\", len(VALIDATION_FILENAMES))\nprint(\"Test files:\", len(TEST_FILENAMES))\n\ndef count_data_items(filenames):\n    nums = [\n        int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1))\n        for filename in filenames\n    ]\n    return np.sum(nums)\n\nNUM_TRAINING_IMAGES = count_data_items(TRAINING_FILENAMES)\nNUM_VALIDATION_IMAGES = count_data_items(VALIDATION_FILENAMES)\nNUM_TEST_IMAGES = count_data_items(TEST_FILENAMES)\n\nprint(\"Training images:\", NUM_TRAINING_IMAGES)\nprint(\"Validation images:\", NUM_VALIDATION_IMAGES)\nprint(\"Test images:\", NUM_TEST_IMAGES)\n\ndef decode_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32)\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    image_id = example[\"id\"]\n    return image, image_id\n\ndef data_augment(image, label):\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_brightness(image, 0.08)\n    image = tf.image.random_contrast(image, 0.9, 1.1)\n    return image, label\n\ndef preprocess_labeled(image, label):\n    image = tf.keras.applications.mobilenet_v2.preprocess_input(image)\n    return image, label\n\ndef preprocess_unlabeled(image, image_id):\n    image = tf.keras.applications.mobilenet_v2.preprocess_input(image)\n    return image, image_id\n\ndef load_dataset(filenames, labeled=True, ordered=False):\n    options = tf.data.Options()\n    if not ordered:\n        options.experimental_deterministic = False\n\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO)\n    dataset = dataset.with_options(options)\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 get_training_dataset():\n    dataset = load_dataset(TRAINING_FILENAMES, labeled=True)\n    dataset = dataset.map(data_augment, num_parallel_calls=AUTO)\n    dataset = dataset.map(preprocess_labeled, num_parallel_calls=AUTO)\n    dataset = dataset.repeat()\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\ndef get_validation_dataset():\n    dataset = load_dataset(VALIDATION_FILENAMES, labeled=True, ordered=True)\n    dataset = dataset.map(preprocess_labeled, num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\ndef get_test_dataset():\n    dataset = load_dataset(TEST_FILENAMES, labeled=False, ordered=True)\n    dataset = dataset.map(preprocess_unlabeled, num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\nwith strategy.scope():\n    try:\n        base_model = tf.keras.applications.MobileNetV2(\n            input_shape=[*IMAGE_SIZE, 3],\n            include_top=False,\n            weights=\"imagenet\"\n        )\n        print(\"成功加载 ImageNet 预训练权重\")\n    except Exception as e:\n        print(\"预训练权重加载失败，改用随机初始化\")\n        print(e)\n        base_model = tf.keras.applications.MobileNetV2(\n            input_shape=[*IMAGE_SIZE, 3],\n            include_top=False,\n            weights=None\n        )\n\n    base_model.trainable = False\n\n    model = tf.keras.Sequential([\n        base_model,\n        tf.keras.layers.GlobalAveragePooling2D(),\n        tf.keras.layers.Dropout(0.25),\n        tf.keras.layers.Dense(NUM_CLASSES, activation=\"softmax\")\n    ])\n\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),\n        loss=\"sparse_categorical_crossentropy\",\n        metrics=[\"sparse_categorical_accuracy\"]\n    )\n\nmodel.summary()\n\nEPOCHS = 10\nSTEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\n\nhistory = model.fit(\n    get_training_dataset(),\n    steps_per_epoch=STEPS_PER_EPOCH,\n    epochs=EPOCHS,\n    validation_data=get_validation_dataset()\n)\n\ntest_dataset = get_test_dataset()\n\ntest_images = test_dataset.map(lambda image, image_id: image)\ntest_ids_dataset = test_dataset.map(lambda image, image_id: image_id).unbatch()\n\npredictions = model.predict(test_images)\npredicted_labels = np.argmax(predictions, axis=1)\n\ntest_ids = next(iter(test_ids_dataset.batch(NUM_TEST_IMAGES))).numpy().astype(\"U\")\n\nsubmission = pd.DataFrame({\n    \"id\": test_ids,\n    \"label\": predicted_labels\n})\n\nsubmission.to_csv(\"/kaggle/working/submission.csv\", index=False)\n\nprint(\"submission.csv 已生成\")\nsubmission.head()","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-07-04T02:45:16.658162Z","iopub.execute_input":"2026-07-04T02:45:16.658426Z","iopub.status.idle":"2026-07-04T03:45:25.962692Z","shell.execute_reply.started":"2026-07-04T02:45:16.658397Z","shell.execute_reply":"2026-07-04T03:45:25.961692Z"}},"outputs":[],"execution_count":null}]}