{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.9","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":13836,"databundleVersionId":1718836,"sourceType":"competition"}],"dockerImageVersionId":30060,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport tensorflow as tf\nimport tensorflow_addons as tfa\nimport glob, warnings\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, classification_report\nimport seaborn as sns\nimport tensorflow as tf\nfrom tensorflow.keras.applications import VGG16\nfrom tensorflow.keras import layers, models\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, classification_report\nimport seaborn as sns\n\nwarnings.filterwarnings('ignore')\nprint('TensorFlow Version ' + tf.__version__)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:54:59.727183Z","iopub.execute_input":"2025-02-26T17:54:59.727503Z","iopub.status.idle":"2025-02-26T17:55:10.034140Z","shell.execute_reply.started":"2025-02-26T17:54:59.727414Z","shell.execute_reply":"2025-02-26T17:55:10.032796Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMAGE_SIZE = 224\nBATCH_SIZE = 16\nEPOCHS = 5\n\nTRAIN_PATH = '/kaggle/input/cassava-leaf-disease-classification/train_images'\nTEST_PATH = '/kaggle/input/cassava-leaf-disease-classification/test_images'\n\nDF_TRAIN = pd.read_csv('/kaggle/input/cassava-leaf-disease-classification/train.csv', dtype='str')\nTEST_IMAGES = glob.glob(TEST_PATH + '/*.jpg')\nDF_TEST = pd.DataFrame(TEST_IMAGES, columns = ['image_path'])\n\nclasses = {0 : \"Cassava Bacterial Blight (CBB)\",\n           1 : \"Cassava Brown Streak Disease (CBSD)\",\n           2 : \"Cassava Green Mottle (CGM)\",\n           3 : \"Cassava Mosaic Disease (CMD)\",\n           4 : \"Healthy\"}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:55:13.821883Z","iopub.execute_input":"2025-02-26T17:55:13.822197Z","iopub.status.idle":"2025-02-26T17:55:13.863052Z","shell.execute_reply.started":"2025-02-26T17:55:13.822157Z","shell.execute_reply":"2025-02-26T17:55:13.862151Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Data Augmentations","metadata":{}},{"cell_type":"code","source":"def data_augment(image):\n    p_spatial = tf.random.uniform([], 0, 1.0, dtype = tf.float32)\n    p_rotate = tf.random.uniform([], 0, 1.0, dtype = tf.float32)\n    p_pixel_1 = tf.random.uniform([], 0, 1.0, dtype = tf.float32)\n    p_pixel_2 = tf.random.uniform([], 0, 1.0, dtype = tf.float32)\n    p_pixel_3 = tf.random.uniform([], 0, 1.0, dtype = tf.float32)\n    \n    # Flips\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_flip_up_down(image)\n    \n    if p_spatial > .75:\n        image = tf.image.transpose(image)\n        \n    # Rotates\n    if p_rotate > .75:\n        image = tf.image.rot90(image, k = 3) # rotate 270º\n    elif p_rotate > .5:\n        image = tf.image.rot90(image, k = 2) # rotate 180º\n    elif p_rotate > .25:\n        image = tf.image.rot90(image, k = 1) # rotate 90º\n        \n    # Pixel-level transforms\n    if p_pixel_1 >= .4:\n        image = tf.image.random_saturation(image, lower = .7, upper = 1.3)\n    if p_pixel_2 >= .4:\n        image = tf.image.random_contrast(image, lower = .8, upper = 1.2)\n    if p_pixel_3 >= .4:\n        image = tf.image.random_brightness(image, max_delta = .1)\n        \n    return image","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:55:17.698112Z","iopub.execute_input":"2025-02-26T17:55:17.698436Z","iopub.status.idle":"2025-02-26T17:55:17.706354Z","shell.execute_reply.started":"2025-02-26T17:55:17.698399Z","shell.execute_reply":"2025-02-26T17:55:17.705141Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Data Generator","metadata":{}},{"cell_type":"code","source":"datagen = tf.keras.preprocessing.image.ImageDataGenerator(rescale = 1./255,\n                                                          samplewise_center = True,\n                                                          samplewise_std_normalization = True,\n                                                          validation_split = 0.2,\n                                                          preprocessing_function = data_augment)\n\ntrain_gen = datagen.flow_from_dataframe(dataframe = DF_TRAIN,\n                                        directory = TRAIN_PATH,\n                                        x_col = 'image_id',\n                                        y_col = 'label',\n                                        subset = 'training',\n                                        batch_size = BATCH_SIZE,\n                                        seed = 1,\n                                        color_mode = 'rgb',\n                                        shuffle = True,\n                                        class_mode = 'categorical',\n                                        target_size = (IMAGE_SIZE, IMAGE_SIZE))\n\nvalid_gen = datagen.flow_from_dataframe(dataframe = DF_TRAIN,\n                                        directory = TRAIN_PATH,\n                                        x_col = 'image_id',\n                                        y_col = 'label',\n                                        subset = 'validation',\n                                        batch_size = BATCH_SIZE,\n                                        seed = 1,\n                                        color_mode = 'rgb',\n                                        shuffle = False,\n                                        class_mode = 'categorical',\n                                        target_size = (IMAGE_SIZE, IMAGE_SIZE))\n\ntest_gen = datagen.flow_from_dataframe(dataframe = DF_TEST,\n                                       x_col = 'image_path',\n                                       y_col = None,\n                                       batch_size = BATCH_SIZE,\n                                       seed = 1,\n                                       color_mode = 'rgb',\n                                       shuffle = False,\n                                       class_mode = None,\n                                       target_size = (IMAGE_SIZE, IMAGE_SIZE))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:55:20.987394Z","iopub.execute_input":"2025-02-26T17:55:20.987709Z","iopub.status.idle":"2025-02-26T17:56:10.244868Z","shell.execute_reply.started":"2025-02-26T17:55:20.987679Z","shell.execute_reply":"2025-02-26T17:56:10.243710Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"images = [train_gen[0][0][i] for i in range(16)]\nfig, axes = plt.subplots(3, 5, figsize = (10, 10))\n\naxes = axes.flatten()\n\nfor img, ax in zip(images, axes):\n    ax.imshow(img.reshape(IMAGE_SIZE, IMAGE_SIZE, 3))\n    ax.axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:56:18.977029Z","iopub.execute_input":"2025-02-26T17:56:18.977312Z","iopub.status.idle":"2025-02-26T17:56:23.079327Z","shell.execute_reply.started":"2025-02-26T17:56:18.977285Z","shell.execute_reply":"2025-02-26T17:56:23.077704Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Building the Model","metadata":{}},{"cell_type":"code","source":"vgg_model = VGG16(\n    weights=\"imagenet\",\n    include_top=False,\n    input_shape=(IMAGE_SIZE, IMAGE_SIZE, 3)\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:56:42.801962Z","iopub.execute_input":"2025-02-26T17:56:42.802327Z","iopub.status.idle":"2025-02-26T17:56:43.596248Z","shell.execute_reply.started":"2025-02-26T17:56:42.802294Z","shell.execute_reply":"2025-02-26T17:56:43.593704Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 1. Vgg Model\n","metadata":{}},{"cell_type":"code","source":"vgg_model.trainable = False\n\n# Add custom layers for fine-tuning\nmodel = tf.keras.Sequential([\n    vgg_model,\n    layers.Flatten(),\n    layers.BatchNormalization(),\n    layers.Dense(256, activation=\"relu\"),\n    layers.BatchNormalization(),\n    layers.Dense(5, activation=\"softmax\")  # 5 classes for Cassava Leaf Disease\n], name=\"vgg16_model\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:56:49.051419Z","iopub.execute_input":"2025-02-26T17:56:49.051750Z","iopub.status.idle":"2025-02-26T17:56:49.193111Z","shell.execute_reply.started":"2025-02-26T17:56:49.051719Z","shell.execute_reply":"2025-02-26T17:56:49.192098Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Print model summary\nmodel.summary()\n\n# Compile the model\nlearning_rate = 1e-4\noptimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate)\n\nmodel.compile(\n    optimizer=optimizer,\n    loss=tf.keras.losses.CategoricalCrossentropy(label_smoothing=0.2),\n    metrics=[\"accuracy\"]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:56:52.367335Z","iopub.execute_input":"2025-02-26T17:56:52.367658Z","iopub.status.idle":"2025-02-26T17:56:52.392614Z","shell.execute_reply.started":"2025-02-26T17:56:52.367627Z","shell.execute_reply":"2025-02-26T17:56:52.391815Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Visualizing Attention Maps of Sample Test Image","metadata":{}},{"cell_type":"markdown","source":"## 2. Fine-tuning the Model","metadata":{}},{"cell_type":"code","source":"# Define callbacks\nreduce_lr = tf.keras.callbacks.ReduceLROnPlateau(\n    monitor=\"val_accuracy\",\n    factor=0.2,\n    patience=2,\n    verbose=1,\n    min_delta=1e-4,\n    min_lr=1e-6,\n    mode=\"max\",\n)\n\nearlystopping = tf.keras.callbacks.EarlyStopping(\n    monitor=\"val_accuracy\",\n    min_delta=1e-4,\n    patience=5,\n    mode=\"max\",\n    restore_best_weights=True,\n    verbose=1,\n)\n\ncheckpointer = tf.keras.callbacks.ModelCheckpoint(\n    filepath=\"./vgg16_model.hdf5\",\n    monitor=\"val_accuracy\",\n    verbose=1,\n    save_best_only=True,\n    save_weights_only=True,\n    mode=\"max\",\n)\n\ncallbacks = [earlystopping, reduce_lr, checkpointer]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:57:02.688616Z","iopub.execute_input":"2025-02-26T17:57:02.688950Z","iopub.status.idle":"2025-02-26T17:57:02.695342Z","shell.execute_reply.started":"2025-02-26T17:57:02.688917Z","shell.execute_reply":"2025-02-26T17:57:02.694280Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train the model\nSTEP_SIZE_TRAIN = train_gen.n // train_gen.batch_size\nSTEP_SIZE_VALID = valid_gen.n // valid_gen.batch_size\n\nhistory = model.fit(\n    x=train_gen,\n    steps_per_epoch=STEP_SIZE_TRAIN,\n    validation_data=valid_gen,\n    validation_steps=STEP_SIZE_VALID,\n    epochs=EPOCHS,\n    callbacks=callbacks,\n)\nmodel.save(\"vgg16_model.h5\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-26T17:57:06.557524Z","iopub.execute_input":"2025-02-26T17:57:06.557823Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Evaluate the model\npredicted_classes = np.argmax(\n    model.predict(valid_gen, steps=valid_gen.n // valid_gen.batch_size + 1), axis=1\n)\ntrue_classes = valid_gen.classes\nclass_labels = list(valid_gen.class_indices.keys())\n\n# Confusion matrix\nconfusionmatrix = confusion_matrix(true_classes, predicted_classes)\nplt.figure(figsize=(16, 16))\nsns.heatmap(confusionmatrix, cmap=\"Blues\", annot=True, cbar=True)\nplt.xlabel(\"Predicted\")\nplt.ylabel(\"True\")\nplt.title(\"Confusion Matrix\")\nplt.show()\n\n# Classification report\nprint(classification_report(true_classes, predicted_classes, target_names=class_labels))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Plot training and validation accuracy\nplt.plot(history.history[\"accuracy\"], label=\"Training Accuracy\")\nplt.plot(history.history[\"val_accuracy\"], label=\"Validation Accuracy\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Accuracy\")\nplt.title(\"Training and Validation Accuracy\")\nplt.legend()\nplt.show()\n\n# Plot training and validation loss\nplt.plot(history.history[\"loss\"], label=\"Training Loss\")\nplt.plot(history.history[\"val_loss\"], label=\"Validation Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.title(\"Training and Validation Loss\")\nplt.legend()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model Results","metadata":{}}]}