Julia 特定噪声下的随机微分方程灵敏度分析

Julia 特定噪声下的随机微分方程灵敏度分析,julia,stochastic,differentialequations.jl,Julia,Stochastic,Differentialequations.jl,我试图计算一个随机微分方程(SDE)解的泛函的梯度,给出噪声的具体实现。如果未指定噪波,则可以成功计算这些渐变,如中所示。我还可以成功地获得特定噪声实现的SDE解决方案,如中所示。但是,当我尝试将两者放在一起时,代码返回一个错误 以下是根据上述两个单独示例改编的一个最小工作示例: using StochasticDiffEq, DiffEqBase, DiffEqNoiseProcess, DiffEqSensitivity, Zygote function lotka_volterra(du

我试图计算一个随机微分方程(SDE)解的泛函的梯度,给出噪声的具体实现。如果未指定噪波,则可以成功计算这些渐变,如中所示。我还可以成功地获得特定噪声实现的SDE解决方案,如中所示。但是,当我尝试将两者放在一起时,代码返回一个错误

以下是根据上述两个单独示例改编的一个最小工作示例:

using StochasticDiffEq, DiffEqBase, DiffEqNoiseProcess, DiffEqSensitivity, Zygote

function lotka_volterra(du,u,p,t)
  x, y = u
  α, β, δ, γ = p
  du[1] = dx = α*x - β*x*y
  du[2] = dy = -δ*y + γ*x*y
end
function lotka_volterra_noise(du,u,p,t)
  du[1] = 0.1u[1]
  du[2] = 0.1u[2]
end
dt = 1//2^(4)
u0 = [1.0,1.0]
p = [2.2, 1.0, 2.0, 0.4]
prob1 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p)
sol1 = solve(prob1,EM(),dt=dt,save_noise=true)

W2 = NoiseWrapper(sol1.W)
prob2 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p,noise=W2)
sol2 = solve(prob2,EM(),dt=dt)

function predict_sde1(p)
  Array(concrete_solve(remake(prob1,p=p),EM(),dt=dt,sensealg=ForwardDiffSensitivity(),saveat=0.1))
end
loss_sde1(p) = sum(abs2,x-1 for x in predict_sde1(p))

loss_sde1(p)

# This gradient is successfully calculated
Zygote.gradient(loss_sde1,p)

function predict_sde2(p)
  W2 = NoiseWrapper(sol1.W)
  Array(concrete_solve(remake(prob2,p=p,noise=W2),EM(),dt=dt,sensealg=ForwardDiffSensitivity(),saveat=0.1))
end
loss_sde2(p) = sum(abs2,x-1 for x in predict_sde2(p))

# This loss is successfully calculated
loss_sde2(p)

# This gradient calculation raises and error
Zygote.gradient(loss_sde2,p)
我在运行此代码结束时遇到的错误是

TypeError: in setfield!, expected Float64, got ForwardDiff.Dual{Nothing,Float64,4}

Stacktrace:
 [1] setproperty! at ./Base.jl:21 [inlined]
...
然后是stacktrace的无休止的结论(如果你认为这会有帮助的话,我可以发布它,但是因为它比这个问题的其余部分要长,我不想把事情弄得一团糟)


当前是否不支持使用指定的噪声实现计算SDE问题的梯度,或者我只是没有进行适当的函数调用?我很容易相信后者,因为要达到上面代码的工作部分的工作点有点困难,但在使用Juno调试器逐步检查此代码之后,我找不到任何关于错误提供内容的线索。

作为堆栈溢出解决方案,您可以使用
ForwardDiffSensitivity(convert_tspan=false)
解决此问题。工作代码:

using StochasticDiffEq, DiffEqBase, DiffEqNoiseProcess, DiffEqSensitivity, Zygote

function lotka_volterra(du,u,p,t)
  x, y = u
  α, β, δ, γ = p
  du[1] = dx = α*x - β*x*y
  du[2] = dy = -δ*y + γ*x*y
end
function lotka_volterra_noise(du,u,p,t)
  du[1] = 0.1u[1]
  du[2] = 0.1u[2]
end
dt = 1//2^(4)
u0 = [1.0,1.0]
p = [2.2, 1.0, 2.0, 0.4]
prob1 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p)
sol1 = solve(prob1,EM(),dt=dt,save_noise=true)

