Performance 随机微分方程组的疯狂空间分配求解系统

Performance 随机微分方程组的疯狂空间分配求解系统,performance,julia,differentialequations.jl,Performance,Julia,Differentialequations.jl,第一次在这里问问题。 我之前使用了一个简单的MATLAB脚本来模拟90 Hopf振荡器,通过一个矩阵耦合,带有randn噪声,带有一个简单的Euler阶跃积分。我想升级这个,所以我进入了朱莉娅,似乎有很多令人兴奋的属性 我有点迷路了。我开始使用Differentialsequations.jl(随机解算器),找到了一个解决方案,发现自己有了一个基准测试,它告诉我解200秒需要4 Gb!!!(2.5GB,带有alg_提示=[:stiff])(我还没有固定dt,以前我使用dt=0.1) 基准测试工

第一次在这里问问题。 我之前使用了一个简单的MATLAB脚本来模拟90 Hopf振荡器,通过一个矩阵耦合,带有randn噪声,带有一个简单的Euler阶跃积分。我想升级这个,所以我进入了朱莉娅,似乎有很多令人兴奋的属性

我有点迷路了。我开始使用Differentialsequations.jl(随机解算器),找到了一个解决方案,发现自己有了一个基准测试,它告诉我解200秒需要4 Gb!!!(2.5GB,带有alg_提示=[:stiff])(我还没有固定dt,以前我使用dt=0.1)

基准测试工具.试用: 内存估计:2.30 GiB

allocs估计数:722769


最短时间:859.224 ms(13.24%GC)

中位时间:942.707毫秒(13.10%GC)

平均时间:975.430 ms(12.99%GC)

最长时间:1.223秒(13.00%GC)


样本:6

评估/样本:1

有什么想法吗?我正在研究几种解决方案,但没有一种能够将内存量减少到合理的程度。
提前感谢。

您正在创建数量惊人的临时阵列。每个切片都会创建一个临时的。你在这里和那里放了一个点,但是你必须把所有的东西都点上才能得到融合的广播。相反,您只需使用
@.
宏即可。此外,使用
@views
将确保切片不会复制:

function Shopf(du, u, p, t)
    @. du[1:90, 1] = @views (p[1:90, 1] - u[1:90, 1]^2 - u[1:90, 2]^2) * u[1:90, 1] -
        p[1:90, 2] * u[1:90,2] + 0.5 * (-p[:, end] * u[:, 1] + p[:, 4:end-1] * u[:,1])
    @. du[1:90, 2] = @views (p[1:90, 1] - u[1:90, 1]^2 - u[1:90, 2]^2) * u[1:90, 1] + 
        p[1:90, 2] * u[1:90,1] + 0.5 * (-p[:, end] * u[:, 2] + p[:, 4:end-1] * u[:,2])  
end
另外,不要写
x^2.0
,使用
x^2
,前者是一个缓慢的浮动电源,而后者是一个快速的
x*x
。事实上,尽可能在乘法、加法等运算中使用整数

还有一件事

function σ_Shopf(du,u,p,t)

du[1:90,1]=0.04*ones(90,1)
du[1:90,2]=0.04*ones(90,1)


end
无需在分配的右侧创建两个临时数组。写下这句话:

function σ_Shopf(du, u, p, t)
    du[1:90, 1:2] .= 0.04
end
更快更简单。请注意,我还没有测试过这个,所以请修复任何拼写错误

(最后,请使用缩进并在运算符周围加空格,这样可以使代码更易于阅读。)

更新:我真的不知道您的代码应该做什么,奇怪的索引应该做什么,但这里有一个可能的改进,它只使用循环(我认为它实际上更干净,可以让您进行进一步的优化):

生成
A
的操作是一个矩阵积,因此您无法避免在那里进行分配,除非您可以使用
mul。除此之外,你不应该有下面的分配

function shopf!(du, u, p, t)
    A = @view p[:, 4:end-1] * u
    # mul!(A, view(p, 4:end-1), u)  # in-place matrix product
    for i in axes(u, 1)
        val = (p[i, 1] - u[i, 1]^2 - u[i, 2]^2) * u[i, 1]  # don't calculate this twice
        du[i, 1] = val - (p[i, 2] * u[i, 2]) - (0.5 * p[i, end] * u[i, 1]) + 
            (0.5 * A[i, 1])
        du[i, 2] = val + (p[i, 2] * u[i, 1]) - (0.5 * p[i, end] * u[i, 2]) + 
            (0.5 * A[i, 2])
    end
end

在此之后,您可以添加各种优化,
@inbounds
,如果您确定数组大小、多线程、
@simd
甚至LoopVectorization实验包中的
@avx

问题是Julia中的切片创建的是副本而不是视图。测试代码并不容易。您没有定义
SC
,除非通过编写
SC=SC这没有多大帮助。同样令人困惑的是,在同一行中,您使用
u[1:90,1]
u[:,1]
,就好像它们的大小一样。如果
u
有90行,那么就没有理由使用这些索引(事实上相当危险),如果没有,那么代码就不应该工作。非常感谢@DNF,我已经尝试了您的解决方案,并且从视图中得到了和错误。我把它改为“视图”,它没有出错。在更新的答案中,我还在for循环之前添加了“视图”。我还对选择不同的解算器所带来的性能提升感到惊讶。我有1Mb的内存空间,速度快了两个数量级(3毫秒)。这是使用您建议的解决方案(带有提到的更正)和LambaEM解算器(其他解算器仅使我的计算时间提高了一个数量级)。再次感谢,循环不包含切片,因此
视图
在那里是多余的。k!我会调查的
function shopf!(du, u, p, t)
    A = @view p[:, 4:end-1] * u
    # mul!(A, view(p, 4:end-1), u)  # in-place matrix product
    for i in axes(u, 1)
        val = (p[i, 1] - u[i, 1]^2 - u[i, 2]^2) * u[i, 1]  # don't calculate this twice
        du[i, 1] = val - (p[i, 2] * u[i, 2]) - (0.5 * p[i, end] * u[i, 1]) + 
            (0.5 * A[i, 1])
        du[i, 2] = val + (p[i, 2] * u[i, 1]) - (0.5 * p[i, end] * u[i, 2]) + 
            (0.5 * A[i, 2])
    end
end