Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ Major release, not backwards compatible except for the AgentLib-MPC integration
first_step_weight=0.25, mode='single_then_multi')` for all keras models (and `ModularANN(solver='ols')` as
initialization). The saved model stays a single step model for AgentLib-MPC.
- Example `executables/bestest_hydronic_heat_pump/TAir_recursive.py`.
- Recurrent models (`RNNModel`) warm themselves up: a sequence of `warmup_width + label_width` steps starts
from zero states, the warmup is not part of the loss. This is how AgentLib-MPC applies the model.
- `RNNModel` with `Change(T)` outputs: the trajectory of T (measured start value plus accumulated changes) is
predicted and trained on (`loss_on='trajectory'`, or `'outputs'`), with optional step weights
(`first_step_weight`, `step_weights`). If T is also an input, the prediction is fed back (closed loop) in
training and evaluation, as in an MPC.
- The saved RNN (`.keras`) is the step model `[sequence, *states] -> [prediction, *states]` used by AgentLib-MPC
(branch 143), verified by contract tests that run as soon as the installed AgentLib-MPC supports RNNs.
- `PreprocessingMultiStep(eval_horizon=..., eval_stride=...)`: evaluation over a horizon longer than the training
horizon; `label_width` / `warmup_width` also as time delta strings ('12h'). RMSE, MAE and bias per step in
`td.horizon_metrics` (per output in `by_feature`).

### Changed
- Python >= 3.11 is required (3.9 and 3.10 are end of life).
Expand All @@ -53,7 +64,11 @@ Major release, not backwards compatible except for the AgentLib-MPC integration
- Data is loaded onto a regular time grid: missing time stamps are missing values instead of being
joined with their neighbours.
- `TrainingData` holds the whole time series as NumPy array with split labels; `TrainingDataMultiStep`
holds NumPy windows and builds `tf.data` pipelines on demand (reshuffled every epoch).
holds sequences as views on it: `X_*` (warmup and prediction), `y_*` (true trajectories), `targets(split)`
and `initial(split)`.
- The batch size of recurrent models is set at the model (`RNNModel(batch_size=...)`), not the preprocessing.
- Feature selection on the multi step error uses `PreprocessingSingleStep(eval_horizon=...)` (mean RMSE over
the horizon on the validation data); the recursive feature is never removed.
- `random_state=None` draws a seed (or uses the global one) and stores it in the config.
- `PreprocessingData.from_config` restores the class from `__class_name__` and all settings.

Expand All @@ -73,6 +88,9 @@ Major release, not backwards compatible except for the AgentLib-MPC integration
- `BuildContext` cached tensors by `id()` of temporary expressions, which Python reuses.
- Early stopping on `val_loss` without validation data; random seeds were set when a model object was
created instead of when the model is generated.
- RNN: the summary was always printed, the verbosity ignored, the `Rescaling` layer held tensors instead of
floats, and the config validation of `init_layer` compared strings with `is not`.
- `PINNModel.pipeline` and `online_pipeline` returned None instead of the trained model.

### Removed
- `physXAI.preprocessing.constructed` (`Feature`, `FeatureConstruction`): lags and `Change(X)` are derived
Expand All @@ -82,5 +100,10 @@ Major release, not backwards compatible except for the AgentLib-MPC integration
`ModularTrainable` -> `px.Param`, `ModularAverage` -> `px.Mean`, `ModularNormalization` -> `px.Normalize`,
`ModularExistingModel` -> `px.Pretrained`). The separate `modular_expression_config.json` is gone, the graph
is part of the model config.
- RNN initialization models (`init_layer`) and the warmup features of the preprocessing (`init_features`,
`warmup_columns_*`). Old configs without initialization model are still accepted.
- Multi step evaluation of single step models with `PreprocessingMultiStep` (`SingleStepModel.evaluate_multi`):
use `PreprocessingSingleStep(eval_horizon=...)`. `physXAI.evaluation.closed_loop` is replaced by the
closed loop of `RNNModel` and by `physXAI.evaluation.rollout`.
- `GitPython` dependency; paths are no longer resolved relative to the git root.
- `requirements.txt` with outdated pins (use `pip install -e .[dev]`).
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from physXAI.feature_selection.recursive_feature_elimination import recursive_feature_elimination_pipeline
from physXAI.models.models import LinearRegressionModel
from physXAI.preprocessing.preprocessing import PreprocessingMultiStep
from physXAI.preprocessing.preprocessing import PreprocessingSingleStep
from physXAI.utils.logging import Logger


Expand All @@ -18,15 +18,14 @@
'weaSta_reaWeaTDryBul_y_lag2', 'weaSta_reaWeaHDirNor_y', 'weaSta_reaWeaHDirNor_y_lag1',
'weaSta_reaWeaHDirNor_y_lag2', 'oveHeaPumY_u', 'oveHeaPumY_u_lag1', 'oveHeaPumY_u_lag2']
# Output feature
output = 'Change(T_zone)'
output = 'Change(reaTZon_y)'

# Lagged inputs ('X_lag1', ...) are derived automatically from their names

# Generic Preprocessing Pipeline
# Model is state model, so multi-step evaluation is choosen
# The model is a state model, so it is evaluated recursively over 48 steps (multi step error)
# See example TAir_evaluateMultiStep.py for more information
prep = PreprocessingMultiStep(inputs=inputs, output=output, label_width=48, warmup_width=0, init_features=['reaTZon_y'],
overlapping_sequences=False, batch_size=1)
prep = PreprocessingSingleStep(inputs=inputs, output=output, eval_horizon=48)

# Generic Model
m = LinearRegressionModel()
Expand Down
32 changes: 10 additions & 22 deletions executables/bestest_hydronic_heat_pump/TAir_evaluateMultiStep.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from physXAI.models.models import LinearRegressionModel
from physXAI.models.ann.ann_design import ClassicalANNModel
from physXAI.preprocessing.preprocessing import PreprocessingMultiStep
from physXAI.preprocessing.preprocessing import PreprocessingSingleStep
from physXAI.utils.logging import Logger


"""
Creates a linear regression to predict the air temperature using the Boptest data
The model is trained as a single step model, but evaluated as a multi step model
Creates a linear regression to predict the air temperature using the Boptest data.
The model is trained as a single step model, but also evaluated over a horizon of 48 steps: it is
applied recursively, as in an MPC, which shows how its error grows over the horizon.
"""
# Setup up logger for saving
Logger.setup_logger(folder_name='TAir', override=True)
Expand All @@ -15,25 +15,13 @@
file_path = r"data/bestest_hydronic_heat_pump/pid_data.csv"

# List of input features. Lagged inputs ('X_lag1') and changes ('Change(X)') are derived automatically
inputs = ['reaTZon_y', 'reaTZon_y_lag1', 'reaTZon_y_lag2', 'weaSta_reaWeaTDryBul_y', 'weaSta_reaWeaTDryBul_y_lag1',
'weaSta_reaWeaHDirNor_y', 'oveHeaPumY_u', 'oveHeaPumY_u_lag1', 'oveHeaPumY_u_lag2']
# Output feature
output = 'Change(T_zone)'
inputs = ['weaSta_reaWeaTDryBul_y', 'weaSta_reaWeaTDryBul_y_lag1', 'weaSta_reaWeaHDirNor_y', 'oveHeaPumY_u',
'oveHeaPumY_u_lag1', 'oveHeaPumY_u_lag2', 'reaTZon_y', 'reaTZon_y_lag1', 'reaTZon_y_lag2']
# Output feature: the change of the air temperature, which is also an input (recursive feature)
output = 'Change(reaTZon_y)'

# Lagged inputs ('X_lag1', ...) are derived automatically from their names

# Create Training data
"""
The model is trained as a single step model and evaluated as a multi step model
warmup_width should be 0 as initial values cannot be processed by single step models
init_features: There are two prediction modes for multi-step:
(0) Predict change of original variable, (1) Predict original variable
init_features should contain original variable, can be None in mode (1)
overlapping_sequence should be False to avoid duplicate labels for single step prediction
batch_size should be 1 as batches are processes differently in single step models
"""
prep = PreprocessingMultiStep(inputs=inputs, output=output, label_width=48, warmup_width=0, init_features=['reaTZon_y'],
overlapping_sequences=False, batch_size=1)
# Create Training data. eval_horizon adds the recursive evaluation over 48 steps
prep = PreprocessingSingleStep(inputs=inputs, output=output, eval_horizon=48)
# Process Training data
td = prep.pipeline(file_path)

Expand Down
38 changes: 18 additions & 20 deletions executables/bestest_hydronic_heat_pump/TAir_rnn.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,40 @@
from physXAI import expr as px
from physXAI.models.ann.ann_design import RNNModel
from physXAI.preprocessing.preprocessing import PreprocessingMultiStep
from physXAI.utils.logging import Logger


"""
Creates a recurrent neural network (RNN) to predict the air temperature using the Boptest data
Creates a recurrent neural network (RNN) to predict the air temperature using the Boptest data.

- The RNN predicts the change of the air temperature. Its trajectory is the measured start value
plus the accumulated changes, and the model is trained on that trajectory.
- The air temperature is also an input: during the prediction the predicted temperature is fed back
(closed loop), as in an MPC.
- There is no separate initialization model. The model starts from zero states and warms up on the
measured past (warmup_width), which is not part of the loss. AgentLib-MPC warms it up the same way.
- label_width (training horizon) should be longer than the MPC horizon, eval_horizon shows the error
beyond it.
"""
# Setup up logger for saving
Logger.setup_logger(folder_name='TAir_rnn', override=True)

# File path to data
file_path = r"data/bestest_hydronic_heat_pump/pid_data.csv"


"""
List of input features. Lagged inputs are derived automatically from their names.
As a RNN is applied, there is no need to add the recursive feature 'reaTZon_y' to the inputs.
RNNs need to be initialized. Therefore a initialization model is trained based on the 'inits' features.
The RNN directly predicts the air temperature instead of the air temperature change.
"""
inputs = ['weaSta_reaWeaTDryBul_y', 'weaSta_reaWeaHDirNor_y', 'oveHeaPumY_u']
inits = ['reaTZon_y']
output = 'reaTZon_y'

# Number of time steps in the output (label) sequence.
label_width = 48
# Number of time steps in the warmup sequence (for RNN state initialization).
warmup_width = 48
inputs = ['weaSta_reaWeaTDryBul_y', 'weaSta_reaWeaHDirNor_y', 'oveHeaPumY_u', 'reaTZon_y']
output = px.Change('reaTZon_y')

# Create Training data. For RNNs MultiStep training data is required
prep = PreprocessingMultiStep(inputs=inputs, output=output, label_width=label_width, warmup_width=warmup_width, init_features=inits)
prep = PreprocessingMultiStep(inputs=inputs, output=output, label_width='12h', warmup_width='6h',
eval_horizon='24h', time_index_col='time')
# Process Training data
td = prep.pipeline(file_path)

# Create RNN model. Models needs a rnn type for the output (rnn_layer) and the initialization (init_layer) model
m = RNNModel(epochs=100, rnn_layer='LSTM', init_layer='LSTM')
# Create RNN model
m = RNNModel(epochs=100, rnn_layer='LSTM', rnn_units=16, early_stopping_epochs=20)

# Training pipeline
# Training pipeline. The saved model is the step model used by AgentLib-MPC.
model = m.pipeline(td)

# Log setup of preprocessing and model as json
Expand Down
199 changes: 0 additions & 199 deletions physXAI/evaluation/closed_loop.py

This file was deleted.

Loading
Loading