прогнозирование параметров ODE с помощью DiffEqFlux - PullRequest
2 голосов
/ 16 октября 2019

Я пытаюсь построить нейронную сеть, которая будет принимать решения для системы ODE и прогнозировать параметры системы. Я использую Джулию и, в частности, пакет 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 Ответ

1 голос
/ 17 октября 2019

Вы сталкиваетесь с https://github.com/JuliaDiffEq/DiffEqFlux.jl/issues/31,, т. Е. AD в прямом режиме для якобиана сейчас плохо играет с Flux.jl. Чтобы обойти это, используйте Rodas4(autodiff=false) вместо.

...