kozy9 commited on
Commit
03b8a8b
·
verified ·
1 Parent(s): 19835c6

Upload TCN — test RMSE 3.5771 m R² 0.334

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ tcn_forecast_comparison.png filter=lfs diff=lfs merge=lfs -text
37
+ tcn_model.keras filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ license: mit
3
+ tags:
4
+ - time-series
5
+ - forecasting
6
+ - tcn
7
+ - hydrology
8
+ - groundwater
9
+ ---
10
+
11
+ # TCN Groundwater Level Forecasting — UK
12
+
13
+ A tuned Temporal Convolutional Network (TCN) for single-step monthly groundwater
14
+ level forecasting using meteorological variables as exogenous inputs.
15
+
16
+ ## Model Details
17
+
18
+ | Parameter | Value |
19
+ |---|---|
20
+ | Architecture | TCN(nb_filters=32, kernel_size=3, dilations=[1, 2, 4, 8]) → Dense(1) |
21
+ | Framework | TensorFlow / Keras (keras-tcn) |
22
+ | Task | Single-step monthly forecasting |
23
+ | Lookback window | 24 months |
24
+ | Input features | water_level, temperature, precipitation, wind_speed |
25
+ | Tuning method | Bayesian Optimisation (Keras Tuner, 20 trials) |
26
+
27
+ ## Data Splits
28
+
29
+ | Split | Period | Months |
30
+ |---|---|---|
31
+ | Training | 1944-01-01 → 2007-10-01 | 766 |
32
+ | Validation | 2007-11-01 → 2015-10-01 | 96 |
33
+ | Test | 2015-11-01 → 2023-10-01 | 96 |
34
+
35
+ ## Best Hyperparameters
36
+
37
+ | Parameter | Value |
38
+ |---|---|
39
+ | nb_filters | 32 |
40
+ | kernel_size | 3 |
41
+ | dilations | [1, 2, 4, 8] |
42
+ | dropout_rate | 0.1 |
43
+ | learning_rate | 0.001000 |
44
+ | Receptive field | 61 months |
45
+
46
+ ## Test Set Performance
47
+
48
+ | Metric | Value |
49
+ |---|---|
50
+ | RMSE | 3.5771 m |
51
+ | MAE | 2.8901 m |
52
+ | MAPE | 4.3138% |
53
+ | R² | 0.334 |
54
+ | NSE | 0.334 |
55
+
56
+ > This model is part of a benchmark study comparing SARIMAX, LSTM, and TCN
57
+ > for UK groundwater level forecasting.
58
+
59
+ ## Important Note
60
+
61
+ Contemporaneous meteorological variables are used as inputs at forecast time
62
+ (oracle assumption). Future met values are treated as known — consistent with
63
+ the experimental setup used across all models in this study.
64
+
65
+ ## Repository Contents
66
+ ```
67
+ ├── tcn_model.keras # Trained Keras TCN model
68
+ ├── scaler_features.pkl # Feature scaler (MinMaxScaler, fit on train only)
69
+ ├── scaler_target.pkl # Target scaler (MinMaxScaler, for inverse transform)
70
+ ├── model_config.json # Config, hyperparameters & metrics
71
+ ├── inference.py # Load model & generate forecasts
72
+ └── README.md # This file
73
+ ```
74
+
75
+ ## Quick Start
76
+ ```python
77
+ from huggingface_hub import hf_hub_download
78
+ from tensorflow.keras.models import load_model
79
+ import joblib, pandas as pd, numpy as np
80
+
81
+ model = load_model(hf_hub_download('kozy9/GWTCN', 'tcn_model.keras'))
82
+ scaler_features = joblib.load(hf_hub_download('kozy9/GWTCN', 'scaler_features.pkl'))
83
+ scaler_target = joblib.load(hf_hub_download('kozy9/GWTCN', 'scaler_target.pkl'))
84
+
85
+ # Provide a 24-month window of features
86
+ X_window = pd.DataFrame({
87
+ 'water_level' : [...], # 24 values
88
+ 'temperature' : [...],
89
+ 'precipitation': [...],
90
+ 'wind_speed' : [...],
91
+ })
92
+
93
+ X_scaled = scaler_features.transform(X_window)
94
+ X_input = X_scaled.reshape(1, 24, 4)
95
+ y_scaled = model.predict(X_input)
96
+ pred = scaler_target.inverse_transform(y_scaled)[0][0]
97
+ print(f'Next month forecast: {pred:.2f} m')
98
+ ```
inference.py ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ inference.py — TCN Groundwater Level Forecasting
3
+ =================================================
4
+ Usage
5
+ -----
6
+ from inference import load_model, forecast
7
+ model, scaler_features, scaler_target = load_model()
8
+ prediction = forecast(model, scaler_features, scaler_target, X_window)
9
+ """
10
+
11
+ import json
12
+ import joblib
13
+ import numpy as np
14
+ import pandas as pd
15
+ from pathlib import Path
16
+ from tensorflow.keras.models import load_model as keras_load
17
+
18
+ MODEL_PATH = Path(__file__).parent / "tcn_model.keras"
19
+ SCALER_FEATURES_PATH = Path(__file__).parent / "scaler_features.pkl"
20
+ SCALER_TARGET_PATH = Path(__file__).parent / "scaler_target.pkl"
21
+ CONFIG_PATH = Path(__file__).parent / "model_config.json"
22
+
23
+
24
+ def load_model():
25
+ """Load the TCN model and both scalers."""
26
+ model = keras_load(MODEL_PATH)
27
+ scaler_features = joblib.load(SCALER_FEATURES_PATH)
28
+ scaler_target = joblib.load(SCALER_TARGET_PATH)
29
+ print("TCN model and scalers loaded.")
30
+ return model, scaler_features, scaler_target
31
+
32
+
33
+ def load_config():
34
+ with open(CONFIG_PATH) as f:
35
+ return json.load(f)
36
+
37
+
38
+ def forecast(model, scaler_features, scaler_target, X_window: pd.DataFrame):
39
+ """
40
+ Predict the next month's groundwater level.
41
+
42
+ Parameters
43
+ ----------
44
+ model : loaded Keras TCN model
45
+ scaler_features : fitted MinMaxScaler for all 4 input features
46
+ scaler_target : fitted MinMaxScaler for water_level target
47
+ X_window : DataFrame with columns [water_level, temperature,
48
+ precipitation, wind_speed] and exactly 24 rows
49
+ (the lookback window)
50
+
51
+ Returns
52
+ -------
53
+ prediction : float — forecasted water level in original units (m)
54
+ """
55
+ cfg = load_config()
56
+ required = cfg['features']
57
+ lookback = cfg['lookback_months']
58
+
59
+ missing = [c for c in required if c not in X_window.columns]
60
+ if missing:
61
+ raise ValueError(f"X_window is missing columns: {missing}")
62
+ if len(X_window) != lookback:
63
+ raise ValueError(f"X_window must have {lookback} rows, got {len(X_window)}")
64
+
65
+ X_scaled = scaler_features.transform(X_window[required])
66
+ X_input = X_scaled.reshape(1, lookback, len(required))
67
+
68
+ y_scaled = model.predict(X_input, verbose=0).flatten()
69
+ prediction = scaler_target.inverse_transform(y_scaled.reshape(-1, 1)).flatten()[0]
70
+
71
+ return float(prediction)
72
+
73
+
74
+ if __name__ == "__main__":
75
+ model, scaler_features, scaler_target = load_model()
76
+ cfg = load_config()
77
+ print(f"Model: {cfg['architecture']}")
78
+ print(f"Test RMSE: {cfg['test_metrics']['RMSE']} m")
79
+
80
+ # Dummy window — replace with real data
81
+ dummy = pd.DataFrame({
82
+ 'water_level' : np.random.uniform(60, 75, 24),
83
+ 'temperature' : np.random.uniform(3, 15, 24),
84
+ 'precipitation': np.random.uniform(20, 120, 24),
85
+ 'wind_speed' : np.random.uniform(10, 25, 24),
86
+ })
87
+ pred = forecast(model, scaler_features, scaler_target, dummy)
88
+ print(f"\nForecast (next month): {pred:.4f} m")
model_config.json ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "model_type": "TCN",
3
+ "architecture": "TCN(nb_filters=32, kernel_size=3, dilations=[1, 2, 4, 8]) \u2192 Dense(1)",
4
+ "framework": "TensorFlow/Keras (keras-tcn)",
5
+ "task": "Single-step monthly groundwater level forecasting",
6
+ "features": [
7
+ "water_level",
8
+ "temperature",
9
+ "precipitation",
10
+ "wind_speed"
11
+ ],
12
+ "target": "water_level",
13
+ "lookback_months": 24,
14
+ "horizon_months": 1,
15
+ "tuning": {
16
+ "method": "Bayesian Optimisation (Keras Tuner)",
17
+ "n_trials": 20,
18
+ "best_config": {
19
+ "nb_filters": 32,
20
+ "kernel_size": 3,
21
+ "dilations": [
22
+ 1,
23
+ 2,
24
+ 4,
25
+ 8
26
+ ],
27
+ "dropout_rate": 0.1,
28
+ "learning_rate": 0.001,
29
+ "receptive_field": 61
30
+ }
31
+ },
32
+ "data_splits": {
33
+ "train": {
34
+ "start": "1944-01-01",
35
+ "end": "2007-10-01",
36
+ "n_months": 766
37
+ },
38
+ "validation": {
39
+ "start": "2007-11-01",
40
+ "end": "2015-10-01",
41
+ "n_months": 96
42
+ },
43
+ "test": {
44
+ "start": "2015-11-01",
45
+ "end": "2023-10-01",
46
+ "n_months": 96
47
+ }
48
+ },
49
+ "test_metrics": {
50
+ "RMSE": 3.5771,
51
+ "MAE": 2.8901,
52
+ "MAPE_pct": 4.3138,
53
+ "R2": 0.334,
54
+ "NSE": 0.334
55
+ },
56
+ "notes": "Scaler fitted on train only. Oracle exog assumption \u2014 contemporaneous met vars used at forecast time."
57
+ }
scaler_features.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3c0d11dcc6e97c52246a4bc0a08b926e75edaa58a268400446e4eafdd81c199a
3
+ size 1127
scaler_target.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:865d8113514357d4b75338166ebba5771c914f7cd10b5892fc2187265ae4515c
3
+ size 975
tcn_baseline_training_history.png ADDED
tcn_forecast_comparison.png ADDED

Git LFS Details

  • SHA256: 095ad9982c82cceceed41399ff4820eae6bc0978c30ebea69a642aa182302513
  • Pointer size: 131 Bytes
  • Size of remote file: 393 kB
tcn_model.keras ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:f7b000cf26bedc98461a4d960aa999747d38e39fe1545ddcf093f0f88cd0f537
3
+ size 387592
tcn_residual_analysis.png ADDED
tcn_tuned_training_history.png ADDED