我想在“平凡的可并行化”设置下将ODE的求解系统投放到GPU上。例如,使用512个不同的参数集进行灵敏度分析。
理想情况下,我想使用智能自适应时间步长求解器(例如CVODE)而不是固定时间步长(例如Forward Euler)来执行ODE解决方案,而是在NVIDIA GPU而不是CPU上运行它。
有人这样做吗?有图书馆吗?
我想在“平凡的可并行化”设置下将ODE的求解系统投放到GPU上。例如,使用512个不同的参数集进行灵敏度分析。
理想情况下,我想使用智能自适应时间步长求解器(例如CVODE)而不是固定时间步长(例如Forward Euler)来执行ODE解决方案,而是在NVIDIA GPU而不是CPU上运行它。
有人这样做吗?有图书馆吗?
Answers:
您可能需要研究Boost的odeint库和Thrust。它们可以如此处讨论的那样组合。
DifferentialEquations.jl库是用于高级语言(Julia)的库,该库具有用于将ODE系统自动转换为针对GPU并行解决方案的优化版本的工具。可以采用两种形式的并行性:用于大型ODE系统的基于数组的并行性和用于相对较小(<100)ODE系统的参数研究的参数并行性。它支持高阶隐式和显式方法,并且在性能上通常优于或匹配基准测试中的其他系统(至少,它包装了其他系统,因此很容易检查和使用它们!)
对于此特定功能,您可能需要查看DiffEqGPU.jl,它是用于自动参数并行化的模块。DifferentialEquations.jl库具有用于并行参数研究的功能,并且该模块扩充了现有配置,以使研究自动并行进行。一个人所做的就是将其现有的ODEProblem
(或其他DEProblem
类似的SDEProblem
)转换为,EnsembleProblem
并指定prob_func
如何从原型中产生其他问题。以下内容采用高阶显式自适应方法求解了GPU上10,000条Lorenz方程的轨迹:
using OrdinaryDiffEq, DiffEqGPU
function lorenz(du,u,p,t)
@inbounds begin
du[1] = p[1]*(u[2]-u[1])
du[2] = u[1]*(p[2]-u[3]) - u[2]
du[3] = u[1]*u[2] - p[3]*u[3]
end
nothing
end
u0 = Float32[1.0;0.0;0.0]
tspan = (0.0f0,100.0f0)
p = (10.0f0,28.0f0,8/3f0)
prob = ODEProblem(lorenz,u0,tspan,p)
prob_func = (prob,i,repeat) -> remake(prob,p=rand(Float32,3).*p)
monteprob = EnsembleProblem(prob, prob_func = prob_func)
@time sol = solve(monteprob,Tsit5(),EnsembleGPUArray(),trajectories=10_000,saveat=1.0f0)
请注意,用户无需编写GPU代码,并且使用单个RTX 2080进行基准测试,与使用具有多线程并行性的16核心Xeon机器相比,该基准提高了5倍。然后可以检查出怎样做事喜欢自述利用多GPU和多处理做的GPU +对于同时利用GPU的全集群。请注意,切换到多线程而不是GPU是一行更改:EnsembleThreads()
而不是EnsembleGPUArray()
。
然后对于隐式求解器,将保留相同的接口。例如,以下使用高阶Rosenbrock和隐式Runge-Kutta方法:
function lorenz_jac(J,u,p,t)
@inbounds begin
σ = p[1]
ρ = p[2]
β = p[3]
x = u[1]
y = u[2]
z = u[3]
J[1,1] = -σ
J[2,1] = ρ - z
J[3,1] = y
J[1,2] = σ
J[2,2] = -1
J[3,2] = x
J[1,3] = 0
J[2,3] = -x
J[3,3] = -β
end
nothing
end
function lorenz_tgrad(J,u,p,t)
nothing
end
func = ODEFunction(lorenz,jac=lorenz_jac,tgrad=lorenz_tgrad)
prob_jac = ODEProblem(func,u0,tspan,p)
monteprob_jac = EnsembleProblem(prob_jac, prob_func = prob_func)
@time solve(monteprob_jac,Rodas5(linsolve=LinSolveGPUSplitFactorize()),EnsembleGPUArray(),dt=0.1,trajectories=10_000,saveat=1.0f0)
@time solve(monteprob_jac,TRBDF2(linsolve=LinSolveGPUSplitFactorize()),EnsembleGPUArray(),dt=0.1,trajectories=10_000,saveat=1.0f0)
虽然此格式要求您提供一个Jacobian才能在GPU上使用(当前,将很快修复),但DifferentialEquations.jl文档演示了如何对数字定义的函数执行自动符号雅可比计算,因此仍然没有手册在这里工作。我强烈建议使用这些算法,因为像CVODE这样的方法的分支逻辑通常会导致线程不同步,并且在这些类型的场景中反而看起来不像Rosenbrock方法那样好。
通过使用DifferentialEquations.jl,您还可以访问完整的库,其中包括诸如全局灵敏度分析之类的功能,可以利用此GPU加速功能。它还与双数兼容,可进行快速的局部灵敏度分析。基于GPU的代码获得了DifferentialEquations.jl的所有功能,例如事件处理和针对不同类型问题进行了优化的大量ODE求解器,这意味着它不仅是简单的一次性GPU ODE求解器,而且功能齐全的系统的一部分,该系统也恰好具有有效的GPU支持。