Skip to content

Latest commit

 

History

12 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

holdover

holdover

awesome-ml-systems Hopsworks

Firefighters call it a holdover: a fire that looks done at dusk and is burning again at dawn. This build asks whether tonight's satellite picture of a fire, fused with tomorrow's weather forecast, can say which of today's active fires will still be there tomorrow. Across five Mediterranean countries, five fire seasons and a held-out year, the fusion beats the fire's own persistence and the weather alone, which is the claim: neither feed contains the signal by itself.

The result

holdover_gbm, a calibrated gradient-boosted classifier over active fire cells (0.1 degree, VIIRS S-NPP detections) in Portugal, Spain, France, Italy and Greece, 2020 to now. The unit is an active cell-day; the label is that the same cell has at least one detection the next day. Features are the fire's own state today (detections, radiative power, 3x3 neighbourhood, streak length) and tomorrow's weather at the cell (max temperature, min relative humidity, wind, gusts, precipitation, reference evapotranspiration, trailing 30-day dryness). Split by time, never shuffled: train 2020-2023, test 2024.

What this covers. Weather is backfilled for the cells reachable under the Open-Meteo free tier (Iberia-heavy: Portugal full, Spain two thirds, Italy and Greece about half, France sparse). The five-country backfill was quota-capped, not completed, so this is the model on the data we have. The training job re-runs nightly and gates itself either way.

metric (holdout: 2024 season, 22.2k train / 2.2k test, base rate 0.129) value
PR-AUC, fused 0.557
ROC-AUC, fused 0.822
PR-AUC, persistence only 0.540
PR-AUC, weather only 0.200
PR-AUC, shuffled-label control (mean of 25 seeds) 0.147
precision of the top 1% most confident flags 0.91
precision of the top 5% 0.79

PR curves by ablation

The ablation is the gate. Persistence knows the fire is big; weather knows the night will be dry and windy. FUSED beats both single-source models and beats a shuffled-label control (averaged over 25 seeds, because a single shuffle draw is noisy enough to coin-flip the gate on a test this size). If it did not, the training job would print DOG-HOUSE and the build would go to the dog house instead of this table.

The margin is thin and honest: weather adds 0.017 PR-AUC over persistence alone, and leave-one-country-out shows the lift is uneven. It helps in France (+0.049) and Portugal (+0.013), is flat in Italy and Greece, and on Spain the weather features slightly hurt cross-country transfer (-0.021). Tomorrow's weather carries real but modest signal on top of the fire simply being big.

calibration leave-one-country-out

Judged in public, daily

The app does not just show forecasts. Every morning the previous day's issued probabilities are resolved against what VIIRS actually saw overnight, and the scoreboard (mean predicted vs realized, top-decile precision, the 15 most confident calls with their outcomes) renders on the page. The model gets no second chances on yesterday.

Caveats

Read these before quoting the number anywhere.

  • The label is "VIIRS sees the cell again", not "the fire is out". Clouds, smoke and overpass gaps cut both ways: a smouldering fire under cloud reads as out, a re-detected hotspot on a controlled burn reads as alive.
  • A cell is not a fire. Large fires span several cells; the map is a cell-level risk field, not a fire-perimeter product.
  • Training weather is ERA5 reanalysis; serving uses the real forecast. Live skill sits a little below the holdout number.
  • Not an operational fire product. It is a fundamentals monitor built on open data; nobody should route a crew off this map.

Leakage discipline

  • The weather for day D+1 is a legitimate feature: a forecast for it exists at issue time. Training uses the ERA5 value for D+1 (hindcast), serving uses the actual forecast.
  • Fire-side features are strictly day-D or earlier: detections, FRP, neighbourhood activity, streak. Nothing from D+1 except the label.
  • The split is temporal (2024 held out, never shuffled), the shuffled-label control trains at the base rate, and leave-one-country-out is reported so cross-country transfer is visible.
  • Same-day rows with an unresolved label (the last observed day) are marked pending and excluded from training until the next day's pass resolves them.

Architecture

An FTI (feature, training, inference) system on Hopsworks. Feature extraction is one shared module (holdover_features.py) imported by every pipeline and the app, so training and serving cannot skew.

flowchart LR
  FA([FIRMS archives + NRT feed]):::ext --> FP[fires_pipeline] --> FGF[(holdover_fires)]:::hops
  OM([Open-Meteo: ERA5 + forecast]):::ext --> WP[weather_pipeline] --> FGW[(holdover_weather)]:::hops
  FGF --> FV{{holdover_fv}}:::hops
  FGW --> FV
  FV --> TR[train: GBM + ablation gate] --> MR[(Model Registry)]:::hops
  MR --> INF[predict, daily]
  FGF --> INF
  FGW --> INF
  INF --> FGX[(holdover_predictions)]:::hops
  FGX --> APP[holdover app]
  classDef hops fill:#10b98122,stroke:#34d399,color:#e5e7eb;
  classDef ext fill:none,stroke:#6b7280,color:#9ca3af,stroke-dasharray:4 3;
Loading

The file-by-file map:

holdover_features.py         shared MITs: cell binning, per-cell-day aggregation,
                             persistence features, label, date normalizer.
                             Imported everywhere.
collect/firms.py             FIRMS country archives (keyless backfill) + global
                             7-day NRT CSV (keyless live), Med bbox filter
pipelines/fires_pipeline.py     F  -> holdover_fires   (backfill 2020-2024 + daily NRT)
pipelines/weather_pipeline.py   F  -> holdover_weather (ERA5 activity windows,
                                   quota-paced + resumable; daily forecast)
pipelines/build_fv.py           T  leak-free feature view (day-D fire x day-D+1 weather)
pipelines/train.py              T  temporal split, PERSIST/WEATHER/FUSED ablation,
                                   shuffle control, LOCO, self-gate, calibrate,
                                   register holdover_gbm + plots
pipelines/predict.py            I  daily: tonight's fires -> P(still burning) -> FG
app/server.py + static/         I  FastAPI thin client: Med ember map, watchlist,
                                   the daily self-judging scoreboard
Makefile                        the whole build, one target per stage

Everything keyless end to end: FIRMS for detections (archives and the NRT feed), Open-Meteo for ERA5 and the forecast. No account, no token, fully reproducible.

Reproduce

Clone into a Hopsworks project on the /hopsfs/... FUSE mount. Paths self-derive.

make fires-job weather-job    # F: backfill both FGs (weather is quota-paced,
                              #    resumable: re-run until it reports 0 to fetch)
make fv train-job             # T: leak-free FV, train + gate + register
make predict-job app          # I: score tonight's fires + the live map
make schedule                 # daily cycle: fires 03:30, weather 04:00,
                              #    predict 04:30, train 05:00 UTC

The map

The app (app/) renders an isometric voxel terrain of the Mediterranean on satellite imagery. Every active fire cell is a stacked-cube column whose height and color follow the threat, risk times fire intensity, so the big fires likely to still be burning tomorrow stand up as bright peaks. Past days play back as a muted intensity terrain, today is the colored forecast, and the week animates as a flow. Country and region labels orient the view; a watchlist and a "how honest is this" panel carry the gate verdict, the holdout numbers, and each day's predictions resolved against the next day's detections. Server-rendered, content in the initial payload.

The cluster deployment (feature groups, model, jobs, live app) was torn down after the run to free shared resources. The build is fully reproducible from the pipelines below on any Hopsworks project; nothing here needs a key.

About

Which of tonight's Mediterranean fires will still be burning tomorrow. FTI on Hopsworks, keyless, self-judging daily.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages