Matlab:预定义有帮助的对象还是不预定义更快?

4

我将使用matlab进行非常大矩阵的计算。 我已经尽可能地使用了矩阵运算等,现在正在尝试微调。

假设A、B、C和D是矩阵:

C=A*B;
D=cos(C);

如果我没记错的话,以下操作似乎更快:

D=cos(A*B)

我的问题是如果预定义对象被多次调用,那么是否执行速度更快:

D=f1(A*B) + f2(A*B) + …;

与其预定义C=A*B(这样可以节省很多计算,我想)。我有很多这样的表达式,因此一些通用的见解会很有用(至少要知道它依赖哪种参数,例如矩阵大小)。


3
似乎这是你可以轻松进行基准测试的事情。在某些情况下(通常以使代码不那么模块化和难以理解为代价),内联代码可以更快,但性能将取决于诸多因素,例如“A”和“B”的大小以及您的代码对即时编译器的易读程度。此外,请勿过早地进行优化。 - horchler
@Numrok 为什么 D=cos(A*B)C = A * B; D = cos(C) 快得多?我不明白。 - Matthew Gunn
我原本以为因为你保存了一些东西,所以将其保存到内存中。现在你提到了这一点,似乎确实很愚蠢,这应该会显著减慢计算速度。我之所以首先考虑这个问题的原因是我的程序无法运行,因为显然我的启动盘太小了。 - Wolpertinger
2个回答

5

根据我的经验,我知道改变以下内容:

y = f1(A*B) + f2(A*B)...

为了

C = A*B;
y = f1(C) + f2(C)...

在优化代码的场景下,当针对中间变量“C”的操作被多次执行时,使用这种方式会更快。如果只执行一次操作,则不太可能产生性能改进或退化,因为我认为Matlab会在将变量传递到函数之前内联执行该操作。
为了证明这一点,您可以查看下面的基准函数,该函数测试变量A和B上的单个和多个操作(3次)。
底部的图表显示了结果,与上述观点相符。
function benchmark

  % test array
  testArray = 100:100:5000;  % 5000 will take quite a while - to test start with smaller (e.g. 500)
  % preallocate
  sep=zeros(numel(testArray),1);
  inline=sep;
  sepcombined = sep;
  inlinecombined = sep;
  fcnSep1    = @() sepfcn;
  fcnInline1 = @() inlinefcn;
  fcnSep2    = @() sepfcn2;
  fcnInline2 = @() inlinefcn2;
  % set up array counter
  count = 1;
  % run throuh all tests
  for i=testArray
    % create A&B
    A = zeros(i,i)+2;
    B = A+1;
    % run single actions
    sep(count)    = timeit (fcnSep1);
    inline(count) = timeit (fcnInline1);
    % combined actions
    sepcombined(count)    = timeit (fcnSep2);
    inlinecombined(count) = timeit (fcnInline2);
    % increment the counter
    count = count + 1;
    % monitor progress
    disp ( i );
  end
  % use nested functions for the actions
  function sepfcn
    C = A*B;
    sum(C);
  end
  function inlinefcn
    sum(A*B);
  end
  function sepfcn2
    C = A*B;
    sum(C)+max(C)+min(C);
  end
  function inlinefcn2
    sum(A*B)+max(A*B)+min(A*B);
  end
  %% plot the results
  figure;
  subplot ( 2, 1, 1 );
  plot ( testArray, sep, 'r-', testArray, inline,'b-' );
  legend ( 'sep', 'inline' )
  title ( 'single action' );
  ylabel ( 'time (s)' )
  xlabel ( 'matrix size' )
  subplot ( 2, 1, 2 );
  plot ( testArray, sepcombined, 'r-', testArray, inlinecombined,'b-' );
  legend ( 'sep', 'inline' )
  title ( 'multiple actions' );
  xlabel ( 'matrix size' )
  ylabel ( 'time (s)' )
end

enter image description here


1
而且不重复自己是一个好的实践,从而减少错误的机会,提高可读性,降低维护成本。 - Nick

0

是的,您可以通过将代码从像这样的语句更改为加快速度:

D=f1(A*B) + f2(A*B) + …;

像这样的语句:

C = A * B;

D=f1(C) + f2(C) + …;

因为明显执行的乘法较少。我看过很多Matlab代码,由于作者只是在复制和粘贴,所以重复表达式。

至少,将有更少的表达式需要维护和调试。因此,一般情况下不要重复自己。


1
你测试过这个吗?创建变量C需要时间和内存。然后还有Matlab的JIT编译器,它可能能够优化像f1(A*B)+f2(A*B)这样的语句... 你有这些说法的任何证据吗?我想这不是绝对的肯定或否定。 - David
@David 我“猜测”,只要有足够的内存,预计算A*B应该会更快。如果不再需要,可以随时清除内存中的AB - Robert Seifert
@David,我没有计时,但JIT将分配和使用相同的内存,无法避免。采用这种方式更有说服力的论据是不重复表达式,从而减少错误机会,提高可读性,减少维护成本。 - Nick

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接