在Julia中有效地将标量添加到矩阵中

时间:2014-10-30 15:17:30

标签: math matrix julia

我需要为巨大矩阵的所有元素添加标量。矩阵将尽可能大。在示例中,我将使用2 GiB的大小,但在我的实际计算中,它将更大。

A = rand(2^14, 2^14)

如果我执行

A += 1.0

Julia分配额外的2 GiB内存。该操作大约需要1秒。我可以使用for循环:

for jj = 1:size(A, 2), ii = 1:size(A, 1)
  A[ii, jj] = A[ii, jj] + 1.0
end

这不会分配任何内存,但需要一分钟。这两种方法对我来说都不可行,因为第一种方法违反了内存约束,第二种方法明显效率低下。对于逐元素乘法,有scal!,它使用BLAS。有没有办法像使用scal!

那样有效地执行加法

2 个答案:

答案 0 :(得分:12)

@ DSM的答案很好。不过,我还有很多事情需要解决。你的for循环很慢的原因是因为A是一个非常量的全局变量而你的代码直接改变了那个全局变量。由于A是非常量的,因此代码必须防止A在执行循环期间在任何时刻以不同类型变为不同值的可能性。代码必须在循环的每次迭代中查找A的类型和位置,并在表达式A[ii, jj] = A[ii, jj] + 1.0中动态调度方法调用 - 这是对getindex的调用,{{1 }和+,所有这些都取决于setindex!的静态未知类型。只需在函数中执行此工作,即可立即获得更好的性能:

A

避免像这样的非常数全局变量是本手册Performance Tips部分的第一个建议。您可能也想仔细阅读本章的其余部分。

我们可以使用julia> A = rand(2^10, 2^10); julia> @time for jj = 1:size(A, 2), ii = 1:size(A, 1) A[ii, jj] += 1 end elapsed time: 0.288340785 seconds (84048040 bytes allocated, 15.59% gc time) julia> function inc!(A) for jj = 1:size(A, 2), ii = 1:size(A, 1) A[ii, jj] += 1 end end inc! (generic function with 1 method) julia> @time inc!(A) elapsed time: 0.006076414 seconds (171336 bytes allocated) julia> @time inc!(A) elapsed time: 0.000888457 seconds (80 bytes allocated) 注释进一步提高inc!函数的性能,以指示此代码不需要边界检查,并使用线性索引而不是二维索引:

@inbounds

大多数加速来自julia> function inc!(A) @inbounds for i = 1:length(A) A[i] += 1 end end inc! (generic function with 1 method) julia> @time inc!(A) elapsed time: 0.000637934 seconds (80 bytes allocated) 注释而不是线性索引,尽管这确实提高了一点速度。但是,应谨慎使用@inbounds注释,并且只有在确定索引不能超出范围并且性能至关重要的情况下才能使用@inbounds注释。正如您所看到的,现有的额外性能改进并非压倒性的。大多数好处来自于不直接改变全局变量。

答案 1 :(得分:6)

您可以进行就地广播操作:

julia> A = rand(2^14, 2^14); A[1:5, 1:5]
5x5 Array{Float64,2}:
 0.229662  0.680236    0.131202  0.111664   0.802698
 0.500575  0.580994    0.385844  0.983806   0.324382
 0.701694  0.577749    0.532591  0.0508955  0.94325 
 0.592929  0.00319653  0.759241  0.448704   0.706204
 0.867945  0.0413606   0.586151  0.82561    0.679233

julia> @time broadcast!(.+, A, A, 100);
elapsed time: 0.382669486 seconds (11490976 bytes allocated)

julia> A[1:5, 1:5]
5x5 Array{Float64,2}:
 100.23   100.68   100.131  100.112  100.803
 100.501  100.581  100.386  100.984  100.324
 100.702  100.578  100.533  100.051  100.943
 100.593  100.003  100.759  100.449  100.706
 100.868  100.041  100.586  100.826  100.679

仅使用总共约2G的内存。