{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.13.15","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\n# Use the kagglehub client library to attach Kaggle resources like competitions, datasets, and models to your session\n# Learn more about kagglehub: https://github.com/Kaggle/kagglehub/blob/main/README.md\n\nimport kagglehub\n# kagglehub.dataset_download('<owner>/<dataset-slug>')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:33:13.891192Z","iopub.execute_input":"2026-10-07T12:33:13.891759Z","iopub.status.idle":"2026-10-07T12:34:52.551188Z","shell.execute_reply.started":"2026-10-07T12:33:13.891727Z","shell.execute_reply":"2026-10-07T12:34:52.550328Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport os\nimport json\n\nDATA_DIR = \"/kaggle/input/competitions/cassava-leaf-disease-classification\"\n\ntrain_df = pd.read_csv(os.path.join(DATA_DIR, \"train.csv\"))\n\nprint(\"Dataset shape:\", train_df.shape)\nprint(\"\\nFirst 5 rows:\")\nprint(train_df.head())\n\nprint(\"\\nClass counts:\")\nprint(train_df[\"label\"].value_counts().sort_index())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:34:52.553157Z","iopub.execute_input":"2026-10-07T12:34:52.553504Z","iopub.status.idle":"2026-10-07T12:34:52.718548Z","shell.execute_reply.started":"2026-10-07T12:34:52.55348Z","shell.execute_reply":"2026-10-07T12:34:52.717592Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"with open(os.path.join(DATA_DIR, \"label_num_to_disease_map.json\"), \"r\") as f:\n    label_map = json.load(f)\n\nprint(\"Label to Disease Mapping:\")\nfor label, disease in label_map.items():\n    print(label, \"=\", disease)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:34:52.719561Z","iopub.execute_input":"2026-10-07T12:34:52.719907Z","iopub.status.idle":"2026-10-07T12:34:52.76608Z","shell.execute_reply.started":"2026-10-07T12:34:52.719886Z","shell.execute_reply":"2026-10-07T12:34:52.765151Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nfrom PIL import Image\n\nTRAIN_IMG_DIR = os.path.join(DATA_DIR, \"train_images\")\n\nfig, axes = plt.subplots(1, 5, figsize=(20, 4))\n\nfor label in range(5):\n    sample = train_df[train_df[\"label\"] == label].iloc[0]\n    img_path = os.path.join(TRAIN_IMG_DIR, sample[\"image_id\"])\n    img = Image.open(img_path)\n\n    axes[label].imshow(img)\n    axes[label].set_title(f\"{label}: {label_map[str(label)]}\")\n    axes[label].axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:34:52.767121Z","iopub.execute_input":"2026-10-07T12:34:52.767445Z","iopub.status.idle":"2026-10-07T12:34:53.814983Z","shell.execute_reply.started":"2026-10-07T12:34:52.767414Z","shell.execute_reply":"2026-10-07T12:34:53.813822Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"Missing values:\")\nprint(train_df.isnull().sum())\n\nprint(\"\\nDuplicate rows:\")\nprint(train_df.duplicated().sum())\n\nprint(\"\\nDuplicate image IDs:\")\nprint(train_df[\"image_id\"].duplicated().sum())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:34:53.818281Z","iopub.execute_input":"2026-10-07T12:34:53.819052Z","iopub.status.idle":"2026-10-07T12:34:53.848767Z","shell.execute_reply.started":"2026-10-07T12:34:53.818954Z","shell.execute_reply":"2026-10-07T12:34:53.847822Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class_counts = train_df[\"label\"].value_counts().sort_index()\n\nclass_names = [label_map[str(i)] for i in class_counts.index]\nplt.figure(figsize=(10, 5))\nplt.bar(class_names, class_counts.values)\n\nplt.title(\"Class Distribution of Cassava Leaf Dataset\")\nplt.xlabel(\"Disease Class\")\nplt.ylabel(\"Number of Images\")\nplt.xticks(rotation=25)\n\nfor i, count in enumerate(class_counts.values):\n    plt.text(i, count + 100, str(count), ha=\"center\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:34:53.849768Z","iopub.execute_input":"2026-10-07T12:34:53.850685Z","iopub.status.idle":"2026-10-07T12:34:54.031355Z","shell.execute_reply.started":"2026-10-07T12:34:53.850654Z","shell.execute_reply":"2026-10-07T12:34:54.030653Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\ntrain_data, val_data = train_test_split(\n    train_df,\n    test_size=0.20,\n    random_state=42,\n    stratify=train_df[\"label\"]\n)\n\nprint(\"Total images:\", len(train_df))\nprint(\"Training images:\", len(train_data))\nprint(\"Validation images:\", len(val_data))\n\nprint(\"\\nTraining class distribution:\")\nprint(train_data[\"label\"].value_counts().sort_index())\n\nprint(\"\\nValidation class distribution:\")\nprint(val_data[\"label\"].value_counts().sort_index())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:34:54.032335Z","iopub.execute_input":"2026-10-07T12:34:54.032611Z","iopub.status.idle":"2026-10-07T12:34:54.338346Z","shell.execute_reply.started":"2026-10-07T12:34:54.032577Z","shell.execute_reply":"2026-10-07T12:34:54.337672Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\n\nIMG_SIZE = (224, 224)\nBATCH_SIZE = 32\n\ndata_augmentation = tf.keras.Sequential([\n    tf.keras.layers.RandomFlip(\"horizontal\"),\n    tf.keras.layers.RandomRotation(0.1),\n    tf.keras.layers.RandomZoom(0.1)\n], name=\"data_augmentation\")\n\nprint(\"Image size:\", IMG_SIZE)\nprint(\"Batch size:\", BATCH_SIZE)\nprint(\"Data augmentation created successfully.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:34:54.339392Z","iopub.execute_input":"2026-10-07T12:34:54.339942Z","iopub.status.idle":"2026-10-07T12:35:01.969104Z","shell.execute_reply.started":"2026-10-07T12:34:54.339917Z","shell.execute_reply":"2026-10-07T12:35:01.968218Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data = train_data.copy()\nval_data = val_data.copy()\n\ntrain_data[\"label\"] = train_data[\"label\"].astype(str)\nval_data[\"label\"] = val_data[\"label\"].astype(str)\n\ntrain_gen = tf.keras.preprocessing.image.ImageDataGenerator()\n\ntrain_generator = train_gen.flow_from_dataframe(\n    dataframe=train_data,\n    directory=TRAIN_IMG_DIR,\n    x_col=\"image_id\",\n    y_col=\"label\",\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"sparse\",\n    shuffle=True,\n    seed=42\n)\n\nval_gen = tf.keras.preprocessing.image.ImageDataGenerator()\n\nval_generator = val_gen.flow_from_dataframe(\n    dataframe=val_data,\n    directory=TRAIN_IMG_DIR,\n    x_col=\"image_id\",\n    y_col=\"label\",\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"sparse\",\n    shuffle=False\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:35:01.970071Z","iopub.execute_input":"2026-10-07T12:35:01.970776Z","iopub.status.idle":"2026-10-07T12:35:49.775464Z","shell.execute_reply.started":"2026-10-07T12:35:01.97075Z","shell.execute_reply":"2026-10-07T12:35:49.774411Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.applications import MobileNetV2\n\nWEIGHTS_PATH = \"/kaggle/input/models/spunkybro/mobilenetv2-weights/tensorflow2/default/1/mobilenet_v2_weights_tf_dim_ordering_tf_kernels_1.0_224_no_top.h5\"\n\nbase_model = MobileNetV2(\n    weights=None,\n    include_top=False,\n    input_shape=(224, 224, 3)\n)\n\nbase_model.load_weights(WEIGHTS_PATH)\n\nbase_model.trainable = False\n\nprint(\"MobileNetV2 pretrained weights loaded successfully!\")\nprint(\"Base model trainable:\", base_model.trainable)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:35:49.776702Z","iopub.execute_input":"2026-10-07T12:35:49.777037Z","iopub.status.idle":"2026-10-07T12:35:54.406829Z","shell.execute_reply.started":"2026-10-07T12:35:49.777014Z","shell.execute_reply":"2026-10-07T12:35:54.406013Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras import layers, models\nfrom tensorflow.keras.applications.mobilenet_v2 import preprocess_input\n\ninputs = layers.Input(shape=(224, 224, 3))\n\nx = data_augmentation(inputs)\nx = preprocess_input(x)\n\nx = base_model(x, training=False)\n\nx = layers.GlobalAveragePooling2D()(x)\nx = layers.Dropout(0.2)(x)\n\noutputs = layers.Dense(5, activation=\"softmax\")(x)\n\nmodel_m0 = models.Model(inputs, outputs)\n\nmodel_m0.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:35:54.407836Z","iopub.execute_input":"2026-10-07T12:35:54.408188Z","iopub.status.idle":"2026-10-07T12:35:54.47065Z","shell.execute_reply.started":"2026-10-07T12:35:54.408164Z","shell.execute_reply":"2026-10-07T12:35:54.469996Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model_m0.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n    loss=\"sparse_categorical_crossentropy\",\n    metrics=[\"accuracy\"],\n    run_eagerly=False\n)\n\nprint(\"M0 compiled in fast mode!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:35:54.471657Z","iopub.execute_input":"2026-10-07T12:35:54.472558Z","iopub.status.idle":"2026-10-07T12:35:54.488456Z","shell.execute_reply.started":"2026-10-07T12:35:54.472527Z","shell.execute_reply":"2026-10-07T12:35:54.487762Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"early_stopping = tf.keras.callbacks.EarlyStopping(\n    monitor=\"val_loss\",\n    patience=2,\n    restore_best_weights=True\n)\n\nhistory_m0 = model_m0.fit(\n    train_generator,\n    validation_data=val_generator,\n    epochs=4,\n    callbacks=[early_stopping]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:35:54.489829Z","iopub.execute_input":"2026-10-07T12:35:54.490183Z","iopub.status.idle":"2026-10-07T12:57:51.837877Z","shell.execute_reply.started":"2026-10-07T12:35:54.49015Z","shell.execute_reply":"2026-10-07T12:57:51.837109Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"m0_val_loss, m0_val_accuracy = model_m0.evaluate(val_generator)\n\nprint(\"M0 Validation Loss:\", round(m0_val_loss, 4))\nprint(\"M0 Validation Accuracy:\", round(m0_val_accuracy * 100, 2), \"%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:57:51.841325Z","iopub.execute_input":"2026-10-07T12:57:51.841746Z","iopub.status.idle":"2026-10-07T12:58:15.287582Z","shell.execute_reply.started":"2026-10-07T12:57:51.841723Z","shell.execute_reply":"2026-10-07T12:58:15.286858Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n\n# Validation images ki predictions\npredictions = model_m0.predict(val_generator)\n\n# Highest probability wali class choose karo\npredicted_labels = np.argmax(predictions, axis=1)\n\n# Actual correct labels\ntrue_labels = val_generator.classes\n\n# Confusion matrix\ncm = confusion_matrix(true_labels, predicted_labels)\n\nclass_names = [\n    \"CBB\",\n    \"CBSD\",\n    \"CGM\",\n    \"CMD\",\n    \"Healthy\"\n]\n\ndisp = ConfusionMatrixDisplay(\n    confusion_matrix=cm,\n    display_labels=class_names\n)\n\ndisp.plot(xticks_rotation=45)\nplt.title(\"M0 Confusion Matrix\")\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:58:15.288612Z","iopub.execute_input":"2026-10-07T12:58:15.288888Z","iopub.status.idle":"2026-10-07T12:58:42.080307Z","shell.execute_reply.started":"2026-10-07T12:58:15.288867Z","shell.execute_reply":"2026-10-07T12:58:42.079306Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import classification_report\n\nprint(\"M0 Classification Report:\\n\")\n\nprint(classification_report(\n    true_labels,\n    predicted_labels,\n    target_names=class_names,\n    digits=4\n))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:58:42.081525Z","iopub.execute_input":"2026-10-07T12:58:42.08192Z","iopub.status.idle":"2026-10-07T12:58:42.105548Z","shell.execute_reply.started":"2026-10-07T12:58:42.081885Z","shell.execute_reply":"2026-10-07T12:58:42.104955Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.utils.class_weight import compute_class_weight\nimport numpy as np\n\nclass_weights_array = compute_class_weight(\n    class_weight=\"balanced\",\n    classes=np.unique(train_data[\"label\"].astype(int)),\n    y=train_data[\"label\"].astype(int)\n)\n\nclass_weights = {\n    i: weight for i, weight in enumerate(class_weights_array)\n}\n\nprint(\"Class Weights:\")\nfor label, weight in class_weights.items():\n    print(label, \"=\", round(weight, 3))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:58:42.106608Z","iopub.execute_input":"2026-10-07T12:58:42.10697Z","iopub.status.idle":"2026-10-07T12:58:42.11983Z","shell.execute_reply.started":"2026-10-07T12:58:42.106949Z","shell.execute_reply":"2026-10-07T12:58:42.119025Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# M1 - Improved Model\n\ninputs = tf.keras.Input(shape=(224, 224, 3))\n\nx = data_augmentation(inputs)\nx = preprocess_input(x)\n\nx = base_model(x, training=False)\n\nx = tf.keras.layers.GlobalAveragePooling2D()(x)\nx = tf.keras.layers.Dropout(0.4)(x)\n\noutputs = tf.keras.layers.Dense(5, activation=\"softmax\")(x)\n\nmodel_m1 = tf.keras.Model(inputs, outputs)\n\nmodel_m1.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n    loss=\"sparse_categorical_crossentropy\",\n    metrics=[\"accuracy\"],\n    run_eagerly=False\n)\n\nmodel_m1.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:58:42.120807Z","iopub.execute_input":"2026-10-07T12:58:42.121195Z","iopub.status.idle":"2026-10-07T12:58:42.17411Z","shell.execute_reply.started":"2026-10-07T12:58:42.121168Z","shell.execute_reply":"2026-10-07T12:58:42.17344Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"early_stopping_m1 = tf.keras.callbacks.EarlyStopping(\n    monitor=\"val_loss\",\n    patience=2,\n    restore_best_weights=True\n)\n\nhistory_m1 = model_m1.fit(\n    train_generator,\n    validation_data=val_generator,\n    epochs=4,\n    class_weight=class_weights,\n    callbacks=[early_stopping_m1]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T12:58:42.175018Z","iopub.execute_input":"2026-10-07T12:58:42.175365Z","iopub.status.idle":"2026-10-07T13:07:11.296958Z","shell.execute_reply.started":"2026-10-07T12:58:42.175342Z","shell.execute_reply":"2026-10-07T13:07:11.296221Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"m1_val_loss, m1_val_accuracy = model_m1.evaluate(val_generator)\n\nprint(\"M1 Validation Loss:\", round(m1_val_loss, 4))\nprint(\"M1 Validation Accuracy:\", round(m1_val_accuracy * 100, 2), \"%\")\n\nprint(\"\\nM0 Validation Accuracy:\", round(m0_val_accuracy * 100, 2), \"%\")\nprint(\"M1 Validation Accuracy:\", round(m1_val_accuracy * 100, 2), \"%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:07:11.298024Z","iopub.execute_input":"2026-10-07T13:07:11.298438Z","iopub.status.idle":"2026-10-07T13:07:35.790394Z","shell.execute_reply.started":"2026-10-07T13:07:11.298401Z","shell.execute_reply":"2026-10-07T13:07:35.789682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n\nval_generator.reset()\n\nm1_predictions = model_m1.predict(val_generator)\nm1_pred_labels = np.argmax(m1_predictions, axis=1)\nm1_true_labels = val_generator.classes\n\ncm_m1 = confusion_matrix(m1_true_labels, m1_pred_labels)\n\ndisplay = ConfusionMatrixDisplay(\n    confusion_matrix=cm_m1,\n    display_labels=[\"CBB\", \"CBSD\", \"CGM\", \"CMD\", \"Healthy\"]\n)\n\ndisplay.plot()\nplt.title(\"M1 Confusion Matrix\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:07:35.791336Z","iopub.execute_input":"2026-10-07T13:07:35.791705Z","iopub.status.idle":"2026-10-07T13:08:06.346338Z","shell.execute_reply.started":"2026-10-07T13:07:35.791605Z","shell.execute_reply":"2026-10-07T13:08:06.345661Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.metrics import classification_report\n\nprint(\"M1 Classification Report:\")\nprint(\n    classification_report(\n        m1_true_labels,\n        m1_pred_labels,\n        target_names=[\"CBB\", \"CBSD\", \"CGM\", \"CMD\", \"Healthy\"],\n        digits=4\n    )\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:08:06.347168Z","iopub.execute_input":"2026-10-07T13:08:06.347458Z","iopub.status.idle":"2026-10-07T13:08:06.364476Z","shell.execute_reply.started":"2026-10-07T13:08:06.347435Z","shell.execute_reply":"2026-10-07T13:08:06.363639Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# M2 - Fine-tuning MobileNetV2\n\nbase_model.trainable = True\n\n# Freeze all layers except the last 20\nfor layer in base_model.layers[:-20]:\n    layer.trainable = False\n\nmodel_m2 = tf.keras.models.clone_model(model_m0)\nmodel_m2.set_weights(model_m0.get_weights())\n\nmodel_m2.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=0.00001),\n    loss=\"sparse_categorical_crossentropy\",\n    metrics=[\"accuracy\"],\n    run_eagerly=False\n)\n\nprint(\"M2 created successfully!\")\nprint(\"Trainable parameters:\", sum(\n    tf.keras.backend.count_params(w)\n    for w in model_m2.trainable_weights\n))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:08:06.365393Z","iopub.execute_input":"2026-10-07T13:08:06.365826Z","iopub.status.idle":"2026-10-07T13:08:07.227566Z","shell.execute_reply.started":"2026-10-07T13:08:06.365794Z","shell.execute_reply":"2026-10-07T13:08:07.226833Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"early_stopping_m2 = tf.keras.callbacks.EarlyStopping(\n    monitor=\"val_loss\",\n    patience=2,\n    restore_best_weights=True\n)\n\nhistory_m2 = model_m2.fit(\n    train_generator,\n    validation_data=val_generator,\n    epochs=4,\n    callbacks=[early_stopping_m2]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:08:07.228537Z","iopub.execute_input":"2026-10-07T13:08:07.228939Z","iopub.status.idle":"2026-10-07T13:17:15.270711Z","shell.execute_reply.started":"2026-10-07T13:08:07.228914Z","shell.execute_reply":"2026-10-07T13:17:15.269697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"m2_val_loss, m2_val_accuracy = model_m2.evaluate(val_generator)\n\nprint(\"M2 Validation Loss:\", round(m2_val_loss, 4))\nprint(\"M2 Validation Accuracy:\", round(m2_val_accuracy * 100, 2), \"%\")\n\nprint(\"\\nModel Comparison:\")\nprint(\"M0:\", round(m0_val_accuracy * 100, 2), \"%\")\nprint(\"M1:\", round(m1_val_accuracy * 100, 2), \"%\")\nprint(\"M2:\", round(m2_val_accuracy * 100, 2), \"%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:17:15.271962Z","iopub.execute_input":"2026-10-07T13:17:15.272884Z","iopub.status.idle":"2026-10-07T13:17:42.735371Z","shell.execute_reply.started":"2026-10-07T13:17:15.272857Z","shell.execute_reply":"2026-10-07T13:17:42.73471Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_generator.reset()\n\nm2_predictions = model_m2.predict(val_generator)\nm2_pred_labels = np.argmax(m2_predictions, axis=1)\nm2_true_labels = val_generator.classes\n\ncm_m2 = confusion_matrix(m2_true_labels, m2_pred_labels)\n\ndisplay = ConfusionMatrixDisplay(\n    confusion_matrix=cm_m2,\n    display_labels=[\"CBB\", \"CBSD\", \"CGM\", \"CMD\", \"Healthy\"]\n)\n\ndisplay.plot()\nplt.title(\"M2 Confusion Matrix\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:17:42.736516Z","iopub.execute_input":"2026-10-07T13:17:42.737073Z","iopub.status.idle":"2026-10-07T13:18:11.150994Z","shell.execute_reply.started":"2026-10-07T13:17:42.737048Z","shell.execute_reply":"2026-10-07T13:18:11.150234Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"M2 Classification Report:\")\nprint(\n    classification_report(\n        m2_true_labels,\n        m2_pred_labels,\n        target_names=[\"CBB\", \"CBSD\", \"CGM\", \"CMD\", \"Healthy\"],\n        digits=4\n    )\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:18:11.152104Z","iopub.execute_input":"2026-10-07T13:18:11.15255Z","iopub.status.idle":"2026-10-07T13:18:11.170559Z","shell.execute_reply.started":"2026-10-07T13:18:11.152527Z","shell.execute_reply":"2026-10-07T13:18:11.169689Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(8, 5))\n\nplt.plot(history_m2.history[\"accuracy\"], marker=\"o\", label=\"Training Accuracy\")\nplt.plot(history_m2.history[\"val_accuracy\"], marker=\"o\", label=\"Validation Accuracy\")\n\nplt.title(\"M2 Training vs Validation Accuracy\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Accuracy\")\nplt.legend()\nplt.grid()\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:18:11.171678Z","iopub.execute_input":"2026-10-07T13:18:11.172003Z","iopub.status.idle":"2026-10-07T13:18:11.346509Z","shell.execute_reply.started":"2026-10-07T13:18:11.171975Z","shell.execute_reply":"2026-10-07T13:18:11.345925Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(8, 5))\n\nplt.plot(history_m2.history[\"loss\"], marker=\"o\", label=\"Training Loss\")\nplt.plot(history_m2.history[\"val_loss\"], marker=\"o\", label=\"Validation Loss\")\n\nplt.title(\"M2 Training vs Validation Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.legend()\nplt.grid()\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:18:11.347515Z","iopub.execute_input":"2026-10-07T13:18:11.347937Z","iopub.status.idle":"2026-10-07T13:18:11.518897Z","shell.execute_reply.started":"2026-10-07T13:18:11.347915Z","shell.execute_reply":"2026-10-07T13:18:11.518079Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results = pd.DataFrame({\n    \"Model\": [\"M0 - Baseline\", \"M1 - Class Weights\", \"M2 - Fine-Tuned\"],\n    \"Validation Accuracy (%)\": [\n        round(m0_val_accuracy * 100, 2),\n        round(m1_val_accuracy * 100, 2),\n        round(m2_val_accuracy * 100, 2)\n    ]\n})\n\nresults","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:18:11.519973Z","iopub.execute_input":"2026-10-07T13:18:11.520372Z","iopub.status.idle":"2026-10-07T13:18:11.541908Z","shell.execute_reply.started":"2026-10-07T13:18:11.52034Z","shell.execute_reply":"2026-10-07T13:18:11.541139Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TEST_DIR = os.path.join(DATA_DIR, \"test_images\")\nsample_submission = pd.read_csv(\n    os.path.join(DATA_DIR, \"sample_submission.csv\")\n)\n\nprint(\"Number of test images:\", len(os.listdir(TEST_DIR)))\nprint(\"\\nSample submission:\")\nprint(sample_submission.head())\nprint(\"\\nSubmission shape:\", sample_submission.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:18:11.543034Z","iopub.execute_input":"2026-10-07T13:18:11.543371Z","iopub.status.idle":"2026-10-07T13:18:11.6196Z","shell.execute_reply.started":"2026-10-07T13:18:11.54334Z","shell.execute_reply":"2026-10-07T13:18:11.618926Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# Test image generator\ntest_datagen = ImageDataGenerator()\n\ntest_generator = test_datagen.flow_from_dataframe(\n    dataframe=sample_submission,\n    directory=TEST_DIR,\n    x_col=\"image_id\",\n    y_col=None,\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=None,\n    shuffle=False\n)\n\ntest_generator.reset()\ntest_predictions = model_m1.predict(test_generator)\ntest_labels = np.argmax(test_predictions, axis=1)\n\nprint(\"Predicted label:\", test_labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:18:11.620578Z","iopub.execute_input":"2026-10-07T13:18:11.620934Z","iopub.status.idle":"2026-10-07T13:18:13.295346Z","shell.execute_reply.started":"2026-10-07T13:18:11.620912Z","shell.execute_reply":"2026-10-07T13:18:13.294684Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"submission = sample_submission.copy()\n\nsubmission[\"label\"] = test_labels\n\nsubmission.to_csv(\"/kaggle/working/submission.csv\", index=False)\n\nprint(\"Submission file created successfully!\")\nprint(submission)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T13:18:13.296393Z","iopub.execute_input":"2026-10-07T13:18:13.296977Z","iopub.status.idle":"2026-10-07T13:18:13.311586Z","shell.execute_reply.started":"2026-10-07T13:18:13.296951Z","shell.execute_reply":"2026-10-07T13:18:13.310702Z"}},"outputs":[],"execution_count":null}]}