прогнозирование параметров ODE с помощью DiffEqFlux

Я пытаюсь построить нейронную сеть, которая будет принимать решения системы ODE и предсказывать параметры системы. Я использую Julia и, в частности, пакет DiffEqFlux. Структура сети несколько проста.Denseсвязанные вместе слои, которые предсказывают некоторые промежуточные параметры (в данном случае некоторые свободные энергии химических реакций), которые затем передаются в некоторые детерминированные (необученные) слои, которые преобразуют эти параметры в те, которые входят в систему уравнений (в данном случае, константы скорости реакции). Я пробовал два разных подхода отсюда:

  1. Цепочка решения ODE выполняется непосредственно на последнем уровне сети. В этом случае функция потерь просто сравнивает входы с выходами.

  2. Пусть 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) вместо.

Другие вопросы по тегам