从矩阵向量中减去矩阵的最佳方法

Best way to subtract Matrix from Vector of Matrix

我想从矩阵向量中减去一个矩阵。例如,在下面定义的变量中,我想为 xl

的每个元素减去 y
xl = [Matrix{Float64}(undef, 2, 3) for i in 1:1000]
y = Matrix{Float64}(undef, 2, 3)

我知道这可以用地图函数来完成

map(x -> x-y, xl)

但是有没有更好的方法来做到这一点,或者我们可以通过多线程来减少运行时间吗?我尝试对简单地图和 ThreadsX.map 进行基准测试,发现 ThreadsX.map 比任何减少运行时间的建议都慢。

@btime map(x -> x-y, xl);          # 55.558 μs (1010 allocations: 117.59 KiB)
@btime ThreadsX.map(x -> x-y, xl); # 99.764 μs (5414 allocations: 285.47 KiB)

注意:这里的 Matrix 只是一个示例,我想在支持减法的自定义结构的大向量上执行此操作。

默认情况下,Julia 仅从一个线程开始。要使用多个线程启动 Julia,您可以使用 --threads=n 选项:

PS C:\Users\Elias> julia --threads=4
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.7.2 (2022-02-06)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> xl = [rand(2, 3) for i in 1:1000];

julia> y = rand(2, 3);

julia> using ThreadsX

julia> using BenchmarkTools

julia> @btime ThreadsX.map(x -> x-$y, $xl);
  42.700 μs (1353 allocations: 206.77 KiB)

详情请见:https://docs.julialang.org/en/v1/manual/multi-threading/

首先,map 并不是最快的,循环几乎总是能打败它。这个数组理解比 map.

快 70%
@btime [[x[i]-$y[i] for i in eachindex($y)] for x in $xl];
  33.300 μs (1001 allocations: 117.31 KiB)

现在,对于多线程速度较慢的原因,答案可能是此简单计算的多线程设置具有 non-negligible 开销。您希望对多线程进行更繁重的计算以产生显着效果。另外,不要忘记在 @btime.

计时时插入 ($)
@btime map(x -> x-$y, $xl);
  55.600 μs (1001 allocations: 117.31 KiB)

@btime $xl .- ($y,);     # broadcasting
  56.100 μs (1001 allocations: 117.31 KiB)

@btime ThreadsX.map(x -> x-$y, $xl);
  53.600 μs (1602 allocations: 242.05 KiB)

看这个更重的例子,多线程加速大约 6 倍:

julia> @btime ThreadsX.map(x -> exp.(sin.(x))-exp.(sin.($y)), $xl);
  303.700 μs (3605 allocations: 460.89 KiB)

julia> @btime map(x -> exp.(sin.(x))-exp.(sin.($y)), $xl);
  1.673 ms (3001 allocations: 336.06 KiB)