DiffEqFlux.jl实现模型预测控制

DiffEqFlux.jl简介

DiffEqFlux.jl 是 SciML 生态系统的参数估计系统。它是一个高级接口,将所有工具与结合在一起。神经网络可以是模型的全部或一部分。它们可以在微分方程周围、成本函数中或微分方程内部。

控制问题

控制方程:
x ′ ′ = u 3 ( t ) x'' = u^3(t) x=u3(t)

通过优化控制变量: u ( t ) u(t) u(t) 使得损失函数最小:

L o s s ( θ ) = ∑ i ∣ ∣ 4 − x ( t i ) ∣ ∣ + 2 ∣ ∣ x ′ ( t i ) ∣ ∣ + ∣ ∣ u ( t i ) ∣ ∣ Loss(\theta) = \sum_{i} ||4-x(t_i)||+2||x'(t_i)||+||u(t_i)|| Loss(θ)=i4x(ti)+2x(ti)+u(ti)

在求解时,把微分方程都将为一阶:
x ′ = v x' = v x=v

v ′ = u 3 ( t ) v' = u^3(t) v=u3(t)

损失函数变为:

L o s s ( θ ) = ∑ i ∣ ∣ 4 − x ( t i ) ∣ ∣ + 2 ∣ ∣ v ( t i ) ∣ ∣ + ∣ ∣ u ( t i ) ∣ ∣ Loss(\theta) = \sum_{i} ||4-x(t_i)||+2||v(t_i)||+||u(t_i)|| Loss(θ)=i4x(ti)+2v(ti)+u(ti)

基于DifferentialEquations.jl建模方式实现控制

代码分析:

使用相关的函数包:

using DiffEqFlux, DifferentialEquations, Plots, Statistics

定义与初始化神经网络ann
ann为一个3层神经网络,第一层1输入32输出,第二次32输入32输出,第三层32输入1输出。

可将其看作一个黑盒函数,一个输入对应一个输出。在控制问题中,即输入时间域上的某个时间t,神经网络通过计算可以输出在该时间点最优的一个控制值 u u u。经过训练的神经网络ann可以代表经过计算后的一段时间域上的控制曲线 u ( t ) u(t) u(t)

ann = FastChain(FastDense(1,32,tanh), FastDense(32,32,tanh), FastDense(32,1))
θ = initial_params(ann) #初始化参数

定义微分方程,以DifferentialEquations方式定义
ann在问题中相当于一个函数u(t),p是神经网络的参数,t是自变量。 u ( t ) = a n n ( t , p ) u(t)=ann(t,p) u(t)=ann(t,p)

function dxdt_(dx,x,p,t)
    x1, x2 = x
    dx[1] = x[2]
    dx[2] = ann([t],p)[1]^3
end

定义相关参数与构造问题:

tspan = (0.0f0,8.0f0)
x0 = [-4f0,0f0]
prob = ODEProblem(dxdt_,x0,tspan,θ)

尝试求解:

solve(prob,Vern9(),abstol=1e-10,reltol=1e-10)

定义预测函数与损失函数:
predict_adjoint函数计算在当前神经网络参数下u,v的值,即求解微分方程
loss_adjoint函数计算损失函数的值

ts = Float32.(collect(0.0:0.01:tspan[2]))
function predict_adjoint(θ)
  Array(solve(prob,Vern9(),p=θ,saveat=ts,sensealg=InterpolatingAdjoint(autojacvec=ReverseDiffVJP(true))))
end
function loss_adjoint(θ)
  x = predict_adjoint(θ)
  mean(abs2,4.0 .- x[1,:]) + 2mean(abs2,x[2,:]) + mean(abs2,[first(ann([t],θ)) for t in ts])/10
end

尝试计算在初始参数下,loss的大小:

l = loss_adjoint(θ)

设置callback
该函数可以显示优化过程中,loss的变化情况以及函数图像(画图可以删除省略)

cb = function (θ,l)
  println(l)
  p = plot(solve(remake(prob,p=θ),Tsit5(),saveat=0.01),ylim=(-6,6),lw=3)
  plot!(p,ts,[first(ann([t],θ)) for t in ts],label="u(t)",lw=3)
  display(p)
  return false
end

最后,训练优化:
res1,res2,res3进行了三轮优化

res1 = DiffEqFlux.sciml_train(loss_adjoint, θ, ADAM(0.005), cb = cb,maxiters=100)
res2 = DiffEqFlux.sciml_train(loss_adjoint, res1.u,
                              BFGS(initial_stepnorm=0.01), cb = cb,maxiters=100,
                              allow_f_increases = false)
function loss_adjoint(θ)
  x = predict_adjoint(θ)
  mean(abs2,4.0 .- x[1,:]) + 2mean(abs2,x[2,:]) + mean(abs2,[first(ann([t],θ)) for t in ts])
end

res3 = DiffEqFlux.sciml_train(loss_adjoint, res2.u,
                              BFGS(initial_stepnorm=0.01), cb = cb,maxiters=100,
                              allow_f_increases = false)

全部代码(训练完成之后会有画图查看结果等操作):

