【问题标题】:Julia multiply each matrix along dimJulia 将每个矩阵沿 dim 相乘
【发布时间】:2017-05-05 09:45:05
【问题描述】:

我有一个 3 维数组

x = rand(6,6,2^10)

我想将沿第三维的每个矩阵乘以一个向量。有没有比这样做更干净的方法:

y = rand(6,1)
z = zeros(6,1,2^10)
for i in 1:2^10
    z[:,:,i] = x[:,:,i] * y
end

【问题讨论】:

    标签: julia matrix-multiplication


    【解决方案1】:

    如果您正在使用矩阵,将x 视为矩阵向量而不是 3D 数组可能是合适的。那你就可以了

    x = [rand(6,6) for _ in 1:2^10]
    y = [rand(6)]
    z = x .* y
    

    z 现在是向量的向量。

    如果z 是预先分配的,那将是

    z .= x .* y
    

    而且,如果你想要非常快,请使用 StaticArrays 的向量

    using StaticArrays
    
    x = [@SMatrix rand(6, 6) for _ in 1:2^10]
    y = [@SVector rand(6)]
    z = x .* y
    

    在我的计算机上显示了 10 倍的加速,运行时间为 12us。

    【讨论】:

    • 这只是一个虚拟变量。例如,我本可以使用i,但通常让_ 表示一个不再使用的一次性变量,并且名称并不重要。
    【解决方案2】:

    mapslices(i->i*y, x, (1,2)) 可能更“干净”,但会更慢。

    读作:将函数“times by y”应用于前两个维度的每个切片。

    function tst(x,y)
       z = zeros(6,1,2^10)
       for i in 1:2^10
           z[:,:,i] = x[:,:,i] * y
       end
       return z
    end
    
    tst2(x,y) = mapslices(i->i*y, x, (1,2))
    

    time tst(x,y); 0.002152 秒(4.10 k 分配:624.266 KB)

    @time tst2(x,y); 0.005720 秒(13.36 k 分配:466.969 KB)

    【讨论】:

    • 我同意这个解决方案更“干净”,但另一方面我也觉得不太清楚发生了什么。
    • 也许...虽然我同意@DNF 的观点,如果您只想迭代该维度,那么矩阵向量将更具可读性。
    【解决方案3】:

    sum(x.*y',2) 是一个简洁的解决方案。

    它还具有良好的速度和记忆特性。诀窍是将矩阵向量乘法视为由向量元素缩放的矩阵列的线性组合。我们没有对矩阵 x[:,:,i] 进行每个线性组合,而是对 x[:,i,:] 使用相同的尺度 y[i]。在代码中:

    const x = rand(6,6,2^10);
    const y = rand(6,1);
    function tst(x,y)
        z = zeros(6,1,2^10)
        for i in 1:2^10
            z[:,:,i] = x[:,:,i]*y
        end
        return z
    end
    tst2(x,y) = mapslices(i->i*y,x,(1,2))
    tst3(x,y) = sum(x.*y',2)
    

    基准测试给出:

    julia> using BenchmarkTools
    julia> z = tst(x,y); z2 = tst2(x,y); z3 = tst3(x,y);
    julia> @benchmark tst(x,y)
      BenchmarkTools.Trial: 
        memory estimate:  688.11 KiB
        allocs estimate:  8196
        --------------
        median time:      759.545 μs (0.00% GC)
        samples:          6068
    julia> @benchmark tst2(x,y)
      BenchmarkTools.Trial: 
        memory estimate:  426.81 KiB
        allocs estimate:  10798
        --------------
        median time:      1.634 ms (0.00% GC)
        samples:          2869
    julia> @benchmark tst3(x,y)
      BenchmarkTools.Trial: 
        memory estimate:  336.41 KiB
        allocs estimate:  12
        --------------
        median time:      114.060 μs (0.00% GC)
        samples:          10000
    

    所以使用sumtst3 具有更好的性能(大约是tst 的7 倍和大约是tst2 的15 倍)。

    按照@DNF 的建议使用StaticArrays 也是一种选择,最好将其与此处的解决方案进行比较。

    【讨论】:

    • reducedim(+, x.*y', 2)sum(x.*y', 2)有区别吗?
    • 并非如此。嗯,是的,sum 更好。我将编辑以反映这一点。谢谢。
    • 顺便说一句,要真正优化,将索引的顺序更改为 (6,2^10,6) 并使用循环手动编码操作,@inbounds 可以获得另一个 10x乙>。这是为了让内存布局和索引计算更容易。
    • @DNF 和 DanGetz:是否有使用 TensorOperations 包的等效操作?如果是这样,它的表现如何?编辑:也许@tensor z[a,b,c] = x[a,d,c]*y[d,b]
    • @rickhg12hs 如果将y 定义为random(6)(即向量而不是矩阵),则建议的表达式有效,甚至tst4(x,y) = @tensor z[a,c] := x[a,b,c]*y[b] 也有效。性能很快!与tst3 大致相同,使其在速度(和内存)方面打成平手
    猜你喜欢
    • 2018-01-21
    • 1970-01-01
    • 1970-01-01
    • 2013-07-07
    • 2018-07-09
    • 2011-11-24
    • 2019-11-15
    • 2019-10-19
    • 1970-01-01
    相关资源
    最近更新 更多