在Julia中有效地向矩阵添加标量 [英] Adding a scalar to a matrix efficiently in Julia

查看:115
本文介绍了在Julia中有效地向矩阵添加标量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to add a scalar to all elements of a huge matrix. The matrix will be as big as possible. In the example I will use a size of 2 GiB but in my real computation it will be much larger.

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

如果我执行

A += 1.0

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

Julia allocates an additional 2 GiB of memory. The operation takes about 1s. I could use a for loop:

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

这不会分配任何内存,但是需要一分钟.这两种方法对我都不可行,因为第一种违反了内存限制,第二种显然效率低下.对于逐元素乘法,有scal!,它使用BLAS.有什么方法可以像使用scal!一样有效地执行加法运算?

This does not allocate any memory, but it takes one minute. Both approaches are not viable for me, because the first one violates memory constraints and the second is clearly inefficient. For element-wise multiplication there is scal!, which uses BLAS. Is there any way of performing addition as effciently as multiplication using scal!?

推荐答案

@DSM的答案很好.不过,我还要解决许多其他问题. for循环缓慢的原因是A是一个非常量全局变量,并且您的代码直接对该全局变量进行了突变.由于A是非恒定的,因此代码必须防止在循环执行期间的任何时刻A变为具有不同类型的不同值的可能性.代码必须在循环的每次迭代中查找A的类型和位置,并在表达式A[ii, jj] = A[ii, jj] + 1.0中动态分派方法调用-这是对getindex+setindex!的调用其中取决于A的静态未知类型.仅通过在函数中执行以下工作即可立即获得更好的性能:

@DSM's answer is a good one. There are a number of things going on here that I'd like to address in addition, however. The reason your for loop is slow is because A is a non-constant global variable and your code is directly mutating that global. Since A is non-constant, the code has to guard against the possibility of A becoming a different value with a different type at any point during the execution of the loop. The code has to look up the type and location of A on every iteration of the loop and dynamically dispatch the method calls in the expression A[ii, jj] = A[ii, jj] + 1.0 – that's a call to getindex, + and setindex!, all of which depend on the statically unknown type of A. You can immediately get much better performance just by doing this work in a function:

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)

性能提示部分.您可能还需要仔细阅读本章的其余部分.

Avoiding non-constant globals like this is the first recommendation in the Performance Tips section of the manual. You'll probably want to peruse the rest of this chapter as well.

我们可以通过使用@inbounds批注来指示此代码不需要边界检查,并使用线性索引而不是二维索引,可以进一步提高inc!函数的性能:

We can further improve the performance of the inc! function using the @inbounds annotation to indicate that bounds checks aren't necessary for this code, and by using linear indexing instead of two-dimensional indexing:

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批注,并且只有在两者都可以确定索引不能超出范围并且性能才是最重要的情况下,才应使用.正如您所看到的,附加的性能改进虽然存在,但并没有压倒一切.大多数好处来自于不直接突变全局变量.

Most of the speedup is from the @inbounds annotation rather than the linear indexing, although that does give a little speed boost. The @inbounds annotation should be used sparingly, however, and only where one is both certain that the indexing cannot be out of bounds and performance is of the utmost importance. As you can see, the additional performance improvement while existent, is not overwhelming. Most of the benefit comes from not directly mutating global variables.

这篇关于在Julia中有效地向矩阵添加标量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