-
-
Notifications
You must be signed in to change notification settings - Fork 157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid closure in LV system by passing parameters as kwargs #834
Comments
Using |
I am not getting it. Could you please illustrate it with the example above (tutorial example) |
Like: using ComponentArrays
# Define the hybrid model
function ude_dynamics!(du, u, p, t)
û = U(u, p.p, st)[1] # Network prediction
du[1] = p.p_true[1] * u[1] + û[1]
du[2] = -p.p_true[4] * u[2] + û[2]
end
# Closure with the known parameter
nn_dynamics!(du, u, p, t) = ude_dynamics!(du, u, ComponentArray(p=p, p_true=p_), t)
# Define the problem
prob_nn = ODEProblem(nn_dynamics!, Xₙ[:, 1], tspan, p) For update: remake(prob_nn, p = ComponentArray(p=θ, p_true=[1,2,3,4])) I didn't test it, though; so maybe I'm wrong. |
That code is giving me the following error:
|
Any suggestion on how to solve this? Edit: Apparently this solved the issue: (could you please confirm)
The rest is as in the tutorial. [the results with this approach have slight numerical differences to the original version(which I do not know why)] |
@prbzrg any idea why the numerical differences? and will create the ComponentArray everytime in the predictmethod kill the performance? |
Yeah creating a CA everytime does have some cost, because it needs to allocate an entirely new vector. A workaround I have been using in certain contexts is a "lazy" version of component array. Something like: using ChainRulesCore
import ChainRulesCore as CRC
const ∂∅ = NoTangent()
const ∂0 = ZeroTangent()
struct InputInjectionParameters{T, X, P <: ComponentArray} <: AbstractArray{T, 1}
x::X
p::P
end
function InputInjectionParameters(x, ps)
@assert eltype(ps) == eltype(x)
return InputInjectionParameters{eltype(x), typeof(x), typeof(ps)}(x, ps)
end
get_input(x::InputInjectionParameters) = x.x
get_parameters(x::InputInjectionParameters) = x.p
Base.size(x::InputInjectionParameters) = (length(x.x) + length(x.p),)
function Base.getindex(x::InputInjectionParameters, i::Int)
return i ≤ length(x.x) ? x.x[i] : x.p[i - length(x.x)]
end
Base.IndexStyle(::Type{<:InputInjectionParameters}) = IndexLinear()
function CRC.rrule(::typeof(get_input), x::InputInjectionParameters)
function get_input_pullback(Δ)
_has_no_gradient(Δ) && return (∂∅, ∂∅)
return ∂∅, InputInjectionParameters(Δ, zero(x.p))
end
return x.x, get_input_pullback
end
function CRC.rrule(::typeof(get_parameters), x::InputInjectionParameters)
function get_parameters_pullback(Δ)
_has_no_gradient(Δ) && return (∂∅, ∂∅)
return ∂∅, InputInjectionParameters(zero(x.x), Δ)
end
return x.p, get_parameters_pullback
end
function CRC.rrule(::Type{<:InputInjectionParameters}, x, p)
arr = InputInjectionParameters(x, p)
function InputInjectionParametersPullback(Δarr::AbstractVector)
∂x = reshape(Δarr[1:length(x)], size(x))
∂p = ComponentArray(Δarr[(length(x) + 1):end], getaxes(p))
return ∂∅, ∂x, ∂p
end
return arr, InputInjectionParametersPullback
end You can pass it in as function ude_dynamics!(du, u, p::InputInjectionParameters, t)
p_true = get_input(p)
ps = get_parameters(p)
û = U(u, ps, st)[1] # Network prediction
du[1] = p_true[1] * u[1] + û[1]
du[2] = -p_true[4] * u[2] + û[2]
end I haven't tested this, so might need some additional changes. But this overall gets rid of the cost of creating the componentarray. |
This is just a band-aid solution. In certain cases, we might just want to create a LazyComponentArray (which indexes into the original arrays but without actually creating a flattened structure) but that requires a bit more engineering. |
Hi @avik-pal, Thanks for the suggestions. I have also been tinkering with a solution of my own. It is: And update it in
And use it in:
This appears to work, although I do not know if it is good practice/ possible implications |
Does anyone know where the numerical differences come from? I remade this approach for a different case and I still get slight numerical differences. |
The latest version of the tutorial does fine with type stability |
Hi,
I would like to know if it is possible to avoid the closure relationship in the Lotka-Volterra system
In order to pass
p_
in theremake
function of thepredict
method:_prob = remake(prob_nn, u0 = X, tspan = (T[1], T[end]), p = θ)
Say, put
p_
as akwarg
ofude_dynamics!
and update it in theremake
function forprob_nn
?Is this possible? If so, how can it be achieved?
I have tried the following:
But this gives an error.
Which indicates that I can only change
kwargs
related to thesolve
. Is there a way to change thekwargs
from the function insideODEProblem
?The text was updated successfully, but these errors were encountered: