2

将两个矩阵相乘时,我尝试了以下两个选项:

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
4

4 回答 4

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

因此,永远不要根据单次运行得出时间结论。

于 2011-02-06T21:37:19.697 回答
2

这很可能是缓存的影响。 a在你做第二个版本的时候已经在缓存中,所以它有一个优势。尝试创建一组独立的输入以使其公平。此外,最好测量例如 100 万次迭代的时间,以消除由于外部影响导致的典型变化。

于 2011-02-06T21:07:12.787 回答
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 在哪里(在缓存中或没有)。

希望这再次有所帮助。

于 2011-02-06T23:30:37.637 回答
-3

在我看来,您没有正确地乘以矩阵,您需要将 X 矩阵的第 i 行和 A 矩阵的第 j 列的所有乘积相加,这可能是一个原因。看这里,看看它是如何完成的。

于 2011-02-06T21:01:53.693 回答