1

Compare commits

...

2 Commits

Author SHA1 Message Date
2495e9365e Scripts et figures manquantes 2025-11-26 01:47:48 +01:00
7ba4287399 Ajout d'une transition à la conclusion 2025-11-26 01:07:16 +01:00
7 changed files with 185 additions and 14 deletions

View File

@ -21,6 +21,7 @@ Le script :
## Lecture rapide des résultats (validation) ## Lecture rapide des résultats (validation)
![](./figures/models_tree_mae_validation.png) ![](./figures/models_tree_mae_validation.png)
![](./figures/models_tree_rain_validation.png) ![](./figures/models_tree_rain_validation.png)
- Température : le gradient boosting est meilleur que la forêt sur le très court terme (MAE ≈0,13 à +10 min), mais reste derrière les modèles linéaires du chapitre 9 (MAE ≈0,14 à +60 min avec Ridge). La sousutilisation des données dapprentissage (1/10) pèse sur la performance. - Température : le gradient boosting est meilleur que la forêt sur le très court terme (MAE ≈0,13 à +10 min), mais reste derrière les modèles linéaires du chapitre 9 (MAE ≈0,14 à +60 min avec Ridge). La sousutilisation des données dapprentissage (1/10) pèse sur la performance.
@ -29,4 +30,7 @@ Le script :
## Conclusion provisoire ## Conclusion provisoire
Ces modèles non linéaires apportent de la flexibilité mais, avec un apprentissage allégé pour tenir le temps de calcul, ils ne battent pas les baselines ni les modèles linéaires sur les horizons courts. Pour progresser, il faudra soit élargir léchantillon dapprentissage (temps de calcul plus long), soit régler finement les hyperparamètres, soit enrichir les features (ou combiner les deux), tout en vérifiant que le gain justifie leffort. Ces modèles non linéaires apportent de la flexibilité mais, avec un apprentissage allégé pour tenir le temps de calcul, ils ne battent pas les baselines ni les modèles linéaires sur les horizons courts. Pour progresser, il faudra soit élargir léchantillon dapprentissage (temps de calcul plus long), soit régler finement les hyperparamètres, soit enrichir les features (ou combiner les deux).
À ce stade, les modèles non-linéaires "naïfs" que l'on a implémenté ici travaillent pendant plusieurs minutes et ne sont pas capables de faire mieux que les modèles vus précédemment.
Je doute donc qu'il soit pertinent de creuser le sujet, mais cela a aiguisé ma curiosité pour des modèles existants, pré-entraînés, tels que Chronos, d'Amazon.

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

View File

