Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Validation and Model Selection - Fed-Batch Bioreactor

A hybrid model that fits its training data is not necessarily a good model: a large enough network can memorise measurement noise. The way to tell the difference, and to choose how big the network should be, is to measure performance on data the model never saw during training.

This notebook uses the fed-batch bioreactor from Importing Measured Data and a leave-one-batch-out protocol:

  1. Train the hybrid model on a subset of the logged batches.

  2. Predict the held-out batch from its initial charge with model.predict(), and score the prediction against that batch’s measurements.

  3. Sweep the network width and read off the size that generalises best.

Because the held-out batch never enters the fit, its error is an honest estimate of how the model will do on a new run.

Imports, including HybridDAE for the fit/predict pipeline.

Problem and data

The problem definition is the standard fed-batch model (all four states observed), identical to the first fed-batch example.

We load the three logged batches and split them: batches 0 and 1 are used for training, and batch 2 is held out for validation.

Training on batches [0, 1], validating on batch 2

A reusable train-and-validate routine

fit_and_score trains a network of a given width on the training batches with HybridDAE, then predicts the held-out batch with model.predict() and reports the root-mean-square error against both the training measurements and the held-out measurements.

Sweep the network width

We fit a small, a medium, and a large network and compare their training and held-out errors.

/var/folders/bd/5y876_fs4td3chn71x256drh0000gn/T/ipykernel_50556/1037312101.py:62: UserWarning: HybridDAE smoother solve terminated with 'maxIterations' (not optimal); results may be unreliable.
  model.fit(problem)
width  2:  train RMSE = 0.758   held-out RMSE = 0.753
/var/folders/bd/5y876_fs4td3chn71x256drh0000gn/T/ipykernel_50556/1037312101.py:62: UserWarning: HybridDAE smoother solve terminated with 'maxIterations' (not optimal); results may be unreliable.
  model.fit(problem)
width  4:  train RMSE = 0.758   held-out RMSE = 0.761
/var/folders/bd/5y876_fs4td3chn71x256drh0000gn/T/ipykernel_50556/1037312101.py:62: UserWarning: HybridDAE smoother solve terminated with 'maxIterations' (not optimal); results may be unreliable.
  model.fit(problem)
width  8:  train RMSE = 0.757   held-out RMSE = 0.770
/var/folders/bd/5y876_fs4td3chn71x256drh0000gn/T/ipykernel_50556/1037312101.py:62: UserWarning: HybridDAE smoother solve terminated with 'maxIterations' (not optimal); results may be unreliable.
  model.fit(problem)
width 16:  train RMSE = 0.756   held-out RMSE = 0.773
/var/folders/bd/5y876_fs4td3chn71x256drh0000gn/T/ipykernel_50556/1037312101.py:62: UserWarning: HybridDAE smoother solve terminated with 'maxIterations' (not optimal); results may be unreliable.
  model.fit(problem)
width 32:  train RMSE = 0.756   held-out RMSE = 0.775

Training error is essentially flat indicating that every network is large enough to fit the noisy training batches down to the measurement-noise floor. But the held-out error grows with network size. This is symptomatic of overfitting, where the larger networks fits to noise that does not generalise to the unseen batch.

<Figure size 1800x1200 with 1 Axes>
Validation selects width = 2

A check against the known kinetics

Validation chose the network purely from held-out data. Because this is a synthetic study we can also compare each network’s recovered growth rate against the true Monod law.

width  2:  mu MAE vs true Monod = 0.0128
width  4:  mu MAE vs true Monod = 0.0192
width  8:  mu MAE vs true Monod = 0.0229
width 16:  mu MAE vs true Monod = 0.0244
width 32:  mu MAE vs true Monod = 0.0247
<Figure size 1500x1200 with 1 Axes>

Summary

  • A held-out batch gives an honest measure of generalisation: split the logged runs, train on some, and predict the rest with model.predict().

  • Training error alone is misleading here. It sits at the noise floor for every network size, while held-out error reveals that larger networks overfit.

  • Selecting the network by held-out RMSE also yields the best recovery of the underlying kinetics, even though the selection used no knowledge of the truth.