提高Julia中for循环的速度
这是我在Julia平台上的代码,我喜欢加速它。有没有什么方法可以让这更快?50k*50k的数据集需要0.5秒。我希望Julia会比这快很多,或者我不确定我是否在做一个愚蠢的实现提高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
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
在数据的一次传递中计算最小值和最大值。我编辑了这个答案,添加了一个版本,其中最大值/最小值的计算是通过显式循环完成的,这大大加快了速度。在我的笔记本电脑中,我变得更好了