Reinforcement Learning
stable-baselines3
deep-reinforcement-learning
agricultural-ai
weather-modelling
curriculum-learning
edge-ai
Instructions to use DHDRL/monsoon-rl with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- stable-baselines3
How to use DHDRL/monsoon-rl with stable-baselines3:
from huggingface_sb3 import load_from_hub checkpoint = load_from_hub( repo_id="DHDRL/monsoon-rl", filename="{MODEL FILENAME}.zip", ) - Notebooks
- Google Colab
- Kaggle
Update zone_observation.py
Browse files- zone_observation.py +57 -4
zone_observation.py
CHANGED
|
@@ -10,7 +10,7 @@ import logging
|
|
| 10 |
import math
|
| 11 |
import random
|
| 12 |
import zlib
|
| 13 |
-
from dataclasses import dataclass, field, asdict
|
| 14 |
from datetime import datetime, timedelta, timezone
|
| 15 |
from enum import Enum, unique
|
| 16 |
from typing import Any, ClassVar, Dict, List, Optional, Tuple
|
|
@@ -172,11 +172,27 @@ class ForecastConfig:
|
|
| 172 |
|
| 173 |
seed: Optional[int] = None
|
| 174 |
|
| 175 |
-
real_data_ratio: float = 0.7 # fraction of episodes that attempt real data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 176 |
era5_ratio: float = 0.5 # of real-data attempts, fraction using ERA5
|
| 177 |
force_data_source: Optional[DataSource] = None # pin source for debug/test (overrides above)
|
| 178 |
-
inject_noise: bool = False # apply stochastic noise after fetch
|
|
|
|
| 179 |
noise_scale: float = 0.05 # noise magnitude (fraction of field range)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 180 |
|
| 181 |
use_satellite_precip: bool = False # prefer IMERG/CHIRPS over ERA5 precip
|
| 182 |
use_satellite_soil: bool = False # prefer SMAP over ERA5 soil moisture
|
|
@@ -313,6 +329,7 @@ class ForecastConfig:
|
|
| 313 |
),
|
| 314 |
"inject_noise": self.inject_noise,
|
| 315 |
"noise_scale": self.noise_scale,
|
|
|
|
| 316 |
"use_satellite_precip": self.use_satellite_precip,
|
| 317 |
"use_satellite_soil": self.use_satellite_soil,
|
| 318 |
"include_basin_context": self.include_basin_context,
|
|
@@ -947,7 +964,25 @@ class BasinContext:
|
|
| 947 |
_check_schema(sv, "BasinContext")
|
| 948 |
d["valid_date"] = datetime.fromisoformat(d["valid_date"])
|
| 949 |
d["source"] = DataSource(d.get("source", "synthetic"))
|
| 950 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 951 |
|
| 952 |
def make_synthetic_basin_context(
|
| 953 |
valid_date: Optional[datetime] = None,
|
|
@@ -1382,6 +1417,11 @@ if __name__ == "__main__":
|
|
| 1382 |
_assert(cfg2.force_data_source is None, "ForecastConfig force_data_source round-trip")
|
| 1383 |
_assert(cfg2.inject_noise is False, "ForecastConfig inject_noise round-trip")
|
| 1384 |
_assert(cfg2.noise_scale == 0.05, "ForecastConfig noise_scale round-trip")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1385 |
cfg_era5 = ForecastConfig(force_data_source=DataSource.ERA5_REANALYSIS)
|
| 1386 |
cfg_era5_back = ForecastConfig.from_dict(cfg_era5.to_dict())
|
| 1387 |
_assert(
|
|
@@ -1514,6 +1554,19 @@ if __name__ == "__main__":
|
|
| 1514 |
f"kp={bc.kp_index:.1f} regime={bc.helio_regime} "
|
| 1515 |
f"round-trip OK, EpisodeContext integration OK")
|
| 1516 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1517 |
# 11. New optional ZoneObs satellite fields: None-by-default, clipping, round-trip
|
| 1518 |
obs_sat = ZoneObs(
|
| 1519 |
zone_id="sat_zone", valid_time=now,
|
|
|
|
| 10 |
import math
|
| 11 |
import random
|
| 12 |
import zlib
|
| 13 |
+
from dataclasses import dataclass, field, asdict, fields as _dc_fields
|
| 14 |
from datetime import datetime, timedelta, timezone
|
| 15 |
from enum import Enum, unique
|
| 16 |
from typing import Any, ClassVar, Dict, List, Optional, Tuple
|
|
|
|
| 172 |
|
| 173 |
seed: Optional[int] = None
|
| 174 |
|
| 175 |
+
real_data_ratio: float = 0.7 # fraction of episodes that attempt real data.
|
| 176 |
+
# Consumed by era5_data_pipeline.py when
|
| 177 |
+
# BUILDING a historical cache, AND (new) by
|
| 178 |
+
# WeatherForecastEnv.reset() when
|
| 179 |
+
# real_data_pkl_path is set, as the
|
| 180 |
+
# per-episode probability of sampling a real
|
| 181 |
+
# historical EpisodeContext instead of a
|
| 182 |
+
# synthetic one during training.
|
| 183 |
era5_ratio: float = 0.5 # of real-data attempts, fraction using ERA5
|
| 184 |
force_data_source: Optional[DataSource] = None # pin source for debug/test (overrides above)
|
| 185 |
+
inject_noise: bool = False # apply stochastic noise after fetch, AND (new)
|
| 186 |
+
# after WeatherForecastEnv real-data sampling
|
| 187 |
noise_scale: float = 0.05 # noise magnitude (fraction of field range)
|
| 188 |
+
real_data_pkl_path: Optional[str] = None # path to a historical trajectory cache
|
| 189 |
+
# (see real_episode_sampler.RealEpisodeIndex).
|
| 190 |
+
# When set, WeatherForecastEnv.reset() may
|
| 191 |
+
# sample real episodes for training with
|
| 192 |
+
# probability real_data_ratio, respecting
|
| 193 |
+
# RealEpisodeIndex's holdout exclusion. When
|
| 194 |
+
# None (default), training is 100% synthetic,
|
| 195 |
+
# unchanged from prior behavior.
|
| 196 |
|
| 197 |
use_satellite_precip: bool = False # prefer IMERG/CHIRPS over ERA5 precip
|
| 198 |
use_satellite_soil: bool = False # prefer SMAP over ERA5 soil moisture
|
|
|
|
| 329 |
),
|
| 330 |
"inject_noise": self.inject_noise,
|
| 331 |
"noise_scale": self.noise_scale,
|
| 332 |
+
"real_data_pkl_path": self.real_data_pkl_path,
|
| 333 |
"use_satellite_precip": self.use_satellite_precip,
|
| 334 |
"use_satellite_soil": self.use_satellite_soil,
|
| 335 |
"include_basin_context": self.include_basin_context,
|
|
|
|
| 964 |
_check_schema(sv, "BasinContext")
|
| 965 |
d["valid_date"] = datetime.fromisoformat(d["valid_date"])
|
| 966 |
d["source"] = DataSource(d.get("source", "synthetic"))
|
| 967 |
+
known = {f.name for f in _dc_fields(cls)}
|
| 968 |
+
unrecognized = {
|
| 969 |
+
k: v for k, v in d.items()
|
| 970 |
+
if not k.startswith("_") and k not in known
|
| 971 |
+
}
|
| 972 |
+
if unrecognized:
|
| 973 |
+
# Forward-compat, not silent data loss: seen in practice with
|
| 974 |
+
# historical_continuous_indonesia_v1_helio_backfilled_canonical_v2.pkl,
|
| 975 |
+
# which stamps helio_source_label / helio_backfill_valid_date
|
| 976 |
+
# directly into basin_context dicts from an out-of-repo backfill
|
| 977 |
+
# script (surgical_helio_backfill_v2.py) rather than through this
|
| 978 |
+
# class. Dropping them here is deliberate -- add a real field to
|
| 979 |
+
# BasinContext if this provenance data should be preserved and
|
| 980 |
+
# consumed, rather than widening this filter.
|
| 981 |
+
logger.debug(
|
| 982 |
+
"BasinContext.from_dict: dropping unrecognized fields %s "
|
| 983 |
+
"(schema forward-compat)", sorted(unrecognized),
|
| 984 |
+
)
|
| 985 |
+
return cls(**{k: v for k, v in d.items() if k in known})
|
| 986 |
|
| 987 |
def make_synthetic_basin_context(
|
| 988 |
valid_date: Optional[datetime] = None,
|
|
|
|
| 1417 |
_assert(cfg2.force_data_source is None, "ForecastConfig force_data_source round-trip")
|
| 1418 |
_assert(cfg2.inject_noise is False, "ForecastConfig inject_noise round-trip")
|
| 1419 |
_assert(cfg2.noise_scale == 0.05, "ForecastConfig noise_scale round-trip")
|
| 1420 |
+
_assert(cfg2.real_data_pkl_path is None, "ForecastConfig real_data_pkl_path default round-trip")
|
| 1421 |
+
cfg_pkl = ForecastConfig(real_data_pkl_path="/tmp/example.pkl")
|
| 1422 |
+
cfg_pkl_back = ForecastConfig.from_dict(cfg_pkl.to_dict())
|
| 1423 |
+
_assert(cfg_pkl_back.real_data_pkl_path == "/tmp/example.pkl",
|
| 1424 |
+
"non-default real_data_pkl_path round-trip")
|
| 1425 |
cfg_era5 = ForecastConfig(force_data_source=DataSource.ERA5_REANALYSIS)
|
| 1426 |
cfg_era5_back = ForecastConfig.from_dict(cfg_era5.to_dict())
|
| 1427 |
_assert(
|
|
|
|
| 1554 |
f"kp={bc.kp_index:.1f} regime={bc.helio_regime} "
|
| 1555 |
f"round-trip OK, EpisodeContext integration OK")
|
| 1556 |
|
| 1557 |
+
# 10b. BasinContext.from_dict tolerates unrecognized fields (schema
|
| 1558 |
+
# drift from out-of-repo backfill scripts) instead of crashing.
|
| 1559 |
+
d_drift = bc.to_dict()
|
| 1560 |
+
d_drift["helio_source_label"] = "gfz_kp_daily_max+neutral_sw_goes_v2"
|
| 1561 |
+
d_drift["helio_backfill_valid_date"] = "2023-08-04"
|
| 1562 |
+
bc_drift = BasinContext.from_dict(d_drift)
|
| 1563 |
+
_assert(abs(bc_drift.enso_oni - bc.enso_oni) < 1e-9,
|
| 1564 |
+
"BasinContext.from_dict with unrecognized fields lost a known field")
|
| 1565 |
+
_assert(not hasattr(bc_drift, "helio_source_label"),
|
| 1566 |
+
"BasinContext.from_dict should not silently attach unknown attrs")
|
| 1567 |
+
print(" BasinContext.from_dict schema-drift tolerance OK "
|
| 1568 |
+
"(helio_source_label-style extra keys no longer crash)")
|
| 1569 |
+
|
| 1570 |
# 11. New optional ZoneObs satellite fields: None-by-default, clipping, round-trip
|
| 1571 |
obs_sat = ZoneObs(
|
| 1572 |
zone_id="sat_zone", valid_time=now,
|