Example usage with the CLI
This notebook demonstrates usage of petab_select to perform model selection with commands.
Note that the criterion values in this notebook are for demonstrative purposes only, and are not real. An additional point is that models store the iteration where they were calibrated, but the iteration counter is stored in the candidate space. Hence, when the candidate space (or method) changes in this notebook, the iteration counter is reset.
[1]:
# Cleanup the state and candidate models output by a previous run of this notebook
import shutil
from pathlib import Path
output_path = Path().resolve() / "output_cli"
output_path_str = str(output_path)
if output_path.exists():
shutil.rmtree(output_path_str)
output_path.mkdir(exist_ok=False, parents=True)
First iteration
Iterations of model selection start and end with start_iteration and end_iteration.
In each call to petab_select start_iteration, the following options are required:
--problem: The PEtab Select problem YAML file, which normally defines the method too--state: A file that is used to store the state of the problem (e.g., such that models are not revisited)--output: A file to store the models proposed by PEtab Select
Other options can be viewed with petab_select start_iteration --help.
In this initial call, a PEtab Select problem is used to identify possible models for selection. Instead of using the method defined in the PEtab Select problem, we use the brute force method, which normally outputs all possible models. Here, the number of models in the output is explicitly limited to 3. Subsequent calls with the same command will output different models.
[2]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select start_iteration \
--problem model_selection/petab_select_problem.yaml \
--state $output_path_str/state.dill \
--method brute_force \
--limit 3 \
--output-uncalibrated-models $output_path_str/uncalibrated_models_1.yaml \
--relative-paths
The output format is a list of the PEtab Select model YAML format.
[3]:
with open(output_path / "uncalibrated_models_1.yaml") as f:
print(f.read())
- model_subspace_id: M1_0
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_0-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 1
model_id: M1_0-000
model_label: null
parameters:
k1: 0
k2: 0
k3: 0
predecessor_model_hash: virtual_initial_model-
- model_subspace_id: M1_1
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_1-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 1
model_id: M1_1-000
model_label: null
parameters:
k1: 0.2
k2: 0.1
k3: estimate
predecessor_model_hash: virtual_initial_model-
- model_subspace_id: M1_2
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_2-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 1
model_id: M1_2-000
model_label: null
parameters:
k1: 0.2
k2: estimate
k3: 0
predecessor_model_hash: virtual_initial_model-
At this point, the calibration tool should calibrate the models, and save the calibration results to disk in the PEtab Select model YAML format. For this example, we have stored the results in model_selection/calibrated_models_1.yaml.
Next, we finalize the iteration by calling petab_select end_iteration, which requires:
--state: seestart_iteration--output-models: A file used to store the models from this iteration of calibration. Note that, if the user has supplied calibration results from previous model selection jobs, then thisend_iterationoutput might differ from the output of the calibration tool. Thisend_iterationoutput should be considered the real set of models calibrated in this iteration.--output-metadata: A file where metadata from the iteration is stored. This includes the signal of whether model selection has terminated.
[4]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select end_iteration \
--state=$output_path_str/state.dill \
--calibrated-models=model_selection/calibrated_models_1.yaml \
--output-models=$output_path_str/models_1.yaml \
--output-metadata=$output_path_str/metadata.yaml \
--relative-paths
Second iteration
Between iterations, the models from the first iteration have been calibrated, and the model with the best criterion value is M1_2. In this iteration, we will switch to the forward method and manually specify M1_2 as the predecessor model. In subsequent iterations, the predecessor model will default to the best model of the previous iteration.
[5]:
with open("model_selection/calibrated_models_1.yaml") as f:
print(f.read())
- model_subspace_id: M1_0
model_subspace_indices:
- 0
- 0
- 0
criteria:
AIC: 180
model_hash: M1_0-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: {}
iteration: 1
model_id: M1_0-000
parameters:
k1: 0
k2: 0
k3: 0
predecessor_model_hash: virtual_initial_model-
- model_subspace_id: M1_1
model_subspace_indices:
- 0
- 0
- 0
criteria:
AIC: 100
model_hash: M1_1-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: {}
iteration: 1
model_id: M1_1-000
parameters:
k1: 0.2
k2: 0.1
k3: estimate
predecessor_model_hash: virtual_initial_model-
- model_subspace_id: M1_2
model_subspace_indices:
- 0
- 0
- 0
criteria:
AIC: 50
model_hash: M1_2-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: {}
iteration: 1
model_id: M1_2-000
parameters:
k1: 0.2
k2: estimate
k3: 0
predecessor_model_hash: virtual_initial_model-
To perform the method change, we: delete the current state, select and store the model M1_2 to disk via petab_select get_best, customize the problem to use the predecessor model via candidate_space_arguments, and supply the new method to petab_select start_iteration.
[6]:
%%bash -s "$output_path_str"
output_path_str=$1
# save the best model of the previous iteration (`M1_2`)
petab_select get_best \
--problem model_selection/petab_select_problem.yaml \
--models model_selection/calibrated_models_1.yaml \
--output $output_path_str/predecessor_model.yaml
# create a copy of the original PEtab select problem and update its paths
cp model_selection/petab_select_problem.yaml $output_path_str/custom_problem.yaml
sed -i 's|- model_space.tsv|- ../model_selection/model_space.tsv|' $output_path_str/custom_problem.yaml
# add the predecessor model to the problem copy
echo """candidate_space_arguments:
predecessor_model: predecessor_model.yaml
""" >> $output_path_str/custom_problem.yaml
# remove the state from the previous iteration
rm $output_path_str/state.dill
# request models with the customized problem with the predecessor model `M1_2`, using the forward method
petab_select start_iteration \
--problem $output_path_str/custom_problem.yaml \
--state $output_path_str/state.dill \
--output-uncalibrated-models $output_path_str/uncalibrated_models_2.yaml \
--method forward \
--relative-paths
M1_2 has one estimated parameter, k2(*). As expected, the new candidates identified with the forward method have two estimated parameters, and one of them is k2.
(*) There may be additional estimated parameters specified in the PEtab problem, which are not a part of the model selection problem.
[7]:
with open(output_path / "uncalibrated_models_2.yaml") as f:
print(f.read())
- model_subspace_id: M1_4
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_4-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 1
model_id: M1_4-000
model_label: null
parameters:
k1: 0.2
k2: estimate
k3: estimate
predecessor_model_hash: M1_2-000
- model_subspace_id: M1_6
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_6-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 1
model_id: M1_6-000
model_label: null
parameters:
k1: estimate
k2: estimate
k3: 0
predecessor_model_hash: M1_2-000
The calibration tool does not need to calibrate every uncalibrated model. For example, the calibration tool might return all calibration results, as soon as an improvement over the previous iteration is identified. Here, we only return the results for the M1_4 model.
[8]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select end_iteration \
--state=$output_path_str/state.dill \
--calibrated-models=model_selection/calibrated_M1_4.yaml \
--output-models=$output_path_str/models_2.yaml \
--output-metadata=$output_path_str/metadata.yaml \
--relative-paths
Third iteration
The models from the previous iteration (i.e. M1_4) were stored in the state. Here, we perform an iteration of the forward method, which is automatically initialized with the M1_4 model.
[9]:
with open("model_selection/calibrated_M1_4.yaml") as f:
print(f.read())
model_subspace_id: M1_4
model_subspace_indices:
- 0
- 0
- 0
criteria:
AIC: 15
model_hash: M1_4-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters:
k2: 0.15
k3: 0.0
iteration: 1
model_id: M1_4-000
parameters:
k1: 0
k2: estimate
k3: estimate
predecessor_model_hash: M1_2-000
[10]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select start_iteration \
--problem $output_path_str/custom_problem.yaml \
--state $output_path_str/state.dill \
--output-uncalibrated-models $output_path_str/uncalibrated_models_3.yaml \
--method forward \
--relative-paths
As we are performing a forward search from M1_4, which has two parameters, then all models in this iteration will have 3+ parameters. This model space contains only one model with 3 or more estimated parameters. We finalize the iteration with its calibration results.
[11]:
with open(output_path / "uncalibrated_models_3.yaml") as f:
print(f.read())
- model_subspace_id: M1_7
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_7-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 2
model_id: M1_7-000
model_label: null
parameters:
k1: estimate
k2: estimate
k3: estimate
predecessor_model_hash: M1_4-000
[12]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select end_iteration \
--state=$output_path_str/state.dill \
--calibrated-models=model_selection/calibrated_M1_7.yaml \
--output-models=$output_path_str/models_3.yaml \
--output-metadata=$output_path_str/metadata.yaml \
--relative-paths
Fourth iteration
As there are no models in the model space with 4+ parameters, subsequent forward searches will return no candidate models. Tools can detect when to terminate by inspecting the metadata produced by end_iteration, as demonstrated at the end of this iteration.
[13]:
with open("model_selection/calibrated_M1_7.yaml") as f:
print(f.read())
model_subspace_id: M1_7
model_subspace_indices:
- 0
- 0
- 0
criteria:
AIC: 20
model_hash: M1_7-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters:
k1: 0.25
k2: 0.1
k3: 0.0
iteration: 2
model_id: M1_7-000
parameters:
k1: estimate
k2: estimate
k3: estimate
predecessor_model_hash: M1_4-000
[14]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select start_iteration \
--problem model_selection/petab_select_problem.yaml \
--state $output_path_str/state.dill \
--output-uncalibrated-models $output_path_str/uncalibrated_models_4.yaml \
--method forward \
--relative-paths
[15]:
with open(output_path / "uncalibrated_models_4.yaml") as f:
print(f.read())
[]
[16]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select end_iteration \
--state=$output_path_str/state.dill \
--output-models=$output_path_str/models_4.yaml \
--output-metadata=$output_path_str/metadata.yaml \
--relative-paths
[17]:
with open("output_cli/metadata.yaml") as f:
print(f.read())
terminate: true
Fifth iteration
Although no additional models are found with a forward search initialized at the best model so far (M1_7), there are additional models in the model space that were not calibrated, which can be identified by using the brute force method with exclusions for the calibrated models.
[18]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select start_iteration \
--problem model_selection/petab_select_problem.yaml \
--state $output_path_str/state_5.dill \
--output-uncalibrated-models $output_path_str/uncalibrated_models_5.yaml \
--method brute_force \
--excluded-models $output_path_str/models_1.yaml \
--excluded-models $output_path_str/models_2.yaml \
--excluded-models $output_path_str/models_3.yaml \
--relative-paths
[19]:
with open(output_path / "uncalibrated_models_5.yaml") as f:
print(f.read())
- model_subspace_id: M1_3
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_3-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 1
model_id: M1_3-000
model_label: null
parameters:
k1: estimate
k2: 0.1
k3: 0
predecessor_model_hash: virtual_initial_model-
- model_subspace_id: M1_5
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_5-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 1
model_id: M1_5-000
model_label: null
parameters:
k1: estimate
k2: 0.1
k3: estimate
predecessor_model_hash: virtual_initial_model-
- model_subspace_id: M1_6
model_subspace_indices:
- 0
- 0
- 0
criteria: {}
model_hash: M1_6-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters: null
iteration: 1
model_id: M1_6-000
model_label: null
parameters:
k1: estimate
k2: estimate
k3: 0
predecessor_model_hash: virtual_initial_model-
Post-processing
After the selection algorithm has terminated, the best model can be stored separately by supplying a list of calibrated models.
[20]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select get_best \
--problem model_selection/petab_select_problem.yaml \
--models $output_path_str/models_1.yaml \
--models $output_path_str/models_2.yaml \
--models $output_path_str/models_3.yaml \
--output $output_path_str/best_model.yaml \
--state $output_path_str/state.dill \
--relative-paths
[21]:
with open(output_path / "best_model.yaml") as f:
print(f.read())
model_subspace_id: M1_4
model_subspace_indices:
- 0
- 0
- 0
criteria:
AIC: 15.0
model_hash: M1_4-000
model_subspace_petab_yaml: ../model_selection/petab_problem.yaml
estimated_parameters:
k2: 0.15
k3: 0.0
iteration: 1
model_id: M1_4-000
model_label: null
parameters:
k1: 0
k2: estimate
k3: estimate
predecessor_model_hash: M1_2-000
This model can be converted to a PEtab problem with either model_to_petab or models_to_petab.
[22]:
%%bash -s "$output_path_str"
output_path_str=$1
petab_select model_to_petab \
--model $output_path_str/best_model.yaml \
--output $output_path_str/best_model_petab
/home/docs/checkouts/readthedocs.org/user_builds/petab-select/checkouts/latest/doc/examples/output_cli/best_model_petab/problem.yaml