XAI-FLOWS flood risk models
Two models that back the flood-risk prediction pipeline in the XAI-FLOWS backend (link once the hub repo exists): a drain-blockage image classifier and a weather-based risk model, combined by a hand-written explainable rule layer that lives in the backend code, not in either model.
What's in this repository
| File | Type | Purpose |
|---|---|---|
vgg16_model.keras | Keras 3 / TensorFlow (VGG16 transfer learning) | Classifies a drain-camera image into one of three blockage states |
xgb.pkl | XGBoost regressor | A precipitation-regression model, used here for its SHAP feature attribution — see Model 2 below, this is not a classifier |
scaler.pkl | scikit-learn StandardScaler | Feature scaler paired with xgb.pkl, fit on 6,950 weather-feature rows |
All facts below were verified directly by loading each artifact and inspecting it — nothing here is inferred or guessed.
Model 1 — drain-blockage image classifier
- Architecture: the full VGG16 convolutional stack (13 conv layers across 5 blocks, standard VGG16 layout) as a frozen/transfer-learned feature extractor, followed by
Flatten → Dense(256, ReLU) → Dense(3, softmax). - Input: RGB image, resized to 256×256, normalized to [0, 1] — input tensor shape
(None, 256, 256, 3). - Output: one of three classes —
0full blockage,1no blockage,2partial blockage — plus a softmax confidence score for the predicted class. - Training setup (from the saved model's compile config):
categorical_crossentropyloss,accuracytracked as the training metric. Saved with Keras 3.4.1 on 2024-08-23. - Explainability: none at inference time. SHAP/Grad-CAM-style explanations were evaluated but a full SHAP explainer over this CNN takes seconds to minutes per image, which doesn't fit a real-time prediction endpoint — see Limitations.
Model 2 — weather regression model (SHAP attribution only)
- Architecture: XGBoost, 100 trees, max depth 6,
reg:squarederrorobjective — this is a regressor, not a classifier, over 18 weather features (app_temp,clouds,dewpt,dhi,dni,elev_angle,ghi,pres,rh,slp,solar_rad,temp,uv,vis,wind_dir,wind_spd,hour,month— exact order matters, seeINPUT_COLUMNSin the backend'sapp/core/config.py). - Input: the 18-feature vector, scaled with
scaler.pkl(fit on 6,950 samples; see per-feature means/scale below) before prediction. - What it's actually used for: this is important and easy to misread from the backend code alone — the pipeline never calls this model's own
.predict(). The precipitation and weather-condition values shown to the user come directly from the live Weatherbit API response, not from this model. This regressor is loaded and run only to generateshap.Explainerfeature-attribution values, which are shipped alongside the live weather data as the "why" behind the prediction's weather context. In other words: live data drives the number, this model drives the explanation. - Explainability: this is the model the "XAI" in XAI-FLOWS most directly refers to — its SHAP breakdown of which weather features are pushing precipitation risk up or down ships with every prediction.
- Scaler feature statistics (from the fitted
StandardScaler, 6,950 samples): e.g. mean temperature ≈ 28.4°C, mean humidity ≈ 67%, mean month ≈ 6.6, mean hour ≈ 11.5 — consistent with a dataset gathered across multiple months and times of day rather than a single narrow window.
How these combine into a flood-risk verdict
Neither model outputs "flood risk" directly. The backend's HeuristicModel (not part of this repository — see the backend repo's app/utils/heuristic_rule.py) takes the blockage class + confidence from Model 1 and the live weather signal (informed by Model 2's SHAP attribution) and applies an explicit, human-readable rule table to produce the final Minimal / Low / Moderate / High verdict with a plain-English reason. This is deliberate: a rule table a person can read and challenge was chosen over training a third, less transparent model on top of these two.
Loading these models
import pickle
from huggingface_hub import hf_hub_download
from tensorflow.keras.models import load_model
repo_id = "ubada11/xai-flows-flood-risk-models"
vgg16_path = hf_hub_download(repo_id=repo_id, filename="vgg16_model.keras")
xgb_path = hf_hub_download(repo_id=repo_id, filename="xgb.pkl")
scaler_path = hf_hub_download(repo_id=repo_id, filename="scaler.pkl")
vgg_model = load_model(vgg16_path)
with open(xgb_path, "rb") as f:
xgb_model = pickle.load(f)
with open(scaler_path, "rb") as f:
scaler = pickle.load(f)
This repository is gated — hf_hub_download needs an authenticated, approved Hugging Face token (huggingface-cli login, or token=...) the first time you download.
Model details
Verified directly by loading and inspecting each artifact — nothing here is inferred or copied from documentation that doesn't exist.
- Weather regressor: fit on 6,950 rows, 18 features (matching
INPUT_COLUMNSexactly), 100 trees, max depth 6. - Image classifier: 3-class softmax output, trained with categorical cross-entropy, saved 2024-08-23 with Keras 3.4.1.
- Both models' feature/class shapes match what the backend code expects — no mismatch between what's saved here and what
app/core/config.pyandapp/utils/*.pyassume.
Formal accuracy/precision/recall/F1 figures aren't published here — the training process for these models happened outside version control, so there's no held-out test set or evaluation log to report from.
Limitations
- The blockage classifier has no per-inference explanation attached (see above) — only a class and a confidence score.
- The weather model's SHAP values explain that model's output, not the final flood-risk verdict directly — the verdict is a downstream rule applied to both models' outputs, and that rule itself isn't a statistical model, so it has no SHAP values of its own.
- Both models were trained for a specific geography/camera setup and are not validated for drains, cameras, or climates outside that context.
Intended use
Built for and used exclusively by the XAI-FLOWS backend prediction pipeline. Not intended for standalone reuse — the feature order the XGBoost model and scaler expect is tightly coupled to app/core/config.py::INPUT_COLUMNS in that repository, and using these weights outside that pipeline without matching preprocessing will silently produce meaningless results.
License
All rights reserved. Part of a PhD research project — access granted for academic review or portfolio evaluation only, not for reuse, modification, or redistribution.