ODEの解法システムを「自明な並列処理」設定でGPUに展開したいと思います。たとえば、512の異なるパラメーターセットを使用して感度分析を行います。
理想的には、フォワードオイラーのような固定タイムステップではなく、CVODEのようなスマートアダプティブタイムステップソルバーを使用してODEソルビングを実行したいのですが、CPUの代わりにNVIDIA GPUで実行します。
誰かこれをやったことがありますか?ライブラリはありますか?
ODEの解法システムを「自明な並列処理」設定でGPUに展開したいと思います。たとえば、512の異なるパラメーターセットを使用して感度分析を行います。
理想的には、フォワードオイラーのような固定タイムステップではなく、CVODEのようなスマートアダプティブタイムステップソルバーを使用してODEソルビングを実行したいのですが、CPUの代わりにNVIDIA GPUで実行します。
誰かこれをやったことがありますか?ライブラリはありますか?
回答:
BoostのodeintライブラリとThrustを調べてみてください。ここで説明するように、これらを組み合わせることができます。
DifferentialEquations.jlライブラリは、ODEシステムをGPUでの並列ソリューション用に最適化されたバージョンに自動的に変換するためのツールを備えた高水準言語(Julia)用のライブラリです。使用できる並列処理には2つの形式があります。大規模なODEシステムの配列ベースの並列処理と、比較的小さい(<100)ODEシステムのパラメーター調査のパラメーター並列処理です。高次の暗黙的および明示的な方法をサポートし、ベンチマークで他のシステムを日常的に上回るか、または一致させます(少なくとも、他のシステムをラップして、チェックして簡単に使用できるようにします!)
この特定の機能については、自動パラメーター並列処理用のモジュールであるDiffEqGPU.jlをご覧ください。DifferentialEquations.jlライブラリには、並列パラメータスタディの機能があり、このモジュールは既存の構成を拡張して、スタディを自動的に並列で実行させます。どのような1が行うのは、既存のトランスフォームODEProblem
(またはその他DEProblem
などSDEProblem
に)EnsembleProblem
として指定したprob_func
他の問題は、プロトタイプから生成されていますか。以下は、GPU上のローレンツ方程式の10,000の軌跡を高次の明示的適応法で解決します。
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倍向上します。次に、READMEをチェックして、複数のGPUを利用する方法や、GPUの完全なクラスターを同時に利用するマルチプロセッシング+ GPUを実行する方法などを確認できます。:マルチスレッドの代わりのGPUへの切り替えが1行の変更であることに注意してください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)
このフォームでは、GPUで使用するためにヤコビアンを指定する必要があります(現在、すぐに修正される予定です)が、DifferentialEquations.jlのドキュメントでは、数値的に定義された関数で自動シンボリックヤコビアン計算を実行する方法を示しているため、マニュアルはまだありませんここで労働。CVODEのようなメソッドの分岐ロジックは一般にスレッドの非同期化を引き起こし、いずれにしてもこれらのタイプのシナリオではRosenbrockメソッドほどうまく機能しないため、これらのアルゴリズムを強くお勧めします。
DifferentialEquations.jl を使用すると、このGPUアクセラレーションを利用できるグローバル感度分析などの機能を含む完全なライブラリにもアクセスできます。また、高速のローカル感度分析のためのデュアル番号とも互換性があります。GPUベースのコードは、イベント処理やさまざまな種類の問題に最適化されたODEソルバーの大規模なセットなど、DifferentialEquations.jlのすべての機能を取得します。つまり、単純な1回限りのGPU ODEソルバーではなく、フル機能のシステムの一部であり、効率的なGPUサポートも備えています。