给定矩阵A
,我需要与其他n
向量Bi
(即i=1...n
)相乘。 A
的大小可能类似于5000x5000
,因此Bi
的大小类似于5000x1
。
如果我按以下方式评估产品:
for i=1:n
product=A*Bi;
% do something with product
end
结果比计算产品的方式(数量级)慢:
%assume that S is a matrix that contains the vectors Bi as columns, i.e. S(:,i)=Bi, then:
results=A*S; %stores all the products in matrix form
% do something with results
问题是向量n
的数量Bi
可能太大而无法存储在内存中,例如n=300000
,所以我需要每次都使用循环方法我评估产品,使用它,然后丢弃向量Bi
。
为什么这种方法与直接乘法相比这么慢,有没有办法克服这个问题?
答案 0 :(得分:4)
您可以尝试循环批量,例如
for i = 0:(n/k)-1
product = A*S(:,(i*k+1):(i+1)*k)
end
并调整k
以找到最佳的速度和记忆权衡。
MATLAB的循环很慢,因为它是一种解释型语言。所以它必须在运行中解决很多问题。由于JIT编译器,这些天的循环得到了极大的改进,但是与用C编写和编译的内置函数相比,它们仍然很慢。此外,它们使用真正尖端的超快速矩阵乘法算法,通过循环实现你相当天真的算法,这也有助于你所经历的加速。
答案 1 :(得分:3)
为简单起见,我的答案将采用n×n方阵A,但对于非正方形也是如此。
你的循环方法使用矩阵向量乘法。天真的解决方案也是最为人所知的,导致O(n ^ 2)的运行时间重复n次。最终总运行时间为O(n ^ 3)。
对于矩阵乘法,有一种更好的方法。最着名的算法只需要少于O(n ^ 2.4)的运行时间,这使得它对于大数字来说要快得多。
使用矩阵乘法一次乘以多个向量Bi时,您将获得更好的运行时间。这将无法实现纯矩阵乘法的性能,但使用较大的b片段可能是最快的内存有效解决方案。
针对不同讨论方法的一些代码:
n=5000;
k=100;
A=rand(n,n);
S=rand(n,n);
workers=matlabpool('size');
%for a parfor solution, the batch size must be smaller because multiple batches are stred in memory at once
kparallel=k/workers;
disp('simple loop:');
tic;
for i = 1:n
product = A*S(:,n);
end
toc
disp('batched loop:');
tic;
for i = 1:(n/k)
product = A*S(:,(i-1)*k+1:(i)*k);
end
toc
disp('batched parfor loop:');
tic;
parfor i = 1:(n/kparallel)
product = A*S(:,(i-1)*kparallel+1:(i)*kparallel);
end
toc
disp('matrix multiplication:');
tic;
A*S;
toc
答案 2 :(得分:1)
除了@Dan's answer之外,您可以尝试并行,只要您有足够的内核和足够大的操作来使其盈利(有关this answer的内存消耗的更多详细信息,请参阅parfor
) :
parfor ii = 0:(n/k)-1
product = A*S(:,(ii*k+1):(ii+1)*k)
end
我无法在docs on mtimes
(*
运算符)中看到它是否是隐式多线程的,但我认为它值得一试。
答案 3 :(得分:0)
为了将每个数组与矩阵进行乘法运算,只需将矩阵与一个矩阵相乘,该矩阵将所需的数组作为列。
所以,如果你想检查一下
如果
size(a)=3,3
然后
a*b==horzcat(a*b(:,1),a*b(:,2),a*b(:,3))
是真的
通过这种方式,您可以节省大量的时间