当乘以两个矩阵时,我尝试了以下两个选项:
1)
res = X*A;
2)
for i = 1:size(A,2)
res(:,i) = X*A(:,i);
end
我在两者中预先分配了res的内存。令人惊讶的是,我发现选项2更快。
有人能解释一下这是怎么回事吗?
编辑: 我试过了
K=10000;
clear t1 t2
t1=zeros(K,1);
t2=zeros(K,1);
for k=1:K
clear res
x = rand(100,100);
a = rand(100,100);
tic
res = x*a;
t1(k) = toc;
end
for k=1:K
clear res2
res2 = zeros(100,100);
x = rand(100,100);
a = rand(100,100);
tic
for i = 1:100
res2(:,i) = x*a(:,i);
end
t2(k) = toc;
end
答案 0 :(得分:3)
我在循环中运行两个代码1000次。平均而言(但并非总是如此),第一个矢量化代码的速度提高了3-4倍。我清除了结果变量并在启动计时器之前预分配。
x = rand(100,100);
a = rand(100,100);
K=1000;
clear t1 t2
t1=zeros(K,1);
t2=zeros(K,1);
for k=1:K
clear res
tic
res = x*a;
t1(k) = toc;
end
for k=1:K
clear res2
res2 = zeros(100,100);
tic
for i = 1:100
res2(:,i) = x*a(:,i);
end
t2(k) = toc;
end
因此,永远不要基于单次运行得出时间结论。
答案 1 :(得分:2)
这很可能是缓存的影响。在您执行第二个版本时,a
已经在缓存中,因此它具有优势。尝试创建一组独立的输入以使其公平。而且,测量例如时间可能更好。 100万次迭代,以消除由于外部效应引起的典型变化。
答案 2 :(得分:2)
我相信我可以了解两种方法之间的时间差异,以及人们获得不同相对速度的原因。
在Matlab版本2008a(或该版本附近的版本)之前,for循环在任何Matlab代码中都受到重创,因为解释器(非常易读的脚本和代码的低级实现之间的层)必须重新编写 - 每次通过for循环解释代码。
从那个版本开始,解释器逐渐变得更好,所以当运行现代版本的Matlab时,解释器可以查看你的代码并说“啊哈!我知道他在做什么,让我稍微优化一下“并且通过重新解释代码来避免它可能会遭受的打击。
我希望在相同的时间内执行矩阵乘法的两种方法,为什么for循环实现运行得更快是因为解释器的优化中的一些细节,我们凡人都不知道。
我们应该从中学到一个广泛的教训,并非所有版本都是平等的。我使用两个Matlab附件,SimBiology和并行计算工具箱来处理几个前沿案例,这两个案例(特别是如果你想让它们一起工作)都依赖于版本执行的速度,并且不时其他稳定性问题。因此,我保留了Matlab的三个最新版本,将测试我从每个版本得到相同的答案,如果我发现某些功能的问题,我偶尔会回滚到早期版本。这对大多数人来说可能有些过分,但可以让您了解版本差异。
希望这有帮助。
编辑:
为了澄清,代码矢量化仍然很重要。但是给出了一个类似的脚本:
x_slow = zeros(1,1e5);
x_fast = zeros(1,1e5);
tic;
for i=1:1e5
x_slow(i) = log(i);
end
time_slow = toc; % evaluates for me in .0132 seconds
tic;
x_fast = log(1:1e5);
time_fast = toc; % evaluates for me in .0055 seconds
基于解释器的改进,time_slow和time_fast之间的差异在过去的几个版本中有所减少。我看到的例子是2000a与2008b相比,但这取决于我的回忆。
Oli和Yuk解决了其他可能发生的问题。 time_1和time_2之间通常存在差异:
tic; x = log(1:1e5); time_1 = toc
tic; x = log(1:1e5); time_2 = toc
因此,对一百万次评估与一次评估的测试是有价值的,具体取决于内存x的位置(缓存中或否)。
希望这会有所帮助。
答案 3 :(得分:-3)
在我看来,你没有正确地乘以矩阵,你需要将来自X矩阵的第i行和A矩阵的第j列的所有乘积相加,这可能是一个原因。 看here看看它是如何完成的。