{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "**Table of contents** \n", "- [Sources](#toc1_) \n", "- [Load and import](#toc2_) \n", " - [Import libraries](#toc2_1_) \n", " - [Load configuration](#toc2_2_) \n", " - [Load, split, export data](#toc2_3_) \n", "- [EDA](#toc3_) \n", " - [Classes distribution](#toc3_1_) \n", " - [π§ Constats :](#toc3_2_) \n", " - [π§ Image exploration](#toc3_3_) \n", "- [Data preprocessing](#toc4_) \n", "- [π¦π¦ CHECKPOINT π¦π¦](#toc5_) \n", "- [Model Training](#toc6_) \n", " - [Load configuration](#toc6_1_) \n", "- [π§ MODEL CHOICE](#toc7_) \n", " - [Prepare data](#toc7_1_) \n", " - [Prepare model](#toc7_2_) \n", " - [Training](#toc7_3_) \n", " - [Random Baseline](#toc7_4_) \n", "\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# [Sources](#toc0_)\n", "\n", "https://huggingface.co/datasets/pyronear/pyro-sdis\n", "\n", "https://frugalaichallenge.org/participate/" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# [Load and import](#toc0_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Import libraries](#toc0_)" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "/Users/julmat/Documents/hugging_face/frugal_cviz/.venv/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", " from .autonotebook import tqdm as notebook_tqdm\n", "[codecarbon WARNING @ 23:01:31] Multiple instances of codecarbon are allowed to run at the same time.\n", "[codecarbon INFO @ 23:01:31] [setup] RAM Tracking...\n", "[codecarbon INFO @ 23:01:31] [setup] CPU Tracking...\n", "[codecarbon WARNING @ 23:01:31] No CPU tracking mode found. Falling back on CPU constant mode. \n", " Mac OS and ARM processor detected: Please enable PowerMetrics sudo to measure CPU\n", "\n", "[codecarbon INFO @ 23:01:31] CPU Model on constant consumption mode: Apple M1\n", "[codecarbon INFO @ 23:01:31] [setup] GPU Tracking...\n", "[codecarbon INFO @ 23:01:31] No GPU found.\n", "[codecarbon INFO @ 23:01:31] >>> Tracker's metadata:\n", "[codecarbon INFO @ 23:01:31] Platform system: macOS-15.2-arm64-arm-64bit\n", "[codecarbon INFO @ 23:01:31] Python version: 3.12.7\n", "[codecarbon INFO @ 23:01:31] CodeCarbon version: 2.8.3\n", "[codecarbon INFO @ 23:01:31] Available RAM : 16.000 GB\n", "[codecarbon INFO @ 23:01:31] CPU count: 8\n", "[codecarbon INFO @ 23:01:31] CPU model: Apple M1\n", "[codecarbon INFO @ 23:01:31] GPU count: None\n", "[codecarbon INFO @ 23:01:31] GPU model: None\n", "[codecarbon INFO @ 23:01:34] Saving emissions data to file /Users/julmat/Documents/hugging_face/frugal_cviz/emissions.csv\n" ] } ], "source": [ "from datetime import datetime\n", "from fastapi import APIRouter\n", "import logging\n", "import matplotlib.pyplot as plt\n", "import os\n", "from PIL import Image, ImageOps, ImageEnhance, ImageFilter\n", "import plotly.express as px\n", "import random\n", "import yaml\n", "\n", "# ML\n", "from keras import Model\n", "from keras.applications import EfficientNetB0, EfficientNetV2M\n", "from keras.layers import Flatten, Dense, Dropout\n", "from keras.metrics import Precision, Recall\n", "from keras.optimizers import AdamW\n", "from keras.utils import image_dataset_from_directory\n", "import numpy as np\n", "import pandas as pd\n", "from scipy.ndimage import median_filter\n", "from sklearn.metrics import accuracy_score, precision_score, recall_score\n", "import tensorflow as tf\n", "\n", "# Local package libraries\n", "from src.eda import make_autopct\n", "from src.load_data import load_raw_data, clean_df, format_data_keras, oversample_class\n", "from src.models import eval_pretrained_model, ConditionalAugmentation\n", "from tasks.utils.evaluation import ImageEvaluationRequest\n", "from tasks.utils.emissions import tracker, clean_emissions_data, get_space_info\n", "from tasks.image import parse_boxes, compute_iou, compute_max_iou\n", "\n", "\n", "# Logging outputs config (DEBUG < INFO)\n", "logger = logging.getLogger()\n", "logger.setLevel(logging.INFO)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Load configuration](#toc0_)" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "# local config\n", "with open(\"config.yaml\", \"r\") as f:\n", " cfg = yaml.safe_load(f)\n", "# Data\n", "OUTPUT_DIR = cfg[\"data_root_dir\"]\n", "DB_RAW_INFO_URI = os.path.join(OUTPUT_DIR, cfg[\"db_raw_info_uri\"])\n", "DB_KERAS_INFO_URI = os.path.join(OUTPUT_DIR, cfg[\"db_keras_info_uri\"])\n", "DB_AUG_INFO_URI = os.path.join(OUTPUT_DIR, cfg[\"db_aug_info_uri\"])\n", "REPO_ID = cfg[\"repo_id\"]\n", "SPLIT_SIZE = cfg[\"split_size\"]\n", "RDM_SEED = cfg[\"rdm_seed\"]\n", "# Model (common)\n", "MODELS_ROOT_DIR = cfg[\"models_common\"][\"models_root_dir\"]\n", "CLASSES = cfg[\"models_common\"][\"classes\"]\n", "LOG_DIR = cfg[\"models_common\"][\"log_dir\"]\n", "CHKPT_DIR = cfg[\"models_common\"][\"chkpts_dir\"]\n", "\n", "request = ImageEvaluationRequest()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Load, split, export data](#toc0_)\n", "\n", "π Load and split data, export in selected format, save DB information in CSV file, delete HF cache folder" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "df_raw = load_raw_data()" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Splits shapes:\n", "Train: (23629, 12)\n", "Val: (4099, 12)\n", "Test: (5908, 12)\n", "TOTAL: (33636, 12)\n" ] } ], "source": [ "df_raw_train = df_raw.loc[df_raw[\"split\"] == \"train\"]\n", "df_raw_val = df_raw.loc[df_raw[\"split\"] == \"val\"]\n", "df_raw_test = df_raw.loc[df_raw[\"split\"] == \"test\"]\n", "\n", "print(\n", " f\"Splits shapes:\\nTrain: {df_raw_train.shape}\\nVal: {df_raw_val.shape}\\nTest: {df_raw_test.shape}\\nTOTAL: {df_raw.shape}\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# [EDA](#toc0_)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", " | name | \n", "label | \n", "split | \n", "format | \n", "mode | \n", "width | \n", "height | \n", "camera | \n", "partner | \n", "timestamp | \n", "annotations | \n", "uri | \n", "
---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | \n", "sdis-07_marguerite-282_2024-01-30T17-01-57.jpg | \n", "no_smoke | \n", "train | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "marguerite-282 | \n", "sdis-07 | \n", "2024-01-30T17-01-57 | \n", "NaN | \n", "data/raw/images/train/sdis-07_marguerite-282_2... | \n", "
1 | \n", "force-06_courmettes-212_2024-01-04T12-06-07.jpg | \n", "smoke | \n", "train | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "courmettes-212 | \n", "force-06 | \n", "2024-01-04T12-06-07 | \n", "1 0.109793 0.510421 0.04459380000000002 0.0355... | \n", "data/raw/images/train/force-06_courmettes-212_... | \n", "
2 | \n", "force-06_courmettes-212_2024-01-16T09-53-11.jpg | \n", "no_smoke | \n", "train | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "courmettes-212 | \n", "force-06 | \n", "2024-01-16T09-53-11 | \n", "NaN | \n", "data/raw/images/train/force-06_courmettes-212_... | \n", "
3 | \n", "force-06_courmettes-160_2024-04-26T09-19-42.jpg | \n", "no_smoke | \n", "train | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "courmettes-160 | \n", "force-06 | \n", "2024-04-26T09-19-42 | \n", "NaN | \n", "data/raw/images/train/force-06_courmettes-160_... | \n", "
4 | \n", "force-06_courmettes-212_2024-01-12T12-47-33.jpg | \n", "no_smoke | \n", "train | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "courmettes-212 | \n", "force-06 | \n", "2024-01-12T12-47-33 | \n", "NaN | \n", "data/raw/images/train/force-06_courmettes-212_... | \n", "
... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "... | \n", "
33631 | \n", "sdis-07_brison-200_2024-01-04T12-49-23.jpg | \n", "smoke | \n", "test | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "brison-200 | \n", "sdis-07 | \n", "2024-01-04T12-49-23 | \n", "1 0.018262 0.733698 0.0361838 0.05748799999999... | \n", "data/raw/images/test/sdis-07_brison-200_2024-0... | \n", "
33632 | \n", "sdis-07_brison-110_2024-03-08T11-23-33.jpg | \n", "smoke | \n", "test | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "brison-110 | \n", "sdis-07 | \n", "2024-03-08T11-23-33 | \n", "1 0.416189 0.647031 0.032136900000000024 0.050... | \n", "data/raw/images/test/sdis-07_brison-110_2024-0... | \n", "
33633 | \n", "sdis-07_marguerite-29_2024-01-31T12-18-29.jpg | \n", "smoke | \n", "test | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "marguerite-29 | \n", "sdis-07 | \n", "2024-01-31T12-18-29 | \n", "1 0.0340379 0.634492 0.036966 0.05185609999999996 | \n", "data/raw/images/test/sdis-07_marguerite-29_202... | \n", "
33634 | \n", "sdis-07_marguerite-29_2024-01-31T09-19-45.jpg | \n", "smoke | \n", "test | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "marguerite-29 | \n", "sdis-07 | \n", "2024-01-31T09-19-45 | \n", "1 0.0624102 0.650866 0.035558900000000004 0.03... | \n", "data/raw/images/test/sdis-07_marguerite-29_202... | \n", "
33635 | \n", "sdis-07_marguerite-29_2024-03-25T10-11-12.jpg | \n", "smoke | \n", "test | \n", "JPEG | \n", "RGB | \n", "1280 | \n", "720 | \n", "marguerite-29 | \n", "sdis-07 | \n", "2024-03-25T10-11-12 | \n", "1 0.794183 0.595804 0.011687299999999956 0.032... | \n", "data/raw/images/test/sdis-07_marguerite-29_202... | \n", "
33636 rows Γ 12 columns
\n", "\n", " | name | \n", "label | \n", "split | \n", "format | \n", "mode | \n", "width | \n", "height | \n", "camera | \n", "partner | \n", "timestamp | \n", "annotations | \n", "uri | \n", "
---|---|---|---|---|---|---|---|---|---|---|---|---|
count | \n", "33636 | \n", "33636 | \n", "33636 | \n", "33636 | \n", "33636 | \n", "33636.0 | \n", "33636.0 | \n", "33636 | \n", "33636 | \n", "33636 | \n", "28103 | \n", "33636 | \n", "
unique | \n", "33636 | \n", "2 | \n", "3 | \n", "1 | \n", "1 | \n", "NaN | \n", "NaN | \n", "40 | \n", "3 | \n", "33464 | \n", "27247 | \n", "33636 | \n", "
top | \n", "sdis-07_marguerite-282_2024-01-30T17-01-57.jpg | \n", "smoke | \n", "train | \n", "JPEG | \n", "RGB | \n", "NaN | \n", "NaN | \n", "brison-200 | \n", "sdis-07 | \n", "2024-01-20T10-47-07 | \n", "1 0.0776863 0.568912 0.029480299999999987 0.08... | \n", "data/raw/images/train/sdis-07_marguerite-282_2... | \n", "
freq | \n", "1 | \n", "28103 | \n", "23629 | \n", "33636 | \n", "33636 | \n", "NaN | \n", "NaN | \n", "4971 | \n", "17766 | \n", "3 | \n", "6 | \n", "1 | \n", "
mean | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "1280.0 | \n", "720.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
std | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "0.0 | \n", "0.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
min | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "1280.0 | \n", "720.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
25% | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "1280.0 | \n", "720.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
50% | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "1280.0 | \n", "720.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
75% | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "1280.0 | \n", "720.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
max | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "1280.0 | \n", "720.0 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
Model: \"functional\"\n",
"
\n"
],
"text/plain": [
"\u001b[1mModel: \"functional\"\u001b[0m\n"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"βββββββββββββββββββββββββββββββ³ββββββββββββββββββββββββ³βββββββββββββ³ββββββββ\n", "β Layer (type) β Output Shape β Param # β Traiβ¦ β\n", "β‘βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ©\n", "β input_layer_1 (InputLayer) β (None, 224, 224, 3) β 0 β - β\n", "βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββΌββββββββ€\n", "β efficientnetv2-m β (None, 7, 7, 1280) β 53,150,388 β N β\n", "β (Functional) β β β β\n", "βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββΌββββββββ€\n", "β flatten (Flatten) β (None, 62720) β 0 β - β\n", "βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββΌββββββββ€\n", "β dense (Dense) β (None, 1) β 62,721 β Y β\n", "βββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββ΄βββββββββββββ΄ββββββββ\n", "\n" ], "text/plain": [ "βββββββββββββββββββββββββββββββ³ββββββββββββββββββββββββ³βββββββββββββ³ββββββββ\n", "β\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0mβ\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0mβ\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0mβ\u001b[1m \u001b[0m\u001b[1mTraiβ¦\u001b[0m\u001b[1m \u001b[0mβ\n", "β‘βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ©\n", "β input_layer_1 (\u001b[38;5;33mInputLayer\u001b[0m) β (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m3\u001b[0m) β \u001b[38;5;34m0\u001b[0m β \u001b[1m-\u001b[0m β\n", "βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββΌββββββββ€\n", "β efficientnetv2-m β (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m1280\u001b[0m) β \u001b[38;5;34m53,150,388\u001b[0m β \u001b[1;91mN\u001b[0m β\n", "β (\u001b[38;5;33mFunctional\u001b[0m) β β β β\n", "βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββΌββββββββ€\n", "β flatten (\u001b[38;5;33mFlatten\u001b[0m) β (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m62720\u001b[0m) β \u001b[38;5;34m0\u001b[0m β \u001b[1m-\u001b[0m β\n", "βββββββββββββββββββββββββββββββΌββββββββββββββββββββββββΌβββββββββββββΌββββββββ€\n", "β dense (\u001b[38;5;33mDense\u001b[0m) β (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1\u001b[0m) β \u001b[38;5;34m62,721\u001b[0m β \u001b[1;38;5;34mY\u001b[0m β\n", "βββββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββ΄βββββββββββββ΄ββββββββ\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Total params: 53,213,109 (202.99 MB)\n", "\n" ], "text/plain": [ "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m53,213,109\u001b[0m (202.99 MB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Trainable params: 62,721 (245.00 KB)\n", "\n" ], "text/plain": [ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m62,721\u001b[0m (245.00 KB)\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "
Non-trainable params: 53,150,388 (202.75 MB)\n", "\n" ], "text/plain": [ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m53,150,388\u001b[0m (202.75 MB)\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Load pre-trained model without top layers\n", "base_model = EfficientNetV2M(\n", " weights=\"imagenet\", # pre-trained weights\n", " include_top=False, # no dense layer\n", " input_shape=(input_size[0], input_size[1], 3), # input shape,\n", ")\n", "\n", "# For feature extraction\n", "base_model.trainable = False\n", "# # For partial fine-tuning: freeze bottom layers\n", "# for layer in base_model.layers[:735]:\n", "# layer.trainable = False\n", "\n", "# Create explicit input layer\n", "inputs = tf.keras.Input(shape=(input_size[0], input_size[1], 3))\n", "\n", "x = base_model(inputs)\n", "\n", "# # Dropout for regularization\n", "# x = Dropout(0.2)(x)\n", "# Flatten output\n", "x = Flatten()(x)\n", "# New FC layer for binary classification\n", "predictions = Dense(1, activation=\"sigmoid\")(x)\n", "\n", "# Define new model\n", "model_ready = Model(inputs=inputs, outputs=predictions)\n", "\n", "# Display model summary\n", "model_ready.summary(show_trainable=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Prepare data](#toc0_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create datasets from local images and labels" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Train dataset:\n", "Found 39654 files belonging to 2 classes.\n", "\n", "Val dataset:\n", "Found 6670 files belonging to 2 classes.\n", "\n", "Test dataset:\n", "Found 5908 files belonging to 2 classes.\n" ] } ], "source": [ "# Prepare for outputs\n", "os.makedirs(MODELS_ROOT_DIR, exist_ok=True)\n", "y = df[\"label\"]\n", "X = df[\"uri\"]\n", "\n", "# Create datasets\n", "print(\"Train dataset:\")\n", "train_ds = image_dataset_from_directory(\n", " train_dir,\n", " labels=\"inferred\", # class names upon folders structure\n", " label_mode=\"int\", # integer encoding\n", " shuffle=True, # shuffle images\n", " seed=42, # random seed\n", " image_size=input_size, # automatic resizing\n", " batch_size=batch_size, # tensor shape[0]\n", ")\n", "\n", "print(\"\\nVal dataset:\")\n", "val_ds = image_dataset_from_directory(\n", " val_dir,\n", " labels=\"inferred\", # class names upon folders structure\n", " label_mode=\"int\", # integer encoding\n", " shuffle=True, # shuffle images\n", " seed=42, # random seed\n", " image_size=input_size, # automatic resizing\n", " batch_size=batch_size, # tensor shape[0]\n", ")\n", "\n", "print(\"\\nTest dataset:\")\n", "test_ds = image_dataset_from_directory(\n", " test_dir,\n", " labels=\"inferred\", # class names upon folders structure\n", " label_mode=\"int\", # integer encoding\n", " shuffle=False, # do not shuffle images\n", " seed=42, # random seed\n", " image_size=input_size, # automatic resizing\n", " batch_size=batch_size, # tensor shape[0]\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Training](#toc0_)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Follow with : `tensorboard --logdir models/EfficientNetB0/runs`" ] }, { "cell_type": "code", "execution_count": 101, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "INFO:root:βοΈ compiling\n", "INFO:root:ποΈ declaring callbacks\n", "INFO:root:πͺ starting training\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ "Epoch 1/100\n", "\u001b[1m 7/1240\u001b[0m \u001b[37mββββββββββββββββββββ\u001b[0m \u001b[1m36:58\u001b[0m 2s/step - accuracy: 0.4936 - loss: 0.8204 - precision: 0.5297 - recall: 0.5054" ] } ], "source": [ "model_trained, history = eval_pretrained_model(\n", " model=model_ready,\n", " train_ds=train_ds,\n", " val_ds=val_ds,\n", " test_ds=test_ds,\n", " LOG_DIR=LOG_PATH,\n", " CHKPT_DIR=CHKPT_PATH,\n", " model_name=model_name,\n", " input_size=input_size,\n", " batch_size=batch_size,\n", " n_epochs=n_epochs,\n", " optimizer=optimizer,\n", " loss=loss,\n", " metrics=metrics,\n", ")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [ { "ename": "NameError", "evalue": "name 'stop' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", "Cell \u001b[0;32mIn[33], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mstop\u001b[49m\n", "\u001b[0;31mNameError\u001b[0m: name 'stop' is not defined" ] } ], "source": [ "stop" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Training** with Ultralytics YOLO" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# from huggingface_hub import hf_hub_download\n", "\n", "# # Correctly set repo_id and repo_type\n", "# repo_id = \"pyronear/pyro-sdis\"\n", "# filename = \"data.yaml\"\n", "\n", "# # Download data.yaml to the current directory\n", "# yaml_path = hf_hub_download(repo_id=repo_id, filename=filename, repo_type=\"dataset\", local_dir=\".\")\n", "# print(f\"data.yaml downloaded to: {yaml_path}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Train with Yolo (command line)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# yolo task=detect mode=train data=data.yaml model=yolov8n.pt epochs=50 imgsz=640 single_cls=True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## [Random Baseline](#toc0_)" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[codecarbon WARNING @ 17:11:39] Already started tracking\n", "[codecarbon INFO @ 17:11:39] A task is already under measure\n" ] } ], "source": [ "# Start tracking emissions\n", "tracker.start()\n", "tracker.start_task(\"inference\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# π§ INFERENCE" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# import keras\n", "# from keras.applications.resnet50 import ResNet50\n", "# from keras.applications.resnet50 import preprocess_input, decode_predictions\n", "# import numpy as np\n", "\n", "# model = ResNet50(weights='imagenet')\n", "\n", "# img_path = 'elephant.jpg'\n", "# img = keras.utils.load_img(img_path, target_size=(224, 224))\n", "# x = keras.utils.img_to_array(img)\n", "# x = np.expand_dims(x, axis=0)\n", "# x = preprocess_input(x)\n", "\n", "# preds = model.predict(x)\n", "# # decode the results into a list of tuples (class, description, probability)\n", "# # (one such list for each sample in the batch)\n", "# print('Predicted:', decode_predictions(preds, top=3)[0])\n", "# # Predicted: [(u'n02504013', u'Indian_elephant', 0.82658225), (u'n01871265', u'tusker', 0.1122357), (u'n02504458', u'African_elephant', 0.061040461)]\n" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "# --------------------------------------------------------------------------------------------\n", "# YOUR MODEL INFERENCE CODE HERE\n", "# Update the code below to replace the random baseline by your model inference within the inference pass where the energy consumption and emissions are tracked.\n", "# --------------------------------------------------------------------------------------------\n", "\n", "# Make random predictions (placeholder for actual model inference)\n", "\n", "predictions = []\n", "true_labels = []\n", "pred_boxes = []\n", "true_boxes_list = [] # List of lists, each inner list contains boxes for one image\n", "\n", "for example in test_dataset:\n", " # Parse true annotation (YOLO format: class_id x_center y_center width height)\n", " annotation = example.get(\"annotations\", \"\").strip()\n", " has_smoke = len(annotation) > 0\n", " true_labels.append(int(has_smoke))\n", "\n", " # Make random classification prediction\n", " pred_has_smoke = random.random() > 0.5\n", " predictions.append(int(pred_has_smoke))\n", "\n", " # If there's a true box, parse it and make random box prediction\n", " if has_smoke:\n", " # Parse all true boxes from the annotation\n", " image_true_boxes = parse_boxes(annotation)\n", " true_boxes_list.append(image_true_boxes)\n", "\n", " # For baseline, make one random box prediction per image\n", " # In a real model, you might want to predict multiple boxes\n", " random_box = [\n", " random.random(), # x_center\n", " random.random(), # y_center\n", " random.random() * 0.5, # width (max 0.5)\n", " random.random() * 0.5, # height (max 0.5)\n", " ]\n", " pred_boxes.append(random_box)\n", "\n", "\n", "# --------------------------------------------------------------------------------------------\n", "# YOUR MODEL INFERENCE STOPS HERE\n", "# --------------------------------------------------------------------------------------------" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "[codecarbon WARNING @ 17:12:24] Background scheduler didn't run for a long period (1885s), results might be inaccurate\n", "[codecarbon INFO @ 17:12:24] Energy consumed for RAM : 0.003142 kWh. RAM Power : 6.0 W\n", "[codecarbon INFO @ 17:12:24] Energy consumed for all CPUs : 0.002618 kWh. Total CPU Power : 5.0 W\n", "[codecarbon INFO @ 17:12:24] 0.005760 kWh of electricity used since the beginning.\n" ] } ], "source": [ "# Stop tracking emissions\n", "emissions_data = tracker.stop_task()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "\n", "# Calculate classification metrics\n", "classification_accuracy = accuracy_score(true_labels, predictions)\n", "classification_precision = precision_score(true_labels, predictions)\n", "classification_recall = recall_score(true_labels, predictions)\n", "\n", "# Calculate mean IoU for object detection (only for images with smoke)\n", "# For each image, we compute the max IoU between the predicted box and all true boxes\n", "ious = []\n", "for true_boxes, pred_box in zip(true_boxes_list, pred_boxes):\n", " max_iou = compute_max_iou(true_boxes, pred_box)\n", " ious.append(max_iou)\n", "\n", "mean_iou = float(np.mean(ious)) if ious else 0.0" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'submission_timestamp': '2025-01-23T17:13:47.158903',\n", " 'classification_accuracy': 0.4974610697359513,\n", " 'classification_precision': 0.8362892223738063,\n", " 'classification_recall': 0.49625581866019025,\n", " 'mean_iou': 0.0026954029097350594,\n", " 'energy_consumed_wh': 5.759879923426909,\n", " 'emissions_gco2eq': 0.2006914961719638,\n", " 'emissions_data': {'run_id': 'fbab9dd9-2893-4216-91c4-232be358d4dd',\n", " 'duration': 1885.054949500016,\n", " 'emissions': 0.0002006914961719638,\n", " 'emissions_rate': 1.0646457428260931e-07,\n", " 'cpu_power': 5.0,\n", " 'gpu_power': 0.0,\n", " 'ram_power': 6.0,\n", " 'cpu_energy': 0.002618128800231918,\n", " 'gpu_energy': 0,\n", " 'ram_energy': 0.0031417511231949906,\n", " 'energy_consumed': 0.005759879923426909,\n", " 'country_name': 'Switzerland',\n", " 'country_iso_code': 'CHE',\n", " 'region': 'zurich',\n", " 'cloud_provider': '',\n", " 'cloud_region': '',\n", " 'os': 'macOS-15.2-arm64-arm-64bit',\n", " 'python_version': '3.12.7',\n", " 'codecarbon_version': '2.8.3',\n", " 'cpu_count': 8,\n", " 'cpu_model': 'Apple M1',\n", " 'gpu_count': None,\n", " 'gpu_model': None,\n", " 'ram_total_size': 16.0,\n", " 'tracking_mode': 'machine',\n", " 'on_cloud': 'N',\n", " 'pue': 1.0},\n", " 'dataset_config': {'dataset_name': 'pyronear/pyro-sdis',\n", " 'test_size': 0.2,\n", " 'test_seed': 42}}" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Prepare results dictionary\n", "results = {\n", " \"submission_timestamp\": datetime.now().isoformat(),\n", " \"classification_accuracy\": float(classification_accuracy),\n", " \"classification_precision\": float(classification_precision),\n", " \"classification_recall\": float(classification_recall),\n", " \"mean_iou\": mean_iou,\n", " \"energy_consumed_wh\": emissions_data.energy_consumed * 1000,\n", " \"emissions_gco2eq\": emissions_data.emissions * 1000,\n", " \"emissions_data\": clean_emissions_data(emissions_data),\n", " \"dataset_config\": {\n", " \"dataset_name\": request.dataset_name,\n", " \"test_size\": request.test_size,\n", " \"test_seed\": request.test_seed,\n", " },\n", "}\n", "results" ] }, { "cell_type": "markdown", "metadata": {}, "source": [] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.7" } }, "nbformat": 4, "nbformat_minor": 2 }