【发布时间】:2020-12-12 02:22:59
【问题描述】:
问题说明:矩阵的行范数
考虑这个玩具示例,我计算随机矩阵 M 的所有列的范数
julia> M = rand(Float64, 10000, 10000);
julia> @time map(x -> norm(x), M[:,j] for j in 1:size(M)[2]);
0.363795 seconds (166.70 k allocations: 770.086 MiB, 27.78% gc time)
然后计算行范数
julia> @time map(x -> norm(x), M[:,i] for i in 1:size(M)[1]);
1.288872 seconds (176.19 k allocations: 770.232 MiB, 0.37% gc time)
两次执行之间的因素是(我认为)矩阵的内存布局(主要列)。实际上,行规范的计算是对非连续数据的循环,这会导致缓存未命中的非向量化代码。 我希望两种规范计算的执行时间相同。
在计算行的范数时是否可以将M的布局转换为行主要以获得相同的速度?
我做了什么
我尝试使用 transpose 和 permutedims 没有成功,似乎在使用这些函数时,内存现在是行优先的(所以原始矩阵的主要列)。
julia> Mt = copy(transpose(M));
julia> @time map(x -> norm(x), Mt[j,:] for j in 1:size(M)[2]);
1.581778 seconds (176.19 k allocations: 770.230 MiB)
julia> Mt = copy(permutedims(M,[2,1]));
julia> @time map(x -> norm(x), Mt[j,:] for j in 1:size(M)[2]);
1.454153 seconds (176.19 k allocations: 770.236 MiB, 9.98% gc time)
我在这里使用copy 来尝试强制使用新布局。
如何强制转置的列优先布局,或原始矩阵的行优先布局?
编辑
正如@mcabbott 和@przemyslaw-szufel 所指出的,我显示的最后一个代码中有一个错误,我计算了Mt 行的范数而不是列的范数。
对Mt的列范数的检验改为:
julia> Mt = transpose(M);
julia> @time map(x -> norm(x), M[:,j] for j in 1:size(M)[2]);
1.307777 seconds (204.52 k allocations: 772.032 MiB, 0.45% gc time)
julia> Mt = permutedims(M)
julia> @time map(x -> norm(x), M[:,j] for j in 1:size(M)[2]);
0.334047 seconds (166.53 k allocations: 770.079 MiB, 1.42% gc time)
所以最后看来permutedims 以列为主存储,正如预期的那样。事实上,Julia 数组总是以列为主。 transpose 是一种例外,因为它是列优先存储矩阵的行优先view。
【问题讨论】:
-
我刚刚发现this thread 是相关的,但它已经很老了
-
我认为所有这 4 个计算相同的结果。前两个是相同的条定时噪声,但
map(norm, eachcol(M))会更快。请注意,copy(transpose(M))是permutedims(M),两者都返回一个新的Array(它始终是列主要的)并移动数据,而transpose(M)是一个包装器,具有行主要存储。 -
相关问题:github.com/JuliaLang/julia/issues/34830 about
norm(A; dims), github.com/JuliaLang/julia/issues/38774 aboutview(transpose(A), i,:).
标签: julia