Matlab子矩阵乘法性能差

时间:2017-03-28 22:23:33

标签: matlab

matlab中子系数的乘法似乎比它们从中得到的矩阵的乘法要慢得多。

>> m = rand(1e7, 40);
>> tic; m' * m; toc % (1)
Elapsed time is 0.245803 seconds.
>> tic; m(1:2.5e6, :)' * m(1:2.5e6, :); toc % (2)
Elapsed time is 1.810981 seconds.
>> tic; t = m(1:2.5e6, :); t' * t; toc % (3)
Elapsed time is 0.885764 seconds.

我原本希望有一些快速内置的方法,因为数据已经在内存中,但似乎没有办法阻止matlab制作中间副本。 (3)我们制作副本的速度更快但是很野心。

matlab中是否有任何技术可以在矩阵的子集上快速进行操作(例如,多重转换,转置)?

使用mex实现这一目标的唯一快捷方式是什么?

编辑:使用列主要数据可以全速提升速度(正如预期的那样),但在将子系统倍增时仍然会慢得多。

>> m = rand(40,1e7);
>> tic; m * m'; toc
Elapsed time is 0.251958 seconds.
>> tic; m(:, 1:2.5e6) * m(:, 1:2.5e6)'; toc
Elapsed time is 1.461321 seconds.
>> tic; s=m(:, 1:2.5e6); s * s'; toc
Elapsed time is 0.555667 seconds.

显然matlab在索引时会复制,但有没有办法防止这种情况(显然这样的乘法算法可以存在而不复制数据,我只想知道它是否可以在matlab中表达)。

2 个答案:

答案 0 :(得分:2)

这是更多的测试结果。

已经测试了五种执行矩阵乘法的方法,其中3种涉及子矩阵。正如@Cris指出的那样,如果使用rand(1e7,40)可能会有所不同,因此测试了另一整套。

已经使用10次重复循环和Profiler来提高准确性。测试了具有丰富RAM的i7。

测试代码

% clear;clc;close all

A = rand(1e7, 40);
for ii = 1:10
    m = A;
    m(end) = m(end-1);

    m' * m; % 1

    n = m';
    n * m; % 2

    m(1:2.5e6, :)' * m(1:2.5e6, :); % 3

    t = m(1:2.5e6, :);
    t' * t; % 4

    t2 = t';
    t2 * t; % 5

    clearvars -except A
end
clearvars A
B = rand(40, 1e7);
for ii = 1:10
    m = B;
    m(end) = m(end-1);

    m * m'; % 1

    n = m';
    m * n; % 2

    m(:,1:2.5e6) * m(:,1:2.5e6)'; % 3

    t = m(:,1:2.5e6);
    t * t'; % 4

    t2 = t';
    t * t2; % 5

    clearvars -except B
end

Profiler结果

Total time for each method

Profiler screenshot

评论

  1. 任何小于10%的时差都被视为相同。
  2. 在每个循环开始时,矩阵被强制复制一个简单的赋值。副本很慢(11.5秒)。
  3. 对于完整矩阵,MxN和NxM维度之间没有差异。然而,对于子矩阵测试,40x2.5e6显然更快。
  4. 缓冲转置会使整个过程减慢100%。我认为这是因为Matlab失去了优化的能力;可能如果一个类型m'*m它识别模式并跳过转置操作。
  5. 未优化子集和转置。
  6. 缓冲子集确实加速了乘法。

答案 1 :(得分:1)

MATLAB执行写时复制,这意味着复制矩阵并不真正复制数据,至少在您尝试更改指向相同数据的两个矩阵之一之前。但是,复制矩阵的一部分时,始终会复制数据。也就是说,矩阵从不指向不同矩阵的值的子集。 MATLAB总是将数据连续存储在内存中(列主要排序),因此很少会出现您索引的矩阵部分在内存中连续的情况。尝试这一点的一种方法是使用format debug并查看数据指针:

>> format debug
>> q=rand(10,100)
q =
Structure address = 127e64560
m = 10
n = 100
pr = 7f9f5c835420
pi = 0
  Columns 1 through 9
    0.8147    0.1576    0.6557    0.7060    0.4387    0.2760    0.7513    0.8407    0.3517
    ...

>> q(:,1:2)
ans =
Structure address = 11dadd750
m = 10
n = 2
pr = 7f9f5b792700
pi = 0
  0.8147    0.1576
  ..

注意pr值(指向数据的实值部分的指针)如何变化。这表明数据已被复制。

如果你不能使用矢量化代码(即在矩阵上作为一个整体应用操作),加速计算的最佳选择是MEX文件。