【问题标题】:Stochastic differential equation sensitivity analysis with specified noise具有指定噪声的随机微分方程灵敏度分析
【发布时间】:2020-03-06 23:43:16
【问题描述】:

在给定噪声的特定实现的情况下,我正在尝试计算随机微分方程 (SDE) 解的泛函梯度。如果不指定噪声,我可以成功计算这些梯度,如DiffEqFlux.jl: Using Other Differential Equations 所示。我还可以成功获得针对特定噪声实现的 SDE 的解决方案,如DifferentialEquations.jl: NoiseWrapper Example 所示。但是,当我尝试将两者放在一起时,代码会返回错误。

这是一个根据上面引用的两个单独示例改编的最小工作示例:

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]
...

然后是对堆栈跟踪的无休止的结论(如果您认为它会有所帮助,我可以发布它,但由于它比这个问题的其余部分更长,我宁愿不把事情搞得一团糟)。

当前不支持为具有指定噪声实现的 SDE 问题计算梯度,还是我只是没有进行适当的函数调用?我很容易相信后者,因为要达到上述代码的工作部分工作的地步有点困难,但是在逐步完成后我找不到任何线索来说明我错误地提供了什么使用 Juno 调试器编写代码。

【问题讨论】:

    标签: julia stochastic differentialequations.jl


    【解决方案1】:

    作为 StackOverflow 解决方案,您可以使用 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)
    

    作为开发人员...这不是一个好的解决方案,我们的默认设置应该更好。我会努力的。您可以在这里https://github.com/JuliaDiffEq/DiffEqSensitivity.jl/issues/204 跟踪开发。大概一个小时左右就能解决。

    编辑:修复已发布,您的原始代码有效。

    【讨论】:

    • 我注意到您将predict_sde2 更改为不使用remake,并且不再包含噪音。我每次都重新包装噪音,因为我观察到一些副作用,即重新使用相同的包装噪音会给出不同的解决方案。我遇到这个问题的原因很简单,为什么你的更改很重要,还是我应该打开另一个问题?
    • 我认为这并不重要:它应该已经有 W2,并且在内部它正在调用一个 remake 版本。但改造自己也应该奏效。
    猜你喜欢
    • 1970-01-01
    • 2011-06-20
    • 1970-01-01
    • 2020-09-21
    • 1970-01-01
    • 2016-05-18
    • 1970-01-01
    • 2017-10-12
    • 2015-08-21
    相关资源
    最近更新 更多