La libreria DifferentialEquations.jl è una libreria per un linguaggio di alto livello (Julia) che ha strumenti per trasformare automaticamente il sistema ODE in una versione ottimizzata per soluzioni parallele su GPU. Esistono due forme di parallelismo che possono essere impiegate: parallelismo basato su array per sistemi ODE di grandi dimensioni e parallelismo dei parametri per studi di parametri su sistemi ODE relativamente piccoli (<100). Supporta metodi impliciti ed espliciti di ordine elevato e sovraperforma regolarmente o abbina altri sistemi nei benchmark (almeno, avvolge gli altri, quindi è facile controllarli e usarli!)
Per questa specifica funzionalità, potresti voler dare un'occhiata a DiffEqGPU.jl che è il modulo per il parallelismo automatico dei parametri. La libreria DifferentialEquations.jl ha funzionalità per studi di parametri paralleli e questo modulo migliora le configurazioni esistenti per far sì che lo studio avvenga automaticamente in parallelo. Quello che uno fa è trasformare il loro esistente ODEProblem
(o altro DEProblem
simile SDEProblem
) in un EnsembleProblem
e specificare con un prob_func
come gli altri problemi sono generati dal prototipo. Quanto segue risolve 10.000 traiettorie dell'equazione di Lorenz sulla GPU con un metodo adattivo esplicito di alto ordine:
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)
Si noti che l'utente non ha bisogno di scrivere alcun codice GPU e con un singolo RTX 2080 questo benchmark è un miglioramento di 5 volte rispetto all'utilizzo di una macchina Xeon a 16 core con parallelismo multithread. Si può quindi controllare il README per come fare cose come utilizzare più GPU e fare multiprocessing + GPU per utilizzare contemporaneamente un intero cluster di GPU . Si noti che il passaggio al multithreading anziché alle GPU è un cambio di riga: EnsembleThreads()
anziché EnsembleGPUArray()
.
Quindi, per i risolutori impliciti, vale la stessa interfaccia. Ad esempio, quanto segue utilizza Rosenbrock di alto ordine e i metodi impliciti di 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)
Mentre questo modulo richiede che tu dia un giacobino per essere usato sulla GPU (attualmente, verrà risolto presto), la documentazione DifferentialEquations.jl mostra come eseguire calcoli simbolici giacobini simbolici su funzioni definite numericamente , quindi non c'è ancora nessun manuale lavoro qui. Consiglio vivamente questi algoritmi perché la logica di ramificazione di un metodo come CVODE generalmente provoca la desincronizzazione dei thread e non sembra funzionare come un metodo Rosenbrock in questi tipi di scenari.
Usando DifferentialEquations.jl, puoi anche accedere alla libreria completa, che include funzionalità come l'analisi della sensibilità globale che può fare uso di questa accelerazione GPU. È inoltre compatibile con due numeri per un'analisi rapida della sensibilità locale . Il codice basato su GPU ottiene tutte le funzionalità di DifferentialEquations.jl, come la gestione degli eventi e l' ampia serie di solutori ODE che sono ottimizzati per diversi tipi di problemi , il che significa che non è solo un semplice solutore ODE GPU una tantum, ma invece un parte di un sistema completo che ha anche un efficiente supporto GPU.