{"cells":[{"cell_type":"markdown","id":"1bba959e-b8d0-4dc2-b6a0-01b190efb3e4","metadata":{},"source":"EDA, classes, GPUs, Pipeline, Model building using VGG16 and Training"},{"cell_type":"code","execution_count":null,"id":"163f5856-01e2-4cf6-8c5f-5f99f3269bbd","metadata":{},"outputs":[],"source":"import tensorflow as tf\nimport os\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport re\nfrom sklearn.metrics import f1_score, precision_score, recall_score, confusion_matrix\n\n# Clear memory before starting\nimport gc\nfrom numba import cuda\n\ngc.collect()\ncuda.select_device(0)\ncuda.close()\nprint(\"Memory cleared and GPU reset.\")\n\n# Enable dynamic memory growth for GPUs\ngpus = tf.config.experimental.list_physical_devices('GPU')\nif gpus:\n    try:\n        for gpu in gpus:\n            tf.config.experimental.set_memory_growth(gpu, True)\n        print(f\"{len(gpus)} Physical GPUs set for memory growth.\")\n    except RuntimeError as e:\n        print(f\"Error setting memory growth: {e}\")\n\n# Constants\nIMAGE_SIZE = [512, 512]\nBATCH_SIZE = 8  # Reverted batch size to prevent OOM errors\nAUTO = tf.data.AUTOTUNE\n\n# Set directories\ntfrecord_dir = './tfrecords-jpeg-512x512'\nTRAINING_FILENAMES = tf.io.gfile.glob(os.path.join(tfrecord_dir, 'train', '*.tfrec'))\nVALIDATION_FILENAMES = tf.io.gfile.glob(os.path.join(tfrecord_dir, 'val', '*.tfrec'))\nTEST_FILENAMES = tf.io.gfile.glob(os.path.join(tfrecord_dir, 'test', '*.tfrec'))\n\n# Classes\nCLASSES = [\n    'pink primrose', 'hard-leaved pocket orchid', 'canterbury bells', 'sweet pea', 'wild geranium',\n    'tiger lily', 'moon orchid', 'bird of paradise', 'monkshood', 'globe thistle', \n    'snapdragon', \"colt's foot\", 'king protea', 'spear thistle', 'yellow iris', \n    'globe-flower', 'purple coneflower', 'peruvian lily', 'balloon flower', 'giant white arum lily',\n    'fire lily', 'pincushion flower', 'fritillary', 'red ginger', 'grape hyacinth', \n    'corn poppy', 'prince of wales feathers', 'stemless gentian', 'artichoke', 'sweet william', \n    'carnation', 'garden phlox', 'love in the mist', 'cosmos', 'alpine sea holly', \n    'ruby-lipped cattleya', 'cape flower', 'great masterwort', 'siam tulip', 'lenten rose', \n    'barberton daisy', 'daffodil', 'sword lily', 'poinsettia', 'bolero deep blue', \n    'wallflower', 'marigold', 'buttercup', 'daisy', 'common dandelion', \n    'petunia', 'wild pansy', 'primula', 'sunflower', 'lilac hibiscus', \n    'bishop of llandaff', 'gaura', 'geranium', 'orange dahlia', 'pink-yellow dahlia', \n    'cautleya spicata', 'japanese anemone', 'black-eyed susan', 'silverbush', 'californian poppy', \n    'osteospermum', 'spring crocus', 'iris', 'windflower', 'tree poppy', \n    'gazania', 'azalea', 'water lily', 'rose', 'thorn apple', \n    'morning glory', 'passion flower', 'lotus', 'toad lily', 'anthurium', \n    'frangipani', 'clematis', 'hibiscus', 'columbine', 'desert-rose', \n    'tree mallow', 'magnolia', 'cyclamen ', 'watercress', 'canna lily', \n    'hippeastrum ', 'bee balm', 'pink quill', 'foxglove', 'bougainvillea', \n    'camellia', 'mallow', 'mexican petunia', 'bromelia', 'blanket flower', \n    'trumpet creeper', 'blackberry lily', 'common tulip', 'wild rose'\n]\n\n# Functions to process TFRecord files\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.image.resize(image, IMAGE_SIZE)\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\n# Data pipeline functions\ndef data_augment(image, label):\n    image = tf.image.random_flip_left_right(image)\n    return image, label\n\ndef get_training_dataset():\n    dataset = tf.data.TFRecordDataset(TRAINING_FILENAMES, num_parallel_reads=AUTO)\n    dataset = dataset.map(read_labeled_tfrecord, num_parallel_calls=AUTO)\n    dataset = dataset.map(data_augment, num_parallel_calls=AUTO)\n    dataset = dataset.shuffle(2048).batch(BATCH_SIZE).prefetch(AUTO)\n    return dataset\n\ndef get_validation_dataset():\n    dataset = tf.data.TFRecordDataset(VALIDATION_FILENAMES, num_parallel_reads=AUTO)\n    dataset = dataset.map(read_labeled_tfrecord, num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE).prefetch(AUTO)\n    return dataset\n\ndef get_test_dataset():\n    dataset = tf.data.TFRecordDataset(TEST_FILENAMES, num_parallel_reads=AUTO)\n    dataset = dataset.map(read_unlabeled_tfrecord, num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE).prefetch(AUTO)\n    return dataset\n\n# Count function for dataset sizes\ndef count_data_items(filenames):\n    n = [int(re.search(r\"-(\\\\d+)\\\\.tfrec$\", os.path.basename(filename)).group(1)) for filename in filenames if re.search(r\"-(\\\\d+)\\\\.tfrec$\", os.path.basename(filename))]\n    return np.sum(n)\n\n# Dataset information\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(f'Dataset: {NUM_TRAINING_IMAGES} training images, {NUM_VALIDATION_IMAGES} validation images, {NUM_TEST_IMAGES} unlabeled test images')\n\n# Load datasets\nds_train = get_training_dataset()\nds_valid = get_validation_dataset()\nds_test = get_test_dataset()\n\n# Model building using VGG16\nEPOCHS = 12\npretrained_model = tf.keras.applications.VGG16(\n    weights='imagenet', include_top=False, input_shape=(512, 512, 3)\n)\npretrained_model.trainable = False\n\nmodel = tf.keras.Sequential([\n    pretrained_model,\n    tf.keras.layers.GlobalAveragePooling2D(),\n    tf.keras.layers.Dense(len(CLASSES), activation='softmax')\n])\n\n# Compile the model\nmodel.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])\nmodel.summary()\n\n# Train the model\nhistory = model.fit(\n    ds_train,\n    validation_data=ds_valid,\n    epochs=EPOCHS,\n    steps_per_epoch=NUM_TRAINING_IMAGES // BATCH_SIZE,\n    validation_steps=NUM_VALIDATION_IMAGES // BATCH_SIZE\n)\n\n# Save the model\nmodel.save('trained_model.h5')\n"},{"cell_type":"markdown","id":"cc6a1a21-51c9-4501-a390-ac918e1a66a6","metadata":{},"source":"Load the saved model, Evaluate predictions and generate confusion matrix, test predictions, and submission"},{"cell_type":"code","execution_count":null,"id":"2310b2ff-e39c-4242-8286-fb57072f813d","metadata":{},"outputs":[],"source":"import tensorflow as tf\nimport os\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport re\nfrom sklearn.metrics import f1_score, precision_score, recall_score, confusion_matrix\n\n# Clear memory before starting\nimport gc\nfrom numba import cuda\n\n# Close GPU and reset context\ntry:\n    cuda.select_device(0)\n    cuda.close()\n    print(\"Memory cleared and GPU reset.\")\nexcept cuda.cudadrv.error.CudaSupportError:\n    print(\"CUDA device not found or already reset.\")\n\n# Enable dynamic memory growth for GPUs\ngpus = tf.config.experimental.list_physical_devices('GPU')\nif gpus:\n    try:\n        for gpu in gpus:\n            tf.config.experimental.set_memory_growth(gpu, True)\n        print(f\"{len(gpus)} Physical GPUs set for memory growth.\")\n    except RuntimeError as e:\n        print(f\"Error setting memory growth: {e}\")\n\n# Constants\nIMAGE_SIZE = [512, 512]\nBATCH_SIZE = 8\nAUTO = tf.data.AUTOTUNE\n\n# Set directories\ntfrecord_dir = './tfrecords-jpeg-512x512'\nVALIDATION_FILENAMES = tf.io.gfile.glob(os.path.join(tfrecord_dir, 'val', '*.tfrec'))\nTEST_FILENAMES = tf.io.gfile.glob(os.path.join(tfrecord_dir, 'test', '*.tfrec'))\n\n# Classes\nCLASSES = [\n    'pink primrose', 'hard-leaved pocket orchid', 'canterbury bells', 'sweet pea', 'wild geranium',\n    'tiger lily', 'moon orchid', 'bird of paradise', 'monkshood', 'globe thistle', \n    'snapdragon', \"colt's foot\", 'king protea', 'spear thistle', 'yellow iris', \n    'globe-flower', 'purple coneflower', 'peruvian lily', 'balloon flower', 'giant white arum lily',\n    'fire lily', 'pincushion flower', 'fritillary', 'red ginger', 'grape hyacinth', \n    'corn poppy', 'prince of wales feathers', 'stemless gentian', 'artichoke', 'sweet william', \n    'carnation', 'garden phlox', 'love in the mist', 'cosmos', 'alpine sea holly', \n    'ruby-lipped cattleya', 'cape flower', 'great masterwort', 'siam tulip', 'lenten rose', \n    'barberton daisy', 'daffodil', 'sword lily', 'poinsettia', 'bolero deep blue', \n    'wallflower', 'marigold', 'buttercup', 'daisy', 'common dandelion', \n    'petunia', 'wild pansy', 'primula', 'sunflower', 'lilac hibiscus', \n    'bishop of llandaff', 'gaura', 'geranium', 'orange dahlia', 'pink-yellow dahlia', \n    'cautleya spicata', 'japanese anemone', 'black-eyed susan', 'silverbush', 'californian poppy', \n    'osteospermum', 'spring crocus', 'iris', 'windflower', 'tree poppy', \n    'gazania', 'azalea', 'water lily', 'rose', 'thorn apple', \n    'morning glory', 'passion flower', 'lotus', 'toad lily', 'anthurium', \n    'frangipani', 'clematis', 'hibiscus', 'columbine', 'desert-rose', \n    'tree mallow', 'magnolia', 'cyclamen ', 'watercress', 'canna lily', \n    'hippeastrum ', 'bee balm', 'pink quill', 'foxglove', 'bougainvillea', \n    'camellia', 'mallow', 'mexican petunia', 'bromelia', 'blanket flower', \n    'trumpet creeper', 'blackberry lily', 'common tulip', 'wild rose'\n]\n\n# Functions to process TFRecord files\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.image.resize(image, IMAGE_SIZE)\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\n# Data pipeline functions\ndef get_validation_dataset():\n    dataset = tf.data.TFRecordDataset(VALIDATION_FILENAMES, num_parallel_reads=AUTO)\n    dataset = dataset.map(read_labeled_tfrecord, num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE).prefetch(AUTO)\n    return dataset\n\ndef get_test_dataset():\n    dataset = tf.data.TFRecordDataset(TEST_FILENAMES, num_parallel_reads=AUTO)\n    dataset = dataset.map(read_unlabeled_tfrecord, num_parallel_calls=AUTO)\n    dataset = dataset.batch(BATCH_SIZE).prefetch(AUTO)\n    return dataset\n\n# Load the saved model\nmodel = tf.keras.models.load_model('trained_model.h5')\n\n# Load datasets\nds_valid = get_validation_dataset()\nds_test = get_test_dataset()\n\n# Evaluate predictions and generate confusion matrix\ncmdataset = ds_valid\nimages_ds = cmdataset.map(lambda image, label: image)\nlabels_ds = cmdataset.map(lambda image, label: label).unbatch()\n\nlabels_list = [label.numpy() for label in labels_ds]\nif labels_list:\n    cm_correct_labels = np.array(labels_list)\n    cm_probabilities = model.predict(images_ds)\n    cm_predictions = np.argmax(cm_probabilities, axis=-1)\n\n    if len(cm_correct_labels) != len(cm_predictions):\n        raise ValueError(f\"Inconsistent numbers of samples: {len(cm_correct_labels)} true labels vs {len(cm_predictions)} predictions.\")\n\n    labels = range(len(CLASSES))\n    cmat = confusion_matrix(cm_correct_labels, cm_predictions, labels=labels)\n    cmat = (cmat.T / cmat.sum(axis=1)).T\n\n    # Display confusion matrix\n    def display_confusion_matrix(cmat, score, precision, recall):\n        plt.figure(figsize=(15, 15))\n        ax = plt.gca()\n        ax.matshow(cmat, cmap='Reds')\n        ax.set_xticks(range(len(CLASSES)))\n        ax.set_xticklabels(CLASSES, fontsize=7, rotation=45, ha=\"left\")\n        ax.set_yticks(range(len(CLASSES)))\n        ax.set_yticklabels(CLASSES, fontsize=7, rotation=45, ha=\"right\")\n        titlestring = f'f1 = {score:.3f}\\nprecision = {precision:.3f}\\nrecall = {recall:.3f}'\n        ax.text(101, 1, titlestring, fontsize=18, color='#804040', ha='right', va='top')\n        plt.show()\n\n    score = f1_score(cm_correct_labels, cm_predictions, labels=labels, average='macro')\n    precision = precision_score(cm_correct_labels, cm_predictions, labels=labels, average='macro')\n    recall = recall_score(cm_correct_labels, cm_predictions, labels=labels, average='macro')\n\n    display_confusion_matrix(cmat, score, precision, recall)\nelse:\n    print(\"No validation data found to generate confusion matrix.\")\n\n# Make test predictions\ntest_ds = ds_test\nprint('Computing predictions...')\n\ntest_images_ds = test_ds.map(lambda image, idnum: image)\nprobabilities = model.predict(test_images_ds)\npredictions = np.argmax(probabilities, axis=-1)\n\n# Generate submission.csv\nprint('Generating submission.csv file...')\ntest_ids_ds = test_ds.map(lambda image, idnum: idnum).unbatch()\ntest_ids = np.array([idnum.numpy().decode('utf-8') for idnum in test_ids_ds])\n\nnp.savetxt('submission.csv', np.rec.fromarrays([test_ids, predictions]), fmt=['%s', '%d'], delimiter=',', header='id,label', comments='')\n\n# Display first few predictions\nos.system('head submission.csv')\n"},{"cell_type":"code","execution_count":null,"id":"d463d1a1-7c79-4b0b-b548-a945f7c353b6","metadata":{},"outputs":[],"source":""},{"cell_type":"code","execution_count":null,"id":"d5de8e68-f65e-4aed-ba5c-bc5688a4e0ed","metadata":{},"outputs":[],"source":""},{"cell_type":"code","execution_count":null,"id":"6465ffaf-d950-4530-bfa7-fc5f1973b4ef","metadata":{},"outputs":[],"source":""},{"cell_type":"code","execution_count":null,"id":"5c9c1e37-9e14-46c9-ab75-1027948f4703","metadata":{},"outputs":[],"source":""},{"cell_type":"code","execution_count":null,"id":"01e5f5d5-c77c-4cb3-9993-eb5b5ecf2e2c","metadata":{},"outputs":[],"source":""}],"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.16"}},"nbformat":4,"nbformat_minor":5}