diff --git a/doc/examples/how_to_dmms/conditions.tsv b/doc/examples/how_to_dmms/conditions.tsv new file mode 100644 index 0000000..da6fd62 --- /dev/null +++ b/doc/examples/how_to_dmms/conditions.tsv @@ -0,0 +1,3 @@ +conditionId +cond1 +cond2 diff --git a/doc/examples/how_to_dmms/how_to_dmms.ipynb b/doc/examples/how_to_dmms/how_to_dmms.ipynb new file mode 100644 index 0000000..4d06b25 --- /dev/null +++ b/doc/examples/how_to_dmms/how_to_dmms.ipynb @@ -0,0 +1,566 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "b3339048-6d80-4eeb-befa-4bc1b3c468ec", + "metadata": {}, + "source": [ + "# How To: Deep Mechanistic Models" + ] + }, + { + "cell_type": "markdown", + "id": "d54f42a2-a31d-4fad-926a-b562ba26cc11", + "metadata": {}, + "source": [ + "This is the case where the neural network is executed prior to the simulation and the output from it sets values of parameters in the ODE. We assume some familiarity with the getting started tutorial, which examines an entire PEtab SciML problem, while this guide focuses on the parts that are relevant to this use case. \n", + "\n", + "In this case, using the Lotka-Voltera system as an example, the output from the network replaces the parameter $\\gamma$.\n", + "\n", + "$$\\frac{\\mathrm{d} \\text{prey}}{\\mathrm{d} t} = \\alpha \\cdot \\text{prey} - \\beta \\cdot \\text{prey} \\cdot \\text{predator}$$\n", + "\n", + "$$\\frac{\\mathrm{d} \\text{predator}}{\\mathrm{d} t} = \\text{NN}[0] \\cdot \\text{prey} \\cdot \\text{predator} - \\delta \\cdot \\text{predator}$$\n", + "\n", + "The input to the neural network can be either vector based (see other tutorials) or provided via an array file, as demonstrated in this tutorial." + ] + }, + { + "cell_type": "markdown", + "id": "292488b8-24c6-43c9-9e88-5270fa0efb33", + "metadata": {}, + "source": [ + "## Loading the PEtab problem" + ] + }, + { + "cell_type": "markdown", + "id": "79c7c39c-e010-4bfd-971f-70bf26c82d93", + "metadata": {}, + "source": [ + "Let's load the PEtab problem, build our model and define the overall hybrid problem as a ``JAXProblem``." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e9880e7f-a9dd-4a00-9ee1-5ed95eda9110", + "metadata": {}, + "outputs": [], + "source": [ + "from amici.petab import import_petab_problem\n", + "from amici.jax import (\n", + " JAXProblem,\n", + " run_simulations,\n", + ")\n", + "from petab.v2 import Problem\n", + "\n", + "# Create the PEtab problem\n", + "petab_problem = Problem.from_yaml(\"problem.yaml\")\n", + "\n", + "# Create AMICI model for the petab problem\n", + "jax_model = import_petab_problem(\n", + " petab_problem,\n", + " model_output_dir=\"model\",\n", + " compile_=True,\n", + " jax=True\n", + ")\n", + "\n", + "# Create the JAXProblem - wrapper for the AMICI model\n", + "jax_problem = JAXProblem(jax_model, petab_problem)" + ] + }, + { + "cell_type": "markdown", + "id": "da148931-f7ba-4b1b-850d-8c8754cd4ad9", + "metadata": {}, + "source": [ + "By looking at the hybridization, parameters and mapping tables we can see how this deep mechanistic modelling problem has been defined." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "7c1e0233-7e4b-411b-8ff7-ac57a2febf06", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
targetValue
targetId
gammanet3_output1
\n", + "
" + ], + "text/plain": [ + " targetValue\n", + "targetId \n", + "gamma net3_output1" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "jax_problem._petab_problem.hybridization_df" + ] + }, + { + "cell_type": "markdown", + "id": "38411614-bf14-4854-b655-5b29c3e345ec", + "metadata": {}, + "source": [ + "The ``gamma`` species from the model is mapped to a parameter with PEtab identifier ``net3_output1``. Looking at the mapping table, we can see that that PEtab id is defined as the first output from the neural network." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "832c8deb-927d-4189-b278-0bc8e5dfdfbd", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
modelEntityId
petabEntityId
input0net3.inputs[0]
net3_output1net3.outputs[0][0]
net3_psnet3.parameters
\n", + "
" + ], + "text/plain": [ + " modelEntityId\n", + "petabEntityId \n", + "input0 net3.inputs[0]\n", + "net3_output1 net3.outputs[0][0]\n", + "net3_ps net3.parameters" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "petab_problem.mapping_df" + ] + }, + { + "cell_type": "markdown", + "id": "c999332c-e901-4f2c-877a-7ca482f75fdd", + "metadata": {}, + "source": [ + "Finally, in the parameters table, the network parameters are listed with infinite bounds and no nominal value, so that they are free to be optimised. Also note that $\\gamma$ does not appear in the parameters table, as its value is set by the neural network model." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "3cb05448-ca2a-4fbc-92e8-9d6f1f8ff630", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
parameterScalelowerBoundupperBoundnominalValueestimate
parameterId
alphalin0.015.01.31
deltalin0.015.01.81
betalin0.015.00.91
net3_pslin-infinfNaN1
\n", + "
" + ], + "text/plain": [ + " parameterScale lowerBound upperBound nominalValue estimate\n", + "parameterId \n", + "alpha lin 0.0 15.0 1.3 1\n", + "delta lin 0.0 15.0 1.8 1\n", + "beta lin 0.0 15.0 0.9 1\n", + "net3_ps lin -inf inf NaN 1" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "petab_problem.parameter_df" + ] + }, + { + "cell_type": "markdown", + "id": "bb0d08d2-088b-4850-96e2-d0c12e1605eb", + "metadata": {}, + "source": [ + "### Array input data\n", + "\n", + "The PEtab problem specified under ``extensions_config`` that there were two files of array data to be added to the problem:\n", + "- ``net3_ps.hdf5`` to set the values of the network parameters\n", + "- ``net3_input2.hdf5`` to provide the inputs into the network" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "c30ec3c9-6de5-403f-999d-cfe7020c6c69", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{\n", + " \"sciml\": {\n", + " \"array_files\": [\n", + " \"net3_ps.hdf5\",\n", + " \"net3_input2.hdf5\"\n", + " ],\n", + " \"hybridization_files\": [\n", + " \"hybridization.tsv\"\n", + " ],\n", + " \"neural_nets\": {\n", + " \"net3\": {\n", + " \"location\": \"net3.yaml\",\n", + " \"static\": true,\n", + " \"format\": \"YAML\"\n", + " }\n", + " }\n", + " }\n", + "}\n" + ] + } + ], + "source": [ + "import json # for pretty printing only\n", + "\n", + "print(json.dumps(petab_problem.extensions_config, indent=4))" + ] + }, + { + "cell_type": "markdown", + "id": "3393b6c1-b193-4f64-8269-838c054bce97", + "metadata": {}, + "source": [ + "The nested structure of the neural network input file can be seen below. The input data to the neural network is under ``inputs/input0`` and data for two conditions is specified. The keys for the different conditions match those defined in the conditions table." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "87200584-39ec-4bb2-a4ee-919065598b65", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " inputs\n", + " input0\n", + " cond1\n", + " cond2\n", + " metadata\n", + " perm\n" + ] + } + ], + "source": [ + "import h5py\n", + "\n", + "# Convenience function to show the nested structure of an HDF5 file\n", + "def show_h5_struct(file):\n", + " file.visit(lambda x: print(\" \" * (len(x.split(\"/\")) - 1), x.split(\"/\")[-1]))\n", + "\n", + "file = h5py.File(\"net3_input2.hdf5\")\n", + "show_h5_struct(file)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "78615c62-63c7-4b53-ab69-1a0cff91482d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
conditionId
cond1
cond2
\n", + "
" + ], + "text/plain": [ + "Empty DataFrame\n", + "Columns: []\n", + "Index: [cond1, cond2]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "petab_problem.condition_df" + ] + }, + { + "cell_type": "markdown", + "id": "c26425d8-2b07-4262-9bbe-fb67f7dc24d0", + "metadata": {}, + "source": [ + "
\n", + "Also note the ``static: true`` setting in the neural network definition of the extensions config. This means the input to the neural network is not expected to depend on the model. This keyword will indicate to PEtab SciML importers that the network precedes the ODE, as opposed to being inside it (i.e. a UDE) or in one of the observable formulae.\n", + "
\n" + ] + }, + { + "cell_type": "markdown", + "id": "c6a998ed-e561-4025-8572-36d7d1eb350a", + "metadata": {}, + "source": [ + "### Network Architecture\n", + "\n", + "The PyTorch snippet below shows how a network architecture would be defined and exported to YAML format using PEtab SciML. The predefined YAML file is also provided in the PEtab SciML repo for completeness. We have used a convolution architecture here to indicate how the DMM problem set up could enable inclusion of information from high dimensional inputs in the mechanistic model. " + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "743ed691-5ceb-41b8-9255-6576bfcc3996", + "metadata": {}, + "outputs": [], + "source": [ + "from petab_sciml.standard.nn_model import Input, NNModel, NNModelStandard\n", + "import torch\n", + "from torch import nn\n", + "import torch.nn.functional as F\n", + "\n", + "class NeuralNetwork(nn.Module):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.layer1 = torch.nn.Conv2d(\n", + " 3, 1, (5, 5), stride=(1, 1), padding=(0, 0), dilation=(1, 1)\n", + " )\n", + " self.layer2 = torch.nn.Flatten()\n", + " self.layer3 = torch.nn.Linear(36, 1)\n", + "\n", + " def forward(self, net_input):\n", + " x = self.layer1(net_input)\n", + " x = self.layer2(x)\n", + " x = self.layer3(x)\n", + " x = F.relu(x)\n", + " return x\n", + "\n", + "net1 = NeuralNetwork()\n", + "nn_model1 = NNModel.from_pytorch_module(\n", + " module=net1, nn_model_id=\"net3\", inputs=[Input(input_id=\"input0\")]\n", + ")\n", + "NNModelStandard.save_data(\n", + " data=nn_model1, filename=\"net3_from_pytorch.yaml\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "8b04d5fe-42f0-443b-b02d-38832b6523f6", + "metadata": {}, + "source": [ + "### Parameterizing network inputs\n", + "\n", + "A straightforward alternative to defining network inputs as array data in files, is to define them in the parameters table, with appropriate bounds and nominal values. \n", + "\n", + "| parameterId | parameterScale | lowerBound | upperBound | nominalValue | estimate |\n", + "|-----------------|----------------|------------|------------|--------------|----------|\n", + "| net1_input_pre1 | lin | -inf | inf | 1 | 0 |\n", + "| net1_input_pre2 | lin | -inf | inf | 1 | 0 |\n", + "| | | | | | |\n", + "\n", + "And the corresponding mapping table to define the model entities for those PEtab identifiers.\n", + "\n", + "| petabEntityId | modelEntityId |\n", + "|-----------------|-------------------|\n", + "| net1_input_pre1 | net1.inputs[0][0] |\n", + "| net1_input_pre2 | net1.inputs[0][1] |" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/examples/how_to_dmms/hybridization.tsv b/doc/examples/how_to_dmms/hybridization.tsv new file mode 100644 index 0000000..8dc4719 --- /dev/null +++ b/doc/examples/how_to_dmms/hybridization.tsv @@ -0,0 +1,2 @@ +targetId targetValue +gamma net3_output1 diff --git a/doc/examples/how_to_dmms/lv.xml b/doc/examples/how_to_dmms/lv.xml new file mode 100644 index 0000000..3ec6640 --- /dev/null +++ b/doc/examples/how_to_dmms/lv.xml @@ -0,0 +1,117 @@ + + + + + +
PEtab implementation of the simple model
+ +
+ + + + + + + + Ognissanti + Damiano + + + + + + 2022-08-19T11:46:48Z + + + 2022-08-19T11:46:48Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + alpha + prey + + + + + + + + + + + + + delta + predator + + + + + + + + + + + + + beta + prey + predator + + + + + + + + + + + + + gamma + predator + prey + + + + + +
+
\ No newline at end of file diff --git a/doc/examples/how_to_dmms/mapping.tsv b/doc/examples/how_to_dmms/mapping.tsv new file mode 100644 index 0000000..f4aa306 --- /dev/null +++ b/doc/examples/how_to_dmms/mapping.tsv @@ -0,0 +1,4 @@ +petabEntityId modelEntityId +input0 net3.inputs[0] +net3_output1 net3.outputs[0][0] +net3_ps net3.parameters diff --git a/doc/examples/how_to_dmms/measurements.tsv b/doc/examples/how_to_dmms/measurements.tsv new file mode 100644 index 0000000..3a2ab59 --- /dev/null +++ b/doc/examples/how_to_dmms/measurements.tsv @@ -0,0 +1,41 @@ +observableId simulationConditionId measurement time +prey_o cond1 0.17301723066961405 1.0 +prey_o cond1 0.48917673783409993 2.0 +prey_o cond1 1.6439955318035595 3.0 +prey_o cond1 5.451962785760956 4.0 +prey_o cond1 2.977522019296872 5.0 +prey_o cond1 0.18166337921190132 6.0 +prey_o cond1 0.34811222588891116 7.0 +prey_o cond1 0.9379191086100471 8.0 +prey_o cond1 3.1132400328752725 9.0 +prey_o cond1 8.86393324304537 10.0 +predator_o cond1 0.8474159434933868 1.0 +predator_o cond1 0.21113451571705152 2.0 +predator_o cond1 -0.025053892754896945 3.0 +predator_o cond1 0.1250104939525384 4.0 +predator_o cond1 6.700454555504469 5.0 +predator_o cond1 2.0071582885977066 6.0 +predator_o cond1 0.4200924826891049 7.0 +predator_o cond1 0.048031851600281825 8.0 +predator_o cond1 0.128669393707342 9.0 +predator_o cond1 1.1927837762326177 10.0 +prey_o cond2 0.2219828904947475 1.0 +prey_o cond2 0.5276545477245373 2.0 +prey_o cond2 1.4489892769025072 3.0 +prey_o cond2 4.870854183709297 4.0 +prey_o cond2 1.4339315443619947 5.0 +prey_o cond2 0.20198520102077788 6.0 +prey_o cond2 0.35315037605528066 7.0 +prey_o cond2 0.9502200881229326 8.0 +prey_o cond2 3.4021902017878376 9.0 +prey_o cond2 4.8268184728460115 10.0 +predator_o cond2 0.9788999227307986 1.0 +predator_o cond2 0.24676970118818284 2.0 +predator_o cond2 0.0635336820792109 3.0 +predator_o cond2 0.250021606661362 4.0 +predator_o cond2 6.3573469863762835 5.0 +predator_o cond2 1.661922951387048 6.0 +predator_o cond2 0.355368743021419 7.0 +predator_o cond2 0.056211961187334625 8.0 +predator_o cond2 0.16872950412564128 9.0 +predator_o cond2 4.457131477744339 10.0 diff --git a/doc/examples/how_to_dmms/net3.yaml b/doc/examples/how_to_dmms/net3.yaml new file mode 100644 index 0000000..7ffd123 --- /dev/null +++ b/doc/examples/how_to_dmms/net3.yaml @@ -0,0 +1,72 @@ +nn_model_id: net3 +inputs: +- input_id: input0 +layers: +- layer_id: layer1 + layer_type: Conv2d + args: + stride: + - 1 + - 1 + padding: + - 0 + - 0 + dilation: + - 1 + - 1 + groups: 1 + padding_mode: zeros + in_channels: 3 + out_channels: 1 + kernel_size: + - 5 + - 5 + bias: true +- layer_id: layer2 + layer_type: Flatten + args: + start_dim: 1 + end_dim: -1 +- layer_id: layer3 + layer_type: Linear + args: + in_features: 36 + out_features: 1 + bias: true +forward: +- name: net_input + op: placeholder + target: net_input + args: [] + kwargs: {} +- name: layer1 + op: call_module + target: layer1 + args: + - net_input + kwargs: {} +- name: layer2 + op: call_module + target: layer2 + args: + - layer1 + kwargs: {} +- name: layer3 + op: call_module + target: layer3 + args: + - layer2 + kwargs: {} +- name: relu + op: call_function + target: relu + args: + - layer3 + kwargs: + inplace: false +- name: output + op: output + target: output + args: + - relu + kwargs: {} diff --git a/doc/examples/how_to_dmms/net3_from_pytorch.yaml b/doc/examples/how_to_dmms/net3_from_pytorch.yaml new file mode 100644 index 0000000..7ffd123 --- /dev/null +++ b/doc/examples/how_to_dmms/net3_from_pytorch.yaml @@ -0,0 +1,72 @@ +nn_model_id: net3 +inputs: +- input_id: input0 +layers: +- layer_id: layer1 + layer_type: Conv2d + args: + stride: + - 1 + - 1 + padding: + - 0 + - 0 + dilation: + - 1 + - 1 + groups: 1 + padding_mode: zeros + in_channels: 3 + out_channels: 1 + kernel_size: + - 5 + - 5 + bias: true +- layer_id: layer2 + layer_type: Flatten + args: + start_dim: 1 + end_dim: -1 +- layer_id: layer3 + layer_type: Linear + args: + in_features: 36 + out_features: 1 + bias: true +forward: +- name: net_input + op: placeholder + target: net_input + args: [] + kwargs: {} +- name: layer1 + op: call_module + target: layer1 + args: + - net_input + kwargs: {} +- name: layer2 + op: call_module + target: layer2 + args: + - layer1 + kwargs: {} +- name: layer3 + op: call_module + target: layer3 + args: + - layer2 + kwargs: {} +- name: relu + op: call_function + target: relu + args: + - layer3 + kwargs: + inplace: false +- name: output + op: output + target: output + args: + - relu + kwargs: {} diff --git a/doc/examples/how_to_dmms/net3_input2.hdf5 b/doc/examples/how_to_dmms/net3_input2.hdf5 new file mode 100644 index 0000000..ac76834 Binary files /dev/null and b/doc/examples/how_to_dmms/net3_input2.hdf5 differ diff --git a/doc/examples/how_to_dmms/net3_ps.hdf5 b/doc/examples/how_to_dmms/net3_ps.hdf5 new file mode 100644 index 0000000..258ba97 Binary files /dev/null and b/doc/examples/how_to_dmms/net3_ps.hdf5 differ diff --git a/doc/examples/how_to_dmms/observables.tsv b/doc/examples/how_to_dmms/observables.tsv new file mode 100644 index 0000000..fc5f605 --- /dev/null +++ b/doc/examples/how_to_dmms/observables.tsv @@ -0,0 +1,3 @@ +observableId observableFormula noiseFormula observableTransformation noiseDistribution +prey_o prey 0.05 lin normal +predator_o predator 0.05 lin normal diff --git a/doc/examples/how_to_dmms/parameters.tsv b/doc/examples/how_to_dmms/parameters.tsv new file mode 100644 index 0000000..ecad86e --- /dev/null +++ b/doc/examples/how_to_dmms/parameters.tsv @@ -0,0 +1,5 @@ +parameterId parameterScale lowerBound upperBound nominalValue estimate +alpha lin 0.0 15.0 1.3 1 +delta lin 0.0 15.0 1.8 1 +beta lin 0.0 15.0 0.9 1 +net3_ps lin -inf inf 1 diff --git a/doc/examples/how_to_dmms/problem.yaml b/doc/examples/how_to_dmms/problem.yaml new file mode 100644 index 0000000..1ddb698 --- /dev/null +++ b/doc/examples/how_to_dmms/problem.yaml @@ -0,0 +1,27 @@ +problems: + - model_files: + lv: + location: "lv.xml" + language: "sbml" + measurement_files: + - "measurements.tsv" + observable_files: + - "observables.tsv" + condition_files: + - "conditions.tsv" + mapping_files: + - "mapping.tsv" +format_version: 2.0.0 +extensions: + sciml: + array_files: + - "net3_ps.hdf5" + - "net3_input2.hdf5" + hybridization_files: + - "hybridization.tsv" + neural_nets: + net3: + location: "net3.yaml" + static: true + format: "YAML" +parameter_file: "parameters.tsv" diff --git a/doc/examples/how_to_neural_ode/conditions.tsv b/doc/examples/how_to_neural_ode/conditions.tsv new file mode 100644 index 0000000..fdcc030 --- /dev/null +++ b/doc/examples/how_to_neural_ode/conditions.tsv @@ -0,0 +1,2 @@ +conditionId +cond1 diff --git a/doc/examples/how_to_neural_ode/how_to_neural_ode.ipynb b/doc/examples/how_to_neural_ode/how_to_neural_ode.ipynb new file mode 100644 index 0000000..76f6e94 --- /dev/null +++ b/doc/examples/how_to_neural_ode/how_to_neural_ode.ipynb @@ -0,0 +1,446 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "85e61efa-c382-4fcd-a649-19aff93f7309", + "metadata": {}, + "source": [ + "# How To: Neural ODE" + ] + }, + { + "cell_type": "markdown", + "id": "e2ae1512-526e-4287-82a8-f95234bc5f84", + "metadata": {}, + "source": [ + "In this guide we will cover how to set up a Neural ODE problem using the PEtab SciML format and utility functions from the `petab_sciml` Python library. We assume some familiarity with the getting started tutorial, which examines an entire PEtab SciML problem, while this guide focuses on the parts that are relevant to the Neural ODE use case. \n", + "\n", + "In the Neural ODE case, the whole right-hand-side of the ODE model is replaced with a neural network. As an example, we use the Lotka-Voltera system,\n", + "\n", + "$$\\frac{\\mathrm{d} \\text{prey}}{\\mathrm{d} t} = \\alpha \\cdot \\text{prey} - \\beta \\cdot \\text{prey} \\cdot \\text{predator}$$\n", + "\n", + "$$\\frac{\\mathrm{d} \\text{predator}}{\\mathrm{d} t} = \\gamma \\cdot \\text{prey} \\cdot \\text{predator} - \\delta \\cdot \\text{predator}$$\n", + "\n", + "which simply becomes,\n", + "\n", + "$$\\frac{\\mathrm{d} \\text{prey}}{\\mathrm{d} t} = \\text{NN}(\\text{prey}, \\text{predator})[0]$$\n", + "\n", + "$$\\frac{\\mathrm{d} \\text{predator}}{\\mathrm{d} t} = \\text{NN}(\\text{prey}, \\text{predator})[1]$$\n", + "\n", + "to configure it as a Neural ODE problem." + ] + }, + { + "cell_type": "markdown", + "id": "a706dd6a-98c8-493b-b73e-a4173af450cd", + "metadata": {}, + "source": [ + "## Defining the network architecture" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "c1d328c2-8032-4ab8-9fe6-fd2e74622a61", + "metadata": {}, + "outputs": [], + "source": [ + "from petab_sciml.standard.nn_model import Input, NNModel, NNModelStandard\n", + "import torch\n", + "from torch import nn\n", + "import torch.nn.functional as F\n", + "\n", + "class NeuralNetwork(nn.Module):\n", + " def __init__(self):\n", + " super().__init__()\n", + " self.layer1 = torch.nn.Linear(2, 10)\n", + " self.layer2 = torch.nn.Linear(10, 10)\n", + " self.layer3 = torch.nn.Linear(10, 2)\n", + "\n", + " def forward(self, net_input):\n", + " x = self.layer1(net_input)\n", + " x = F.tanh(x)\n", + " x = self.layer2(x)\n", + " x = F.tanh(x)\n", + " x = self.layer3(x)\n", + " return x\n", + "\n", + "net1 = NeuralNetwork()\n", + "nn_model1 = NNModel.from_pytorch_module(\n", + " module=net1, nn_model_id=\"net1\", inputs=[Input(input_id=\"input0\")]\n", + ")\n", + "NNModelStandard.save_data(\n", + " data=nn_model1, filename=\"net1.yaml\"\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "320f12b5-8b91-42c4-ab26-0e9977746e47", + "metadata": {}, + "source": [ + "The network architecture in this example is kept simple for demonstration purposes. Refer to the page on supported layers and activation functions for more inspiration, but note that PEtab SciML and its importers currently only support networks with vector outputs. " + ] + }, + { + "cell_type": "markdown", + "id": "56e1044a-da75-4766-a063-db803c64962b", + "metadata": {}, + "source": [ + "## Generating the PEtab files\n", + "\n", + "The PEtab SciML Python package provides utility functions to generate the model and PEtab files for a neural ODE case. The names of the species in the ODE system are required to generate the model. The utility functions will generate hybridization, mapping and parameter files." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "47c89dd2-822d-465c-bc15-3406aa91a59f", + "metadata": {}, + "outputs": [], + "source": [ + "from petab_sciml.problem_utils.neural_ode import (\n", + " create_neural_ode, \n", + " create_neural_ode_problem\n", + ")\n", + "\n", + "create_neural_ode([\"prey\", \"predator\"], model_filename=\"lv.xml\")" + ] + }, + { + "cell_type": "markdown", + "id": "ee0a9cd6-ce92-4e35-a89e-ee820b90b292", + "metadata": {}, + "source": [ + "In order to completely define the PEtab problem, the measurement, observable and array input files need to be supplied by the user. There is then a utility function to generate the `problem.yaml` file and reference all the PEtab files in it. Example files are included in the docs as a demonstration." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "1e6b4ea0-2e9f-48d5-9205-3c6bb4ca6c24", + "metadata": {}, + "outputs": [], + "source": [ + "create_neural_ode_problem(\n", + " \"lv.xml\", \n", + " \"measurements.tsv\", \n", + " \"observables.tsv\", \n", + " \"net1.yaml\", \n", + " [\"net1_ps.hdf5\"]\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "d6af94a7-08fe-456b-a91b-6f326f2e286e", + "metadata": {}, + "source": [ + "## Loading the PEtab problem" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37db1309-2d0d-47c6-ba23-8b513db2a128", + "metadata": { + "slideshow": { + "slide_type": "subslide" + } + }, + "outputs": [], + "source": [ + "from amici.petab import import_petab_problem\n", + "from amici.jax import (\n", + " JAXProblem,\n", + " run_simulations,\n", + ")\n", + "from petab.v2 import Problem\n", + "\n", + "# Create the PEtab problem\n", + "petab_problem = Problem.from_yaml(\"problem.yaml\")\n", + "\n", + "# Create AMICI model for the petab problem\n", + "jax_model = import_petab_problem(\n", + " petab_problem,\n", + " model_output_dir=\"model\",\n", + " compile_=True,\n", + " jax=True\n", + ")\n", + "\n", + "# Create the JAXProblem - wrapper for the AMICI model\n", + "jax_problem = JAXProblem(jax_model, petab_problem)" + ] + }, + { + "cell_type": "markdown", + "id": "b8ab3aa8-a5dc-498e-9457-34e3e0d5bcec", + "metadata": {}, + "source": [ + "The hybridization and mapping tables show us how the neural network inputs and outputs are mapped to the model." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c33ade41-69d5-4b7c-8e4c-6f06137c017a", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
targetValue
targetId
net1_input0prey
net1_input1predator
prey_paramnet1_output0
predator_paramnet1_output1
\n", + "
" + ], + "text/plain": [ + " targetValue\n", + "targetId \n", + "net1_input0 prey\n", + "net1_input1 predator\n", + "prey_param net1_output0\n", + "predator_param net1_output1" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "jax_problem._petab_problem.hybridization_df" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "0b42b898-b3a9-4163-9847-d40170f18835", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
modelEntityId
petabEntityId
net1_input0net1.inputs[0][0]
net1_input1net1.inputs[0][1]
net1_output0net1.outputs[0][0]
net1_output1net1.outputs[0][1]
net1_psnet1.parameters
\n", + "
" + ], + "text/plain": [ + " modelEntityId\n", + "petabEntityId \n", + "net1_input0 net1.inputs[0][0]\n", + "net1_input1 net1.inputs[0][1]\n", + "net1_output0 net1.outputs[0][0]\n", + "net1_output1 net1.outputs[0][1]\n", + "net1_ps net1.parameters" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "petab_problem.mapping_df" + ] + }, + { + "cell_type": "markdown", + "id": "736d0ff5-a4b3-427b-a2e4-ccd3516a60bf", + "metadata": {}, + "source": [ + "The inputs to the neural network are given by the ``prey`` and ``predator`` species. $\\alpha$, the ``prey`` amount over time as defined by the SBML model, is given by the first output of the network. $\\delta$, the ``predator`` amount over time, is given by the second output of the network." + ] + }, + { + "cell_type": "markdown", + "id": "c134e21c-1654-4ec8-a5ec-e3a3be337314", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "It is also worth showing that the parameter table only has the network parameters defined in it. Unlike previous examples, there are no other parameters to be estimated in the problem. We will optimise the network parameters and then the outputs of the network will give us the solution to our ODEs." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "53d584e2-b3c5-485c-a648-7139a6f4c4ca", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
parameterScalelowerBoundupperBoundnominalValueestimate
parameterId
net1_pslin-infinfNaN1
\n", + "
" + ], + "text/plain": [ + " parameterScale lowerBound upperBound nominalValue estimate\n", + "parameterId \n", + "net1_ps lin -inf inf NaN 1" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "petab_problem.parameter_df" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/examples/how_to_neural_ode/hybridization.tsv b/doc/examples/how_to_neural_ode/hybridization.tsv new file mode 100644 index 0000000..e031c89 --- /dev/null +++ b/doc/examples/how_to_neural_ode/hybridization.tsv @@ -0,0 +1,5 @@ +targetId targetValue +net1_input0 prey +net1_input1 predator +prey_param net1_output0 +predator_param net1_output1 diff --git a/doc/examples/how_to_neural_ode/lv.xml b/doc/examples/how_to_neural_ode/lv.xml new file mode 100644 index 0000000..e014704 --- /dev/null +++ b/doc/examples/how_to_neural_ode/lv.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + prey_param + + + + + predator_param + + + + + diff --git a/doc/examples/how_to_neural_ode/mapping.tsv b/doc/examples/how_to_neural_ode/mapping.tsv new file mode 100644 index 0000000..f941d67 --- /dev/null +++ b/doc/examples/how_to_neural_ode/mapping.tsv @@ -0,0 +1,6 @@ +petabEntityId modelEntityId +net1_input0 net1.inputs[0][0] +net1_input1 net1.inputs[0][1] +net1_output0 net1.outputs[0][0] +net1_output1 net1.outputs[0][1] +net1_ps net1.parameters diff --git a/doc/examples/how_to_neural_ode/measurements.tsv b/doc/examples/how_to_neural_ode/measurements.tsv new file mode 100644 index 0000000..3721571 --- /dev/null +++ b/doc/examples/how_to_neural_ode/measurements.tsv @@ -0,0 +1,21 @@ +observableId simulationConditionId measurement time +prey_o cond1 0.17301723066954827 1.0 +prey_o cond1 0.48917673783383914 2.0 +prey_o cond1 1.643995531803569 3.0 +prey_o cond1 5.45196278566626 4.0 +prey_o cond1 2.9775220192442062 5.0 +prey_o cond1 0.18166337927167636 6.0 +prey_o cond1 0.3481122259853288 7.0 +prey_o cond1 0.9379191088947356 8.0 +prey_o cond1 3.113240033804055 9.0 +prey_o cond1 8.863933242141234 10.0 +predator_o cond1 0.8474159434934865 1.0 +predator_o cond1 0.2111345157163205 2.0 +predator_o cond1 -0.025053892755649274 3.0 +predator_o cond1 0.12501049397609923 4.0 +predator_o cond1 6.700454554758639 5.0 +predator_o cond1 2.007158288516007 6.0 +predator_o cond1 0.42009248269510124 7.0 +predator_o cond1 0.04803185161440934 8.0 +predator_o cond1 0.12866939374360575 9.0 +predator_o cond1 1.192783778293036 10.0 diff --git a/doc/examples/how_to_neural_ode/net1.yaml b/doc/examples/how_to_neural_ode/net1.yaml new file mode 100644 index 0000000..e968edf --- /dev/null +++ b/doc/examples/how_to_neural_ode/net1.yaml @@ -0,0 +1,64 @@ +nn_model_id: net1 +inputs: +- input_id: input0 +layers: +- layer_id: layer1 + layer_type: Linear + args: + in_features: 2 + out_features: 10 + bias: true +- layer_id: layer2 + layer_type: Linear + args: + in_features: 10 + out_features: 10 + bias: true +- layer_id: layer3 + layer_type: Linear + args: + in_features: 10 + out_features: 2 + bias: true +forward: +- name: net_input + op: placeholder + target: net_input + args: [] + kwargs: {} +- name: layer1 + op: call_module + target: layer1 + args: + - net_input + kwargs: {} +- name: tanh + op: call_method + target: tanh + args: + - layer1 + kwargs: {} +- name: layer2 + op: call_module + target: layer2 + args: + - tanh + kwargs: {} +- name: tanh_1 + op: call_method + target: tanh + args: + - layer2 + kwargs: {} +- name: layer3 + op: call_module + target: layer3 + args: + - tanh_1 + kwargs: {} +- name: output + op: output + target: output + args: + - layer3 + kwargs: {} diff --git a/doc/examples/how_to_neural_ode/net1_ps.hdf5 b/doc/examples/how_to_neural_ode/net1_ps.hdf5 new file mode 100644 index 0000000..84b0490 Binary files /dev/null and b/doc/examples/how_to_neural_ode/net1_ps.hdf5 differ diff --git a/doc/examples/how_to_neural_ode/observables.tsv b/doc/examples/how_to_neural_ode/observables.tsv new file mode 100644 index 0000000..fc5f605 --- /dev/null +++ b/doc/examples/how_to_neural_ode/observables.tsv @@ -0,0 +1,3 @@ +observableId observableFormula noiseFormula observableTransformation noiseDistribution +prey_o prey 0.05 lin normal +predator_o predator 0.05 lin normal diff --git a/doc/examples/how_to_neural_ode/parameters.tsv b/doc/examples/how_to_neural_ode/parameters.tsv new file mode 100644 index 0000000..07910d8 --- /dev/null +++ b/doc/examples/how_to_neural_ode/parameters.tsv @@ -0,0 +1,2 @@ +parameterId parameterScale lowerBound upperBound nominalValue estimate +net1_ps lin -inf inf 1 diff --git a/doc/examples/how_to_neural_ode/problem.yaml b/doc/examples/how_to_neural_ode/problem.yaml new file mode 100644 index 0000000..1804dfa --- /dev/null +++ b/doc/examples/how_to_neural_ode/problem.yaml @@ -0,0 +1,26 @@ +problems: + - model_files: + model: + location: lv.xml + language: sbml + measurement_files: + - measurements.tsv + observable_files: + - observables.tsv + condition_files: + - conditions.tsv + mapping_files: + - mapping.tsv +format_version: 2.0.0 +extensions: + sciml: + array_files: + - net1_ps.hdf5 + hybridization_files: + - hybridization.tsv + neural_nets: + net1: + location: net1.yaml + static: false + format: YAML +parameter_file: parameters.tsv diff --git a/doc/examples/how_to_observable/conditions.tsv b/doc/examples/how_to_observable/conditions.tsv new file mode 100644 index 0000000..fdcc030 --- /dev/null +++ b/doc/examples/how_to_observable/conditions.tsv @@ -0,0 +1,2 @@ +conditionId +cond1 diff --git a/doc/examples/how_to_observable/how_to_observable.ipynb b/doc/examples/how_to_observable/how_to_observable.ipynb new file mode 100644 index 0000000..1f12f47 --- /dev/null +++ b/doc/examples/how_to_observable/how_to_observable.ipynb @@ -0,0 +1,466 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "81cd17cb-2d7f-4d74-a63f-e6ff16ec8319", + "metadata": {}, + "source": [ + "# How To: Machine Learning models in the observables\n", + "\n", + "This guide covers how to include a machine learning (ML) model in the observable formula, which links the model output to the observed measurement data. We assume some familiarity with the getting started tutorial, which examines an entire PEtab SciML problem, while this guide focuses on the parts that are relevant to the observable use case. As a case study we will use the Lotka-Voltera system:\n", + "\n", + "$$\\frac{\\mathrm{d} \\text{prey}}{\\mathrm{d} t} = \\alpha \\cdot \\text{prey} - \\beta \\cdot \\text{prey} \\cdot \\text{predator}$$\n", + "\n", + "$$\\frac{\\mathrm{d} \\text{predator}}{\\mathrm{d} t} = \\gamma \\cdot \\text{prey} \\cdot \\text{predator} - \\delta \\cdot \\text{predator}$$\n", + "\n", + "There are two observables in this system, `prey` and `predator`, which will have measurements associated with them. The species in these expressions are not substituted in the SBML model file, but instead the inclusion of the ML model is accomplished by correctly formulating the observable, hybridization and mapping PEtab tables." + ] + }, + { + "cell_type": "markdown", + "id": "51c1a0d5-102f-46a4-821d-28f58bc4be48", + "metadata": {}, + "source": [ + "## Loading the PEtab problem" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d810c818-7914-4e3f-acbf-9596fe4cbfda", + "metadata": {}, + "outputs": [], + "source": [ + "from amici.petab import import_petab_problem\n", + "from amici.jax import (\n", + " JAXProblem,\n", + " run_simulations,\n", + ")\n", + "from petab.v2 import Problem\n", + "\n", + "# Create the PEtab problem\n", + "petab_problem = Problem.from_yaml(\"problem.yaml\")\n", + "\n", + "# Create AMICI model for the petab problem\n", + "jax_model = import_petab_problem(\n", + " petab_problem,\n", + " model_output_dir=\"model\",\n", + " compile_=True,\n", + " jax=True\n", + ")\n", + "\n", + "# Create the JAXProblem - wrapper for the AMICI model\n", + "jax_problem = JAXProblem(jax_model, petab_problem)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "d44cbd06-a3fe-4984-86dc-d5a48c7718c5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
observableFormulanoiseFormulaobservableTransformationnoiseDistribution
observableId
prey_onet1_output10.05linnormal
predator_opredator0.05linnormal
\n", + "
" + ], + "text/plain": [ + " observableFormula noiseFormula observableTransformation \\\n", + "observableId \n", + "prey_o net1_output1 0.05 lin \n", + "predator_o predator 0.05 lin \n", + "\n", + " noiseDistribution \n", + "observableId \n", + "prey_o normal \n", + "predator_o normal " + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "petab_problem.observable_df" + ] + }, + { + "cell_type": "markdown", + "id": "618ca834-e138-4189-bf93-16c46c5daa7a", + "metadata": {}, + "source": [ + "We can see here that the formula for the ``prey`` observable is defined by a PEtab identifier indicating a network output. The model definition of that PEtab id can be found in the mapping table. It is given by the first output of the neural network." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "217954a4-3488-4f23-9a8e-15ca29ca5a08", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
modelEntityId
petabEntityId
net1_input1net1.inputs[0][0]
net1_input2net1.inputs[0][1]
net1_output1net1.outputs[0][0]
net1_psnet1.parameters
\n", + "
" + ], + "text/plain": [ + " modelEntityId\n", + "petabEntityId \n", + "net1_input1 net1.inputs[0][0]\n", + "net1_input2 net1.inputs[0][1]\n", + "net1_output1 net1.outputs[0][0]\n", + "net1_ps net1.parameters" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "petab_problem.mapping_df" + ] + }, + { + "cell_type": "markdown", + "id": "8b8e370f-49ea-40e3-93b2-b3c7c4a74f48", + "metadata": {}, + "source": [ + "Wherever the problem formulation refers to the prey observable (``prey_o``) the neural network will be evaluated and its output used in place of that observable value, for instance, in the measurements table." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e1fac571-1ad7-4acc-9fb6-c43b06e6d53d", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
observableIdsimulationConditionIdmeasurementtime
0prey_ocond10.1730171.0
1prey_ocond10.4891772.0
2prey_ocond11.6439963.0
3prey_ocond15.4519634.0
4prey_ocond12.9775225.0
5prey_ocond10.1816636.0
6prey_ocond10.3481127.0
7prey_ocond10.9379198.0
8prey_ocond13.1132409.0
9prey_ocond18.86393310.0
10predator_ocond10.8474161.0
11predator_ocond10.2111352.0
12predator_ocond1-0.0250543.0
13predator_ocond10.1250104.0
14predator_ocond16.7004555.0
15predator_ocond12.0071586.0
16predator_ocond10.4200927.0
17predator_ocond10.0480328.0
18predator_ocond10.1286699.0
19predator_ocond11.19278410.0
\n", + "
" + ], + "text/plain": [ + " observableId simulationConditionId measurement time\n", + "0 prey_o cond1 0.173017 1.0\n", + "1 prey_o cond1 0.489177 2.0\n", + "2 prey_o cond1 1.643996 3.0\n", + "3 prey_o cond1 5.451963 4.0\n", + "4 prey_o cond1 2.977522 5.0\n", + "5 prey_o cond1 0.181663 6.0\n", + "6 prey_o cond1 0.348112 7.0\n", + "7 prey_o cond1 0.937919 8.0\n", + "8 prey_o cond1 3.113240 9.0\n", + "9 prey_o cond1 8.863933 10.0\n", + "10 predator_o cond1 0.847416 1.0\n", + "11 predator_o cond1 0.211135 2.0\n", + "12 predator_o cond1 -0.025054 3.0\n", + "13 predator_o cond1 0.125010 4.0\n", + "14 predator_o cond1 6.700455 5.0\n", + "15 predator_o cond1 2.007158 6.0\n", + "16 predator_o cond1 0.420092 7.0\n", + "17 predator_o cond1 0.048032 8.0\n", + "18 predator_o cond1 0.128669 9.0\n", + "19 predator_o cond1 1.192784 10.0" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "petab_problem.measurement_df" + ] + }, + { + "cell_type": "markdown", + "id": "261867c9-48a2-4310-ac0a-e52ae2012e85", + "metadata": {}, + "source": [ + "It is worth noting that the PEtab standard supports [mathematical expressions](https://petab.readthedocs.io/en/latest/v2/documentation_data_format.html#math-expressions-syntax) in the observables table. For instance, instead of `net1_output1`, we could write `sum(net1_output1) + 2` in its place and PEtab importers would duly perform that arithmetic. " + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/doc/examples/how_to_observable/hybridization.tsv b/doc/examples/how_to_observable/hybridization.tsv new file mode 100644 index 0000000..ccfd3d7 --- /dev/null +++ b/doc/examples/how_to_observable/hybridization.tsv @@ -0,0 +1,3 @@ +targetId targetValue +net1_input1 prey +net1_input2 predator diff --git a/doc/examples/how_to_observable/lv.xml b/doc/examples/how_to_observable/lv.xml new file mode 100644 index 0000000..3ec6640 --- /dev/null +++ b/doc/examples/how_to_observable/lv.xml @@ -0,0 +1,117 @@ + + + + + +
PEtab implementation of the simple model
+ +
+ + + + + + + + Ognissanti + Damiano + + + + + + 2022-08-19T11:46:48Z + + + 2022-08-19T11:46:48Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + alpha + prey + + + + + + + + + + + + + delta + predator + + + + + + + + + + + + + beta + prey + predator + + + + + + + + + + + + + gamma + predator + prey + + + + + +
+
\ No newline at end of file diff --git a/doc/examples/how_to_observable/mapping.tsv b/doc/examples/how_to_observable/mapping.tsv new file mode 100644 index 0000000..767a48a --- /dev/null +++ b/doc/examples/how_to_observable/mapping.tsv @@ -0,0 +1,5 @@ +petabEntityId modelEntityId +net1_input1 net1.inputs[0][0] +net1_input2 net1.inputs[0][1] +net1_output1 net1.outputs[0][0] +net1_ps net1.parameters diff --git a/doc/examples/how_to_observable/measurements.tsv b/doc/examples/how_to_observable/measurements.tsv new file mode 100644 index 0000000..3721571 --- /dev/null +++ b/doc/examples/how_to_observable/measurements.tsv @@ -0,0 +1,21 @@ +observableId simulationConditionId measurement time +prey_o cond1 0.17301723066954827 1.0 +prey_o cond1 0.48917673783383914 2.0 +prey_o cond1 1.643995531803569 3.0 +prey_o cond1 5.45196278566626 4.0 +prey_o cond1 2.9775220192442062 5.0 +prey_o cond1 0.18166337927167636 6.0 +prey_o cond1 0.3481122259853288 7.0 +prey_o cond1 0.9379191088947356 8.0 +prey_o cond1 3.113240033804055 9.0 +prey_o cond1 8.863933242141234 10.0 +predator_o cond1 0.8474159434934865 1.0 +predator_o cond1 0.2111345157163205 2.0 +predator_o cond1 -0.025053892755649274 3.0 +predator_o cond1 0.12501049397609923 4.0 +predator_o cond1 6.700454554758639 5.0 +predator_o cond1 2.007158288516007 6.0 +predator_o cond1 0.42009248269510124 7.0 +predator_o cond1 0.04803185161440934 8.0 +predator_o cond1 0.12866939374360575 9.0 +predator_o cond1 1.192783778293036 10.0 diff --git a/doc/examples/how_to_observable/net1.yaml b/doc/examples/how_to_observable/net1.yaml new file mode 100644 index 0000000..01b1003 --- /dev/null +++ b/doc/examples/how_to_observable/net1.yaml @@ -0,0 +1,64 @@ +nn_model_id: net1 +inputs: +- input_id: input0 +layers: +- layer_id: layer1 + layer_type: Linear + args: + in_features: 2 + out_features: 5 + bias: true +- layer_id: layer2 + layer_type: Linear + args: + in_features: 5 + out_features: 5 + bias: true +- layer_id: layer3 + layer_type: Linear + args: + in_features: 5 + out_features: 1 + bias: true +forward: +- name: net_input + op: placeholder + target: net_input + args: [] + kwargs: {} +- name: layer1 + op: call_module + target: layer1 + args: + - net_input + kwargs: {} +- name: tanh + op: call_method + target: tanh + args: + - layer1 + kwargs: {} +- name: layer2 + op: call_module + target: layer2 + args: + - tanh + kwargs: {} +- name: tanh_1 + op: call_method + target: tanh + args: + - layer2 + kwargs: {} +- name: layer3 + op: call_module + target: layer3 + args: + - tanh_1 + kwargs: {} +- name: output + op: output + target: output + args: + - layer3 + kwargs: {} diff --git a/doc/examples/how_to_observable/net1_ps.hdf5 b/doc/examples/how_to_observable/net1_ps.hdf5 new file mode 100644 index 0000000..d1318c0 Binary files /dev/null and b/doc/examples/how_to_observable/net1_ps.hdf5 differ diff --git a/doc/examples/how_to_observable/observables.tsv b/doc/examples/how_to_observable/observables.tsv new file mode 100644 index 0000000..3213df8 --- /dev/null +++ b/doc/examples/how_to_observable/observables.tsv @@ -0,0 +1,3 @@ +observableId observableFormula noiseFormula observableTransformation noiseDistribution +prey_o net1_output1 0.05 lin normal +predator_o predator 0.05 lin normal diff --git a/doc/examples/how_to_observable/parameters.tsv b/doc/examples/how_to_observable/parameters.tsv new file mode 100644 index 0000000..609676d --- /dev/null +++ b/doc/examples/how_to_observable/parameters.tsv @@ -0,0 +1,6 @@ +parameterId parameterScale lowerBound upperBound nominalValue estimate +alpha lin 0.0 15.0 1.3 1 +delta lin 0.0 15.0 1.8 1 +beta lin 0.0 15.0 0.9 1 +gamma lin 0.0 15.0 0.8 1 +net1_ps lin -inf inf 1 diff --git a/doc/examples/how_to_observable/problem.yaml b/doc/examples/how_to_observable/problem.yaml new file mode 100644 index 0000000..c24db02 --- /dev/null +++ b/doc/examples/how_to_observable/problem.yaml @@ -0,0 +1,26 @@ +problems: + - model_files: + lv: + location: "lv.xml" + language: "sbml" + measurement_files: + - "measurements.tsv" + observable_files: + - "observables.tsv" + condition_files: + - "conditions.tsv" + mapping_files: + - "mapping.tsv" +format_version: 2.0.0 +extensions: + sciml: + array_files: + - "net1_ps.hdf5" + hybridization_files: + - "hybridization.tsv" + neural_nets: + net1: + location: "net1.yaml" + static: false + format: "YAML" +parameter_file: "parameters.tsv" diff --git a/doc/index.rst b/doc/index.rst index 4ad82dd..6dbff0a 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -11,6 +11,14 @@ PEtab SciML - Scientific Machine Learning Format and Tooling Introduction Getting Started +.. toctree:: + :maxdepth: 3 + :caption: How To Guides + + Deep Mechanistic Models + Observable Formulae + Neural ODE + .. toctree:: :caption: PEtab SciML file format :maxdepth: 3