每个矩阵I具有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
每个矩阵I具有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
如果使用矩阵工作,也可适当将x
视为矩阵的向量而不是3D阵列。那么你可以做
x = [rand(6,6) for _ in 1:2^10]
y = [rand(6)]
z = x .* y
z
现在是一个载体的载体。
如果z
预先分配,这将是
z .= x .* y
而且,如果你想它的真快,使用这显示在我的电脑上10倍的加速比StaticArrays
using StaticArrays
x = [@SMatrix rand(6, 6) for _ in 1:2^10]
y = [@SVector rand(6)]
z = x .* y
载体,运行在12us。
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ķ分配:624.266 KB)
@time tst2(x,y);
0.005720秒(13.36ķ分配:466.969 KB)
我会同意这个解决方案更“干净”,但另一方面我也不清楚发生了什么。 –
也许...虽然我会同意@DNF,如果你只是想迭代这个维度,那么矩阵的矢量将更具可读性。 –
sum(x.*y',2)
是一个简洁的解决方案。
它也具有良好的速度和记忆性能。诀窍是将矩阵向量乘法看作由向量元素缩放的矩阵列的线性组合。我们对x [:,i:]使用相同的尺度y [i],而不是对矩阵x [:,: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
所以tst3
sum
具有更好的性能(〜7倍以上tst
和15X〜在tst2
)。
按@DNF的建议使用StaticArrays
也是一种选择,并且将它与此处的解决方案进行比较将会很好。
'reducedim(+,x。* y',2)'和'sum(x。* y',2)'是否有区别? – DNF
不是。嗯,是的,'sum'比较好。我将编辑以反映这一点。谢谢。 –
顺便说一句,要真正优化,将索引的顺序改为(6,2^10,6),并使用循环和'@ inbounds'手动编码操作可以获得另一个** 10x **。这是为了使内存布局和索引计算更容易。 –
'_'如何在理解中工作? –
这只是一个虚拟变量。例如,我可以使用'i',但通常让'_'表示一个一次性使用的变量,它不被进一步使用,并且哪个名称不重要。 – DNF