2

我正在尝试构建一个神经网络,它将接受 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_adjointdiffeq_rddiffeq_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

抛出与上面相同的错误。

我已经破解了一个多星期了,完全被难住了;有任何想法吗?

4

1 回答 1

1

您遇到了https://github.com/JuliaDiffEq/DiffEqFlux.jl/issues/31,即雅可比行列式的前向模式 AD 现在与 Flux.jl 不兼容。要解决此问题,请Rodas4(autodiff=false)改用。

于 2019-10-16T23:56:35.733 回答