An easy-to-use tool for implementing Neural Ordinary Differential Equations (NODEs) in pharmacometric software such as 'Monolix', 'NONMEM', and 'nlmixr2', see Bräm et al. (2024)

The goal of pmxNODE is to facilitate the implementation of neural ordinary differential equations (NODEs) in pharmacometric software, i.e., Monolix, NONMEM, and nlmixr2.
You can install the development version of pmxNODE like so:
devtools::install_github("braemd/pmxNODE")
The general workflow of pmxNODE consists of few steps:
Write a structural model, as you would do normaly for Monolix, NONMEM, or nlmixr2. However, you can utilize NN functions in your model code, e.g., for complex or unknown model parts.
Convert the written model file with the nn_converter_XXX function
from the pmxNODE package, e.g. nn_converter_mlx for Monolix. This
function can also directly generate a .mlxtran file with
automatically initialized model parameters.
We suggest to fit the model to the data first without inter-individual
variability on neural networks parameters (argument pop_only = True
in the nn_converter_mlx function) and add the random effects in a
second run, where parameters were initialized with last estimates.
The NN functions in your structural model do need to be of following form:
They must be named in order to uniquely identify them in the model (e.g., if the same NN is used to outflow of an absorption compartment and as inflow into the central compartment) and to generate uniquly identifiable parameters.
The following arguments are mandatory:
state: Defines the state that goes into the NNmin_init: The minimal expected input into the NNmax_init: The maximal expected input into the NN The minimal and
maximal expected inputs are needed to properly initialize the
weights of the NN. They don’t need to be exact but should roughly
give the range of expected inputs.The following arguments are optional:
n_hidden: Number of units in the hidden layer. Default is 5.act: Activation function to be used in the hidden layer.
Currently, only “ReLU” and “Softplus” are available. Default is
“ReLU”.time_nn: Whether the NN should be a “Time-dependent NN” according
to https://doi.org/10.1007/s10928-023-09886-4, i.e., whether the
weights from input to hidden layer should be negative. Default is
FALSE.We first need to load the pmxNODE package and to initialize the
lixoftConnectors package (can be done with the software_initializer
function from pmxNODE).
If the lixoftConnectors package is not yet installed, an installation path to the package .tar.gz file from Monolix must be provided.
library(pmxNODE)
library(ggplot2)
software_initializer(software = "Monolix",
mlx_path = "C:/ProgramData/Lixoft/MonolixSuite2021R2")
Some examples are available in the pmxNODE package. To see all example
files, you can use the get_example_list function. To copy an example
to a folder of your choice, you can use the copy_example function.
After calling the copy_examples function, two files should be in the
target folder, a data file and a Monolix model file.
get_example_list()
copy_examples(
target_folder = "~/pmxNODE",
example_nr = 1,
example_software = "Monolix"
)
Before fitting the model, it needs to be converted with the
nn_converter_mlx function. In addition to the path/file name of the
unconverted Monolix model and the argument on including inter-individual
variability for the neural network parameters, a Monolix .mlxtran file
can be automatically generated with the gen_mlx_file = TRUE argument.
In order to do so, a data file and the header types must be provided. If
no file name for the new Monolix file is given through the mlx_name
argument, the Monolix file name is automatically generated based on the
Monolix model file. Note that a suffix is added to the file name, either
_pop if pop_only = TRUE or _ind if pop_only = FALSE.
The model can be automatically run from R with the function run_mlx
from the pmxNODE package.
nn_converter_mlx(mlx_path = "~/pmxNODE/mlx_example1_model.txt",
pop_only = TRUE,
gen_mlx_file = TRUE,
mlx_name = "~/pmxNODE/mlx_example1",
data_file = "~/pmxNODE/data_example1_mlx.csv",
header_types = c("id","time","amount","observation"))
run_mlx("~/pmxNODE/mlx_example1_pop.mlxtran")
In order to get the parameter estimations from the population fit
(without inter-individual variability), the pre_fixef_extractor_mlx
function can be utilized.
These parameter estimates can be given as additional argument
pre_fixef to the nn_converter_mlx function. To include
inter-individual variability, the population argument is set to false
(pop_only = FALSE) in the nn_converter_mlx function.
The final model with inter-individual variability can then be fitted
again with the run_mlx function.
est_parms <- pre_fixef_extractor_mlx("~/pmxNODE/mlx_example1_pop.mlxtran")
nn_converter_mlx(mlx_path = "~/pmxNODE/mlx_example1_model.txt",
pop_only = FALSE,
pre_fixef = est_parms,
gen_mlx_file = TRUE,
mlx_name = "~/pmxNODE/mlx_example1",
data_file = "~/pmxNODE/data_example1_mlx.csv",
header_types = c("id","time","amount","observation"))
run_mlx("~/pmxNODE/mlx_example1_ind.mlxtran")