Using UODE in Lotka-Volterra for multiple species

Hello everyone,

I am brand new to Julia, machine learning and sciML so forgive me if I still don’t have the technical jargon.

I have read through Automatically Discover Missing Physics by Embedding Machine Learning into Differential Equations · Overview of Julia's SciML and would like to ask a question regarding UODE’s which I would like to apply to the Lotka-Volterra [predator-prey] system.

In the tutorial, the data is generated for an initial condition u0 = 5.0f0 * rand(rng, 2) and a set of parameters \alpha, \beta, \gamma, \delta = [1.3, 0.9, 0.8, 1.8].

Latter we assume only partial knowledge of the physics and try to capture what the physics is missing with a neural network.

\left\{\begin{matrix} \frac{\mathrm{d} x}{\mathrm{d} t}=\alpha x + NN_1 \\ \frac{\mathrm{d} y}{\mathrm{d} t}=\delta y + NN_2 \end{matrix}\right.

Now, my question.

Let us assume that I have data on several types of [predator-prey] populations.

[wolf-rabit], [cat-mouse], [human-mamuth]
A similar approach to generate the data can be used as in the example.

function lotka!(du, u, p, t)

α, β, γ, δ = p

du[1] = α * u[1] - β * u[2] * u[1]

du[2] = γ * u[1] * u[2] - δ * u[2]

end

# Define the experimental parameter

t_true= LinRange(0.0,5.0,300)

tspan = (0.0, 5.0)

u0_wolf_rabit = 5.0f0 * rand(rng, 2)

p_wolf_rabit = [1.3, 0.9, 0.8, 1.8]

prob_wolf_rabit = ODEProblem(lotka!, u0_wolf_rabit, tspan, p_wolf_rabit)

solution_wolf_rabit = solve(prob_wolf_rabit, Vern7(), abstol = 1e-12, reltol = 1e-12, saveat = t_true)

u0_cat_mouse = 4.0f0 * rand(rng, 2)

p_cat_mouse = [1.5, 1.1, 1.0, 2.0]

prob_cat_mouse = ODEProblem(lotka!, u0_cat_mouse, tspan, p_cat_mouse)

solution_cat_mouse = solve(prob_cat_mouse, Vern7(), abstol = 1e-12, reltol = 1e-12, saveat = t_true)

u0_human_mamuth = 3.0f0 * rand(rng, 2)

p_human_mamuth = [1.1, 0.7, 0.6, 1.6]

prob_human_mamuth = ODEProblem(lotka!, u0_human_mamuth, tspan, p_human_mamuth)

solution_human_mamuth = solve(prob_human_mamuth, Vern7(), abstol = 1e-12, reltol = 1e-12, saveat = t_true)

plt= plot(solution_wolf_rabit, alpha = 0.75, color = :black, label = ["wolf-rabit" nothing])

plot!(plt,solution_cat_mouse, alpha = 0.75, color = :red, label = ["cat-mouse" nothing] )

plot!(plt,solution_human_mamuth, alpha = 0.75, color = :blue, label = ["human-mamuth" nothing] )

I want to do the same thing as in the post. Given the same limited physical knowledge how can I use these data to train a network? Basically, how can I train the NN with sets of populations?

Best Regards,
James

Just define the loss function. What did you try?

Hello Dr. Rackauckas,

Thank you for participating in this discussion.

Unfortunately, I did not change anything from the tutorial case (apart from generating new data) as I do not understand what to change :frowning: .

I have the data but how do I feed it to the system? Should I put everything together in a single array and build something similar to the get_batch() method in [https://github.com/rtqichen/torchdiffeq/blob/master/examples/ode_demo.py] and train in random population batches? (Is there any example where batches are used in UODE?)

What should the cost function take into account? Won’t the MSE be sufficient?

Thank you for your time and availability!

I would also appreciate literature recommendations where something similar is used!

The way to do it depends on what you want the end result to be.

Do you expect a single model for all different species combinations? If yes, concatenating the individual data and taking MSE over all the trajectories would be the way to go. Intuitively I would expect the NN size to be larger here. If you think the dynamics for the different species should be identical conditional on the initial values and trained parameters, that’s all you’d need to do. If you want it to distinguish between the species I am expecting that the NN will be able to learn the species-specific dynamics and you can additionally change the parameterization of the physical model part to match what you have in the simulation script above. It would also need some way to tell it which species combination it is currently so you might want to add an auxiliary parameter for encoding that.

If you want to have different models for each species then you can do it separately and have the MSE for each dataset and train the UDEs with even smaller NNs.

For the first case, if you see the training take too long per iteration, though I would expect it not too, you can use the batching functionality described in Data Iterators and Minibatching · Optimization.jl.

hmm, I will re-frame the problem a bit (if the moderator thinks it is necessary I will also change the question/post a new question).

Assume that the UODE is approximating

\left\{\begin{matrix} \frac{\mathrm{d} x}{\mathrm{d} t} = \alpha x + \beta NN_1 \\ \frac{\mathrm{d} y}{\mathrm{d} t} = \delta y + \gamma NN_2 \end{matrix}\right.

I have information on x(0), y(0), \alpha, \beta, \gamma, \delta for each species together with data from x(t), y(t) for t \in [0, 5]. I want the network to approximate xy on the dynamics. However, I do not know that the term that is missing in the dynamics is xy. But I have data!

In fact, lots of data. Since this is a toy problem, I can randomly generate as much data as necessary.

Now how can I use all the data I have on [wolf-rabit], [cat-mouse], [human-mamuth] to train the network?

Do I concatenate everything in one matrix and collect batches to train the network? Do I need to create an “interpolator” or sorts to do this?

Best Regards

How can I use batches with UODES? Is there any example of this? In [ Data Iterators and Minibatching · Optimization.jl](Data Iterators and Minibatching · Optimization.jl) the FLUX library is used. Is it the same thing with Lux? I think that creating batches (each one with the data from a pair of predator prey species) would solve my problems. But so far I have not been able to make it work.