@ -2,33 +2,67 @@
Objectif : tester un modèle de prévision généraliste récent (**Chronos-2**, Amazon) en zéro-shot sur notre station. On resample la température à lheure, on coupe les dernières 96 h pour évaluer la prévision, et on compare le forecast à lobservé. Objectif : tester un modèle de prévision généraliste récent (**Chronos-2**, Amazon) en zéro-shot sur notre station. On resample la température à lheure, on coupe les dernières 96 h pour évaluer la prévision, et on compare le forecast à lobservé.
### Mise en route ```shell
python "docs/11 - Modèle Chronos/scripts/run_chronos.py"
```
Installez les dépendances (`pip install -r requirements.txt`), puis lancez `run_chronos.py`. Le script lit `data/weather_minutely.csv`, resample la température en pas horaire, prend les 336 dernières heures en contexte et les 96 suivantes en cible. Il charge `amazon/chronos-t5-small` par défaut (modifiable via `CHRONOS_MODEL`), génère 20 échantillons dont on prend la moyenne, calcule MAE/RMSE, sauvegarde les CSV `chronos_forecast_<model>.csv` et `chronos_errors_<model>.csv`, et produit les figures associées dans `docs/11 - Modèle Chronos/figures/`. ### Résultats comparés
Pour comparer plusieurs tailles, lancez `run_chronos.py` avec différents `CHRONOS_MODEL` (mini/small/base), puis `compare_chronos.py` agrège les CSV et trace la comparaison. Nous avons utilisé les variables denvironnement suivantes : `CHRONOS_CONTEXT` (336 h), `CHRONOS_HORIZON` (96 h), `CHRONOS_RESAMPLE` (`1h`), `CHRONOS_SAMPLES` (20).
### Paramètres
Modifiables via variables denvironnement : `CHRONOS_MODEL` (défaut `amazon/chronos-t5-small`), `CHRONOS_CONTEXT` (336 h), `CHRONOS_HORIZON` (96 h), `CHRONOS_RESAMPLE` (`1h`), `CHRONOS_SAMPLES` (20).
### Résultats comparés (mêmes données, horizon 96 h)
![Comparaison des tailles Chronos](./figures/chronos_models_comparison.png) ![Comparaison des tailles Chronos](./figures/chronos_models_comparison.png)
Sur la même fenêtre de validation locale, nous avons testé trois tailles : `chronos-t5-mini`, `chronos-t5-small` et `chronos-t5-base`. Le modèle **small** est ressorti devant (MAE ≈ 3,68 °C, RMSE ≈ 4,53 °C), les versions mini et base étant derrière (MAE ≈ 4,184,24 °C, RMSE ≈ 5,35,6 °C). Autrement dit, monter en taille na pas amélioré la prévision à 96 h sur ces données locales ; la version small offre le meilleur compromis précision/poids. Sur la même fenêtre de validation locale, nous avons testé trois tailles (`CHRONOS_MODEL`) : `chronos-t5-mini`, `chronos-t5-small` et `chronos-t5-base`. Le modèle **small** semble le plus précis (MAE ≈ 3,68 °C, RMSE ≈ 4,53 °C), les versions mini et base étant derrière (MAE ≈ 4,184,24 °C, RMSE ≈ 5,35,6 °C). Autrement dit, monter en taille na pas amélioré la prévision à 96 h sur ces données locales ; la version `small` offre le meilleur compromis précision/poids.
```shell
python "docs/11 - Modèle Chronos/scripts/compare_chronos.py"
```
#### chronos-t5-mini
![Trajectoire prédit vs observé mini](./figures/chronos_forecast_amazon__chronos-t5-mini.png) ![Trajectoire prédit vs observé mini](./figures/chronos_forecast_amazon__chronos-t5-mini.png)
#### chronos-t5-small
![Trajectoire prédit vs observé small](./figures/chronos_forecast_amazon__chronos-t5-small.png) ![Trajectoire prédit vs observé small](./figures/chronos_forecast_amazon__chronos-t5-small.png)
Le modèle suit un peu mieux la courbe de référence que les autres, mais une forte amplitude existe.
#### chronos-t5-base
![Trajectoire prédit vs observé base](./figures/chronos_forecast_amazon__chronos-t5-base.png) ![Trajectoire prédit vs observé base](./figures/chronos_forecast_amazon__chronos-t5-base.png)
### Lecture et portée ### Lecture et portée
Pour coller à nos horizons cibles, `run_chronos_multi.py` évalue Chronos-small sur 1 h, 6 h et 24 h pour la température, le vent et la pluie (horaire uniquement ; lhorizon 10 minutes nest pas couvert par Chronos qui est pré-entraîné en pas horaire). Les figures `chronos_multi_temperature.png`, `chronos_multi_wind_speed.png` et `chronos_multi_rain_rate.png` illustrent où le modèle est le plus fiable : à 1 h, la température reste sous ~1,3 °C de MAE et le vent sous ~0,6 (unités du jeu) ; à 6 h, lerreur grimpe modérément (≈2 °C temp., ≈3 km/h vent) ; à 24 h, elle dépasse 46 (°C/ km/h). Sur la pluie, le F1 reste nul à 1 h/6 h et ne monte quà ~0,15 à 24 h, signe que le modèle “foundation” horaire ne capture pas bien les occurrences locales rares. Les figures individuelles (`chronos_forecast_<model>.png`, `chronos_errors_<model>.png`) permettent de voir la trajectoire prédit vs observé et lerreur par horizon. Pour coller à nos horizons cibles, `run_chronos_multi.py` évalue Chronos-small sur 1 h, 6 h et 24 h pour la température, le vent et la pluie (horaire uniquement ; lhorizon 10 minutes nest pas couvert par Chronos qui est pré-entraîné en pas horaire). Les figures `chronos_multi_temperature.png`, `chronos_multi_wind_speed.png` et `chronos_multi_rain_rate.png` illustrent où le modèle est le plus fiable : à 1 h, la température reste sous ~1,3 °C de MAE et le vent sous ~0,6 km/h ; à 6 h, lerreur grimpe modérément (≈2 °C temp., ≈3 km/h vent) ; à 24 h, elle dépasse 46 (°C/ km/h). Sur la pluie, le F1 reste nul à 1 h/6 h et ne monte quà ~0,15 à 24 h, signe que le modèle “foundation” horaire ne capture pas bien les occurrences locales rares.
Au total, Chronos-small fournit un signal exploitable sur la température et un peu sur le vent pour des horizons courts à intermédiaires, mais reste faible sur la pluie et se dégrade nettement au-delà de 24 h. Une calibration locale, davantage de contexte ou une cible adaptée (pluie binaire calibrée) seraient nécessaires pour en faire un outil de prévision robuste sur toutes les variables. ```shell
python "docs/11 - Modèle Chronos/scripts/run_chronos_multi.py"
```
![Chronos small température (1/6/24 h)](./figures/chronos_multi_temperature.png)
![Chronos small vent (1/6/24 h)](./figures/chronos_multi_wind_speed.png)
![Chronos small pluie (1/6/24 h)](./figures/chronos_multi_rain_rate.png)
```shell
python "docs/11 - Modèle Chronos/scripts/plot_chronos_errors_combined.py"
```
![Chronos small erreurs temp/vent](./figures/chronos_multi_errors_temp_wind.png)
![Chronos small pluie (F1/Brier)](./figures/chronos_multi_errors_rain.png)
Les figures individuelles permettent de voir la trajectoire prédite vs observée (dans la section précédente) et lerreur par horizon (ci-dessous).
```shell
python "docs/11 - Modèle Chronos/scripts/run_chronos_multi_errors.py"
```
![Erreur absolue vs horizon mini/small/base](./figures/chronos_errors_combined.png)
Au final, Chronos-small fournit un signal exploitable sur la température et un peu sur le vent pour des horizons courts à intermédiaires, mais reste faible sur la pluie et se dégrade nettement au-delà de 24 h. Une calibration locale, davantage de contexte ou une cible adaptée (pluie binaire calibrée) seraient nécessaires pour en faire un outil de prévision robuste sur toutes les variables.
### Réglages prudents (contexte 288 h, horizon limité à 64 h, 100 échantillons) ### Réglages prudents (contexte 288 h, horizon limité à 64 h, 100 échantillons)
@ -40,7 +74,11 @@ Au total, Chronos-small fournit un signal exploitable sur la température et un
Avec `run_chronos_tuned.py`, on réduit le contexte (288 h) et lhorizon maximum (64 h) tout en augmentant les échantillons (100). Sur la même fenêtre locale, la température saméliore nettement : MAE ~0,75 °C à 1 h, ~1,27 °C à 6 h, ~3,40 °C à 24 h (vs 1,33/2,02/4,84 auparavant). Le vent progresse surtout à 24 h (≈2,39 contre ~6,38 auparavant), même si le 1 h est moins bon que la première passe. La pluie reste instable : le F1 peut atteindre 0,220,28 à 2448 h mais les scores courts sont peu fiables. Limiter lhorizon à 64 h, raccourcir le contexte et lisser par davantage déchantillons améliorent donc la température et le vent, mais ne suffisent pas à rendre la pluie prédictible. Avec `run_chronos_tuned.py`, on réduit le contexte (288 h) et lhorizon maximum (64 h) tout en augmentant les échantillons (100). Sur la même fenêtre locale, la température saméliore nettement : MAE ~0,75 °C à 1 h, ~1,27 °C à 6 h, ~3,40 °C à 24 h (vs 1,33/2,02/4,84 auparavant). Le vent progresse surtout à 24 h (≈2,39 contre ~6,38 auparavant), même si le 1 h est moins bon que la première passe. La pluie reste instable : le F1 peut atteindre 0,220,28 à 2448 h mais les scores courts sont peu fiables. Limiter lhorizon à 64 h, raccourcir le contexte et lisser par davantage déchantillons améliorent donc la température et le vent, mais ne suffisent pas à rendre la pluie prédictible.
### Dernier essai “comme en vrai” : prévision sur les 6 dernières heures ### Dernier essai en conditions réelles : prévision sur les 6 dernières heures
```shell
python "docs/11 - Modèle Chronos/scripts/run_chronos_holdout6.py"
```
![Chronos small erreurs 6 h holdout](./figures/chronos_holdout6_errors.png) ![Chronos small erreurs 6 h holdout](./figures/chronos_holdout6_errors.png)

View File

@ -0,0 +1,57 @@
# scripts/plot_chronos_errors_combined.py
from __future__ import annotations
from pathlib import Path
import re
import matplotlib.pyplot as plt
import pandas as pd
DOC_DIR = Path(__file__).resolve().parent.parent
DATA_DIR = DOC_DIR / "data"
FIG_DIR = DOC_DIR / "figures"
def load_errors() -> pd.DataFrame:
pattern = re.compile(r"chronos_forecast_(amazon__chronos-t5-[a-z]+)\.csv")
records = []
for csv in DATA_DIR.glob("chronos_forecast_*.csv"):
m = pattern.match(csv.name)
if not m:
continue
model = m.group(1).replace("__", "/")
df = pd.read_csv(csv)
if not {"y_true", "y_pred"}.issubset(df.columns):
continue
err = (df["y_pred"] - df["y_true"]).abs()
for i, v in enumerate(err, start=1):
records.append({"model": model, "horizon_h": i, "abs_error": v})
return pd.DataFrame(records)
def plot_errors(df: pd.DataFrame, output_path: Path) -> None:
output_path.parent.mkdir(parents=True, exist_ok=True)
fig, ax = plt.subplots(figsize=(8, 4))
for model, sub in df.groupby("model"):
sub_sorted = sub.sort_values("horizon_h")
ax.plot(sub_sorted["horizon_h"], sub_sorted["abs_error"], label=model, linewidth=2)
ax.set_xlabel("Horizon (heures)")
ax.set_ylabel("Erreur absolue (°C)")
ax.set_title("Chronos T5 erreur absolue vs horizon")
ax.grid(True, linestyle=":", alpha=0.4)
ax.legend()
fig.tight_layout()
fig.savefig(output_path, dpi=150)
plt.close(fig)
def main() -> None:
df = load_errors()
if df.empty:
raise SystemExit("Aucun fichier chronos_forecast_*.csv trouvé ou colonnes manquantes.")
plot_errors(df, FIG_DIR / "chronos_errors_combined.png")
print("✔ Figure : figures/chronos_errors_combined.png")
if __name__ == "__main__":
main()

View File

@ -0,0 +1,72 @@
# scripts/plot_chronos_multi_errors.py
from __future__ import annotations
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
DOC_DIR = Path(__file__).resolve().parent.parent
DATA_DIR = DOC_DIR / "data"
FIG_DIR = DOC_DIR / "figures"
def _plot_temp_wind(df: pd.DataFrame, output: Path) -> None:
output.parent.mkdir(parents=True, exist_ok=True)
fig, ax = plt.subplots(figsize=(6, 4))
for target in ("temperature", "wind_speed"):
sub = df[(df["target"] == target) & (df["kind"] == "reg")].sort_values("horizon_h")
ax.plot(sub["horizon_h"], sub["mae"], marker="o", label=f"{target} MAE")
ax.plot(sub["horizon_h"], sub["rmse"], marker="s", label=f"{target} RMSE", linestyle="--")
ax.set_xlabel("Horizon (heures)")
ax.set_ylabel("Erreur")
ax.set_title("Chronos small erreurs température / vent")
ax.grid(True, linestyle=":", alpha=0.4)
ax.legend()
fig.tight_layout()
fig.savefig(output, dpi=150)
plt.close(fig)
def _plot_rain(df: pd.DataFrame, output: Path) -> None:
output.parent.mkdir(parents=True, exist_ok=True)
sub = df[(df["target"] == "rain_rate") & (df["kind"] == "cls")].sort_values("horizon_h")
fig, ax1 = plt.subplots(figsize=(6, 4))
ax1.plot(sub["horizon_h"], sub["f1"], marker="o", color="tab:blue", label="F1")
ax1.set_ylabel("F1", color="tab:blue")
ax1.tick_params(axis="y", labelcolor="tab:blue")
ax2 = ax1.twinx()
ax2.plot(sub["horizon_h"], sub["brier"], marker="s", color="tab:red", linestyle="--", label="Brier")
ax2.set_ylabel("Brier", color="tab:red")
ax2.tick_params(axis="y", labelcolor="tab:red")
ax1.set_xlabel("Horizon (heures)")
ax1.set_title("Chronos small pluie (F1/Brier)")
ax1.grid(True, linestyle=":", alpha=0.4)
# Combine legends
handles, labels = [], []
for ax in (ax1, ax2):
h, l = ax.get_legend_handles_labels()
handles += h
labels += l
ax1.legend(handles, labels, loc="upper right")
fig.tight_layout()
fig.savefig(output, dpi=150)
plt.close(fig)
def main() -> None:
metrics_path = DATA_DIR / "chronos_multi_metrics.csv"
if not metrics_path.exists():
raise SystemExit("chronos_multi_metrics.csv introuvable. Lancez run_chronos_multi.py d'abord.")
df = pd.read_csv(metrics_path)
_plot_temp_wind(df, FIG_DIR / "chronos_multi_errors_temp_wind.png")
_plot_rain(df, FIG_DIR / "chronos_multi_errors_rain.png")
print("✔ Figures : chronos_multi_errors_temp_wind.png, chronos_multi_errors_rain.png")
if __name__ == "__main__":
main()