W2 = NoiseWrapper(sol1.W)
prob2 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p,noise=W2)
sol2 = solve(prob2,EM(),dt=dt)

function predict_sde1(p)
  Array(concrete_solve(remake(prob1,p=p),EM(),dt=dt,sensealg=ForwardDiffSensitivity(convert_tspan=false),saveat=0.1))
end
loss_sde1(p) = sum(abs2,x-1 for x in predict_sde1(p))

loss_sde1(p)

# This gradient is successfully calculated
Zygote.gradient(loss_sde1,p)

function predict_sde2(p)
  Array(concrete_solve(prob2,EM(),prob2.u0,p,dt=dt,sensealg=ForwardDiffSensitivity(convert_tspan=false),saveat=0.1))
end
loss_sde2(p) = sum(abs2,x-1 for x in predict_sde2(p))

# This loss is successfully calculated
loss_sde2(p)

# This gradient calculation raises and error
Zygote.gradient(loss_sde2,p)
作为一个开发人员…这不是一个好的解决方案,我们的默认设置应该更好。我会处理这个问题。你可以在这里跟踪开发。它可能会在一个小时左右得到解决


编辑:修复程序已发布,您的原始代码正常工作。

作为堆栈溢出解决方案,您可以使用
ForwardDiffSensitivity(convert\u tspan=false)
解决此问题。工作代码:

using StochasticDiffEq, DiffEqBase, DiffEqNoiseProcess, DiffEqSensitivity, Zygote

function lotka_volterra(du,u,p,t)
  x, y = u
  α, β, δ, γ = p
  du[1] = dx = α*x - β*x*y
  du[2] = dy = -δ*y + γ*x*y
end
function lotka_volterra_noise(du,u,p,t)
  du[1] = 0.1u[1]
  du[2] = 0.1u[2]
end
dt = 1//2^(4)
u0 = [1.0,1.0]
p = [2.2, 1.0, 2.0, 0.4]
prob1 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p)
sol1 = solve(prob1,EM(),dt=dt,save_noise=true)

W2 = NoiseWrapper(sol1.W)
prob2 = SDEProblem(lotka_volterra,lotka_volterra_noise,u0,(0.0,10.0),p,noise=W2)
sol2 = solve(prob2,EM(),dt=dt)

function predict_sde1(p)
  Array(concrete_solve(remake(prob1,p=p),EM(),dt=dt,sensealg=ForwardDiffSensitivity(convert_tspan=false),saveat=0.1))
end
loss_sde1(p) = sum(abs2,x-1 for x in predict_sde1(p))

loss_sde1(p)

# This gradient is successfully calculated
Zygote.gradient(loss_sde1,p)

function predict_sde2(p)
  Array(concrete_solve(prob2,EM(),prob2.u0,p,dt=dt,sensealg=ForwardDiffSensitivity(convert_tspan=false),saveat=0.1))
end
loss_sde2(p) = sum(abs2,x-1 for x in predict_sde2(p))

# This loss is successfully calculated
loss_sde2(p)

# This gradient calculation raises and error
Zygote.gradient(loss_sde2,p)
作为一个开发人员…这不是一个好的解决方案,我们的默认设置应该更好。我会处理这个问题。你可以在这里跟踪开发。它可能会在一个小时左右得到解决


编辑:修复程序已发布,您的原始代码正常工作。

我注意到您将
predict_sde2
更改为不使用
remake
,并且不再包装噪波。我每次都重新包装噪波,因为我观察到一些副作用,重新使用相同的包装噪波会给出不同的解决方案。是否有一个简单的解决方案伊森:为什么我会遇到这个问题,为什么你的改变很重要,或者我应该再问一个问题吗?我不认为这很重要:它应该已经有W2了,在内部它调用了一个版本的重拍。但是重拍你自己也应该行得通。我注意到你改变了
predict\u sde2
,不再使用
remake
,并且不要再包装噪音。我每次都在重新包装噪音,因为我观察到一些副作用,重复使用相同的包装噪音会给出不同的解决方案。我遇到这个问题的原因很简单,为什么你的更改很重要,还是我应该再问一个问题?我不认为这很重要:它应该d已经有W2在里面了,在内部它正在调用一个版本的重拍。但是重拍你自己也应该可以。