{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":13836,"databundleVersionId":1718836,"sourceType":"competition"}],"dockerImageVersionId":31154,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 🌱 Cassava Leaf Disease Classification","metadata":{}},{"cell_type":"markdown","source":"## 🧩 Overview\n\nCassava is a vital food crop in many regions, but its yield is significantly affected by various leaf diseases.  \nEarly detection of these diseases is crucial to prevent crop loss.  \n\nThis project aims to build a **deep learning-based image classification model** to automatically identify different types of cassava leaf diseases from leaf images, enabling timely intervention and better crop management.\n","metadata":{}},{"cell_type":"markdown","source":"## 🛠️ Importing Necessary Modules","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nimport shutil\nfrom tqdm.notebook import tqdm\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.applications import EfficientNetB3\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nfrom tensorflow.keras import callbacks, optimizers, losses, metrics\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T18:25:00.610525Z","iopub.execute_input":"2025-10-07T18:25:00.611009Z","iopub.status.idle":"2025-10-07T18:25:00.616352Z","shell.execute_reply.started":"2025-10-07T18:25:00.610978Z","shell.execute_reply":"2025-10-07T18:25:00.615493Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 📊 Data Analysis\n\n- Load the dataset and check the number of images per class.   \n- Check for class imbalance, image sizes, and any missing or corrupted files.\n","metadata":{}},{"cell_type":"code","source":"labels_df = pd.read_csv('/kaggle/input/cassava-leaf-disease-classification/train.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:11:39.002668Z","iopub.execute_input":"2025-10-07T17:11:39.002972Z","iopub.status.idle":"2025-10-07T17:11:39.022264Z","shell.execute_reply.started":"2025-10-07T17:11:39.002951Z","shell.execute_reply":"2025-10-07T17:11:39.021199Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:11:40.752321Z","iopub.execute_input":"2025-10-07T17:11:40.752679Z","iopub.status.idle":"2025-10-07T17:11:40.769250Z","shell.execute_reply.started":"2025-10-07T17:11:40.752657Z","shell.execute_reply":"2025-10-07T17:11:40.768242Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"labels_df['label'].value_counts()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:11:43.549988Z","iopub.execute_input":"2025-10-07T17:11:43.550851Z","iopub.status.idle":"2025-10-07T17:11:43.561062Z","shell.execute_reply.started":"2025-10-07T17:11:43.550820Z","shell.execute_reply":"2025-10-07T17:11:43.560173Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ncounts = labels_df['label'].value_counts() \n\nplt.figure(figsize=(8,5))\nplt.bar(counts.index, counts.values) \nplt.xlabel('Labels')\nplt.ylabel('Count')\nplt.title('Count of each label')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:11:51.808276Z","iopub.execute_input":"2025-10-07T17:11:51.808946Z","iopub.status.idle":"2025-10-07T17:11:52.056723Z","shell.execute_reply.started":"2025-10-07T17:11:51.808919Z","shell.execute_reply":"2025-10-07T17:11:52.055947Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CSV_PATH = '/kaggle/input/cassava-leaf-disease-classification/train.csv'\nSOURCE_IMAGE_DIR = '/kaggle/input/cassava-leaf-disease-classification/train_images'\nOUTPUT_DIR = '/kaggle/working/data'\n\ntry:\n    train_df = pd.read_csv(CSV_PATH)\n    print(\"✅ Successfully loaded train.csv.\")\n    print(f\"DataFrame contains {len(train_df)} records.\")\nexcept FileNotFoundError:\n    print(f\"Error: Could not find train.csv at {CSV_PATH}\")\n    train_df = pd.DataFrame()\n\nif not train_df.empty:\n    print(f\"\\nCreating base directory at: {OUTPUT_DIR}\")\n    os.makedirs(OUTPUT_DIR, exist_ok=True)\n\n    unique_labels = sorted(train_df['label'].unique())\n    \n    print(f\"Found unique labels: {unique_labels}\")\n    for label in unique_labels:\n        label_dir = os.path.join(OUTPUT_DIR, str(label))\n        os.makedirs(label_dir, exist_ok=True)\n    \n    print(f\"✅ Created {len(unique_labels)} subdirectories for each label.\")\n\n    print(\"\\nStarting to copy images. This may take a few minutes...\")\n    \n    for index, row in tqdm(train_df.iterrows(), total=train_df.shape[0]):\n        image_filename = row['image_id']\n        label = str(row['label'])\n        \n        source_path = os.path.join(SOURCE_IMAGE_DIR, image_filename)\n        destination_path = os.path.join(OUTPUT_DIR, label, image_filename)\n        \n        shutil.copy(source_path, destination_path)\n        \n    print(\"\\n🎉 Successfully sorted all images into their label folders!\")\n\n    print(\"\\nVerifying the new directory structure...\")\n    created_dirs = sorted(os.listdir(OUTPUT_DIR))\n    print(f\"Folders in output directory: {created_dirs}\")\n\n    sample_label = str(unique_labels[0])\n    sample_dir_path = os.path.join(OUTPUT_DIR, sample_label)\n    num_files = len(os.listdir(sample_dir_path))\n    print(f\"Found {num_files} images in the '{sample_label}' folder.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:09:06.012118Z","iopub.execute_input":"2025-10-07T17:09:06.012468Z","iopub.status.idle":"2025-10-07T17:11:19.115766Z","shell.execute_reply.started":"2025-10-07T17:09:06.012443Z","shell.execute_reply":"2025-10-07T17:11:19.114837Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_DIR = '/kaggle/working/data'\nIMG_HEIGHT = 300\nIMG_WIDTH = 300\nBATCH_SIZE = 32\nVALIDATION_SPLIT = 0.2\n\ntrain_ds = tf.keras.utils.image_dataset_from_directory(\n    DATA_DIR,\n    labels='inferred',\n    label_mode='int',\n    validation_split=VALIDATION_SPLIT,\n    subset='training',\n    seed=123,\n    image_size=(IMG_HEIGHT, IMG_WIDTH),\n    batch_size=BATCH_SIZE\n)\n\nval_ds = tf.keras.utils.image_dataset_from_directory(\n    DATA_DIR,\n    labels='inferred',\n    label_mode='int',\n    validation_split=VALIDATION_SPLIT,\n    subset='validation',\n    seed=123,\n    image_size=(IMG_HEIGHT, IMG_WIDTH),\n    batch_size=BATCH_SIZE\n)\n\nprint(\"✅ Datasets created successfully.\")\n\nclass_names = train_ds.class_names\nprint(f\"\\nInferred class names: {class_names}\")\n\nprint(\"\\nVerifying a batch from the training dataset:\")\nfor images, labels in train_ds.take(1):\n    print(f\"Images batch shape: {images.shape}\")\n    print(f\"Labels batch shape: {labels.shape}\")\n\nAUTOTUNE = tf.data.AUTOTUNE\ntrain_ds = train_ds.prefetch(buffer_size=AUTOTUNE)\nval_ds = val_ds.prefetch(buffer_size=AUTOTUNE)\n\nprint(\"\\n✅ Performance optimization applied to both datasets.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:11:34.204009Z","iopub.execute_input":"2025-10-07T17:11:34.204602Z","iopub.status.idle":"2025-10-07T17:11:35.731154Z","shell.execute_reply.started":"2025-10-07T17:11:34.204569Z","shell.execute_reply":"2025-10-07T17:11:35.730408Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 🏷️ Class Mapping\n\nThe dataset consists of **five classes** of cassava leaf conditions, represented by numeric labels `0` to `4`. The mapping is as follows:\n\n- **0: Cassava Bacterial Blight (CBB)** – A bacterial infection causing leaf wilting, yellowing, and necrosis.  \n- **1: Cassava Brown Streak Disease (CBSD)** – A viral disease leading to brown streaks on stems and yellowing leaves.  \n- **2: Cassava Green Mottle (CGM)** – A viral infection causing mottled green patches and distorted leaves.  \n- **3: Cassava Mosaic Disease (CMD)** – A common viral disease resulting in mosaic patterns on leaves and stunted growth.  \n- **4: Healthy** – Leaves without any visible signs of disease.  \n\nThis mapping is crucial for interpreting model predictions and understanding the type of disease present in the leaf images.\n","metadata":{}},{"cell_type":"code","source":"class_map = {\n    '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'\n}\n\ndef plot_class_samples(label_index, dataset = train_ds, class_map = class_map, num_images=9):\n    target_label_name = class_map[str(label_index)]\n    \n    filtered_ds = dataset.unbatch().filter(lambda image, label: label == label_index)\n    \n    images_to_plot = [image.numpy() for image, label in filtered_ds.take(num_images)]\n    \n    if images_to_plot:\n        print(f\"Displaying {len(images_to_plot)} sample images for class: {target_label_name}\")\n        \n        grid_size = int(np.ceil(np.sqrt(len(images_to_plot))))\n        plt.figure(figsize=(grid_size * 3, grid_size * 3))\n        \n        for i, img in enumerate(images_to_plot):\n            ax = plt.subplot(grid_size, grid_size, i + 1)\n            plt.imshow(img.astype(\"uint8\"))\n            plt.axis(\"off\")\n        \n        plt.tight_layout()\n        plt.show()\n    else:\n        print(f\"Could not find any images for label {label_index} ({target_label_name}).\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:12:05.083108Z","iopub.execute_input":"2025-10-07T17:12:05.083729Z","iopub.status.idle":"2025-10-07T17:12:05.091128Z","shell.execute_reply.started":"2025-10-07T17:12:05.083699Z","shell.execute_reply":"2025-10-07T17:12:05.090103Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🔍 Exploratory Data Analysis (EDA)","metadata":{}},{"cell_type":"markdown","source":"## 1️⃣ Cassava Bacterial Blight (CBB)\n\n- Look for **wilting leaves**, **yellowing**, and **necrotic spots**.  \n- The disease often starts from the edges and moves inward.  \n- Sample images can help visualize typical patterns for this class.\n","metadata":{}},{"cell_type":"code","source":"plot_class_samples(0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T16:47:50.789990Z","iopub.execute_input":"2025-10-07T16:47:50.790781Z","iopub.status.idle":"2025-10-07T16:47:51.935305Z","shell.execute_reply.started":"2025-10-07T16:47:50.790752Z","shell.execute_reply":"2025-10-07T16:47:51.934311Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2️⃣ Cassava Brown Streak Disease (CBSD)\n\n- Characterized by **brown streaks on stems** and **yellowing of older leaves**.  \n- Leaves may appear **blotchy** with irregular brown patches.  \n- Visual inspection of several images helps understand its variability.\n","metadata":{}},{"cell_type":"code","source":"plot_class_samples(1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T16:48:02.874316Z","iopub.execute_input":"2025-10-07T16:48:02.875059Z","iopub.status.idle":"2025-10-07T16:48:03.887437Z","shell.execute_reply.started":"2025-10-07T16:48:02.875031Z","shell.execute_reply":"2025-10-07T16:48:03.886568Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3️⃣ Cassava Green Mottle (CGM)\n\n- Shows **mottled green patches** on leaves.  \n- Leaves may be **distorted or curled**.  \n- The pattern is less uniform than other diseases, making it a bit harder to identify.\n","metadata":{}},{"cell_type":"code","source":"plot_class_samples(2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T16:48:10.124926Z","iopub.execute_input":"2025-10-07T16:48:10.125457Z","iopub.status.idle":"2025-10-07T16:48:11.133120Z","shell.execute_reply.started":"2025-10-07T16:48:10.125428Z","shell.execute_reply":"2025-10-07T16:48:11.132049Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 4️⃣ Cassava Mosaic Disease (CMD)\n\n- Displays a **mosaic-like pattern** on leaves.  \n- Leaves often show **patchy yellow and green areas**, with stunted growth.  \n- Recognizable by the distinct contrast between healthy and infected areas.\n","metadata":{}},{"cell_type":"code","source":"plot_class_samples(3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T16:48:23.801084Z","iopub.execute_input":"2025-10-07T16:48:23.801915Z","iopub.status.idle":"2025-10-07T16:48:24.630690Z","shell.execute_reply.started":"2025-10-07T16:48:23.801887Z","shell.execute_reply":"2025-10-07T16:48:24.629575Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 5️⃣ Healthy\n\n- Leaves are **fully green**, with no discoloration, spots, or patterns.  \n- Useful as a reference to compare against diseased classes.  \n- Helps the model learn to distinguish normal leaf patterns from infections.\n","metadata":{}},{"cell_type":"code","source":"plot_class_samples(4)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T16:48:35.119735Z","iopub.execute_input":"2025-10-07T16:48:35.120337Z","iopub.status.idle":"2025-10-07T16:48:36.049476Z","shell.execute_reply.started":"2025-10-07T16:48:35.120314Z","shell.execute_reply":"2025-10-07T16:48:36.048440Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 🏋️ Training","metadata":{}},{"cell_type":"markdown","source":"## 🔹 Model Building","metadata":{}},{"cell_type":"code","source":"IMG_SIZE = 300\nNUM_CLASSES = 5\nEPOCHS = 5\n\ndata_augmentation = keras.Sequential([\n    layers.RandomFlip(\"horizontal_and_vertical\"),\n    layers.RandomRotation(0.2),\n], name=\"data_augmentation\")\n\nbase_model = EfficientNetB3(\n    include_top=False,\n    weights='imagenet',\n    input_shape=(IMG_SIZE, IMG_SIZE, 3)\n)\nbase_model.trainable = False\n\nmodel = keras.Sequential([\n    layers.InputLayer(input_shape=(IMG_SIZE, IMG_SIZE, 3)),\n    data_augmentation,\n    base_model,\n    layers.GlobalAveragePooling2D(),\n    layers.Dense(256, activation='relu'),\n    layers.Dropout(0.3),\n    layers.Dense(NUM_CLASSES, activation='softmax')\n])\n\nmodel.summary()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T18:16:52.091601Z","iopub.execute_input":"2025-10-07T18:16:52.092352Z","iopub.status.idle":"2025-10-07T18:16:54.725891Z","shell.execute_reply.started":"2025-10-07T18:16:52.092326Z","shell.execute_reply":"2025-10-07T18:16:54.725039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(\n    optimizer=optimizers.Adam(learning_rate=1e-3),\n    loss=losses.SparseCategoricalCrossentropy(),\n    metrics=[metrics.SparseCategoricalAccuracy()]\n)\n\nreduce_lr = callbacks.ReduceLROnPlateau(\n    monitor='val_loss',\n    factor=0.5,\n    patience=3,\n    verbose=1,\n    min_lr=1e-6\n)\n\nearly_stop = callbacks.EarlyStopping(\n    monitor='val_loss',\n    patience=5,\n    verbose=1,\n    restore_best_weights=True\n)\n\ncheckpoint = callbacks.ModelCheckpoint(\n    'best_cassava_model.h5',\n    monitor='val_loss',\n    save_best_only=True,\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:36:33.280504Z","iopub.execute_input":"2025-10-07T17:36:33.281154Z","iopub.status.idle":"2025-10-07T17:36:33.294895Z","shell.execute_reply.started":"2025-10-07T17:36:33.281129Z","shell.execute_reply":"2025-10-07T17:36:33.294175Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"For this project, I experimented with multiple approaches to find the most effective architecture for cassava leaf disease classification:\n\n1. **Self-made CNN architectures** – I designed several custom convolutional neural networks from scratch.  \n2. **Transfer Learning on Pre-trained Models** – I tested popular models such as **EfficientNetB3**, **XceptionNet**, and **ResNet50**.  \n3. **Final Choice: EfficientNetB3** – After comparing the performance, **EfficientNetB3 gave the best accuracy and generalization** for this dataset. Its lightweight design and ability to extract fine-grained features made it ideal for leaf disease classification.\n\n**EfficientNetB3 Overview:**  \n- EfficientNetB3 is a **convolutional neural network** that scales width, depth, and resolution efficiently.  \n- Pre-trained on ImageNet, it provides strong feature extraction capabilities.  \n- Using **transfer learning**, I froze the base model initially and trained custom top layers for the 5 classes.  ","metadata":{}},{"cell_type":"markdown","source":"## 🔹 Model Training\n- The input images were resized to **300×300×3** and augmented with horizontal/vertical flips and random rotations.  \n- Top layers included **GlobalAveragePooling**, **Dense layers**, and **Dropout** to prevent overfitting.  \n- The model was compiled with **Adam optimizer**, **categorical crossentropy**, and metrics like **accuracy**. ","metadata":{}},{"cell_type":"code","source":"print(\"\\nStarting model training\")\nhistory = model.fit(\n    train_ds,\n    validation_data=val_ds,\n    epochs=EPOCHS,\n    callbacks=[reduce_lr, early_stop, checkpoint]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:36:37.485199Z","iopub.execute_input":"2025-10-07T17:36:37.485848Z","iopub.status.idle":"2025-10-07T17:51:38.507206Z","shell.execute_reply.started":"2025-10-07T17:36:37.485823Z","shell.execute_reply":"2025-10-07T17:51:38.506190Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 📊 Training & Validation Plots\n\nAfter training, the model's performance was visualized using the following metrics:\n\n- **Accuracy** – Shows how well the model is classifying images correctly.  \n- **Loss** – Indicates the error between predicted and actual labels.  ","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(8, 6))\nplt.plot(history.history['sparse_categorical_accuracy'], label='Training Accuracy')\nplt.plot(history.history['val_sparse_categorical_accuracy'], label='Validation Accuracy')\nplt.title('Training vs Validation Accuracy')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend()\nplt.grid(True)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:54:28.756712Z","iopub.execute_input":"2025-10-07T17:54:28.757068Z","iopub.status.idle":"2025-10-07T17:54:28.980090Z","shell.execute_reply.started":"2025-10-07T17:54:28.757045Z","shell.execute_reply":"2025-10-07T17:54:28.979260Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(8, 6))\nplt.plot(history.history['loss'], label='Training Loss')\nplt.plot(history.history['val_loss'], label='Validation Loss')\nplt.title('Training vs Validation Loss')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend()\nplt.grid(True)\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-07T17:54:44.209892Z","iopub.execute_input":"2025-10-07T17:54:44.210992Z","iopub.status.idle":"2025-10-07T17:54:44.437356Z","shell.execute_reply.started":"2025-10-07T17:54:44.210959Z","shell.execute_reply":"2025-10-07T17:54:44.436424Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# ✅ Conclusion & Links\n\nThe **Cassava Leaf Disease Classification** project successfully demonstrates how **deep learning and transfer learning** can be used to identify leaf diseases with high accuracy.  \n\nKey takeaways:  \n- Transfer learning with **EfficientNetB3** outperformed self-made architectures and other pre-trained models.  \n- Data augmentation and proper training strategies improved generalization.  \n\n### 🔗 Useful Links\n- **Portfolio:** [https://portfolio-govind9825s-projects.vercel.app/](https://portfolio-govind9825s-projects.vercel.app/)  \n- **GitHub Repository:** [https://github.com/Govind9825](https://github.com/Govind9825)\n","metadata":{}}]}