{"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":"gpu","dataSources":[{"sourceId":13836,"databundleVersionId":1718836,"sourceType":"competition"}],"dockerImageVersionId":31193,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout, Input, Concatenate, GlobalAveragePooling2D\nfrom tensorflow.keras.applications import MobileNetV2\nfrom tensorflow.keras.optimizers import Adam\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import classification_report, confusion_matrix\n\n# ==========================================\n# 1. CONFIGURATION & DATA SETUP (KAGGLE VERSION)\n# ==========================================\nIMG_SIZE = 224\nBATCH_SIZE = 32\nEPOCHS = 7   # Good balance for a lab demo\nLEARNING_RATE = 0.0001\nNUM_CLASSES = 5\n\n# KAGGLE SPECIFIC PATHS (No download needed!)\nBASE_DIR = '../input/cassava-leaf-disease-classification/'\nTRAIN_IMG_DIR = os.path.join(BASE_DIR, 'train_images')\nTRAIN_CSV_PATH = os.path.join(BASE_DIR, 'train.csv')\n\n# LOAD DATAFRAME\ntry:\n    df = pd.read_csv(TRAIN_CSV_PATH)\n    df['label'] = df['label'].astype(str) \n    print(f\"✅ Dataset Loaded Successfully. Total Images: {len(df)}\")\nexcept FileNotFoundError:\n    print(\"❌ ERROR: Data not found. Make sure you added the dataset in the right sidebar!\")\n\n# SPLIT DATA (80% Train, 20% Validation)\ntrain_df, val_df = train_test_split(df, test_size=0.2, random_state=42, stratify=df['label'])\n\n# ==========================================\n# 2. DATA GENERATORS\n# ==========================================\nprint(\"⏳ Setting up Data Generators...\")\n\ntrain_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=40,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n\nval_datagen = ImageDataGenerator(rescale=1./255)\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    train_df,\n    directory=TRAIN_IMG_DIR,\n    x_col='image_id',\n    y_col='label',\n    target_size=(IMG_SIZE, IMG_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode='categorical'\n)\n\nval_generator = val_datagen.flow_from_dataframe(\n    val_df,\n    directory=TRAIN_IMG_DIR,\n    x_col='image_id',\n    y_col='label',\n    target_size=(IMG_SIZE, IMG_SIZE),\n    batch_size=BATCH_SIZE,\n    class_mode='categorical',\n    shuffle=False \n)\n\n# Store results for comparison\nmodel_history = {}\nmodel_evaluations = {}\n\n# ==========================================\n# 3. MODEL DEFINITIONS\n# ==========================================\n\n# MODEL 1: BASE MODEL (Simple CNN)\ndef build_base_model():\n    model = Sequential([\n        Conv2D(32, (3, 3), activation='relu', input_shape=(IMG_SIZE, IMG_SIZE, 3)),\n        MaxPooling2D(2, 2),\n        Conv2D(64, (3, 3), activation='relu'),\n        MaxPooling2D(2, 2),\n        Flatten(),\n        Dense(64, activation='relu'),\n        Dropout(0.5),\n        Dense(NUM_CLASSES, activation='softmax')\n    ], name=\"1_Base_CNN\")\n    return model\n\n# MODEL 2: TRANSFER LEARNING (MobileNetV2)\ndef build_transfer_model():\n    base_model = MobileNetV2(weights='imagenet', include_top=False, input_shape=(IMG_SIZE, IMG_SIZE, 3))\n    base_model.trainable = False # Freeze base\n    \n    x = base_model.output\n    x = GlobalAveragePooling2D()(x)\n    x = Dense(128, activation='relu')(x)\n    x = Dropout(0.5)(x)\n    predictions = Dense(NUM_CLASSES, activation='softmax')(x)\n    \n    return Model(inputs=base_model.input, outputs=predictions, name=\"2_Transfer_MobileNet\")\n\n# MODEL 3: HYBRID (Fine-Tuned MobileNet)\n# \"Hybrid\" logic: Combines pre-trained weights (Knowledge) + New trainable layers (Adaptation)\ndef build_hybrid_model():\n    base = MobileNetV2(weights='imagenet', include_top=False, input_shape=(IMG_SIZE, IMG_SIZE, 3))\n    base.trainable = True # Unfreeze for \"Hybrid\" learning\n    \n    # Freeze bottom layers, train top layers\n    for layer in base.layers[:-40]:\n        layer.trainable = False\n        \n    model = Sequential([\n        base,\n        GlobalAveragePooling2D(),\n        Dense(256, activation='relu'),\n        Dropout(0.4),\n        Dense(NUM_CLASSES, activation='softmax')\n    ], name=\"3_Hybrid_FineTuned\")\n    return model\n\n# ==========================================\n# 4. TRAINING LOOP\n# ==========================================\nmodels_list = [build_base_model(), build_transfer_model(), build_hybrid_model()]\n\nfor model in models_list:\n    print(f\"\\n🚀 STARTING TRAINING: {model.name}...\")\n    model.compile(optimizer=Adam(learning_rate=LEARNING_RATE),\n                  loss='categorical_crossentropy',\n                  metrics=['accuracy'])\n    \n    # Train\n    history = model.fit(\n        train_generator,\n        epochs=EPOCHS,\n        validation_data=val_generator,\n        steps_per_epoch=len(train_generator) // 2, # Speed up for lab demo\n        validation_steps=len(val_generator) // 2\n    )\n    \n    model_history[model.name] = history\n    \n    # Evaluate\n    print(f\"📊 Evaluating {model.name}...\")\n    loss, acc = model.evaluate(val_generator)\n    model_evaluations[model.name] = acc\n    print(f\"✅ {model.name} Accuracy: {acc*100:.2f}%\")\n\n# ==========================================\n# 5. RESULTS & COMPARISON\n# ==========================================\nprint(\"\\n📈 GENERATING PLOTS & METRICS...\")\n\n# A. Accuracy & Loss Curves\nplt.figure(figsize=(14, 6))\nplt.subplot(1, 2, 1)\nfor name, history in model_history.items():\n    plt.plot(history.history['val_accuracy'], label=name, linewidth=2)\nplt.title('Validation Accuracy Comparison')\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.legend()\n\nplt.subplot(1, 2, 2)\nfor name, history in model_history.items():\n    plt.plot(history.history['val_loss'], label=name, linewidth=2)\nplt.title('Validation Loss Comparison')\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.legend()\nplt.tight_layout()\nplt.show()\n\n# B. Confusion Matrix (Best Model)\nbest_model_name = max(model_evaluations, key=model_evaluations.get)\nprint(f\"\\n🏆 BEST MODEL: {best_model_name}\")\n\n# Find the object of the best model to predict\nbest_model = [m for m in models_list if m.name == best_model_name][0]\n\nval_generator.reset()\nY_pred = best_model.predict(val_generator)\ny_pred = np.argmax(Y_pred, axis=1)\ny_true = val_generator.classes\n\nplt.figure(figsize=(8, 6))\nsns.heatmap(confusion_matrix(y_true, y_pred), annot=True, fmt='d', cmap='Greens')\nplt.title(f'Confusion Matrix: {best_model_name}')\nplt.ylabel('True Label')\nplt.xlabel('Predicted Label')\nplt.show()\n\n# C. Classification Report\nprint(\"\\n📝 Classification Report:\")\ntarget_names = ['CBB', 'CBSD', 'CGM', 'CMD', 'Healthy']\nprint(classification_report(y_true, y_pred, target_names=target_names))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-12-01T19:23:33.184517Z","iopub.execute_input":"2025-12-01T19:23:33.184735Z","iopub.status.idle":"2025-12-01T19:59:49.697549Z","shell.execute_reply.started":"2025-12-01T19:23:33.184708Z","shell.execute_reply":"2025-12-01T19:59:49.696677Z"}},"outputs":[],"execution_count":null}]}