动机:
在写出要在数万个矢量上执行的矩阵运算时,我不断遇到警告:
请求的200000x200000(298.0GB)阵列超出最大阵列大小 偏爱。创建大于此限制的阵列可能需要很长时间 时间和原因导致MATLAB无法响应。请参阅数组大小限制或 偏好小组了解更多信息。
这样做的原因是我使用diag()
来获取矩阵内积的对角线上的值。因为MATLAB通常针对向量/矩阵运算进行了优化,所以当我第一次编写代码时,我通常会使用向量化形式。然而,在这种情况下,MATLAB必须构建整个矩阵,以获得导致内存和速度问题的对角线。
实验:
我决定测试diag()
与for
循环的使用,看看在任何时候使用diag()
是否更有效:
num = 200000; % Matrix dimension
x = ones(num, 1);
y = 2 * ones(num, 1);
% z = diag(x*y'); % Expression to solve
% Loop approach
tic
z = zeros(num,1);
for i = 1 : num
z(i) = x(i)*y(i);
end
toc
% Dividing the too-large matrix into process-able chunks
fraction = [10, 20, 50, 100, 500, 1000, 5000, 10000, 20000];
time = zeros(size(fraction));
for k = 1 : length(fraction)
f = fraction(k);
% Operation to time
tic
z = zeros(num,1);
for i = 1 : k
first = (i-1) * (num / f);
last = first + (num / f);
z(first + 1 : last) = diag(x(first + 1: last) * y(first + 1 : last)');
end
time(k) = toc;
end
% Plot results
figure;
hold on
plot(log10(fraction), log10(chunkTime));
plot(log10(fraction), repmat(log10(loopTime), 1, length(fraction)));
plot(log10(fraction), log10(chunkTime), 'g*'); % Plot points along time
legend('Partioned Running Time', 'Loop Running Time');
xlabel('Log_{10}(Fractional Size)'), ylabel('Log_{10}(Running Time)'), title('Running Time Comparison');
这是测试的结果: (注意:红线代表循环时间作为一个阈值 - 并不是说总循环时间是恒定的,无论循环次数如何)
从图中可以清楚地看出,将操作分解为大约200x200平方矩阵,使用diag
比使用循环执行相同操作更快。
问题:
有人可以解释为什么我看到这些结果吗?另外,我认为通过MATLAB的更优化设计,可以在diag()
函数调用中内置处理这些大型矩阵。例如,它可以只执行i = j
索引操作。是否有一个特殊的原因可能会让人望而却步呢?
我还没有真正考虑使用分区方法对diag
的内存影响,尽管很明显随着分区大小的减少,内存需求也会下降。
答案 0 :(得分:3)
初始化:
n = 10000;
M = randn(n, n); %create a random matrix.
诊断的测试速度:
tic;
d = diag(M);
toc;
测试循环速度:
tic;
d = zeros(n, 1);
for i=1:n
d(i) = M(i,i);
end;
toc;
这将测试诊断。你的代码不是对诊断的干净测试......
Diag仅提取矩阵的对角线。如果x
和y
是向量,并且d = diag(x * y')
,则MATLAB首先构造n乘n矩阵x*y'
并在其上调用diag。这就是为什么,你得到错误,“不能构造290GB矩阵......”Matlab解释器没有以疯狂的方式优化,实现你只想要对角线并构造一个向量(而不是完整的带x*y'
的矩阵, not 发生。
不确定您是否在询问此问题,但计算d = diag(x*y')
的最快方法是x
和y
是n个1向量,只需:d = x.*y
< / p>