Error while training NeuralODE with exogenous inputs
mariaade26 opened this issue · 6 comments
Hello everyone,
I'm currently in the process of training a NeuralODE model using data obtained from an ordinary differential equation (ODE) that describes the underlying physical phenomenon. In my code, I'm incorporating external disturbance data, Text and phih.
I've encountered an issue while working with two distinct types of disturbances represented by the variable phi. One of these disturbances seems to be causing problems, while the other one works as expected. In one version of my code, I'm able to successfully train the neural network, but in the other, I encounter issues such as DimensionMismatch errors and instability warnings during the simulation.
I'm seeking assistance in understanding the root cause of this problem. Can anyone provide insights or suggestions?
WORKING CODE
using DifferentialEquations, Lux, ComponentArrays, DiffEqFlux, Optimization, OptimizationOptimJL, Plots, Random, OptimizationOptimisers, DataInterpolations, CSV
text = open(f->read(f, String), "File csv/eplusout.csv") |> s -> split(s, "\n")[1:end-1]
data=parse.(Float32, text) #valori di temperatura esterna ogni minuto per una settimana circa
Testerna= data[1:1800];
phi1=0*ones(300)
phi2=5*ones(300)
phi3=10*ones(300)
phi4=30*ones(300)
phi5=20*ones(300)
phi6=0*ones(300)
phih=vcat(Float32.(phi1),Float32.(phi2),Float32.(phi3),Float32.(phi4),Float32.(phi5),Float32.(phi6));
tspan= (0.0f0, 1800.0f00)
t= range(tspan[1], tspan[2], length=1800)
disturbance = LinearInterpolation(Testerna,t);
disturbance2 = LinearInterpolation(phih,t);
function Text(t)
return disturbance(t)
end
function phi(t)
return disturbance2(t)
end
function f(du, u, p, t)
Rv = p[1]
Ci = p[2]
du[1] = 1/(Rv*Ci) .* (Text(t) .- u[1]) .+ phi(t)/Ci
end
u0= [5.0]
p= [0.05, 100.0]
prob = ODEProblem(f, u0, tspan, p)
sol = solve(prob, Tsit5(), saveat=t)
tplot=t
plot(sol, xlabel="Tempo", ylabel="Temperatura [°C]", legend=false)
rng=Random.default_rng()
nn_model = Lux.Chain(Lux.Dense(3, 8, tanh), Lux.Dense(8, 1))
p_model, st = Lux.setup(rng, nn_model)
function dudt(u, p, t)
global st
out, st = nn_model(vcat(u[1], Text(t),phi(t)), p, st)
return out
end
prob = ODEProblem(dudt, u0, tspan, nothing)
function predict_neuralode(p)
_prob = remake(prob, p = p)
Array(solve(_prob, Tsit5(), saveat = t, abstol = 1e-8, reltol = 1e-6))
end
function loss(p)
pred = predict_neuralode(p)
N = length(pred)
return sum(abs2.(sol[1,:] .- pred'))
end
callback = function(p,l)
println(l)
return false
end
adtype = Optimization.AutoZygote()
pinit= ComponentArray(p_model)
optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
optprob = Optimization.OptimizationProblem(optf, pinit)
@time begin
res0 = Optimization.solve(optprob, Optimisers.Adam(0.05), callback=callback, maxiters = 300)
end
pred= predict_neuralode(res0.u)
pred=pred'
plot(t,pred, label= "prediction")
plot!(t, sol[1,:], label= "data", xlabel="Tempo", ylabel="Temperatura [°C]")
optprob2 = remake(optprob,u0 = res0.u)
@time begin
result_neuralode2 = Optimization.solve(optprob2,
Optim.BFGS(initial_stepnorm=0.01),
callback=callback,
allow_f_increases = false)
end
pred2= predict_neuralode(result_neuralode2.u)
pred2=pred2'
plot(t,pred2, label= "prediction")
plot!(t, sol[1,:], label= "data", xlabel="Tempo", ylabel="Temperatura [°C]")
In the non-working version, I only replaced these lines
"phi1=0ones(300)
phi2=5ones(300)
phi3=10ones(300)
phi4=30ones(300)
phi5=20ones(300)
phi6=0ones(300)
phih=vcat(Float32.(phi1),Float32.(phi2),Float32.(phi3),Float32.(phi4),Float32.(phi5),Float32.(phi6));"
with the following
text = open(f->read(f, String), "File csv/phi heating .csv") |> s -> split(s, "\n")[1:end-1]
phih=parse.(Float32, text);
In particular, as soon as I run the simulation with this modification I get this errore "┌ Warning: dt(0.00012207031) <= dtmin(0.00012207031) at t=179.09944, and step error estimate = 1.4775506934013858. Aborting. There is either an error in your model specification or the true solution is unstable.
└ @ SciMLBase C:\Users\Michele.julia\packages\SciMLBase\kTUaf\src\integrator_interface.jl:599
DimensionMismatch: arrays could not be broadcast to a common size; got a dimension with lengths 1800 and 179".
NON WORKING CODE
using DifferentialEquations, Lux, ComponentArrays, DiffEqFlux, Optimization, OptimizationOptimJL, Plots, Random, OptimizationOptimisers, DataInterpolations, CSV
text = open(f->read(f, String), "File csv/eplusout.csv") |> s -> split(s, "\n")[1:end-1]
data=parse.(Float32, text) #valori di temperatura esterna ogni minuto per una settimana circa
Testerna= data[1:1800];
text = openphih=parse.(Float32, text);(f->read(f, String), "File csv/phi heating .csv") |> s -> split(s, "\n")[1:end-1]
phih=parse.(Float32, text);
tspan= (0.0f0, 1800.0f00)
t= range(tspan[1], tspan[2], length=1800)
disturbance = LinearInterpolation(Testerna,t);
disturbance2 = LinearInterpolation(phih,t);
function Text(t)
return disturbance(t)
end
function phi(t)
return disturbance2(t)
end
function f(du, u, p, t)
Rv = p[1]
Ci = p[2]
du[1] = 1/(Rv*Ci) .* (Text(t) .- u[1]) .+ phi(t)/Ci
end
u0= [5.0]
p= [0.05, 100.0]
prob = ODEProblem(f, u0, tspan, p)
sol = solve(prob, Tsit5(), saveat=t)
tplot=t
plot(sol, xlabel="Tempo", ylabel="Temperatura [°C]", legend=false)
rng=Random.default_rng()
nn_model = Lux.Chain(Lux.Dense(3, 8, tanh), Lux.Dense(8, 1))
p_model, st = Lux.setup(rng, nn_model)
function dudt(u, p, t)
global st
out, st = nn_model(vcat(u[1], Text(t),phi(t)), p, st)
return out
end
prob = ODEProblem(dudt, u0, tspan, nothing)
function predict_neuralode(p)
_prob = remake(prob, p = p)
Array(solve(_prob, Tsit5(), saveat = t, abstol = 1e-8, reltol = 1e-6))
end
function loss(p)
pred = predict_neuralode(p)
N = length(pred)
return sum(abs2.(sol[1,:] .- pred'))
end
callback = function(p,l)
println(l)
return false
end
adtype = Optimization.AutoZygote()
pinit= ComponentArray(p_model)
optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
optprob = Optimization.OptimizationProblem(optf, pinit)
@time begin
res0 = Optimization.solve(optprob, Optimisers.Adam(0.05), callback=callback, maxiters = 300)
end
pred= predict_neuralode(res0.u)
pred=pred'
plot(t,pred, label= "prediction")
plot!(t, sol[1,:], label= "data", xlabel="Tempo", ylabel="Temperatura [°C]")
optprob2 = remake(optprob,u0 = res0.u)
@time begin
result_neuralode2 = Optimization.solve(optprob2,
Optim.BFGS(initial_stepnorm=0.01),
callback=callback,
allow_f_increases = false)
end
pred2= predict_neuralode(result_neuralode2.u)
pred2=pred2'
plot(t,pred2, label= "prediction")
plot!(t, sol[1,:], label= "data", xlabel="Tempo", ylabel="Temperatura [°C]")
In particular, as soon as I run the simulation with this modification I get this errore "┌ Warning: dt(0.00012207031) <= dtmin(0.00012207031) at t=179.09944, and step error estimate = 1.4775506934013858. Aborting. There is either an error in your model specification or the true solution is unstable.
It might help to remove Tsit5()
from those two solve
calls.
DimensionMismatch: arrays could not be broadcast to a common size; got a dimension with lengths 1800 and 179".
It might help to read data like:
using CSV, DataFrames, MLJModelInterface
fn = raw"csv/phi heating.csv"
phih_df = CSV.read(fn, DataFrame) # 👈 read as DataFrame
# any manipulation of data 👇
#######################
phih = collect(transpose(MLJModelInterface.matrix(phih_df))) # 👈 convert it to an array (each column is a data point)
Thank you a lot for your help, but that didn't solve my problem!
I read the csv as you said and instead of Tsit5() I used AutoTsit5(Rosenbrock23())
In particular, as soon as I run the simulation with this modification I get this errore "┌ Warning: dt(0.00012207031) <= dtmin(0.00012207031) at t=179.09944, and step error estimate = 1.4775506934013858. Aborting. There is either an error in your model specification or the true solution is unstable.
It might help to remove
Tsit5()
from those twosolve
calls.DimensionMismatch: arrays could not be broadcast to a common size; got a dimension with lengths 1800 and 179".
It might help to read data like:
using CSV, DataFrames, MLJModelInterface fn = raw"csv/phi heating.csv" phih_df = CSV.read(fn, DataFrame) # 👈 read as DataFrame # any manipulation of data 👇 ####################### phih = collect(transpose(MLJModelInterface.matrix(phih_df))) # 👈 convert it to an array (each column is a data point)
@prbzrg if you want to try to run it, ifever you had time, here is the csv files.
phi heating .csv
Temperatura esterna.csv
Changing the algorithm in solve
and reltol
and abstol
values fixed the problem for me.
Try this:
using DifferentialEquations,
Lux,
ComponentArrays,
DiffEqFlux,
Optimization,
OptimizationOptimJL,
Plots,
Random,
OptimizationOptimisers,
DataInterpolations,
CSV,
DataFrames
data_fn = raw"csv/Temperatura.esterna.csv"
data_df = CSV.read(data_fn, DataFrame; header = false);
Testerna = convert.(Float32, data_df[1:1800, 1]);
phih_fn = raw"csv/phi.heating.csv"
phih_df = CSV.read(phih_fn, DataFrame; header = false);
phih = convert.(Float32, phih_df[!, 1]);
tspan = (0.0f0, 1800.0f0)
t = range(tspan[1], tspan[2]; length = 1800)
disturbance = LinearInterpolation(Testerna, t);
disturbance2 = LinearInterpolation(phih, t);
function Text(t)
return disturbance(t)
end
function phi(t)
return disturbance2(t)
end
function f(du, u, p, t)
Rv = p[1]
Ci = p[2]
du[1] = 1.0f0 / (Rv * Ci) .* (Text(t) .- u[1]) .+ phi(t) / Ci
end
u0 = [5.0f0]
p = [0.05f0, 100.0f0]
prob = ODEProblem(f, u0, tspan, p)
sol = solve(
prob,
VCABM();
saveat = t,
reltol = sqrt(eps(one(Float32))),
abstol = eps(one(Float32)),
) # 👈 changed
tplot = t
plot(sol; xlabel = "Tempo", ylabel = "Temperatura [°C]", legend = false)
rng = Random.default_rng()
nn_model = Lux.Chain(Lux.Dense(3, 8, tanh), Lux.Dense(8, 1))
p_model, st = Lux.setup(rng, nn_model)
function dudt(u, p, t)
global st
out, st = nn_model(vcat(u[1], Text(t), phi(t)), p, st)
return out
end
prob = ODEProblem(dudt, u0, tspan, nothing)
function predict_neuralode(p)
_prob = remake(prob; p = p)
Array(
solve(
_prob,
VCABM();
saveat = t,
reltol = sqrt(eps(one(Float32))),
abstol = eps(one(Float32)),
),
) # 👈 changed
end
function loss(p)
pred = predict_neuralode(p)
N = length(pred)
return sum(abs2.(sol[1, :] .- pred'))
end
callback = function (p, l)
println(l)
return false
end
adtype = Optimization.AutoZygote()
pinit = ComponentArray(p_model)
optf = Optimization.OptimizationFunction((x, p) -> loss(x), adtype)
optprob = Optimization.OptimizationProblem(optf, pinit)
@time begin
res0 = Optimization.solve(
optprob,
Optimisers.Adam(0.05f0);
callback = callback,
maxiters = 300,
)
end
pred = predict_neuralode(res0.u)
pred = pred'
plot(t, pred; label = "prediction")
plot!(t, sol[1, :]; label = "data", xlabel = "Tempo", ylabel = "Temperatura [°C]")
optprob2 = remake(optprob; u0 = res0.u)
@time begin
result_neuralode2 = Optimization.solve(
optprob2,
Optim.BFGS(; initial_stepnorm = 0.01f0);
callback = callback,
allow_f_increases = false,
)
end
pred2 = predict_neuralode(result_neuralode2.u)
pred2 = pred2'
plot(t, pred2; label = "prediction")
plot!(t, sol[1, :]; label = "data", xlabel = "Tempo", ylabel = "Temperatura [°C]")
Thank you very very much!
I've just tried this and it seems to work!
I'm immensely grateful