Skip to content

Which types work as container of parameters? #178

@lindnemi

Description

@lindnemi

Our package provides an API that handles parameters differently depending on them being either tuples or arrays. If only arrays are passed everything works fine, but the tuple syntax seems to be incompatible with DiffEqFlux right now. Why is that?

MWE:

using Flux, Optim, DiffEqFlux, OrdinaryDiffEq

function node!(dx, x, p, t)
    dx .= [1.]
    dx .+= prod(p) # .* x
end

function edge!(dx, x, p, t)
    dx .-= sum(p)# .* x
end

function network!(dx, x, p, t)
    node!(dx, x, p, t)
    edge!(dx, x, p, t)
end

function network!(dx, x, p::T, t) where T <: Tuple
    @assert length(p) == 2
    node!(dx, x, p[1], t)
    edge!(dx, x, p[2], t)
end

x0 = [2.]
tspan = (0.,2.)

p = [3.,3.]
prob = ODEProblem(network!, x0, tspan, p)
sol  = solve(prob, Tsit5())

plot(sol)


p2 = ([3., 3.], [3., 3.])
prob2 = ODEProblem(network!, x0, tspan, p2)
sol2  = solve(prob2, Tsit5())

plot!(sol2)

### DiffEqFlux Stuff starts here ###

function predict_adjoint(p) # Our 1-layer neural network
  Array(concrete_solve(prob,Tsit5(),x0, p,saveat=0:0.1:2, adaptive=false, dt=.1))
end

function loss_adjoint(p)
  prediction = predict_adjoint(p)
  loss = sum(abs2, prediction .- 1.)
  loss, prediction
end

cb = function (p, l, pred) # callback function to observe training
  display(l)
  # using `remake` to re-create our `prob` with current parameters `p`
  display(plot(solve(remake(prob,p=p), Tsit5(),adaptive=false, dt=.1)))
  return false
end

# Display the ODE with the initial parameter values.
cb(p,loss_adjoint(p)...)

res = DiffEqFlux.sciml_train(loss_adjoint, p, BFGS(), cb = cb)

### Problems start here 

### Tuples of Parameters are not possible as input to sciml_train
res = DiffEqFlux.sciml_train(loss_adjoint, p2, BFGS(), cb = cb)


# MethodError: no method matching optimize(::NLSolversBase.InplaceObjective{Nothing,DiffEqFlux.var"#30#38"{DiffEqFlux.var"#29#37"{typeof(loss_adjoint)}},Nothing,Nothing,Nothing}, ::Tuple{Array{Float64,1},Array{Float64,1}}, ::BFGS{LineSearches.InitialStatic{Float64},LineSearches.HagerZhang{Float64,Base.RefValue{Bool}},Nothing,Nothing,Flat}, ::Optim.Options{Float64,DiffEqFlux.var"#_cb#36"{var"#77#78",Base.Iterators.Cycle{Tuple{DiffEqFlux.NullData}}}})
### not even if parameters are converted to tuple at a later stage

function predict_adjoint(p) # Our 1-layer neural network
  Array(concrete_solve(prob,Tsit5(),x0, ([3.,3.], p),saveat=0:0.1:2, adaptive=false, dt=.1))
end

function loss_adjoint(p)
  prediction = predict_adjoint(p)
  loss = sum(abs2, prediction .- 1.)
  loss, prediction
end

cb = function (p, l, pred) # callback function to observe training
  display(l)
  # using `remake` to re-create our `prob` with current parameters `p`
  display(plot(solve(remake(prob,p=([3.,3.], p)), Tsit5(),adaptive=false, dt=.1)))
  return false
end

res = DiffEqFlux.sciml_train(loss_adjoint, p, BFGS(), cb = cb)

# MethodError: no method matching param(::Tuple{Array{Float64,1},Array{Float64,1}})

It would be nice if one of the two constructions worked.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions