在条件下访问矩阵元素

Access matrix element in condition

我正在尝试减少我的 MatLab 代码的计算时间。为此,我使用 MatLab profiler.

在某些函数中我遇到了同样的情况。我遍历一个网格(一个二维矩阵)并测试每个单元格是否有(或没有)一些值(每次两个)。而且病情需要很长时间。大部分时间花在这些功能上。

这是我的代码中的一个示例:

  time      Calls    line
                      16   function tGrid=some_compute(grid, tGrid, trans)
  0.005       125     17     global depth width tWidth 
                      18
< 0.001       125     19     for i=1:depth 
  0.022    125000     20       for j=1:width 
  2.270  37500000     21         if (grid(i, j)~=0 && grid(i, j)~=1) 
                      22
                      23           % Get the transformed coordinates of the current cell
  0.864     79997     24           [x, y]=get_trans(trans, i, j); 
                      25
  0.006     79997     26           if (x~=-1 && y~=-1) 
  0.006     79992     27             tGrid(x, y)=grid(i, j); 
  0.004     79992     28           end % If x~=-1 && y~=-1 
  0.004     79997     29         end % If grid~=0 && grid~=1 
  1.933  37500000     30       end % For j=width 
  0.008    125000     31     end % For i=depth 
                      32
< 0.001       125     33   end

此函数共调用125次,耗时5.24s。

正如我们所见,第21行花费了更多的时间来执行。虽然 grid(i, j) 在条件中被访问了两次,并且也在第 27 行中使用了,但我猜想通过将它存储在一个变量之前,它会加速我的代码。

所以,我做了这个简单的修改:

  time      Calls    line
                      16   function tGrid=some_compute(grid, tGrid, trans)
  0.005       125     17     global depth width tWidth
                      18
< 0.001       125     19     for i=1:depth
  0.021    125000     20       for j=1:width
  2.062  37500000     21         val=grid(i, j);
  1.681  37500000     22         if (val~=0 && val~=1)
                      23
                      24           % Get the transformed coordinates of the current cell
  0.793     79997     25           [x, y]=get_trans(trans, i, j);
                      26
  0.005     79997     27           if (x~=-1 && y~=-1)
  0.005     79992     28             tGrid(x, y)=val;
  0.004     79992     29           end % If x~=-1 && y~=-1
  0.004     79997     30         end % If grid~=0 && grid~=1
  1.731  37500000     31       end % For j=width
  0.007    125000     32     end % For i=depth
                      33
< 0.001       125     34   end

而现在,这个函数调用125次总共需要6.32s。

正如我们所见,获取单元格的值所花费的时间与获取它两次并将其与两个值进行比较所花费的时间一样多。第 22 行的 if 和第一个版本一样慢。我不明白为什么。

我不能告诉你到底发生了什么,因为我不知道底层的 MATLAB 库是如何实现的。但是,出现的结果可能是有原因的。

如果我没有算错的话,您正在使用 dense 1000x300 矩阵,这是一个包含 300.000 个浮点数的数组。

来自这一行

2.062  37500000     21         val=grid(i, j);

您可以计算出单次执行大约需要 55 纳秒(时间/调用 * 10^9),这对于简单的数据访问来说是相当长的时间。如果你有一个 2GHz 处理器,一个处理周期需要 0.5 纳秒。那将是 110 个周期。但是,由于您使用的是一个巨大的密集矩阵,您可能会在这里面临很多缓存未命中。可以肯定的是,大幅减小矩阵大小(从 40x12 开始)并计算每次执行的时间。如果您有缓存未命中问题,它应该下降到大约 1-2 纳秒。

如果缓存未命中确实是问题所在,我担心您的问题并没有真正简单的解决方案,因为它需要以内存友好的方式重组数据。 Matlab 是一种脚本语言这一事实​​并没有使它变得更容易,因为您没有为您执行优化的编译器。你可以尝试切换内循环和外循环,希望内存访问模式变得更好。

问候

getting the value of the cell take as much time as getting it twice and compare it to two values. [...] I don't understand why.

这是因为您的代码 运行 在 JIT(即时编译器)下。该编译器优化您的代码。尽管没有记录它究竟是如何工作的以及实施了什么样的优化,但从您的实验中可以清楚地看出 grid(i, j)~=0 && grid(i, j)~=1 被优化为仅获取值 grid(i,j) 一次。