Julia's DifferentialEquations.jl is all GPU-compatible. If you make your arrays GPU-based arrays, then the solver recompiles to be all on the GPU (no data transfers). For example:
using OrdinaryDiffEq, CUDA, LinearAlgebra
u0 = cu(rand(1000))
A = cu(randn(1000,1000))
f(du,u,p,t) = mul!(du,A,u)
prob = ODEProblem(f,u0,(0.0f0,1.0f0)) # Float32 is better on GPUs!
sol = solve(prob,Tsit5())
is all GPU-based. You can make use of this from Python via diffeqpy. There's not much nice syntax exposing GPU usage to Python right now, but you could use the following to do the same:
import diffeqpy
diffeqpy.install()
from diffeqpy import de
sol = Main.eval("""
using CUDA, LinearAlgebra
u0 = cu(rand(1000))
A = cu(randn(1000,1000))
f(du,u,p,t) = mul!(du,A,u)
prob = ODEProblem(f,u0,(0.0f0,1.0f0)) # Float32 is better on GPUs!
sol = solve(prob,Tsit5())
Array(sol) # Return an array
""")
Note that this requires CUDA is installed on your Julia installation.