{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Introduction\n\n?","metadata":{"papermill":{"duration":0.003774,"end_time":"2023-10-05T09:25:25.655653","exception":false,"start_time":"2023-10-05T09:25:25.651879","status":"completed"},"tags":[],"id":"bf6f91d2"}},{"cell_type":"code","source":"import os\nimport re\n\nimport pandas as pd\nimport tensorflow as tf\nfrom matplotlib import pyplot as plt\nfrom kaggle_datasets import KaggleDatasets","metadata":{"_kg_hide-output":true,"papermill":{"duration":7.882392,"end_time":"2023-10-05T09:25:33.541331","exception":false,"start_time":"2023-10-05T09:25:25.658939","status":"completed"},"tags":[],"id":"cd399f06","outputId":"2c1590fb-845d-48dd-d139-0a70ebdacb17","execution":{"iopub.status.busy":"2023-11-13T05:50:50.371387Z","iopub.execute_input":"2023-11-13T05:50:50.372162Z","iopub.status.idle":"2023-11-13T05:50:50.376555Z","shell.execute_reply.started":"2023-11-13T05:50:50.372128Z","shell.execute_reply":"2023-11-13T05:50:50.375674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Configurations\n\nHere we set some of the configurations used for data processing.","metadata":{"papermill":{"duration":0.005654,"end_time":"2023-10-05T09:25:33.553252","exception":false,"start_time":"2023-10-05T09:25:33.547598","status":"completed"},"tags":[],"id":"b9bc81fd"}},{"cell_type":"code","source":"picture_size = 192\nBATCH_SIZE = 32\nkgl_path = KaggleDatasets().get_gcs_path(\"tpu-getting-started\")\nGCS_PATH = kgl_path + f\"/tfrecords-jpeg-{picture_size}x{picture_size}\"\nAUTO = tf.data.experimental.AUTOTUNE\n\ntraining_datafile = tf.io.gfile.glob(GCS_PATH + \"/train/*.tfrec\")\nvalidation_datafile = tf.io.gfile.glob(GCS_PATH + \"/val/*.tfrec\")\ntest_datafile = tf.io.gfile.glob(GCS_PATH + \"/test/*.tfrec\")\n\nCLASSES = ['pink primrose',    'hard-leaved pocket orchid', 'canterbury bells', 'sweet pea',     'wild geranium',     'tiger lily',           'moon orchid',              'bird of paradise', 'monkshood',        'globe thistle',         # 00 - 09\n           'snapdragon',       \"colt's foot\",               'king protea',      'spear thistle', 'yellow iris',       'globe-flower',         'purple coneflower',        'peruvian lily',    'balloon flower',   'giant white arum lily', # 10 - 19\n           'fire lily',        'pincushion flower',         'fritillary',       'red ginger',    'grape hyacinth',    'corn poppy',           'prince of wales feathers', 'stemless gentian', 'artichoke',        'sweet william',         # 20 - 29\n           'carnation',        'garden phlox',              'love in the mist', 'cosmos',        'alpine sea holly',  'ruby-lipped cattleya', 'cape flower',              'great masterwort', 'siam tulip',       'lenten rose',           # 30 - 39\n           'barberton daisy',  'daffodil',                  'sword lily',       'poinsettia',    'bolero deep blue',  'wallflower',           'marigold',                 'buttercup',        'daisy',            'common dandelion',      # 40 - 49\n           'petunia',          'wild pansy',                'primula',          'sunflower',     'lilac hibiscus',    'bishop of llandaff',   'gaura',                    'geranium',         'orange dahlia',    'pink-yellow dahlia',    # 50 - 59\n           'cautleya spicata', 'japanese anemone',          'black-eyed susan', 'silverbush',    'californian poppy', 'osteospermum',         'spring crocus',            'iris',             'windflower',       'tree poppy',            # 60 - 69\n           'gazania',          'azalea',                    'water lily',       'rose',          'thorn apple',       'morning glory',        'passion flower',           'lotus',            'toad lily',        'anthurium',             # 70 - 79\n           'frangipani',       'clematis',                  'hibiscus',         'columbine',     'desert-rose',       'tree mallow',          'magnolia',                 'cyclamen ',        'watercress',       'canna lily',            # 80 - 89\n           'hippeastrum ',     'bee balm',                  'pink quill',       'foxglove',      'bougainvillea',     'camellia',             'mallow',                   'mexican petunia',  'bromelia',         'blanket flower',        # 90 - 99\n           'trumpet creeper',  'blackberry lily',           'common tulip',     'wild rose']                                                                                                                                               # 100 - 102","metadata":{"_kg_hide-input":false,"papermill":{"duration":3.381493,"end_time":"2023-10-05T09:25:36.940410","exception":false,"start_time":"2023-10-05T09:25:33.558917","status":"completed"},"tags":[],"id":"62213cff","execution":{"iopub.status.busy":"2023-11-13T05:50:50.385868Z","iopub.execute_input":"2023-11-13T05:50:50.386177Z","iopub.status.idle":"2023-11-13T05:50:50.908999Z","shell.execute_reply.started":"2023-11-13T05:50:50.386151Z","shell.execute_reply":"2023-11-13T05:50:50.908127Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Helper Functions\n\nHelper functions for data processing.","metadata":{"papermill":{"duration":0.003088,"end_time":"2023-10-05T09:25:36.947061","exception":false,"start_time":"2023-10-05T09:25:36.943973","status":"completed"},"tags":[],"id":"28ceb9ba"}},{"cell_type":"code","source":"def decrypt_image(image_data):\n    image = tf.image.decode_jpeg(image_data, channels=3)\n    image = tf.cast(image, tf.float32) / 255.0  # convert image to floats in [0, 1] range\n    image = tf.reshape(image, [picture_size, picture_size, 3]) # explicit size needed for TPU\n    return image\n\n\ndef r_labeled_tfrecord(example):\n    LABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n        \"class\": tf.io.FixedLenFeature([], tf.int64),  # shape [] means single element\n    }\n    example = tf.io.parse_single_example(example, LABELED_TFREC_FORMAT)\n    image = decrypt_image(example['image'])\n    label = tf.cast(example['class'], tf.int32)\n    return image, tf.one_hot(label, len(CLASSES)) # returns a dataset of (image, label) pairs\n\n\ndef read_unlabeled_tfrecord(example):\n    UNLABELED_TFREC_FORMAT = {\n        \"image\": tf.io.FixedLenFeature([], tf.string), # tf.string means bytestring\n        \"id\": tf.io.FixedLenFeature([], tf.string),  # shape [] means single element\n        # class is missing, this competitions's challenge is to predict flower classes for the test dataset\n    }\n    example = tf.io.parse_single_example(example, UNLABELED_TFREC_FORMAT)\n    image = decrypt_image(example['image'])\n    idnum = example['id']\n    return image, idnum # returns a dataset of image(s)\n\n\ndef datafile_load(filenames, labeled: bool = True, ordered: bool = False):\n    # Read from TFRecords. For optimal performance, reading from multiple files at once and\n    # disregarding data order. Order does not matter since we will be shuffling the data anyway.\n\n    ignore_order = tf.data.Options()\n    if not ordered:\n        ignore_order.experimental_deterministic = False # disable order, increase speed\n\n    dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTO) # automatically interleaves reads from multiple files\n    dataset = dataset.with_options(ignore_order) # uses data as soon as it streams in, rather than in its original order\n    dataset = dataset.map(r_labeled_tfrecord if labeled else read_unlabeled_tfrecord, num_parallel_calls=AUTO)\n    # returns a dataset of (image, label) pairs if labeled=True or (image, id) pairs if labeled=False\n    return dataset\n\n\ndef data_augment(image, label):\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_flip_up_down(image)\n    image = tf.image.random_saturation(image, 0, 2)\n    image = tf.image.random_brightness(image, max_delta=0.5)\n    image = tf.image.random_contrast(image, lower=0.1, upper=0.9)\n    image = tf.image.rot90(image, k=tf.random.uniform([], 0, 4, dtype=tf.int32))\n    return image, label\n\n\ndef get_training_dataload():\n    dataset = datafile_load(training_datafile, labeled=True)\n    dataset = dataset.map(data_augment, num_parallel_calls=AUTO)\n    dataset = dataset.repeat() # the training dataset must repeat for several epochs\n    dataset = dataset.shuffle(2048)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO) # prefetch next batch while training (autotune prefetch buffer size)\n    return dataset\n\n\ndef get_validation_dataload(ordered=False):\n    dataset = datafile_load(validation_datafile, labeled=True, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.cache()\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\n\ndef get_test_dataload(ordered=False):\n    dataset = datafile_load(test_datafile, labeled=False, ordered=ordered)\n    dataset = dataset.batch(BATCH_SIZE)\n    dataset = dataset.prefetch(AUTO)\n    return dataset\n\n\ndef data_items_length(filenames):\n    # the number of data items is written in the name of the .tfrec\n    # files, i.e. flowers00-230.tfrec = 230 data items\n    return sum(int(re.search(r\"-([0-9]*)\\.\", x).group(1)) for x in filenames)\n\n\ndef get_model():\n    backbone = tf.keras.applications.EfficientNetB0(\n        include_top=False,\n        weights=\"imagenet\",\n        input_shape=[picture_size, picture_size, 3],\n    )\n    model = tf.keras.models.Sequential(\n        [\n            backbone,\n            tf.keras.layers.GlobalAveragePooling2D(),\n            tf.keras.layers.Dense(len(CLASSES), activation=\"softmax\"),\n        ]\n    )\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),\n        loss=\"categorical_crossentropy\",\n        metrics=[\"accuracy\"],\n    )\n    return model","metadata":{"_kg_hide-input":true,"papermill":{"duration":0.020949,"end_time":"2023-10-05T09:25:36.971317","exception":false,"start_time":"2023-10-05T09:25:36.950368","status":"completed"},"tags":[],"id":"f1303b0e","execution":{"iopub.status.busy":"2023-11-13T05:50:50.910672Z","iopub.execute_input":"2023-11-13T05:50:50.910992Z","iopub.status.idle":"2023-11-13T05:50:50.932758Z","shell.execute_reply.started":"2023-11-13T05:50:50.910963Z","shell.execute_reply":"2023-11-13T05:50:50.931839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load the Data\n\nDiscover all files, count samples, and create datasets.","metadata":{"papermill":{"duration":0.00296,"end_time":"2023-10-05T09:25:36.977549","exception":false,"start_time":"2023-10-05T09:25:36.974589","status":"completed"},"tags":[],"id":"5a651a15"}},{"cell_type":"code","source":"num_training_images = data_items_length(training_datafile)\nnum_validation_images = data_items_length(validation_datafile)\nnum_test_images = data_items_length(test_datafile)\n\nprint(f\"Number of training images:   {num_training_images:,d}.\")\nprint(f\"Number of validation images: {num_validation_images:,d}.\")\nprint(f\"Number of testing images:    {num_test_images:,d}.\")\n\ntrain_dataset = get_training_dataload()\nval_dataset = get_validation_dataload()\ntest_dataset = get_test_dataload(ordered=True)","metadata":{"papermill":{"duration":3.463566,"end_time":"2023-10-05T09:25:40.444252","exception":false,"start_time":"2023-10-05T09:25:36.980686","status":"completed"},"tags":[],"id":"28cc4dd2","outputId":"0051d43b-0ee1-4b5b-dd7b-9f59f54db18f","execution":{"iopub.status.busy":"2023-11-13T05:50:50.933892Z","iopub.execute_input":"2023-11-13T05:50:50.934168Z","iopub.status.idle":"2023-11-13T05:50:53.535653Z","shell.execute_reply.started":"2023-11-13T05:50:50.934143Z","shell.execute_reply":"2023-11-13T05:50:53.534810Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Inspect the Data\n\nLook at the random samples with the corresponding labels. Note that we are applying data augmentation, including random flips, rotation, hue/saturation, and brightness.","metadata":{"papermill":{"duration":0.003266,"end_time":"2023-10-05T09:25:40.451257","exception":false,"start_time":"2023-10-05T09:25:40.447991","status":"completed"},"tags":[],"id":"017d21de"}},{"cell_type":"code","source":"figure, axes = plt.subplots(5, 5, figsize=(12, 12))\naxes = [y for x in axes for y in x]\n\nfor i, sample in enumerate(train_dataset.unbatch().take(25).as_numpy_iterator()):\n    axes[i].imshow(sample[0])\n\n    flower_type = CLASSES[tf.argmax(sample[1]).numpy()]\n    axes[i].set_title(flower_type)\n    axes[i].axis('off')","metadata":{"papermill":{"duration":10.602517,"end_time":"2023-10-05T09:25:51.057131","exception":false,"start_time":"2023-10-05T09:25:40.454614","status":"completed"},"tags":[],"id":"9fb3fc23","outputId":"df17119b-d26e-4999-be8a-c5fa8df4a82c","execution":{"iopub.status.busy":"2023-11-13T05:50:53.537979Z","iopub.execute_input":"2023-11-13T05:50:53.538305Z","iopub.status.idle":"2023-11-13T05:50:58.671236Z","shell.execute_reply.started":"2023-11-13T05:50:53.538277Z","shell.execute_reply":"2023-11-13T05:50:58.670159Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Inspect the Model\n\nBuild the model and print the summary. We use the EfficientNetB0 model, the smallest in the [EfficientNet][efficientnet] family. We use ImageNet weights and use a lower learning rate with [Reduce LR on Plateau][reducelronlpateau] instead of freezing the model.\n\n[efficientnet]: https://arxiv.org/abs/1905.11946\n[reducelronlpateau]: https://keras.io/api/callbacks/reduce_lr_on_plateau","metadata":{"papermill":{"duration":0.01761,"end_time":"2023-10-05T09:25:51.091726","exception":false,"start_time":"2023-10-05T09:25:51.074116","status":"completed"},"tags":[],"id":"637e14fa"}},{"cell_type":"code","source":"model = get_model()\nmodel.summary()","metadata":{"papermill":{"duration":4.244945,"end_time":"2023-10-05T09:25:55.354660","exception":false,"start_time":"2023-10-05T09:25:51.109715","status":"completed"},"tags":[],"id":"47ea3500","outputId":"4194a0ae-4e90-48e3-aad1-68a7997b06ec","execution":{"iopub.status.busy":"2023-11-13T05:50:58.672602Z","iopub.execute_input":"2023-11-13T05:50:58.672965Z","iopub.status.idle":"2023-11-13T05:51:01.977791Z","shell.execute_reply.started":"2023-11-13T05:50:58.672932Z","shell.execute_reply":"2023-11-13T05:51:01.976805Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train the Model\n\nHere we fit the model for a total of 20 epochs using Model Checkpointer and Reduce LR on Plateau callbacks. The weights of the best model are saved in the `model.h5` file.","metadata":{"papermill":{"duration":0.018886,"end_time":"2023-10-05T09:25:55.392327","exception":false,"start_time":"2023-10-05T09:25:55.373441","status":"completed"},"tags":[],"id":"c7e9c481"}},{"cell_type":"code","source":"history = model.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=10,\n    steps_per_epoch=num_training_images // BATCH_SIZE,\n    validation_steps=num_validation_images // BATCH_SIZE,\n    callbacks=[\n        tf.keras.callbacks.ModelCheckpoint(\n            \"model.h5\",\n            monitor=\"val_accuracy\",\n            mode=\"max\",\n            save_best_only=True,\n            save_weights_only=True,\n            verbose=1,\n        ),\n        tf.keras.callbacks.ReduceLROnPlateau(\n            monitor='val_accuracy',\n            mode='max',\n            patience=5,\n            min_lr=1e-6,\n            verbose=2,\n        ),\n    ],\n    verbose=1 if os.environ[\"KAGGLE_KERNEL_RUN_TYPE\"] == \"Interactive\" else 2,\n).history","metadata":{"_kg_hide-output":true,"papermill":{"duration":2258.063364,"end_time":"2023-10-05T10:03:33.474457","exception":false,"start_time":"2023-10-05T09:25:55.411093","status":"completed"},"tags":[],"id":"6e0c728c","outputId":"93b2adaa-82f2-4aa2-c532-5727b8b4c7cb","execution":{"iopub.status.busy":"2023-11-13T05:51:01.979162Z","iopub.execute_input":"2023-11-13T05:51:01.979441Z","iopub.status.idle":"2023-11-13T05:53:15.239895Z","shell.execute_reply.started":"2023-11-13T05:51:01.979415Z","shell.execute_reply":"2023-11-13T05:53:15.237995Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Learning Curves","metadata":{"papermill":{"duration":0.023757,"end_time":"2023-10-05T10:03:33.522248","exception":false,"start_time":"2023-10-05T10:03:33.498491","status":"completed"},"tags":[],"id":"3284ae3f"}},{"cell_type":"code","source":"figure, axes = plt.subplots(1, 1, figsize=(8, 8))\n\nepochs = list(range(len(history[\"loss\"])))\n\naxes.plot(epochs, history[\"accuracy\"], label=\"train\")\naxes.plot(epochs, history[\"val_accuracy\"], label=\"validation\")\naxes.set_title(\"Learning Curves\")\naxes.set_xlabel(\"Epoch\")\naxes.set_ylabel(\"Accuracy\")\naxes.legend()\naxes.grid()","metadata":{"papermill":{"duration":0.382576,"end_time":"2023-10-05T10:03:33.928132","exception":false,"start_time":"2023-10-05T10:03:33.545556","status":"completed"},"tags":[],"id":"57f52c20","outputId":"4336d8d3-e10d-442f-fc0c-45344a7ef1cf","execution":{"iopub.status.busy":"2023-11-13T05:53:15.241013Z","iopub.status.idle":"2023-11-13T05:53:15.241476Z","shell.execute_reply.started":"2023-11-13T05:53:15.241275Z","shell.execute_reply":"2023-11-13T05:53:15.241301Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## My Contribution","metadata":{}},{"cell_type":"code","source":"history = model.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=10,\n    steps_per_epoch=num_training_images // BATCH_SIZE,\n    validation_steps=num_validation_images // BATCH_SIZE,\n    callbacks=[\n        tf.keras.callbacks.ModelCheckpoint(\n            \"model.h5\", \n            monitor=\"val_accuracy\",\n            mode=\"max\", \n            save_best_only=True,\n            save_weights_only=True,\n            verbose=1,\n        ),\n        tf.keras.callbacks.ReduceLROnPlateau(\n            monitor='val_accuracy',\n            mode='max',\n            patience=3,\n            min_lr=3e-6,\n            verbose=2,\n        ),\n    ],\n    verbose=1 if os.environ[\"KAGGLE_KERNEL_RUN_TYPE\"] == \"Interactive\" else 2,\n).history\n\n## Learning Curves","metadata":{"execution":{"iopub.status.busy":"2023-11-13T05:53:15.242510Z","iopub.status.idle":"2023-11-13T05:53:15.242846Z","shell.execute_reply.started":"2023-11-13T05:53:15.242677Z","shell.execute_reply":"2023-11-13T05:53:15.242692Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\n# Assuming you have the 'history' dictionary from your training\n\n# Generate data for shaded error bands\ntrain_acc = history[\"accuracy\"]\nval_acc = history[\"val_accuracy\"]\ntrain_std = np.std(train_acc, axis=0)\nval_std = np.std(val_acc, axis=0)\n\nfig, axes = plt.subplots(figsize=(8, 8))\n\nepochs = np.arange(1, len(history[\"accuracy\"]) + 1)  # Adjusted epochs range\n\n# Plotting the mean accuracy\naxes.plot(epochs, train_acc, label=\"Train\", marker='o')\naxes.plot(epochs, val_acc, label=\"Validation\", marker='o')\n\n# Plotting shaded error bands\naxes.fill_between(epochs, train_acc - train_std, train_acc + train_std, alpha=0.2)\naxes.fill_between(epochs, val_acc - val_std, val_acc + val_std, alpha=0.2)\n\naxes.set_title(\"Learning Curves with Error Bands\")\naxes.set_xlabel(\"Epoch\")\naxes.set_ylabel(\"Accuracy\")\naxes.legend()\naxes.grid()\n\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-11-13T05:53:15.244435Z","iopub.status.idle":"2023-11-13T05:53:15.244778Z","shell.execute_reply.started":"2023-11-13T05:53:15.244611Z","shell.execute_reply":"2023-11-13T05:53:15.244627Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualise Predictions\n\nFinally, display some random samples from the validation set to visually assess model performance.","metadata":{"papermill":{"duration":0.023965,"end_time":"2023-10-05T10:03:33.975501","exception":false,"start_time":"2023-10-05T10:03:33.951536","status":"completed"},"tags":[],"id":"85a73758"}},{"cell_type":"code","source":"take_dataset = val_dataset.unbatch().take(25).batch(25)\npredicts = model.predict(take_dataset, verbose=0)\n\nfigure, axes = plt.subplots(5, 5, figsize=(12, 12))\naxes = [y for x in axes for y in x]\n\nfor i, (sample, predict) in enumerate(zip(take_dataset.unbatch().as_numpy_iterator(), predicts)):\n    axes[i].imshow(sample[0])\n    true_label = tf.argmax(sample[1]).numpy()\n    predict_label = tf.argmax(predict).numpy()\n    correct = true_label == predict_label\n    axes[i].set_title(f\"{CLASSES[predict_label]} ({'correct' if correct else 'wrong'})\")\n    axes[i].axis(\"off\")","metadata":{"papermill":{"duration":4.485745,"end_time":"2023-10-05T10:03:38.484839","exception":false,"start_time":"2023-10-05T10:03:33.999094","status":"completed"},"tags":[],"id":"4bfb4ebf","outputId":"d42cf2db-9952-4b78-f955-8a29451ca306","execution":{"iopub.status.busy":"2023-11-13T05:53:15.246142Z","iopub.status.idle":"2023-11-13T05:53:15.246552Z","shell.execute_reply.started":"2023-11-13T05:53:15.246335Z","shell.execute_reply":"2023-11-13T05:53:15.246353Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Save Submission File\n\nRun the inference on the test dataset and save the model predictions in the `submission.csv` file to submit the results to the competition.","metadata":{"papermill":{"duration":0.053432,"end_time":"2023-10-05T10:03:38.591664","exception":false,"start_time":"2023-10-05T10:03:38.538232","status":"completed"},"tags":[],"id":"e9625834"}},{"cell_type":"code","source":"predictions = model.predict(test_dataset, verbose=0)\npredictions = tf.argmax(predictions, axis=-1)\nids = [id_.decode() for image, id_ in test_dataset.unbatch().as_numpy_iterator()]\n\nsubmission = pd.DataFrame(data={\"id\": ids, \"label\": predictions})\nsubmission.to_csv(\"submission.csv\", index=False)\nsubmission","metadata":{"papermill":{"duration":36.526604,"end_time":"2023-10-05T10:04:15.168317","exception":false,"start_time":"2023-10-05T10:03:38.641713","status":"completed"},"tags":[],"id":"1f52ccd1","outputId":"68c235c4-60e0-49bf-a03d-9e7a88ddf6cb","execution":{"iopub.status.busy":"2023-11-13T05:53:22.796580Z","iopub.execute_input":"2023-11-13T05:53:22.797278Z","iopub.status.idle":"2023-11-13T05:53:39.588801Z","shell.execute_reply.started":"2023-11-13T05:53:22.797242Z","shell.execute_reply":"2023-11-13T05:53:39.587790Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Reference:\nhttps://www.kaggle.com/code/nickuzmenkov/petals-to-the-metal-tf-efficientnet-baseline\n\nhttps://keras.io/guides/sequential_model/\n\nhttps://www.tensorflow.org/api_docs/python/tf/keras/layers/GlobalAveragePooling2D\n\nhttps://keras.io/api/layers/core_layers/dense/","metadata":{}}]}