{"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":120534,"databundleVersionId":14424293,"sourceType":"competition"}],"dockerImageVersionId":31193,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<div style=\"text-align:center; padding: 20px; border-radius: 10px; background-color: #f7f7f7; border: 1px solid #ddd;\">\n<h1 style=\"color: #4CAF50; font-size: 3em; font-family: 'Arial Black', sans-serif; text-transform: uppercase; letter-spacing: 2px;\"> NEXT CHALLANGE TO IMPLEMENT THESE MODELS ON THIS DATASET </h1>\n\n # 🏆 **EdgeFire Grand Challenge 2025: Next-Gen AI for Early Fire Detection on Edge Devices**\n\n---\n\n## 🔥 **Overview**\n\nThe **EdgeFire Grand Challenge 2025** invites AI researchers, students, and Kaggle competitors to design **novel, efficient deep learning models** for real-time fire and smoke detection on **resource-constrained devices** such as Raspberry Pi, Jetson Nano, Android NPUs, and mini edge computers.\n\nParticipants will explore **lightweight architectures**, **multi-modal fusion**, **privacy-aware learning**, and **domain robustness** to build the next generation of **edge-deployable fire detection systems** capable of saving lives and forests worldwide.\n\nThis competition emphasizes:\n- 🧠 Novelty in model design  \n- ⚙️ Efficiency on edge hardware  \n- 🧩 Robustness under real-world distortions  \n- 🚨 Early detection capability  \n\n---\n\n## 💡 **Challenge Theme**\n\n> “Design a novel, efficient, and explainable AI model for early fire and smoke detection that can run on low-power devices with high accuracy and low latency.”\n\n---\n\n## 🧠 **Objective**\n\nBuild and evaluate deep learning models capable of:\n- Detecting **fire, smoke, and early onset cues**\n- Performing well under **limited compute and memory**\n- Maintaining **robustness** under lighting, compression, and weather distortions\n- Supporting **quantization/pruning** for real-time edge inference\n\n---\n\n## 📊 **Dataset**\n\nParticipants will use the **Forest Fire Dataset for Binary Classification**, featuring:\n- Two classes: `fire` and `nofire`\n- Pre-split into **train**, **val**, and **test**\n- Multi-source, with diverse lighting and weather conditions\n\nThey may **augment**, **expand**, or **restructure** the dataset (as long as their process is documented).  \nSynthetic and weakly labeled data are allowed — provided they are **publicly reproducible**.\n\n---\n\n## 🧩 **Tracks**\n\n### 🥇 **Track 1: Novel Architectures**\n\nImplement or extend any of the following conceptual models — or propose your own:\n\n| Model Name | Concept Focus | Key Innovation |\n|-------------|----------------|----------------|\n| **FireFormer-E** | Early smoke cues | Temporal transformer with onset regression and haze-aware attention |\n| **MultiFire-MM** | RGB + Thermal + Audio fusion | Tri-modal alignment with adaptive fusion and cross-modality voting |\n| **SmokeSeg-YOLO-Decouple** | Lightweight detection + segmentation | Dual-head YOLO with shape-aware focal Tversky loss |\n| **DR-FireNet** | Domain robustness | Frequency and style adapters for compression and lighting variation |\n| **Fed-Private-Fire** | Privacy & scale | Federated LoRA adapters + DP-SGD for CCTV deployment |\n| **EventFire** | Event-based low-latency detection | Spiking-inspired CNN for real-time grayscale/event data |\n\nParticipants can choose one, combine ideas, or propose an entirely **novel variant** — creativity is encouraged.  \n\n---\n\n### 🥈 **Track 2: Edge Efficiency**\n\nDeploy and benchmark your best-performing model on **edge hardware simulators** or **real devices**:\n\n**Targets:** Raspberry Pi 4, Jetson Nano, Jetson Orin Nano, Android NPU, CPU-only MiniPC  \n\nDemonstrate model optimization via:\n- Quantization (QAT or post-training)\n- Pruning\n- TensorRT / TFLite conversion\n\n**Submissions must include:**\n- 🧠 The compressed model file  \n- ⚙️ An inference benchmark report (FPS, latency, power)  \n- 📉 The model size and FLOPs count  \n\n---\n\n## ⚙️ **Evaluation Metrics**\n\n| Metric | Description | Weight |\n|---------|--------------|--------|\n| **Accuracy / mAP** | Fire vs. NoFire detection accuracy | 30% |\n| **Latency (ms/frame)** | Inference time on Raspberry Pi / Jetson | 25% |\n| **Model Size (MB)** | Smaller is better | 15% |\n| **Novelty & Technical Soundness** | Innovation in architecture or optimization | 15% |\n| **Explainability & Reporting** | Visual outputs, overlays, interpretability | 10% |\n| **Robustness** | Under JPEG, fog, night, or blur | 5% |\n\n---\n\n## 🧪 **Submission Requirements**\n\nEach submission must include:\n- 📔 **Notebook (.ipynb)** — Training + inference workflow  \n- 🧠 **Model weights** — `.tflite`, `.onnx`, or `.pt` (max 100 MB)  \n- 📄 **Technical report (PDF)** — Short 2–4 pages explaining:  \n  - Architecture overview  \n  - Optimization techniques used  \n  - Hardware benchmarks  \n  - Visual examples / explainability results  \n- ⚡ **Inference log** showing model speed and power usage  \n- 🎥 *(Optional)* Edge hardware video demo (YouTube or Drive link)\n\n---\n\n## 📦 **Baseline & Benchmark**\n\nA simple CNN baseline (e.g., **MobileNetV2 with 65–70% accuracy**) will be provided as a **Benchmark Submission**.  \nYour model must outperform this benchmark in at least **one dimension** (accuracy, latency, or model size).\n\n---\n\n## 🏁 **Evaluation & Leaderboard**\n\n- **Public Leaderboard:** 40% test data (Public split from `solution.csv`)  \n- **Private Leaderboard:** Remaining 60% test data (revealed post-competition)  \n- 🏆 Winners determined by **Weighted Composite Score** (accuracy + efficiency + novelty)\n\n---\n\n\n## 🧾 **Evaluation Environment**\n\n- **OS:** Ubuntu 22.04 / Jetson Linux  / Raspberry PI Os\n- **Frameworks:** PyTorch, TensorFlow, or ONNX  \n- **Evaluation Tools:**  \n  - `onnxruntime`, `tflite_runtime`, `torch.profiler`  \n  - Power measurement via `tegrastats` or simulated runtime  \n\n---\n\n## 🌱 **Encouraged Techniques**\n\n- Quantization-aware training  \n- Pruning and distillation  \n- Cross-modal alignment (RGB + thermal or audio)  \n- Frequency-domain robustness  \n- Federated privacy adaptation  \n- Spiking or temporal transformers  \n\n---\n\n## 🧭 **Explainability & Trust**\n\nModels must provide interpretable outputs, including:\n- 🔥 Smoke and flame overlays  \n- 🎯 Grad-CAM or feature visualizations  \n- 📈 Uncertainty or confidence maps  \n\n**Bonus points** for:\n- False-alarm review loop  \n- Operator dashboard mockup  \n\n---\n","metadata":{}},{"cell_type":"markdown","source":"# =======================================================\n#  Forest Fire Prediction MobileNetV2 Transfer Learning\n# =======================================================","metadata":{}},{"cell_type":"markdown","source":"**🔬Overview: FFireNet Forest Fire Detection**\n\n**🔥 MobileNetV2 backbone with transfer learning**\n\n⚙️ **Paper's exact hyperparameters:** SGD optimizer (lr=0.01), 64 batch size, 50 epochs\n\n📊 **Balanced dataset:** 45% fire/55% no-fire images (70-20-19 train-test-val split)\n\n**🖼️ Data augmentation:** Rotation, shifts, shear, zoom per paper specifications\n\n**📈 Metrics:** Accuracy, Precision, Recall, AUC (+ confusion matrix visualization)","metadata":{}},{"cell_type":"markdown","source":"**Key results from original paper:**\n\ntest accuracy = 98.42% \n\nprecision = 97.42%  \n\nrecall = 99.47% \n\nrecall = 1.58% ","metadata":{}},{"cell_type":"markdown","source":"# 1. Import Libraries","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.applications import MobileNetV2\nfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Dropout\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.optimizers import Adam\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport seaborn as sns\nfrom sklearn.metrics import classification_report, confusion_matrix\nimport os\nimport shutil\nfrom PIL import Image\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport math\nfrom tensorflow.keras import backend as K\nfrom tensorflow.keras.callbacks import Callback, EarlyStopping","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:21:14.803870Z","iopub.execute_input":"2025-11-10T18:21:14.804535Z","iopub.status.idle":"2025-11-10T18:21:14.809513Z","shell.execute_reply.started":"2025-11-10T18:21:14.804508Z","shell.execute_reply":"2025-11-10T18:21:14.808679Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 2. Loading Dataset","metadata":{}},{"cell_type":"code","source":"# Original dataset paths for V2\ntest_dir = \"/kaggle/input/edge-forest-fire-challenge-2025/Forest-Fire-Cleaned-Processed/test\"\ntrain_dir = \"/kaggle/input/edge-forest-fire-challenge-2025/Forest-Fire-Cleaned-Processed/train\"\nval_dir = \"/kaggle/input/edge-forest-fire-challenge-2025/Forest-Fire-Cleaned-Processed/val\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:21:58.936984Z","iopub.execute_input":"2025-11-10T18:21:58.937322Z","iopub.status.idle":"2025-11-10T18:21:58.940985Z","shell.execute_reply.started":"2025-11-10T18:21:58.937293Z","shell.execute_reply":"2025-11-10T18:21:58.940403Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3. Defining Image Size & Batch Size","metadata":{}},{"cell_type":"code","source":"IMG_SIZE = (224, 224)\nBATCH_SIZE = 32","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:03.190888Z","iopub.execute_input":"2025-11-10T18:22:03.191167Z","iopub.status.idle":"2025-11-10T18:22:03.194795Z","shell.execute_reply.started":"2025-11-10T18:22:03.191146Z","shell.execute_reply":"2025-11-10T18:22:03.194172Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 4. Data Augmentation ","metadata":{}},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=20,\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\nval_test_datagen = ImageDataGenerator(rescale=1./255)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:05.704189Z","iopub.execute_input":"2025-11-10T18:22:05.704497Z","iopub.status.idle":"2025-11-10T18:22:05.708626Z","shell.execute_reply.started":"2025-11-10T18:22:05.704477Z","shell.execute_reply":"2025-11-10T18:22:05.707907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# --- 2. Create the Generators, now pointing to your new, clean directories ---\ntrain_generator = train_datagen.flow_from_directory(\n    train_dir,  # Now uses the correct training directory\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"categorical\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:08.737630Z","iopub.execute_input":"2025-11-10T18:22:08.738349Z","iopub.status.idle":"2025-11-10T18:22:12.581068Z","shell.execute_reply.started":"2025-11-10T18:22:08.738322Z","shell.execute_reply":"2025-11-10T18:22:12.580524Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"val_generator = val_test_datagen.flow_from_directory(\n    val_dir,    # Now uses the correct validation directory\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"categorical\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:20.462284Z","iopub.execute_input":"2025-11-10T18:22:20.462553Z","iopub.status.idle":"2025-11-10T18:22:21.324629Z","shell.execute_reply.started":"2025-11-10T18:22:20.462534Z","shell.execute_reply":"2025-11-10T18:22:21.324040Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_generator = val_test_datagen.flow_from_directory(\n    test_dir,   # Now uses the correct test directory\n    target_size=IMG_SIZE,\n    batch_size=BATCH_SIZE,\n    class_mode=\"categorical\",\n    shuffle=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:24.084597Z","iopub.execute_input":"2025-11-10T18:22:24.085155Z","iopub.status.idle":"2025-11-10T18:22:25.849378Z","shell.execute_reply.started":"2025-11-10T18:22:24.085132Z","shell.execute_reply":"2025-11-10T18:22:25.848713Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 5. Classes in Dataset","metadata":{}},{"cell_type":"code","source":"class_names = list(train_generator.class_indices.keys())\nprint(\"Classes:\", class_names)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:29.089184Z","iopub.execute_input":"2025-11-10T18:22:29.089500Z","iopub.status.idle":"2025-11-10T18:22:29.093846Z","shell.execute_reply.started":"2025-11-10T18:22:29.089479Z","shell.execute_reply":"2025-11-10T18:22:29.093039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class_names = list(test_generator.class_indices.keys())\nprint(\"Classes:\", class_names)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:31.827144Z","iopub.execute_input":"2025-11-10T18:22:31.827837Z","iopub.status.idle":"2025-11-10T18:22:31.831762Z","shell.execute_reply.started":"2025-11-10T18:22:31.827811Z","shell.execute_reply":"2025-11-10T18:22:31.831028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class_names = list(val_generator.class_indices.keys())\nprint(\"Classes:\", class_names)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:34.800814Z","iopub.execute_input":"2025-11-10T18:22:34.801527Z","iopub.status.idle":"2025-11-10T18:22:34.805581Z","shell.execute_reply.started":"2025-11-10T18:22:34.801501Z","shell.execute_reply":"2025-11-10T18:22:34.804808Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(\"VAL CLASSES:\", os.listdir(val_dir))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:40.434560Z","iopub.execute_input":"2025-11-10T18:22:40.435235Z","iopub.status.idle":"2025-11-10T18:22:40.440334Z","shell.execute_reply.started":"2025-11-10T18:22:40.435208Z","shell.execute_reply":"2025-11-10T18:22:40.439547Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# =======================================================\n# 6. Base Model (MobileNetV2 Transfer Learning)","metadata":{}},{"cell_type":"code","source":"base_model = MobileNetV2(weights=\"imagenet\", include_top=False, input_shape=(224,224,3))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:43.884396Z","iopub.execute_input":"2025-11-10T18:22:43.884662Z","iopub.status.idle":"2025-11-10T18:22:46.829574Z","shell.execute_reply.started":"2025-11-10T18:22:43.884646Z","shell.execute_reply":"2025-11-10T18:22:46.828954Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_model.trainable =False #freeze base layer","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:52.669836Z","iopub.execute_input":"2025-11-10T18:22:52.670119Z","iopub.status.idle":"2025-11-10T18:22:52.675697Z","shell.execute_reply.started":"2025-11-10T18:22:52.670099Z","shell.execute_reply":"2025-11-10T18:22:52.674821Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"x = base_model.output\nx = GlobalAveragePooling2D()(x)\nx = Dropout(0.3)(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:55.462999Z","iopub.execute_input":"2025-11-10T18:22:55.463591Z","iopub.status.idle":"2025-11-10T18:22:55.472654Z","shell.execute_reply.started":"2025-11-10T18:22:55.463567Z","shell.execute_reply":"2025-11-10T18:22:55.472007Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"preds = Dense(len(class_names), activation = 'softmax')(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:22:57.851589Z","iopub.execute_input":"2025-11-10T18:22:57.852288Z","iopub.status.idle":"2025-11-10T18:22:57.865763Z","shell.execute_reply.started":"2025-11-10T18:22:57.852245Z","shell.execute_reply":"2025-11-10T18:22:57.865014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = Model(inputs = base_model.input, outputs = preds)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:00.356705Z","iopub.execute_input":"2025-11-10T18:23:00.357280Z","iopub.status.idle":"2025-11-10T18:23:00.367652Z","shell.execute_reply.started":"2025-11-10T18:23:00.357253Z","shell.execute_reply":"2025-11-10T18:23:00.366957Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Compile Model","metadata":{}},{"cell_type":"code","source":"model.compile(optimizer=Adam(learning_rate=0.0001),\n             loss='categorical_crossentropy',\n             metrics=[\"accuracy\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:03.692929Z","iopub.execute_input":"2025-11-10T18:23:03.693676Z","iopub.status.idle":"2025-11-10T18:23:03.707859Z","shell.execute_reply.started":"2025-11-10T18:23:03.693652Z","shell.execute_reply":"2025-11-10T18:23:03.707217Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Model Summary","metadata":{}},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:06.760980Z","iopub.execute_input":"2025-11-10T18:23:06.761241Z","iopub.status.idle":"2025-11-10T18:23:06.896870Z","shell.execute_reply.started":"2025-11-10T18:23:06.761215Z","shell.execute_reply":"2025-11-10T18:23:06.896310Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 7. Model Training","metadata":{}},{"cell_type":"code","source":"# Define No of epochs here\nEPOCHS = 10\nINIT_LR = 1e-2  # initial learning rate","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:15.812591Z","iopub.execute_input":"2025-11-10T18:23:15.813122Z","iopub.status.idle":"2025-11-10T18:23:15.816498Z","shell.execute_reply.started":"2025-11-10T18:23:15.813100Z","shell.execute_reply":"2025-11-10T18:23:15.815763Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define optimizer\noptimizer = tf.keras.optimizers.Adam(learning_rate=INIT_LR)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:18.667249Z","iopub.execute_input":"2025-11-10T18:23:18.667546Z","iopub.status.idle":"2025-11-10T18:23:18.674067Z","shell.execute_reply.started":"2025-11-10T18:23:18.667528Z","shell.execute_reply":"2025-11-10T18:23:18.673305Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Custom callback to log learning rate at the end of each epoch\nclass LrLogger(Callback):\n    def on_epoch_end(self, epoch, logs=None):\n        lr = float(K.get_value(self.model.optimizer.learning_rate))\n        print(f\"\\nEpoch {epoch+1} → Learning Rate: {lr:.6f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:24.463303Z","iopub.execute_input":"2025-11-10T18:23:24.464058Z","iopub.status.idle":"2025-11-10T18:23:24.468110Z","shell.execute_reply.started":"2025-11-10T18:23:24.464018Z","shell.execute_reply":"2025-11-10T18:23:24.467410Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Early stopping to prevent overfitting\nearly_stop = EarlyStopping(\n    monitor=\"val_loss\",   # stop when validation loss stops improving\n    patience=3,           # wait 3 epochs before stopping\n    restore_best_weights=True\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:32.213529Z","iopub.execute_input":"2025-11-10T18:23:32.213778Z","iopub.status.idle":"2025-11-10T18:23:32.217581Z","shell.execute_reply.started":"2025-11-10T18:23:32.213762Z","shell.execute_reply":"2025-11-10T18:23:32.216858Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Compile with all metrics\nmodel.compile(\n    optimizer=optimizer,\n    loss=\"categorical_crossentropy\",\n    metrics=[\n        \"accuracy\",\n        tf.keras.metrics.AUC(name=\"auc\"),\n        tf.keras.metrics.Precision(name=\"precision\"),\n        tf.keras.metrics.Recall(name=\"recall\"),\n    ]\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:34.806421Z","iopub.execute_input":"2025-11-10T18:23:34.806709Z","iopub.status.idle":"2025-11-10T18:23:34.826994Z","shell.execute_reply.started":"2025-11-10T18:23:34.806676Z","shell.execute_reply":"2025-11-10T18:23:34.826276Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train\nhistory = model.fit(\n    train_generator,\n    steps_per_epoch=math.ceil(train_generator.samples / BATCH_SIZE),\n    validation_data=val_generator,\n    validation_steps=math.ceil(val_generator.samples / BATCH_SIZE),\n    epochs=EPOCHS,\n    callbacks=[LrLogger(), early_stop],\n    verbose=1\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:23:38.089458Z","iopub.execute_input":"2025-11-10T18:23:38.089992Z","iopub.status.idle":"2025-11-10T18:27:46.079952Z","shell.execute_reply.started":"2025-11-10T18:23:38.089965Z","shell.execute_reply":"2025-11-10T18:27:46.079285Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 8. Visualizing Results","metadata":{}},{"cell_type":"code","source":"def plot_training_history(history):\n    metrics = [\"accuracy\", \"loss\", \"auc\", \"precision\", \"recall\"]\n    n = len(metrics)\n\n    plt.figure(figsize=(15, 10))\n\n    for i, metric in enumerate(metrics, 1):\n        plt.subplot(3, 2, i)  # 3 rows × 2 cols grid\n        plt.plot(history.history[metric], label=f\"Train {metric.capitalize()}\")\n        plt.plot(history.history[f\"val_{metric}\"], label=f\"Val {metric.capitalize()}\")\n        plt.title(f\"Model {metric.capitalize()}\")\n        plt.xlabel(\"Epochs\")\n        plt.ylabel(metric.capitalize())\n        plt.legend()\n        plt.grid(True, linestyle=\"--\", alpha=0.6)\n\n    plt.tight_layout()\n    plt.show()\n\n# Call function\nplot_training_history(history)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:27:46.081419Z","iopub.execute_input":"2025-11-10T18:27:46.081650Z","iopub.status.idle":"2025-11-10T18:27:47.006476Z","shell.execute_reply.started":"2025-11-10T18:27:46.081633Z","shell.execute_reply":"2025-11-10T18:27:47.005674Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 9. Fine Tuning","metadata":{}},{"cell_type":"code","source":"base_model.trainable = True\nfor layer in base_model.layers[:-30]:  # unfreeze last 30 layers\n    layer.trainable = False","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:34:24.471555Z","iopub.execute_input":"2025-11-10T18:34:24.472303Z","iopub.status.idle":"2025-11-10T18:34:24.476381Z","shell.execute_reply.started":"2025-11-10T18:34:24.472249Z","shell.execute_reply":"2025-11-10T18:34:24.475614Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(optimizer=Adam(learning_rate=1e-5),\n              loss=\"categorical_crossentropy\",\n              metrics=[\"accuracy\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:34:29.260668Z","iopub.execute_input":"2025-11-10T18:34:29.261309Z","iopub.status.idle":"2025-11-10T18:34:29.269478Z","shell.execute_reply.started":"2025-11-10T18:34:29.261252Z","shell.execute_reply":"2025-11-10T18:34:29.268673Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fine_tune_epochs = 15\nhistory_fine = model.fit(\n    train_generator,\n    steps_per_epoch=math.ceil(train_generator.samples / BATCH_SIZE),\n    validation_data=val_generator,\n    validation_steps=math.ceil(val_generator.samples / BATCH_SIZE),\n    epochs=fine_tune_epochs\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:34:34.089738Z","iopub.execute_input":"2025-11-10T18:34:34.090031Z","iopub.status.idle":"2025-11-10T18:48:03.699826Z","shell.execute_reply.started":"2025-11-10T18:34:34.090008Z","shell.execute_reply":"2025-11-10T18:48:03.699204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plot_training_history(history_fine)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:49:16.942023Z","iopub.execute_input":"2025-11-10T18:49:16.942335Z","iopub.status.idle":"2025-11-10T18:49:17.425237Z","shell.execute_reply.started":"2025-11-10T18:49:16.942313Z","shell.execute_reply":"2025-11-10T18:49:17.424301Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# =====================================\n# 10. Model Evaluation on Test Set\n","metadata":{}},{"cell_type":"code","source":"test_loss, test_acc = model.evaluate(test_generator, steps=math.ceil(test_generator.samples / BATCH_SIZE))\nprint(f\"✅ Test Accuracy: {test_acc*100:.2f}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:48:14.125725Z","iopub.execute_input":"2025-11-10T18:48:14.126088Z","iopub.status.idle":"2025-11-10T18:48:19.375329Z","shell.execute_reply.started":"2025-11-10T18:48:14.126064Z","shell.execute_reply":"2025-11-10T18:48:19.374682Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 11. Plotting the Classification Reports and Confusion Matrix","metadata":{}},{"cell_type":"code","source":"# Classification Report\nY_pred = model.predict(test_generator, steps=math.ceil(test_generator.samples / BATCH_SIZE))\ny_pred = np.argmax(Y_pred, axis=1)\n\nprint(\"Classification Report:\\n\")\nprint(classification_report(test_generator.classes, y_pred, target_names=class_names))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:48:19.377087Z","iopub.execute_input":"2025-11-10T18:48:19.377457Z","iopub.status.idle":"2025-11-10T18:48:27.967338Z","shell.execute_reply.started":"2025-11-10T18:48:19.377438Z","shell.execute_reply":"2025-11-10T18:48:27.966697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Confusion Matrix\ncm = confusion_matrix(test_generator.classes, y_pred)\n\nplt.figure(figsize=(6,5))\nsns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\", xticklabels=class_names, yticklabels=class_names)\nplt.title(\"Confusion Matrix\")\nplt.xlabel(\"Predicted\")\nplt.ylabel(\"True\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:48:27.968076Z","iopub.execute_input":"2025-11-10T18:48:27.968361Z","iopub.status.idle":"2025-11-10T18:48:28.114749Z","shell.execute_reply.started":"2025-11-10T18:48:27.968340Z","shell.execute_reply":"2025-11-10T18:48:28.114007Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n# Get the test predictions\ny_pred = model.predict(test_generator)\ny_pred_classes = np.argmax(y_pred, axis=1)\n\n# Get the true labels from the test generator\ny_true = test_generator.classes\n\n# Find the indices of the misclassified images\nmisclassified_indices = np.where(y_true != y_pred_classes)[0]\nprint(f\"Total misclassified images: {len(misclassified_indices)}\")\n\n# Map class indices back to class names\nclass_names = list(test_generator.class_indices.keys())\n\n# Display a few of the misclassified images\nplt.figure(figsize=(15, 15))\nfor i, index in enumerate(misclassified_indices[:25]): # Display up to 25 images\n    plt.subplot(5, 5, i + 1)\n    \n    # Get the image and true/predicted labels\n    img = test_generator[index // test_generator.batch_size][0][index % test_generator.batch_size]\n    true_label = class_names[y_true[index]]\n    predicted_label = class_names[y_pred_classes[index]]\n    \n    # Show the image\n    plt.imshow(img)\n    plt.title(f\"True: {true_label}\\nPred: {predicted_label}\")\n    plt.axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:48:28.115491Z","iopub.execute_input":"2025-11-10T18:48:28.115696Z","iopub.status.idle":"2025-11-10T18:48:34.832566Z","shell.execute_reply.started":"2025-11-10T18:48:28.115679Z","shell.execute_reply":"2025-11-10T18:48:34.831690Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 12. Visualizing Predictions on Images","metadata":{}},{"cell_type":"markdown","source":"import random\n\n# Pick some test images\ntest_img_paths = []\nfor cls in os.listdir(test_generator):\n    cls_path = os.path.join(test_generator, cls)\n    for f in os.listdir(cls_path):\n        test_img_paths.append(os.path.join(cls_path, f))\n\nsample_imgs = random.sample(test_img_paths, 5)\n\nplt.figure(figsize=(15,6))\nfor i, img_path in enumerate(sample_imgs):\n    img = tf.keras.preprocessing.image.load_img(img_path, target_size=IMG_SIZE)\n    img_array = tf.keras.preprocessing.image.img_to_array(img) / 255.0\n    img_array = np.expand_dims(img_array, axis=0)\n\n    pred = model.predict(img_array)\n    pred_class = class_names[np.argmax(pred)]\n\n    plt.subplot(1,5,i+1)\n    plt.imshow(img)\n    plt.title(f\"Pred: {pred_class}\")\n    plt.axis(\"off\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2025-08-28T23:01:14.561591Z","iopub.execute_input":"2025-08-28T23:01:14.562087Z","iopub.status.idle":"2025-08-28T23:01:14.588862Z","shell.execute_reply.started":"2025-08-28T23:01:14.562062Z","shell.execute_reply":"2025-08-28T23:01:14.587342Z"}}},{"cell_type":"markdown","source":"# ================================================\n# 13. Saving Model","metadata":{}},{"cell_type":"code","source":"model.save(\"/kaggle/working/mobilenetv2_fire_detection.h5\")\nprint(\"✅ Model saved in /kaggle/working/\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:48:34.833764Z","iopub.execute_input":"2025-11-10T18:48:34.834078Z","iopub.status.idle":"2025-11-10T18:48:35.184155Z","shell.execute_reply.started":"2025-11-10T18:48:34.834052Z","shell.execute_reply":"2025-11-10T18:48:35.183307Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 14 Reload Model","metadata":{}},{"cell_type":"code","source":"loaded_model = tf.keras.models.load_model(\"/kaggle/working/mobilenetv2_fire_detection.h5\")\nloss, acc = loaded_model.evaluate(test_generator, steps=math.ceil(test_generator.samples / BATCH_SIZE))\nprint(f\"Reloaded Model Test Accuracy: {acc*100:.2f}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:48:35.185048Z","iopub.execute_input":"2025-11-10T18:48:35.185408Z","iopub.status.idle":"2025-11-10T18:48:44.911942Z","shell.execute_reply.started":"2025-11-10T18:48:35.185374Z","shell.execute_reply":"2025-11-10T18:48:44.911323Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 15. Load Model & Evaluate","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# Load model\nmodel = tf.keras.models.load_model(\"/kaggle/working/mobilenetv2_fire_detection.h5\")\n\n# Prepare test dataset (adjust path)\ntest_dir = '/kaggle/input/edge-forest-fire-challenge-2025/Forest-Fire-Cleaned-Processed/test'\n\ntest_datagen = ImageDataGenerator(rescale=1.0/255.0)\n\ntest_generator = test_datagen.flow_from_directory(\n    test_dir,\n    target_size=(224, 224),\n    batch_size=32,\n    class_mode=\"categorical\",\n    shuffle=False\n)\n\n# Evaluate\nresults = model.evaluate(test_generator)\nprint(\"\\n📊 Evaluation Results:\")\nfor metric, value in zip(model.metrics_names, results):\n    print(f\"{metric}: {value:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:51:14.981876Z","iopub.execute_input":"2025-11-10T18:51:14.982472Z","iopub.status.idle":"2025-11-10T18:51:25.234540Z","shell.execute_reply.started":"2025-11-10T18:51:14.982446Z","shell.execute_reply":"2025-11-10T18:51:25.233754Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 16. Load and Test on Images from Google","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport requests\nfrom PIL import Image\nfrom io import BytesIO\n\n# Load the saved model\nmodel = tf.keras.models.load_model(\"/kaggle/working/mobilenetv2_fire_detection.h5\")\nprint(\"✅ Model loaded successfully!\")\n\n# Define your class labels (update if you find a 3rd class)\nclass_labels = [\"Fire\", \"No Fire\"]\n\n# Function to preprocess image and predict\ndef predict_image(url, target_size=(224, 224)):\n    try:\n        # Load image from URL\n        response = requests.get(url)\n        img = Image.open(BytesIO(response.content)).convert(\"RGB\")\n        \n        # Resize and preprocess\n        img_resized = img.resize(target_size)\n        img_array = np.array(img_resized) / 255.0\n        img_array = np.expand_dims(img_array, axis=0)  # Add batch dimension\n\n        # Prediction\n        preds = model.predict(img_array)\n        pred_class = np.argmax(preds, axis=1)[0]\n        confidence = np.max(preds)\n\n        # Show image + prediction\n        plt.imshow(img)\n        plt.axis(\"off\")\n        plt.title(f\"Prediction: {class_labels[pred_class]} ({confidence:.2f})\")\n        plt.show()\n\n    except Exception as e:\n        print(\"❌ Error processing image:\", e)\n\n# Example test images from Google (replace with your own)\ntest_urls = [\n    \"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTBoCPC2CA6n0QjqOyT6gKI-xMT2EMLWEhDQA&s\",  # Fire\n    \"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTSSBhbrWQi_2CyKMpVxfSf6qfgFTfz-To4bA&\"        # No Fire\n]\n\n# Run predictions\nfor url in test_urls:\n    predict_image(url)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:51:38.560283Z","iopub.execute_input":"2025-11-10T18:51:38.560614Z","iopub.status.idle":"2025-11-10T18:51:43.004225Z","shell.execute_reply.started":"2025-11-10T18:51:38.560590Z","shell.execute_reply":"2025-11-10T18:51:43.003329Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!ls -lh /kaggle/working/mobilenetv2_fire_detection.h5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:20:18.115507Z","iopub.status.idle":"2025-11-10T18:20:18.115741Z","shell.execute_reply.started":"2025-11-10T18:20:18.115616Z","shell.execute_reply":"2025-11-10T18:20:18.115625Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Making Zip to Download Trained Model","metadata":{}},{"cell_type":"code","source":"!zip -r mobilenetv2_fire_detection.zip mobilenetv2_fire_detection.h5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T18:20:18.116834Z","iopub.status.idle":"2025-11-10T18:20:18.117113Z","shell.execute_reply.started":"2025-11-10T18:20:18.116980Z","shell.execute_reply":"2025-11-10T18:20:18.116996Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"<div style=\"text-align:center; padding: 20px; border-radius: 10px; background-color: #f7f7f7; border: 1px solid #ddd;\">\n<h1 style=\"color: #4CAF50; font-size: 3em; font-family: 'Arial Black', sans-serif; text-transform: uppercase; letter-spacing: 2px;\">Thank You!</h1>\n<p style=\"color: #555; font-size: 1.2em; margin-top: 15px;\">If you found this notebook helpful, please consider giving it an upvote. Your support is greatly appreciated!</p>\n</div>","metadata":{}}]}