using DiffEqFlux, DifferentialEquations, Plots, Statistics
tspan = (0.0f0,8.0f0)
ann = FastChain(FastDense(1,32,tanh), FastDense(32,32,tanh), FastDense(32,1))
θ = initial_params(ann)
function dxdt_(dx,x,p,t)
    x1, x2 = x
    dx[1] = x[2]
    dx[2] = ann([t],p)[1]^3
end
x0 = [-4f0,0f0]
ts = Float32.(collect(0.0:0.01:tspan[2]))
prob = ODEProblem(dxdt_,x0,tspan,θ)
solve(prob,Vern9(),abstol=1e-10,reltol=1e-10)
function predict_adjoint(θ)
  Array(solve(prob,Vern9(),p=θ,saveat=ts,sensealg=InterpolatingAdjoint(autojacvec=ReverseDiffVJP(true))))
end
function loss_adjoint(θ)
  x = predict_adjoint(θ)
  mean(abs2,4.0 .- x[1,:]) + 2mean(abs2,x[2,:]) + mean(abs2,[first(ann([t],θ)) for t in ts])/10
end
l = loss_adjoint(θ)
cb = function (θ,l)
  println(l)
  p = plot(solve(remake(prob,p=θ),Tsit5(),saveat=0.01),ylim=(-6,6),lw=3)
  plot!(p,ts,[first(ann([t],θ)) for t in ts],label="u(t)",lw=3)
  display(p)
  return false
end
# Display the ODE with the current parameter values.
cb(θ,l)
loss1 = loss_adjoint(θ)
res1 = DiffEqFlux.sciml_train(loss_adjoint, θ, ADAM(0.005), cb = cb,maxiters=100)
res2 = DiffEqFlux.sciml_train(loss_adjoint, res1.u,
                              BFGS(initial_stepnorm=0.01), cb = cb,maxiters=100,
                              allow_f_increases = false)
function loss_adjoint(θ)
  x = predict_adjoint(θ)
  mean(abs2,4.0 .- x[1,:]) + 2mean(abs2,x[2,:]) + mean(abs2,[first(ann([t],θ)) for t in ts])
end

res3 = DiffEqFlux.sciml_train(loss_adjoint, res2.u,
                              BFGS(initial_stepnorm=0.01), cb = cb,maxiters=100,
                              allow_f_increases = false)

l = loss_adjoint(res3.u)
cb(res3.u,l)
p = plot(solve(remake(prob,p=res3.u),Tsit5(),saveat=0.01),ylim=(-6,6),lw=3)
plot!(p,ts,[first(ann([t],res3.u)) for t in ts],label="u(t)",lw=3)

基于ModelingToolkit建模方式实现控制

基于modelingtoolkit方式的建模与differentialequations大同小异。

由于modelingtoolkit是符号建模体系,关键问题在于处理符号问题。上面神经网络的参数在modelingtoolkit中都只能当作parameters处理。同时神经网络的计算式都会被纳入符号体系中去计算。所以针对神经网络这种大量参数的运算,运算速度会下降很快。这是问题所在。

代码:

using DiffEqFlux, DifferentialEquations, Plots, Statistics,ModelingToolkit
tspan = (0.0f0,8.0f0)
ann = FastChain(FastDense(1,6,tanh), FastDense(6,6,tanh), FastDense(6,1))
θ = initial_params(ann)
N = length(θ)
function an(t,p)
    return ann(t,p)[1]^3
end
@register an(t,p)
@variables t,x(t),xx(t)
@parameters p[1:N]
D = Differential(t)
eqs=[ 
    D(x)~ xx
    D(xx) ~ an(t,p[1:N])
]
sys = ODESystem(eqs,t,[x,xx],p)
u0 =[
    x => -4.f0
    xx => 0.f0
]
paras = [p[i]=>θ[i] for i in 1:N]
prob = ODEProblem(structural_simplify(sys),u0,tspan,paras)
sol = solve(prob)
ts = Float32.(collect(0.0:0.01:tspan[2]))
function predict_adjoint(θ)
  Array(solve(prob,Vern9(),p=θ,saveat=ts,sensealg=InterpolatingAdjoint(autojacvec=ReverseDiffVJP(true))))
end
function loss_adjoint(θ)
  x = predict_adjoint(θ)
  mean(abs2,4.0 .- x[1,:]) + 2mean(abs2,x[2,:]) + mean(abs2,[first(ann([t],θ)) for t in ts])/10
end
loss_adjoint(θ)
l = loss_adjoint(θ)
cb = function (θ,l)
  println(l)
  return false
end
res1 = DiffEqFlux.sciml_train(loss_adjoint, θ, ADAM(0.005), cb = cb,maxiters=10)

神经网络的项数由32变为6,精度是大大下降的。这是因为32项要等太久了,等不到结果。这是使用modelingtoolkit的问题之一。计算量太大。

上面的参数用参数向量来定义,是通过在传递初始参数时,为每一个参数都进行了初始赋值。

如果打印sys也可以发现,神经网络的计算公式已经被嵌入到符号计算体系中去。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jake484

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值