прогнозирование параметров ODE с помощью DiffEqFlux
Я пытаюсь построить нейронную сеть, которая будет принимать решения системы ODE и предсказывать параметры системы. Я использую Julia и, в частности, пакет DiffEqFlux. Структура сети несколько проста.Dense
связанные вместе слои, которые предсказывают некоторые промежуточные параметры (в данном случае некоторые свободные энергии химических реакций), которые затем передаются в некоторые детерминированные (необученные) слои, которые преобразуют эти параметры в те, которые входят в систему уравнений (в данном случае, константы скорости реакции). Я пробовал два разных подхода отсюда:
Цепочка решения ODE выполняется непосредственно на последнем уровне сети. В этом случае функция потерь просто сравнивает входы с выходами.
Пусть ODE решит функцию потерь, чтобы выходной сигнал сети был всего лишь параметрами.
Однако ни в том, ни в другом случае я не могу получить Flux.train!
на самом деле бежать.
Глупый маленький пример для первого варианта, который дает ту же ошибку, что и я (я пытался сохранить как можно больше вещей параллельно моему фактическому случаю, то есть решателю и т. Д., Хотя я пропустил промежуточные детерминированные слои поскольку они, кажется, не имеют значения) показан ниже.
using Flux, DiffEqFlux, DifferentialEquations
# let's use Chris' favorite example, Lotka-Volterra
function lotka_volterra(du,u,p,t)
x, y = u
α, β, δ, γ = p
du[1] = dx = α*x - β*x*y
du[2] = dy = -δ*y + γ*x*y
end
u0 = [1.0,1.0]
tspan = (0.0,10.0)
# generate a couple sets of solutions to train on
training_params = [[1.5,1.0,3.0,1.0], [1.4,1.1,3.1,0.9]]
training_sols = [solve(ODEProblem(lotka_volterra, u0, tspan, tp)).u[end] for tp in training_params]
model = Chain(Dense(2,3), Dense(3,4), p -> diffeq_adjoint(p, ODEProblem(lotka_volterra, u0, tspan, p), Rodas4())[:,end])
# in this case we just want outputs to match inputs
# (actual parameters we're after are outputs of next-to-last layer)
training_data = zip(training_sols, training_sols)
# mean squared error loss
loss(x,y) = Flux.mse(model(x), y)
p = Flux.params(model[1:2])
Flux.train!(loss, p, training_data, ADAM(0.001))
# gives TypeError: in typeassert, expected Float64, got ForwardDiff.Dual{Nothing, Float64, 8}
Я пробовал все три уровня решателя, diffeq_adjoint
, diffeq_rd
, а также diffeq_fd
, ни одна из которых не работает, но все они дают разные ошибки, которые у меня возникают при анализе.
Для другого варианта (который я бы предпочел, но в любом случае будет работать) просто замените определения модели и функции потерь следующим образом:
model = Chain(Dense(2,3), Dense(3,4))
function loss(x,y)
p = model(x)
sol = diffeq_adjoint(p, ODEProblem(lotka_volterra, u0, tspan, p), Rodas4())[:,end]
Flux.mse(sol, y)
end
Выдается та же ошибка, что и выше.
Я занимаюсь этим уже больше недели и полностью озадачен; Любые идеи?
1 ответ
Вы столкнулись с https://github.com/JuliaDiffEq/DiffEqFlux.jl/issues/31, т.е. AD прямого режима для якобиана сейчас не очень хорошо работает с Flux.jl. Чтобы обойти это, используйтеRodas4(autodiff=false)
вместо.