{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":13836,"databundleVersionId":1718836,"sourceType":"competition"}],"dockerImageVersionId":31040,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\n\nfile_paths = []\n\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        file_paths.append(os.path.join(dirname, filename))\n\nprint(f\"Total files: {len(file_paths)}\")\nprint(\"Example files:\", file_paths[:5])\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-20T06:42:55.410957Z","iopub.execute_input":"2025-05-20T06:42:55.411246Z","iopub.status.idle":"2025-05-20T06:43:18.750630Z","shell.execute_reply.started":"2025-05-20T06:42:55.411227Z","shell.execute_reply":"2025-05-20T06:43:18.749444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport json\n\n\nwith open('/kaggle/input/cassava-leaf-disease-classification/label_num_to_disease_map.json') as f:\n    label_map = json.load(f)\n\nprint(\"Label Mapping:\", label_map)\n\ndf = pd.read_csv('/kaggle/input/cassava-leaf-disease-classification/train.csv')\nprint(df.head())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T06:44:11.275377Z","iopub.execute_input":"2025-05-20T06:44:11.275636Z","iopub.status.idle":"2025-05-20T06:44:11.341390Z","shell.execute_reply.started":"2025-05-20T06:44:11.275618Z","shell.execute_reply":"2025-05-20T06:44:11.340477Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['image_path'] = df['image_id'].apply(lambda x: os.path.join( '/kaggle/input/cassava-leaf-disease-classification/train_images', x))\ndf['label_str'] = df['label'].apply(lambda x: label_map[str(x)])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T06:49:17.788534Z","iopub.execute_input":"2025-05-20T06:49:17.788773Z","iopub.status.idle":"2025-05-20T06:49:17.818945Z","shell.execute_reply.started":"2025-05-20T06:49:17.788755Z","shell.execute_reply":"2025-05-20T06:49:17.818323Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom sklearn.model_selection import train_test_split\n\ntrain_paths, val_paths, train_labels, val_labels = train_test_split(df['image_path'], df['label'], test_size=0.2, stratify=df['label'], random_state=42)\n\nIMG_SIZE = 224\nBATCH_SIZE = 32\nAUTOTUNE = tf.data.AUTOTUNE\n\ndef process_image(image_path, label):\n    image = tf.io.read_file(image_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, [IMG_SIZE, IMG_SIZE])\n    image = image / 255.0\n    return image, label\n\ntrain_ds = tf.data.Dataset.from_tensor_slices((train_paths, train_labels))\ntrain_ds = train_ds.map(process_image, num_parallel_calls=AUTOTUNE)\ntrain_ds = train_ds.shuffle(1024).batch(BATCH_SIZE).prefetch(AUTOTUNE)\n\nval_ds = tf.data.Dataset.from_tensor_slices((val_paths, val_labels))\nval_ds = val_ds.map(process_image, num_parallel_calls=AUTOTUNE)\nval_ds = val_ds.batch(BATCH_SIZE).prefetch(AUTOTUNE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T07:05:38.895803Z","iopub.execute_input":"2025-05-20T07:05:38.896098Z","iopub.status.idle":"2025-05-20T07:05:38.995929Z","shell.execute_reply.started":"2025-05-20T07:05:38.896083Z","shell.execute_reply":"2025-05-20T07:05:38.995170Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras import layers, models\n\nmodel = models.Sequential([\n    layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3)),\n    layers.Conv2D(32, (3,3), activation='relu'),\n    layers.MaxPooling2D(),\n    layers.Conv2D(64, (3,3), activation='relu'),\n    layers.MaxPooling2D(),\n    layers.Conv2D(128, (3,3), activation='relu'),\n    layers.GlobalAveragePooling2D(),\n    layers.Dense(128, activation='relu'),\n    layers.Dense(5, activation='softmax')\n])\n\nmodel.compile(optimizer='adam',\n             loss='sparse_categorical_crossentropy',\n             metrics =['accuracy'])\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T07:12:50.421629Z","iopub.execute_input":"2025-05-20T07:12:50.421872Z","iopub.status.idle":"2025-05-20T07:12:50.578775Z","shell.execute_reply.started":"2025-05-20T07:12:50.421854Z","shell.execute_reply":"2025-05-20T07:12:50.578047Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"EPOCHS = 10\n\nhistory = model.fit(\n    train_ds,\n    validation_data = val_ds,\n    epochs=EPOCHS\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T07:15:10.364700Z","iopub.execute_input":"2025-05-20T07:15:10.364944Z","iopub.status.idle":"2025-05-20T09:08:00.267470Z","shell.execute_reply.started":"2025-05-20T07:15:10.364929Z","shell.execute_reply":"2025-05-20T09:08:00.261951Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.plot(history.history['accuracy'], label='train acc')\nplt.plot(history.history['val_accuracy'], label='val acc')\nplt.title('Training and Validation Accuracy')\nplt.xlabel=('Epoch')\nplt.ylabel","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T09:08:06.349019Z","iopub.execute_input":"2025-05-20T09:08:06.349905Z","iopub.status.idle":"2025-05-20T09:08:06.965576Z","shell.execute_reply.started":"2025-05-20T09:08:06.349813Z","shell.execute_reply":"2025-05-20T09:08:06.964758Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save(\"cassava_cnn_model.h5\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T09:08:13.789705Z","iopub.execute_input":"2025-05-20T09:08:13.790035Z","iopub.status.idle":"2025-05-20T09:08:14.016292Z","shell.execute_reply.started":"2025-05-20T09:08:13.789979Z","shell.execute_reply":"2025-05-20T09:08:14.015211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport cv2\n\ndef make_gradcam_heatmap(img_array, model, last_conv_layer_name, pred_index=None):\n    grad_model = tf.keras.models.Model(\n        [model.inputs], \n        [model.get_layer(last_conv_layer_name).output, model.output]\n    )\n\n    with tf.GradientTape() as tape:\n        conv_outputs, predictions = grad_model(img_array)\n        if pred_index is None:\n            pred_index = tf.argmax(predictions[0])\n        class_channel = predictions[:, pred_index]\n\n    grads = tape.gradient(class_channel, conv_outputs)\n\n    pooled_grads = tf.reduce_mean(grads, axis=(0, 1, 2))\n    conv_outputs = conv_outputs[0]\n\n    heatmap = conv_outputs @ pooled_grads[..., tf.newaxis]\n    heatmap = tf.squeeze(heatmap)\n    heatmap = tf.maximum(heatmap, 0) / tf.math.reduce_max(heatmap)\n    return heatmap.numpy()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T09:19:44.068520Z","iopub.execute_input":"2025-05-20T09:19:44.068831Z","iopub.status.idle":"2025-05-20T09:19:44.077276Z","shell.execute_reply.started":"2025-05-20T09:19:44.068809Z","shell.execute_reply":"2025-05-20T09:19:44.075964Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def display_gradcam(img_path, model, last_conv_layer_name='conv2d_2'):\n    img = tf.keras.preprocessing.image.load_img(img_path, target_size=(224, 224))\n    img_array = tf.keras.preprocessing.image.img_to_array(img)\n    img_array = np.expand_dims(img_array / 255.0, axis=0)\n\n    heatmap = make_gradcam_heatmap(img_array, model, last_conv_layer_name)\n\n  \n    heatmap = cv2.resize(heatmap, (224, 224))\n    heatmap = np.uint8(255 * heatmap)\n    heatmap = cv2.applyColorMap(heatmap, cv2.COLORMAP_JET)\n\n\n    superimposed_img = heatmap * 0.4 + img_array[0] * 255\n    plt.imshow(superimposed_img.astype(np.uint8))\n    plt.title(\"Grad-CAM Heatmap\")\n    plt.axis('off')\n    plt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T09:20:20.093953Z","iopub.execute_input":"2025-05-20T09:20:20.094270Z","iopub.status.idle":"2025-05-20T09:20:20.099600Z","shell.execute_reply.started":"2025-05-20T09:20:20.094252Z","shell.execute_reply":"2025-05-20T09:20:20.099024Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.applications import EfficientNetB0\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Dropout, Input\n\n# Load base EfficientNetB0 without the top classifier\nbase_model = EfficientNetB0(include_top=False, weights='imagenet', input_shape=(224, 224, 3))\nbase_model.trainable = False  # Freeze the base model\n\n# Add custom classifier head\ninputs = Input(shape=(224, 224, 3))\nx = base_model(inputs, training=False)\nx = GlobalAveragePooling2D()(x)\nx = Dropout(0.3)(x)\nx = Dense(128, activation='relu')(x)\noutputs = Dense(5, activation='softmax')(x)\nmodel_tf = Model(inputs, outputs)\n\n# Compile\nmodel_tf.compile(optimizer='adam',\n                 loss='sparse_categorical_crossentropy',\n                 metrics=['accuracy'])\n\nmodel_tf.summary()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-20T09:22:36.078782Z","iopub.execute_input":"2025-05-20T09:22:36.079158Z","iopub.status.idle":"2025-05-20T09:22:39.162708Z","shell.execute_reply.started":"2025-05-20T09:22:36.079136Z","shell.execute_reply":"2025-05-20T09:22:39.161738Z"}},"outputs":[],"execution_count":null}]}