我有一个大矩阵A,里面有1GB的双精度数值,当我将其重塑为不同的维度时,速度非常快。
A=rand(128,1024,1024);
tic;B=reshape(A,1024,128,1024);toc
Elapsed time is 0.000011 seconds.
为什么这么快?还有一个观察结果是,在运行代码并存储两个1GB大小的矩阵后,MATLAB使用的内存比应该使用的要少: Memory used by MATLAB: 1878 MB (1.969e+09 bytes)
我有一个大矩阵A,里面有1GB的双精度数值,当我将其重塑为不同的维度时,速度非常快。
A=rand(128,1024,1024);
tic;B=reshape(A,1024,128,1024);toc
Elapsed time is 0.000011 seconds.
为什么这么快?还有一个观察结果是,在运行代码并存储两个1GB大小的矩阵后,MATLAB使用的内存比应该使用的要少: Memory used by MATLAB: 1878 MB (1.969e+09 bytes)
好性能的解释
Matlab尽可能使用写时复制。如果你编写像B=A
这样的表达式,MATLAB不会复制A,而是两个变量A
和B
都是对同一数据结构的引用。只有当这两个变量中的一个将被修改时,MATLAB才会创建副本。
现在来看reshape
的特殊情况。在这里,A和B看起来不同,但在内存中它们是相同的。保存数据的基础数组不受reshape
操作的影响,无需移动任何内容:all(A(:)==B(:))
。调用reshape时,MATLAB所需要做的就是创建一个新的引用,并使用矩阵的新维度进行注释。 重塑矩阵只不过是创建对输入数据的新引用,并用新的维度进行注释。reshape的运行时间少于1微秒,大约等于执行两个简单赋值B=A
所需的时间。对于所有实际应用程序而言,这都是一个零时间操作。
>> tic;for i=1:1000;B=reshape(A,1024,128,1024);end;toc
Elapsed time is 0.000724 seconds.
>> tic;for i=1:1000;B=A;end;toc
Elapsed time is 0.000307 seconds.
目前并不清楚这样的引用到底有多大,但我们可以假设它在几个字节以内。
其他零成本操作
已知具有几乎零成本(运行时和内存)的函数:
B=reshape(A,sz)
B=A(:)
B=A.'
- 仅适用于向量B=A'
- 仅适用于实数向量,没有属性 complex
。使用 .'
代替。B=permute(A,p)
- 仅适用于all(A(:)==B(:))
的情况。1B=ipermute(A,p)
- 仅适用于all(A(:)==B(:))
的情况。1B=squeeze(A)
1shiftdim
- 仅适用于all(A(:)==B(:))
的情况,包括以下情况:1
无论它们是否触及内存表示,以下函数都是“昂贵”的(all(A(:)==B(:))
为真)
B(1:numel(A))=A;
2(:)
之外的右侧索引,包括B=A(1:end);
和B=A(:,:,:);
21 运行时比reshape
慢得多,介于1微秒和1毫秒之间。可能是由于某些常量计算开销。内存消耗几乎为零,运行时间与输入大小无关。没有此注释的操作运行时低于1微秒,大致相当于reshape
。
2在OCTAVE中成本为零
本文最初使用MATLAB 2013b编写,用MATLAB 2019b确认了数据。
B(1:numel(A)) = A
这样的整个数据复制,这可以通过B=A(或变体)在零时间成本下完成,正如您所解释的那样...]那么,我如何减少例如B(1:lenx:end, j) = A(i, 1:leny:end).'
的成本?您知道一种(很多)更快的方法吗? - Fat32all(A(:)==B(:))
实际上是正确的? - Daniel