提高Julia中for循环的速度

提高Julia中for循环的速度,julia,Julia,这是我在Julia平台上的代码,我喜欢加速它。有没有什么方法可以让这更快?50k*50k的数据集需要0.5秒。我希望Julia会比这快很多,或者我不确定我是否在做一个愚蠢的实现 ar = [[1,2,3,4,5], [2,3,4,5,6,7,8], [4,7,8,9], [9,10], [2,3,4,5]] SV = rand(10,5) function h_score_0(ar ,SV) m = length(ar) SC = Array{Float64,2}(undef

这是我在Julia平台上的代码,我喜欢加速它。有没有什么方法可以让这更快?50k*50k的数据集需要0.5秒。我希望Julia会比这快很多,或者我不确定我是否在做一个愚蠢的实现

ar = [[1,2,3,4,5], [2,3,4,5,6,7,8], [4,7,8,9], [9,10], [2,3,4,5]]

SV = rand(10,5)

function h_score_0(ar ,SV)
    m = length(ar)
    SC = Array{Float64,2}(undef, size(SV, 2), m)
    for iter = 1:m
        nodes = ar[iter]
        for jj = 1:size(SV, 2)
            mx = maximum(SV[nodes, jj])
            mn = minimum(SV[nodes, jj])
            term1 = (mx - mn)^2;
            SC[jj, iter] = (term1);
        end
    end
    return score = sum(SC, dims = 1)
end


您的代码中有一些不必要的分配:

mx = maximum(SV[nodes, jj])
mn = minimum(SV[nodes, jj])
切片分配,所以每一行在这里复制一个数据,实际上是复制数据两次,每一行一次。您可以确保只复制一次,或者更好:使用
视图
,这样就根本没有复制(请注意,如果您使用的是旧版本,Julia v1.5上的
视图
要快得多)

没有理由在这里创建一个矩阵,然后在上面求和,只需在迭代时累加:

score[i] += (mx - mn)^2
对于您指定的输入数据,在我的笔记本电脑上有一个速度>5倍的函数:

function h_score_1(ar, SV)
    score = zeros(eltype(SV), length(ar))
    @inbounds for i in eachindex(ar)
        nodes = ar[i]
        for j in axes(SV, 2)
            SVview = view(SV, nodes, j)
            mx = maximum(SVview)
            mn = minimum(SVview)
            score[i] += (mx - mn)^2
        end
    end
    return score
end
此函数输出一维向量,而不是原始函数中的1xN矩阵

原则上,如果我们更换

mx = maximum(SVview)
mn = minimum(SVview)

它只遍历向量一次,而不是两次。不幸的是,
extrema
存在性能问题,因此当前的速度不如单独的
maximum/minimum
调用:

最后,为了以简洁为代价获得最佳性能,我们可以完全避免创建视图,并将对
maximum
minimum
的调用转换为单个显式循环遍历:

function h_score_2(ar, SV)
    score = zeros(eltype(SV), length(ar))
    @inbounds for i in eachindex(ar)
        nodes = ar[i]
        for j in axes(SV, 2)
            mx, mn = -Inf, +Inf
            for node in nodes
                x = SV[node, j]
                mx = ifelse(x > mx, x, mx)
                mn = ifelse(x < mn, x, mn)
            end
            score[i] += (mx - mn)^2
        end
    end
    return score
end

因此,在这里显式写出最里面的循环是值得的,这样可以将时间再减少3倍左右。令人恼火的是,Julia编译器还不能如此高效地生成代码,但它确实在每个版本中都变得更加智能。另一方面,显式循环版本将永远快速,因此,如果此代码真的对性能至关重要,则可能值得这样写出来。

您的代码中有一些不必要的分配:

mx = maximum(SV[nodes, jj])
mn = minimum(SV[nodes, jj])
切片分配,所以每一行在这里复制一个数据,实际上是复制数据两次,每一行一次。您可以确保只复制一次,或者更好:使用
视图
,这样就根本没有复制(请注意,如果您使用的是旧版本,Julia v1.5上的
视图
要快得多)

没有理由在这里创建一个矩阵,然后在上面求和,只需在迭代时累加:

score[i] += (mx - mn)^2
对于您指定的输入数据,在我的笔记本电脑上有一个速度>5倍的函数:

function h_score_1(ar, SV)
    score = zeros(eltype(SV), length(ar))
    @inbounds for i in eachindex(ar)
        nodes = ar[i]
        for j in axes(SV, 2)
            SVview = view(SV, nodes, j)
            mx = maximum(SVview)
            mn = minimum(SVview)
            score[i] += (mx - mn)^2
        end
    end
    return score
end
此函数输出一维向量,而不是原始函数中的1xN矩阵

原则上,如果我们更换

mx = maximum(SVview)
mn = minimum(SVview)

它只遍历向量一次,而不是两次。不幸的是,
extrema
存在性能问题,因此当前的速度不如单独的
maximum/minimum
调用:

最后,为了以简洁为代价获得最佳性能,我们可以完全避免创建视图,并将对
maximum
minimum
的调用转换为单个显式循环遍历:

function h_score_2(ar, SV)
    score = zeros(eltype(SV), length(ar))
    @inbounds for i in eachindex(ar)
        nodes = ar[i]
        for j in axes(SV, 2)
            mx, mn = -Inf, +Inf
            for node in nodes
                x = SV[node, j]
                mx = ifelse(x > mx, x, mx)
                mn = ifelse(x < mn, x, mn)
            end
            score[i] += (mx - mn)^2
        end
    end
    return score
end

因此,在这里显式写出最里面的循环是值得的,这样可以将时间再减少3倍左右。令人恼火的是,Julia编译器还不能如此高效地生成代码,但它确实在每个版本中都变得更加智能。另一方面,显式循环版本将永远快速,因此,如果此代码确实对性能至关重要,那么可能值得这样写出来。

什么是
ar
SV
?您是否有另一种更快的语言实现,或者这是您期望的速度?如果您希望对您的问题做出最好的回答,理想情况下,您应该包括为
ar
SV
生成合理模拟值的代码。另外,如果你能知道你是如何安排程序的时间(即显示代码),那就太好了。我刚刚编辑了这篇文章并添加了ar和SV。现在代码可以更好地理解,它实际上可以生成结果。什么是
ar
SV
?您是否有另一种更快的语言实现,或者这是您期望的速度?如果您希望对您的问题做出最好的回答,理想情况下,您应该包括为
ar
SV
生成合理模拟值的代码。另外,如果你能知道你是如何安排程序的时间(即显示代码),那就太好了。我刚刚编辑了这篇文章并添加了ar和SV。现在,代码可以更好地理解,它实际上可以生成结果。谢谢!使用更大的数据集,我的速度也提高了5倍。你有没有其他想法可以让这更快?我考虑过多线程,但一个简短的实验产生了令人不快的结果。你可以使用显式循环来代替视图
SV
。如果你用的是Julia≤ 1.4然后对视图进行堆分配,这可以增加和/或减少优化机会。您还可以使用
extrema
在数据的一次传递中计算最小值和最大值。我编辑了此答案,添加了一个版本,其中最大值/最小值计算通过显式循环完成,速度明显更快。在我的笔记本电脑中,我使用h_分数_1获得了更好的性能。它几乎快了2倍。有什么想法吗?谢谢!使用更大的数据集,我的速度也提高了5倍。你有没有其他想法可以让这更快?我考虑过多线程,但一个简短的实验产生了令人不快的结果。你可以使用显式循环来代替视图
SV
。如果你用的是Julia≤ 1.4然后对视图进行堆分配,这可以增加和/或减少优化机会。您还可以使用
extrema
在数据的一次传递中计算最小值和最大值。我编辑了这个答案,添加了一个版本,其中最大值/最小值的计算是通过显式循环完成的,这大大加快了速度。在我的笔记本电脑中,我变得更好了