나는 '사소한 병렬화'설정으로 ODE 시스템을 GPU에 농사 짓고 싶습니다. 예를 들어 512 개의 서로 다른 파라미터 세트로 감도 분석을 수행합니다.
이상적으로 Forward Euler와 같은 고정 된 시간 단계가 아니라 CVODE와 같은 스마트 적응 형 시간 단계 솔버를 사용하여 ODE를 해결하고 싶지만 CPU 대신 NVIDIA GPU에서 실행하고 싶습니다.
누구든지 이것을 했습니까? 라이브러리가 있습니까?
나는 '사소한 병렬화'설정으로 ODE 시스템을 GPU에 농사 짓고 싶습니다. 예를 들어 512 개의 서로 다른 파라미터 세트로 감도 분석을 수행합니다.
이상적으로 Forward Euler와 같은 고정 된 시간 단계가 아니라 CVODE와 같은 스마트 적응 형 시간 단계 솔버를 사용하여 ODE를 해결하고 싶지만 CPU 대신 NVIDIA GPU에서 실행하고 싶습니다.
누구든지 이것을 했습니까? 라이브러리가 있습니까?
답변:
Boost의 odeint 라이브러리 와 Thrust 를 살펴볼 수 있습니다 . 여기에 설명 된대로 결합 할 수 있습니다 .
DifferentialEquations.jl 라이브러리는 ODE 시스템을 GPU의 병렬 솔루션에 대한 최적화 된 버전으로 자동 변환하는 도구가있는 고급 언어 (Julia) 용 라이브러리입니다. 채택 할 수있는 병렬 처리에는 크게 ODE 시스템에 대한 어레이 기반 병렬 처리와 상대적으로 작은 (<100) ODE 시스템에 대한 파라미터 연구에 대한 매개 변수 병렬 처리의 두 가지 형태가 있습니다. 높은 수준의 암시 적 및 명시 적 방법을 지원 하고 벤치 마크에서 다른 시스템보다 성능이 우수하거나 일상적으로 일치합니다 (적어도 다른 시스템을 래핑하여 쉽게 확인하고 사용할 수 있습니다).
이 특정 기능에 대해서는 자동화 된 매개 변수 병렬 처리를위한 모듈 인 DiffEqGPU.jl 을 살펴볼 수 있습니다 . DifferentialEquations.jl 라이브러리 에는 병렬 매개 변수 연구 기능 이 있으며이 모듈은 기존 구성을 보강하여 연구가 자동으로 병렬로 수행되도록합니다. 하나는 기존 ODEProblem
(또는 다른 DEProblem
것과 같이 SDEProblem
)을로 변환하고 프로토 타입에서 다른 문제가 생성되는 방식으로 EnsembleProblem
지정 prob_func
합니다. 다음은 고차 명시 적 적응 방법으로 GPU에서 Lorenz 방정식의 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 대신 멀티 스레딩으로 전환하면 한 줄만 변경됩니다. 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에서 사용하기 위해 Jacobian을 제공해야하지만 (현재 곧 수정 될 예정 임) DifferentialEquations.jl 설명서 는 숫자로 정의 된 함수에서 자동으로 상징적 인 Jacobian 계산을 수행하는 방법을 보여 주므로 여전히 수동은 없습니다 여기서 노동하십시오. CVODE와 같은 메소드의 분기 논리는 일반적으로 스레드 비 동기화를 유발하고 어쨌든 이러한 유형의 시나리오에서 Rosenbrock 메소드만큼 성능이 좋지 않기 때문에 이러한 알고리즘을 적극 권장합니다.
DifferentialEquations.jl 을 사용하면이 GPU 가속을 사용할 수있는 전역 감도 분석 과 같은 기능이 포함 된 전체 라이브러리에 액세스 할 수 있습니다. 또한 빠른 로컬 감도 분석을 위해 이중 숫자 와 호환됩니다 . GPU 기반 코드는 이벤트 처리 및 다양한 유형의 문제에 최적화 된 대규모 ODE 솔버 와 같이 DifferentialEquations.jl의 모든 기능을 가져옵니다 . 이는 단순한 일회성 GPU ODE 솔버가 아니라 대신 효율적인 GPU 지원을 제공하는 완전한 기능을 갖춘 시스템의 일부입니다.