{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","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":31236,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"\n\nimport os, cv2, json, numpy as np, pandas as pd, matplotlib.pyplot as plt\n\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score\nfrom sklearn.utils.class_weight import compute_class_weight\n\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import (Conv2D, DepthwiseConv2D, BatchNormalization,\n                                     GlobalAveragePooling2D, Dense, Dropout, ReLU)\nfrom tensorflow.keras.applications import VGG16, MobileNetV2, Xception\nfrom tensorflow.keras.optimizers import Adam\n\n# ---------------- PATHS ----------------\nBASE_PATH = \"/kaggle/input/cassava-leaf-disease-classification\"\nIMG_DIR = os.path.join(BASE_PATH, \"train_images\")\nCSV_PATH = os.path.join(BASE_PATH, \"train.csv\")\nLABEL_MAP_PATH = os.path.join(BASE_PATH, \"label_num_to_disease_map.json\")\n\n# ---------------- LOAD DATA ----------------\ndf = pd.read_csv(CSV_PATH)\ndf[\"label\"] = df[\"label\"].astype(str)\n\nwith open(LABEL_MAP_PATH) as f:\n    label_map = json.load(f)\n\n# ---------------- DATA GENERATOR ----------------\nIMG_SIZE = (224,224)\nBATCH_SIZE = 32\n\ndatagen = ImageDataGenerator(rescale=1./255, validation_split=0.2)\n\ntrain_loader = datagen.flow_from_dataframe(\n    df, IMG_DIR, \"image_id\", \"label\",\n    target_size=IMG_SIZE, batch_size=BATCH_SIZE,\n    class_mode=\"categorical\", subset=\"training\"\n)\n\nval_loader = datagen.flow_from_dataframe(\n    df, IMG_DIR, \"image_id\", \"label\",\n    target_size=IMG_SIZE, batch_size=BATCH_SIZE,\n    class_mode=\"categorical\", subset=\"validation\", shuffle=False\n)\n\nnum_classes = len(train_loader.class_indices)\n\n# ---------------- CLASS WEIGHTS (FIXED FOR NEW SKLEARN) ----------------\nclass_weights_arr = compute_class_weight(\n    class_weight=\"balanced\",\n    classes=np.unique(df[\"label\"]),\n    y=df[\"label\"]\n)\nclass_weights = dict(enumerate(class_weights_arr))\n\n# ---------------- MODEL FACTORY ----------------\ndef build_model(name):\n    if name == \"VGG16\":\n        base = VGG16(weights=\"imagenet\", include_top=False, input_shape=(224,224,3))\n        base.trainable = False\n        return Sequential([base, GlobalAveragePooling2D(),\n                           Dense(num_classes, activation=\"softmax\")])\n\n    if name == \"MobileNetV2\":\n        base = MobileNetV2(weights=\"imagenet\", include_top=False, input_shape=(224,224,3))\n        base.trainable = False\n        return Sequential([base, GlobalAveragePooling2D(),\n                           Dense(num_classes, activation=\"softmax\")])\n\n    if name == \"Xception\":\n        base = Xception(weights=\"imagenet\", include_top=False, input_shape=(224,224,3))\n        base.trainable = False\n        return Sequential([base, GlobalAveragePooling2D(),\n                           Dense(num_classes, activation=\"softmax\")])\n\n    if name == \"ShuffleNetV2\":  # lightweight approximation\n        return Sequential([\n            Conv2D(32,3,strides=2,padding=\"same\",input_shape=(224,224,3)),\n            DepthwiseConv2D(3,padding=\"same\"),\n            BatchNormalization(), ReLU(),\n            Conv2D(64,1),\n            GlobalAveragePooling2D(),\n            Dense(num_classes, activation=\"softmax\")\n        ])\n\n    if name == \"ULEN\":  # Compressed CNN\n        return Sequential([\n            Conv2D(32,3,strides=2,padding=\"same\",input_shape=(224,224,3)),\n            BatchNormalization(), ReLU(),\n            DepthwiseConv2D(3,padding=\"same\"),\n            BatchNormalization(), ReLU(),\n            Conv2D(64,1),\n            DepthwiseConv2D(3,strides=2,padding=\"same\"),\n            BatchNormalization(), ReLU(),\n            Conv2D(128,1),\n            GlobalAveragePooling2D(),\n            Dropout(0.3),\n            Dense(num_classes, activation=\"softmax\")\n        ])\n\n# ---------------- SAMPLE IMAGE (USED FOR ALL MODELS) ----------------\nsample_row = df.iloc[0]\nsample_img_path = os.path.join(IMG_DIR, sample_row[\"image_id\"])\nimg = cv2.imread(sample_img_path)\nimg_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\nimg_resized = cv2.resize(img_rgb, IMG_SIZE)/255.0\nimg_input = np.expand_dims(img_resized, axis=0)\n\n# ---------------- RUN ALL MODELS ----------------\nmodels = [\"VGG16\",\"MobileNetV2\",\"Xception\",\"ShuffleNetV2\",\"ULEN\"]\n\nfor model_name in models:\n    print(\"\\n\" + \"=\"*60)\n    print(f\"Model Name: {model_name}\")\n    print(\"=\"*60)\n\n    model = build_model(model_name)\n    model.compile(optimizer=Adam(0.001),\n                  loss=\"categorical_crossentropy\",\n                  metrics=[\"accuracy\"])\n\n    model.fit(train_loader,\n              validation_data=val_loader,\n              epochs=2,               # kept low for Kaggle stability\n              class_weight=class_weights,\n              verbose=0)\n\n    # ---- Metrics ----\n    val_preds = model.predict(val_loader)\n    y_pred = np.argmax(val_preds, axis=1)\n    y_true = val_loader.classes\n\n    acc = accuracy_score(y_true, y_pred)\n    prec = precision_score(y_true, y_pred, average=\"macro\")\n    rec = recall_score(y_true, y_pred, average=\"macro\")\n    f1 = f1_score(y_true, y_pred, average=\"macro\")\n\n    # ---- Single Image Prediction ----\n    pred = model.predict(img_input)\n    cls = np.argmax(pred)\n    disease = label_map[str(cls)]\n    disease_status = \"Healthy\" if disease == \"Healthy\" else \"Diseased\"\n\n    # ---- ExG ----\n    R,G,B = img_rgb[:,:,0], img_rgb[:,:,1], img_rgb[:,:,2]\n    ExG = 2*G - R - B\n    ExG = (ExG - ExG.min()) / (ExG.max() - ExG.min())\n    exg_mean = ExG.mean()\n\n    if exg_mean > 0.6:\n        crop_stress = \"Low\"\n        exg_status = \"Healthy\"\n    elif exg_mean > 0.4:\n        crop_stress = \"Medium\"\n        exg_status = \"Moderate\"\n    else:\n        crop_stress = \"High\"\n        exg_status = \"Unhealthy\"\n\n    # ---- Treatment ----\n    if disease != \"Healthy\":\n        treatment = \"Pesticide\"\n        final_dosage = 1.0\n    elif crop_stress in [\"Medium\",\"High\"]:\n        treatment = \"Fertilizer\"\n        final_dosage = 1.0\n    else:\n        treatment = \"No Action\"\n        final_dosage = 0.0\n\n    # ---- EXACT OUTPUT FORMAT ----\n    print(f\"Predicted Disease: {disease}\")\n    print(f\"Disease Status: {disease_status}\\n\")\n\n    print(f\"Accuracy: {acc:.2f}\")\n    print(f\"Precision: {prec:.2f}\")\n    print(f\"Recall: {rec:.2f}\")\n    print(f\"F1-score: {f1:.2f}\\n\")\n\n    print(f\"ExG Status: {exg_status}\")\n    print(f\"Crop Stress Level: {crop_stress}\")\n    print(f\"Recommended Treatment: {treatment}\")\n    print(f\"Final Dosage: {final_dosage} ml/L\")\n\n# ---------------- SHOW SAMPLE IMAGE AT THE END ----------------\nplt.figure(figsize=(4,4))\nplt.imshow(img_rgb)\nplt.axis(\"off\")\nplt.title(\"Sample Cassava Leaf Image\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-24T02:19:16.146107Z","iopub.execute_input":"2026-01-24T02:19:16.146328Z","iopub.status.idle":"2026-01-24T02:38:22.072256Z","shell.execute_reply.started":"2026-01-24T02:19:16.146306Z","shell.execute_reply":"2026-01-24T02:38:22.071302Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.optimizers import Adam\nfrom tensorflow.keras.models import Model, Sequential\nfrom tensorflow.keras.layers import (\n    Conv2D, MaxPooling2D, GlobalAveragePooling2D,\n    Dense, DepthwiseConv2D, BatchNormalization, ReLU, Input\n)\nfrom tensorflow.keras.applications import MobileNetV2, Xception\n\nfrom sklearn.metrics import f1_score\n\n# ===============================\n# DATASET PATHS (CASSAVA)\n# ===============================\nBASE_PATH = \"/kaggle/input/cassava-leaf-disease-classification\"\nIMG_DIR = os.path.join(BASE_PATH, \"train_images\")\nCSV_PATH = os.path.join(BASE_PATH, \"train.csv\")\n\nIMG_SIZE = (128, 128)\nBATCH_SIZE = 32\nEPOCHS = 20\n\n# ===============================\n# LOAD CSV\n# ===============================\ndf = pd.read_csv(CSV_PATH)\ndf[\"label\"] = df[\"label\"].astype(str)\n\n# ===============================\n# DATA GENERATOR\n# ===============================\ndatagen = ImageDataGenerator(rescale=1./255, validation_split=0.2)\n\ntrain_data = datagen.flow_from_dataframe(\n    dataframe=df,\n    directory=IMG_DIR,\n    x_col=\"image_id\",\n    y_col=\"label\",\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"categorical\",\n    subset=\"training\",\n    shuffle=True\n)\n\nval_data = datagen.flow_from_dataframe(\n    dataframe=df,\n    directory=IMG_DIR,\n    x_col=\"image_id\",\n    y_col=\"label\",\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"categorical\",\n    subset=\"validation\",\n    shuffle=False\n)\n\nnum_classes = len(train_data.class_indices)\n\n# ===============================\n# TRAIN + COLLECT F1\n# ===============================\ndef train_and_collect_f1(model, model_name):\n    f1_scores = []\n    losses = []\n\n    for epoch in range(EPOCHS):\n        print(f\"\\n{model_name} — Epoch {epoch+1}/{EPOCHS}\")\n\n        history = model.fit(\n            train_data,\n            validation_data=val_data,\n            epochs=1,\n            verbose=1\n        )\n\n        losses.append(history.history[\"val_loss\"][0])\n\n        val_data.reset()\n        preds = model.predict(val_data)\n        y_pred = np.argmax(preds, axis=1)\n        y_true = val_data.classes\n\n        f1 = f1_score(y_true, y_pred, average=\"weighted\")\n        f1_scores.append(f1)\n\n        print(f\"F1-score: {f1:.4f}\")\n\n    return f1_scores, losses\n\n# ===============================\n# 1️⃣ VGG-Like CNN\n# ===============================\nvgg_model = Sequential([\n    Conv2D(32, 3, activation=\"relu\", padding=\"same\", input_shape=(128,128,3)),\n    MaxPooling2D(),\n    Conv2D(64, 3, activation=\"relu\", padding=\"same\"),\n    MaxPooling2D(),\n    Conv2D(128, 3, activation=\"relu\", padding=\"same\"),\n    MaxPooling2D(),\n    GlobalAveragePooling2D(),\n    Dense(128, activation=\"relu\"),\n    Dense(num_classes, activation=\"softmax\")\n])\n\nvgg_model.compile(optimizer=Adam(0.001),\n                  loss=\"categorical_crossentropy\",\n                  metrics=[\"accuracy\"])\n\nvgg_f1, vgg_loss = train_and_collect_f1(vgg_model, \"VGG16\")\n\n# ===============================\n# 2️⃣ MobileNetV2\n# ===============================\nmobilenet = MobileNetV2(weights=None, include_top=False,\n                         input_tensor=Input(shape=(128,128,3)))\n\nx = GlobalAveragePooling2D()(mobilenet.output)\nx = Dense(128, activation=\"relu\")(x)\nout = Dense(num_classes, activation=\"softmax\")(x)\n\nmobilenet_model = Model(mobilenet.input, out)\n\nmobilenet_model.compile(optimizer=Adam(0.0001),\n                         loss=\"categorical_crossentropy\",\n                         metrics=[\"accuracy\"])\n\nmobilenet_f1, mobilenet_loss = train_and_collect_f1(mobilenet_model, \"MobileNetV2\")\n\n# ===============================\n# 3️⃣ Xception\n# ===============================\nxception = Xception(weights=None, include_top=False,\n                     input_tensor=Input(shape=(128,128,3)))\n\nx = GlobalAveragePooling2D()(xception.output)\nx = Dense(128, activation=\"relu\")(x)\nout = Dense(num_classes, activation=\"softmax\")(x)\n\nxception_model = Model(xception.input, out)\n\nxception_model.compile(optimizer=Adam(0.0001),\n                        loss=\"categorical_crossentropy\",\n                        metrics=[\"accuracy\"])\n\nxception_f1, xception_loss = train_and_collect_f1(xception_model, \"Xception\")\n\n# ===============================\n# 4️⃣ ShuffleNetV2 (Approx)\n# ===============================\ninputs = Input(shape=(128,128,3))\nx = Conv2D(32, 1, padding=\"same\")(inputs)\nx = DepthwiseConv2D(3, padding=\"same\")(x)\nx = ReLU()(x)\nx = Conv2D(64, 1, padding=\"same\")(x)\nx = GlobalAveragePooling2D()(x)\nout = Dense(num_classes, activation=\"softmax\")(x)\n\nshuffle_model = Model(inputs, out)\n\nshuffle_model.compile(optimizer=Adam(0.001),\n                       loss=\"categorical_crossentropy\",\n                       metrics=[\"accuracy\"])\n\nshuffle_f1, shuffle_loss = train_and_collect_f1(shuffle_model, \"ShuffleNetV2\")\n\n# ===============================\n# 5️⃣ ULEN (Compressed CNN)\n# ===============================\ninputs = Input(shape=(128,128,3))\nx = Conv2D(32, 3, activation=\"relu\", padding=\"same\")(inputs)\nx = MaxPooling2D()(x)\nx = Conv2D(64, 3, activation=\"relu\", padding=\"same\")(x)\nx = MaxPooling2D()(x)\nx = Conv2D(128, 3, activation=\"relu\", padding=\"same\")(x)\nx = GlobalAveragePooling2D()(x)\nout = Dense(num_classes, activation=\"softmax\")(x)\n\nulen_model = Model(inputs, out)\n\nulen_model.compile(optimizer=Adam(0.001),\n                    loss=\"categorical_crossentropy\",\n                    metrics=[\"accuracy\"])\n\nulen_f1, ulen_loss = train_and_collect_f1(ulen_model, \"ULEN\")\n\n# ===============================\n# PLOTS\n# ===============================\nplt.figure(figsize=(10,6))\nplt.plot(vgg_f1, label=\"VGG16\")\nplt.plot(mobilenet_f1, label=\"MobileNetV2\")\nplt.plot(xception_f1, label=\"Xception\")\nplt.plot(shuffle_f1, label=\"ShuffleNetV2\")\nplt.plot(ulen_f1, label=\"ULEN\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"F1-score\")\nplt.title(\"F1-score Curves – Cassava Dataset\")\nplt.legend()\nplt.grid()\nplt.show()\n\nplt.figure(figsize=(10,6))\nplt.plot(vgg_loss, label=\"VGG16\")\nplt.plot(mobilenet_loss, label=\"MobileNetV2\")\nplt.plot(xception_loss, label=\"Xception\")\nplt.plot(shuffle_loss, label=\"ShuffleNetV2\")\nplt.plot(ulen_loss, label=\"ULEN\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Validation Loss\")\nplt.title(\"Loss Curves – Cassava Dataset\")\nplt.legend()\nplt.grid()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-24T02:38:22.07373Z","iopub.execute_input":"2026-01-24T02:38:22.073993Z","iopub.status.idle":"2026-01-24T06:02:54.640147Z","shell.execute_reply.started":"2026-01-24T02:38:22.073969Z","shell.execute_reply":"2026-01-24T06:02:54.639452Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================= IMPORTS =================\nimport os\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\n\nfrom tensorflow.keras.applications import VGG16\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Dense, GlobalAveragePooling2D, Dropout\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.optimizers import Adam\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import f1_score\n\n\n# ================= PATH =================\nBASE_DIR = \"/kaggle/input/cassava-leaf-disease-classification\"\nIMG_DIR = os.path.join(BASE_DIR, \"train_images\")\nCSV_FILE = os.path.join(BASE_DIR, \"train.csv\")\n\n\n# ================= LOAD CSV =================\ndf = pd.read_csv(CSV_FILE)\n\ndf[\"label\"] = df[\"label\"].astype(str)\n\n\n# ================= SPLIT =================\ntrain_df, val_df = train_test_split(\n    df,\n    test_size=0.2,\n    stratify=df[\"label\"],\n    random_state=42\n)\n\n\n# ================= PARAMETERS =================\nIMG_SIZE = (224,224)\nBATCH_SIZE = 32\nEPOCHS = 3\n\n\n# ================= IMAGE GENERATOR =================\ndatagen = ImageDataGenerator(rescale=1./255)\n\ntrain_data = datagen.flow_from_dataframe(\n    train_df,\n    directory=IMG_DIR,\n    x_col=\"image_id\",\n    y_col=\"label\",\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"categorical\",\n    shuffle=True\n)\n\nval_data = datagen.flow_from_dataframe(\n    val_df,\n    directory=IMG_DIR,\n    x_col=\"image_id\",\n    y_col=\"label\",\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"categorical\",\n    shuffle=False\n)\n\n\n# ================= NUMBER OF CLASSES =================\nNUM_CLASSES = len(train_data.class_indices)\n\nprint(\"Number of Classes:\", NUM_CLASSES)\n\n\n# ================= TRAIN & EVALUATE =================\ndef train_and_evaluate(model, name):\n\n    print(f\"\\nTraining {name}...\\n\")\n\n    model.compile(\n        optimizer=Adam(0.0001),\n        loss=\"categorical_crossentropy\",\n        metrics=[\"accuracy\"]\n    )\n\n    model.fit(\n        train_data,\n        validation_data=val_data,\n        epochs=EPOCHS,\n        verbose=1\n    )\n\n    val_data.reset()\n\n    loss, acc = model.evaluate(val_data, verbose=0)\n\n    preds = model.predict(val_data)\n    y_pred = np.argmax(preds, axis=1)\n    y_true = val_data.classes\n\n    f1 = f1_score(y_true, y_pred, average=\"weighted\")\n\n    return loss, acc, f1\n\n\n# ================= MODEL 1: BASIC VGG =================\ndef build_vgg_basic():\n\n    base = VGG16(\n        weights=None,     # Offline safe\n        include_top=False,\n        input_shape=(224,224,3)\n    )\n\n    x = GlobalAveragePooling2D()(base.output)\n    x = Dense(256, activation=\"relu\")(x)\n    out = Dense(NUM_CLASSES, activation=\"softmax\")(x)\n\n    return Model(base.input, out)\n\n\n# ================= MODEL 2: VGG + DROPOUT =================\ndef build_vgg_dropout():\n\n    base = VGG16(\n        weights=None,\n        include_top=False,\n        input_shape=(224,224,3)\n    )\n\n    x = GlobalAveragePooling2D()(base.output)\n    x = Dense(256, activation=\"relu\")(x)\n    x = Dropout(0.5)(x)\n\n    out = Dense(NUM_CLASSES, activation=\"softmax\")(x)\n\n    return Model(base.input, out)\n\n\n# ================= MODEL 3: FINE-TUNED VGG =================\ndef build_vgg_finetuned():\n\n    base = VGG16(\n        weights=None,\n        include_top=False,\n        input_shape=(224,224,3)\n    )\n\n    # Unfreeze last layers\n    for layer in base.layers[-5:]:\n        layer.trainable = True\n\n\n    x = GlobalAveragePooling2D()(base.output)\n    x = Dense(256, activation=\"relu\")(x)\n\n    out = Dense(NUM_CLASSES, activation=\"softmax\")(x)\n\n    return Model(base.input, out)\n\n\n# ================= BUILD MODELS =================\nmodels = {\n    \"VGG Basic\": build_vgg_basic(),\n    \"VGG + Dropout\": build_vgg_dropout(),\n    \"VGG Fine-Tuned\": build_vgg_finetuned()\n}\n\n\n# ================= TRAIN ALL =================\nresults = {}\n\n\nfor name, model in models.items():\n\n    loss, acc, f1 = train_and_evaluate(model, name)\n\n    results[name] = [loss, acc, f1]\n\n\n# ================= FINAL COMPARISON =================\nprint(\"\\n================ MODEL COMPARISON ================\\n\")\n\nbest_f1 = 0\nbest_model = \"\"\n\n\nfor name, res in results.items():\n\n    loss = res[0]\n    acc = res[1]\n    f1 = res[2]\n\n    print(f\"Model: {name}\")\n    print(f\"Loss     : {loss:.2f}\")\n    print(f\"Accuracy : {acc:.2f}\")\n    print(f\"F1-score : {f1:.2f}\\n\")\n\n    if f1 > best_f1:\n        best_f1 = f1\n        best_model = name\n\n\nprint(\"===============================================\")\nprint(\"Best Model:\", best_model)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T06:05:59.904824Z","iopub.execute_input":"2026-02-11T06:05:59.905204Z","iopub.status.idle":"2026-02-11T06:32:59.818612Z","shell.execute_reply.started":"2026-02-11T06:05:59.905171Z","shell.execute_reply":"2026-02-11T06:32:59.817777Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ================= IMPORTS =================\nimport os\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\n\nfrom tensorflow.keras.applications import VGG16\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Dense, Dropout, Input, GlobalAveragePooling2D\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.optimizers import Adam, Adagrad, RMSprop, SGD, Adadelta\nfrom sklearn.metrics import f1_score\n\n\n# ================= REPRODUCIBILITY =================\ntf.random.set_seed(42)\nnp.random.seed(42)\n\n\n# ================= PATHS =================\nBASE_PATH = \"/kaggle/input/cassava-leaf-disease-classification\"\nIMG_PATH  = BASE_PATH + \"/train_images\"\nCSV_PATH  = BASE_PATH + \"/train.csv\"\n\n\n# ================= PARAMETERS =================\nimg_size = (224,224)\nbatch_size = 32\nepochs = 3\n\n\n# ================= LOAD CSV =================\ndf = pd.read_csv(CSV_PATH)\ndf[\"label\"] = df[\"label\"].astype(str)\n\n\n# ================= IMAGE GENERATOR =================\ndatagen = ImageDataGenerator(\n    rescale=1./255,\n    validation_split=0.2\n)\n\ntrain_data = datagen.flow_from_dataframe(\n    dataframe=df,\n    directory=IMG_PATH,\n    x_col=\"image_id\",\n    y_col=\"label\",\n    target_size=img_size,\n    batch_size=batch_size,\n    class_mode=\"categorical\",\n    subset=\"training\",\n    shuffle=True\n)\n\nval_data = datagen.flow_from_dataframe(\n    dataframe=df,\n    directory=IMG_PATH,\n    x_col=\"image_id\",\n    y_col=\"label\",\n    target_size=img_size,\n    batch_size=batch_size,\n    class_mode=\"categorical\",\n    subset=\"validation\",\n    shuffle=False\n)\n\n# ✅ FIXED LINE\nnum_classes = len(train_data.class_indices)\n\nprint(\"Classes:\", num_classes)\nprint(\"Class indices:\", train_data.class_indices)\n\n\n# ================= BUILD VGG + DROPOUT =================\ndef build_vgg_dropout():\n\n    base = VGG16(\n        weights=None,   # keep None if offline\n        include_top=False,\n        input_tensor=Input(shape=(224,224,3))\n    )\n\n    x = GlobalAveragePooling2D()(base.output)\n\n    x = Dense(256, activation=\"relu\")(x)\n    x = Dropout(0.5)(x)\n\n    x = Dense(128, activation=\"relu\")(x)\n    x = Dropout(0.5)(x)\n\n    out = Dense(num_classes, activation=\"softmax\")(x)\n\n    model = Model(base.input, out)\n\n    return model\n\n\n# ================= TRAIN & EVALUATE =================\ndef train_and_evaluate(model, optimizer, name):\n\n    print(f\"\\nTraining with {name} optimizer...\")\n\n    model.compile(\n        optimizer=optimizer,\n        loss=\"categorical_crossentropy\",\n        metrics=[\"accuracy\"]\n    )\n\n    model.fit(\n        train_data,\n        validation_data=val_data,\n        epochs=epochs,\n        verbose=1\n    )\n\n    val_data.reset()\n\n    loss, acc = model.evaluate(val_data, verbose=0)\n\n    preds = model.predict(val_data, verbose=0)\n\n    y_pred = np.argmax(preds, axis=1)\n    y_true = val_data.classes\n\n    f1 = f1_score(y_true, y_pred, average=\"weighted\")\n\n    return loss, acc, f1\n\n\n# ================= OPTIMIZERS =================\noptimizers = {\n\n    \"Adam\" : Adam(0.0001),\n\n    \"Adagrad\" : Adagrad(0.001),\n\n    \"RMSprop\" : RMSprop(0.0001),\n\n    \"SGD + Nesterov\" : SGD(\n        learning_rate=0.01,\n        momentum=0.9,\n        nesterov=True\n    ),\n\n    \"Adadelta\" : Adadelta(1.0)\n}\n\n\n# ================= TRAIN ALL =================\nresults = {}\n\nfor name, opt in optimizers.items():\n\n    model = build_vgg_dropout()\n\n    loss, acc, f1 = train_and_evaluate(model, opt, name)\n\n    results[name] = [loss, acc, f1]\n\n\n# ================= FINAL COMPARISON =================\nprint(\"\\n================ OPTIMIZER COMPARISON ================\\n\")\n\nbest_f1 = 0\nbest_optimizer = \"\"\n\nfor name, val in results.items():\n\n    loss = val[0]\n    acc  = val[1]\n    f1   = val[2]\n\n    print(f\"Optimizer: {name}\")\n    print(f\"Loss     : {loss:.4f}\")\n    print(f\"Accuracy : {acc:.4f}\")\n    print(f\"F1-score : {f1:.4f}\\n\")\n\n    if f1 > best_f1:\n        best_f1 = f1\n        best_optimizer = name\n\nprint(\"===============================================\")\nprint(f\"Best Optimizer based on F1-score: {best_optimizer}\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}