{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","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":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport tensorflow as tf\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision\nfrom torchvision import datasets\nfrom torchvision import transforms \nfrom torch.utils.data import DataLoader\nfrom torch.utils.data.sampler import SubsetRandomSampler\n\nimport keras\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Conv2D, MaxPool2D , Flatten\nfrom tensorflow.keras.applications import VGG16\nfrom tensorflow.keras import layers, models\nfrom keras.optimizers import Adam\n\n#VGG16 = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M']\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport math, re, os\n#for dirname, _, filenames in os.walk('/kaggle/input'):\n    #for filename in filenames:\n        #print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-04-26T20:45:59.586371Z","iopub.execute_input":"2025-04-26T20:45:59.586758Z","iopub.status.idle":"2025-04-26T20:45:59.593259Z","shell.execute_reply.started":"2025-04-26T20:45:59.586733Z","shell.execute_reply":"2025-04-26T20:45:59.592151Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from kaggle_datasets import KaggleDatasets\n\nGCS_DS_PATH = KaggleDatasets().get_gcs_path('tpu-getting-started')\nprint(GCS_DS_PATH)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T20:45:59.594429Z","iopub.execute_input":"2025-04-26T20:45:59.594842Z","iopub.status.idle":"2025-04-26T20:45:59.954157Z","shell.execute_reply.started":"2025-04-26T20:45:59.594817Z","shell.execute_reply":"2025-04-26T20:45:59.953326Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMAGE_SIZE = [224, 224]\nGCS_PATH = GCS_DS_PATH + '/tfrecords-jpeg-224x224'\nAUTO = tf.data.experimental.AUTOTUNE\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\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\n\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  # convert image to floats in [0, 1] range\n    image = tf.reshape(image, [*IMAGE_SIZE, 3]) # explicit size needed for TPU\n    return image\n\ndef read_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 = decode_image(example['image'])\n    label = tf.cast(example['class'], tf.int32)\n    return image, label # returns a dataset of (image, label) pairs\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 = decode_image(example['image'])\n    idnum = example['id']\n    return image, idnum # returns a dataset of image(s)\n\ndef load_dataset(filenames, labeled=True, ordered=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(read_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","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T20:45:59.956177Z","iopub.execute_input":"2025-04-26T20:45:59.956455Z","iopub.status.idle":"2025-04-26T20:46:01.733487Z","shell.execute_reply.started":"2025-04-26T20:45:59.956409Z","shell.execute_reply":"2025-04-26T20:46:01.732484Z"},"jupyter":{"source_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def data_augment(image, label):\n    # Thanks to the dataset.prefetch(AUTO)\n    # statement in the next function (below), this happens essentially\n    # for free on TPU. Data pipeline code is executed on the \"CPU\"\n    # part of the TPU while the TPU itself is computing gradients.\n    image = tf.image.random_flip_left_right(image)\n    #image = tf.image.random_saturation(image, 0, 2)\n    return image, label   \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.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\ndef get_validation_dataset(ordered=False):\n    dataset = load_dataset(VALIDATION_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(ordered=False):\n    dataset = load_dataset(TEST_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    # the number of data items is written in the name of the .tfrec\n    # files, i.e. flowers00-230.tfrec = 230 data items\n    n = [int(re.compile(r\"-([0-9]*)\\.\").search(filename).group(1)) for filename in filenames]\n    return np.sum(n)\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)\nprint('Dataset: {} training images, {} validation images, {} unlabeled test images'.format(NUM_TRAINING_IMAGES, NUM_VALIDATION_IMAGES, NUM_TEST_IMAGES))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T20:46:01.734986Z","iopub.execute_input":"2025-04-26T20:46:01.735234Z","iopub.status.idle":"2025-04-26T20:46:01.743244Z","shell.execute_reply.started":"2025-04-26T20:46:01.735215Z","shell.execute_reply":"2025-04-26T20:46:01.742202Z"},"jupyter":{"source_hidden":true}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BATCH_SIZE = 16\n\nds_train = get_training_dataset()\nds_valid = get_validation_dataset()\nds_test = get_test_dataset()\n\nprint(\"Training:\", ds_train)\nprint (\"Validation:\", ds_valid)\nprint(\"Test:\", ds_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T20:46:01.744086Z","iopub.execute_input":"2025-04-26T20:46:01.744394Z","iopub.status.idle":"2025-04-26T20:46:01.908799Z","shell.execute_reply.started":"2025-04-26T20:46:01.744363Z","shell.execute_reply":"2025-04-26T20:46:01.907957Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load the pre-trained VGG16 model\nbase_model = VGG16(weights='imagenet', include_top=False, input_shape=(224, 224, 3))\n\n# Freeze the convolutional base\nbase_model.trainable = False\n\n# Create classification head\nadd_model = models.Sequential([\n    layers.Flatten(input_shape=base_model.output_shape[1:]),\n    layers.Dense(4096, activation='relu'),\n    layers.Dropout(0.7),\n    layers.Dense(len(CLASSES), activation='softmax')\n])\n\n# Combine the base model and the new head\nmodel = models.Model(inputs=base_model.input, outputs=add_model(base_model.output))\n\n# Compile the model\nmodel.compile(optimizer=Adam(learning_rate=0.0001),  # Use a smaller learning rate for fine-tuning\n              loss='sparse_categorical_crossentropy',\n              metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T20:46:01.909712Z","iopub.execute_input":"2025-04-26T20:46:01.910058Z","iopub.status.idle":"2025-04-26T20:46:02.211931Z","shell.execute_reply.started":"2025-04-26T20:46:01.910021Z","shell.execute_reply":"2025-04-26T20:46:02.211156Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Transfer Learning Model\nbase_model = VGG16(weights='imagenet', include_top=False, input_shape=(*IMAGE_SIZE, 3))\nbase_model.trainable = False  # Freeze the base model\n\nadd_model = models.Sequential([\n    layers.Flatten(input_shape=base_model.output_shape[1:]),\n    layers.Dense(256, activation='relu'),\n    layers.Dropout(0.7),\n    layers.Dense(len(CLASSES), activation='softmax')\n])\n\nmodel = models.Model(inputs=base_model.input, outputs=add_model(base_model.output))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T20:46:02.212677Z","iopub.execute_input":"2025-04-26T20:46:02.212875Z","iopub.status.idle":"2025-04-26T20:46:02.474971Z","shell.execute_reply.started":"2025-04-26T20:46:02.212857Z","shell.execute_reply":"2025-04-26T20:46:02.474184Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Compile Model \nlearning_rate = 0.0001\noptimizer = Adam(learning_rate=learning_rate)\nloss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False)\nmetrics = ['accuracy']\n\nmodel.compile(optimizer=optimizer, loss=loss_fn, metrics=metrics)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T20:46:02.475801Z","iopub.execute_input":"2025-04-26T20:46:02.476064Z","iopub.status.idle":"2025-04-26T20:46:02.483832Z","shell.execute_reply.started":"2025-04-26T20:46:02.476042Z","shell.execute_reply":"2025-04-26T20:46:02.483017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training\nEPOCHS = 100\n\nSTEPS_PER_EPOCH = NUM_TRAINING_IMAGES // BATCH_SIZE\nVALIDATION_STEPS = NUM_VALIDATION_IMAGES // BATCH_SIZE\n\nhistory = model.fit(\n    ds_train,\n    epochs=EPOCHS,\n    steps_per_epoch=STEPS_PER_EPOCH,\n    validation_data=ds_valid,\n    validation_steps=VALIDATION_STEPS\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T21:20:07.558106Z","iopub.execute_input":"2025-04-26T21:20:07.558492Z","iopub.status.idle":"2025-04-26T23:05:10.732833Z","shell.execute_reply.started":"2025-04-26T21:20:07.558460Z","shell.execute_reply":"2025-04-26T23:05:10.732043Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T21:17:48.285861Z","iopub.execute_input":"2025-04-26T21:17:48.286229Z","iopub.status.idle":"2025-04-26T21:17:48.315874Z","shell.execute_reply.started":"2025-04-26T21:17:48.286193Z","shell.execute_reply":"2025-04-26T21:17:48.315232Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"loss, accuracy = model.evaluate(ds_valid)\nprint(f'Validation Loss: {loss:.4f}, Validation Accuracy: {accuracy:.4f}')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-04-26T21:17:48.316724Z","iopub.execute_input":"2025-04-26T21:17:48.317054Z","iopub.status.idle":"2025-04-26T21:18:03.687596Z","shell.execute_reply.started":"2025-04-26T21:17:48.317029Z","shell.execute_reply":"2025-04-26T21:18:03.686905Z"}},"outputs":[],"execution_count":null}]}