【问题标题】:why arrayfun does NOT improve my struct array operation performance为什么 arrayfun 没有提高我的结构数组操作性能
【发布时间】:2012-06-25 13:44:22
【问题描述】:

这是输入数据:

  % @param Landmarks:
  %           Landmarks should be 1*m struct. 
  %           m is the number of training set.
  %           Landmark(i).data is a n*2 matrix

功能:

  function Landmarks=CenterOfGravity(Landmarks)
  % align center of gravity

  for i=1 : length(Landmarks)
      Landmarks(i).data=Landmarks(i).data - ones(size(Landmarks(i).data,1),1)...
          *mean(Landmarks(i).data);
  end
  end

new 使用 arrayfun 的函数:

  function [Landmarks] = center_to_gravity(Landmarks)
  Landmarks = arrayfun(@(struct_data)...
                          struct('data', struct_data.data - repmat(mean(struct_data.data), [size(struct_data.data, 1), 1]))...
                                              ,Landmarks);
  end %function center_to_gravity

在使用分析器时,我发现时间的使用不是我所期望的:

  Function          Total Time    Self Time*
  CenterOfGravity     0.011s      0.004 s
  center_to_gravity   0.029s      0.001 s

谁能告诉我为什么?

顺便说一句...我不能将“arrayfun”添加为我的声誉的新标签。

【问题讨论】:

    标签: matlab struct profiler vectorization


    【解决方案1】:

    使用arrayfun 不能算作“向量化代码”,正如每篇 Matlab 性能博客文章中所描述的那样。

    如果您的 .data 字段对于所有地标条目的长度相同,您可以通过首先将所有数据放入单个 DATASIZE-BY-LANDMARKSIZE 矩阵,然后运行此命令来矢量化此代码

    meanRemovedData = bsxfun(@minus, data, mean(data,1));
    

    但是这样你会失去很多代码清晰度。 (我很确定bsxfun 通常具有类似矢量化的速度优势,但我今天早上还没有进行任何测试。)


    就原因而言,我真的不是问这个问题的合适人选。但是向量化的许多优点都依赖于对连续的内存块执行简单的操作。存储在结构数组中的数据(我相信)存储为指向不同内存位置的指针数组,这就是为什么您可以在不重新分配整个结构数组的情况下更改 Landmarks(i).data 的大小或类的原因。

    【讨论】:

      【解决方案2】:

      考虑以下三个实现(全部使用 BSXFUN 进行矢量化):

      function s = func1(s)
          for i=1:numel(s)
              s(i).data = bsxfun(@minus, s(i).data, mean(s(i).data));
          end
      end
      
      function v = func2(s)
          v = arrayfun(@(ss) bsxfun(@minus,ss.data,mean(ss.data)), ...
              s, 'UniformOutput',false);
          v = struct('data',v);
      end
      
      function v = func3(s)
          v = arrayfun(@(ss) struct('data',bsxfun(@minus,ss.data,mean(ss.data))), ...
              s, 'UniformOutput',true);
      end
      

      解释:

      • 首先使用 for 循环遍历结构数组。
      • 第二次使用 ARRAYFUN 返回数据矩阵的元胞数组,然后将其传递给 STRUCT 以构建结构数组。
      • 最后一个使用 ARRAYFUN 并在每次迭代时直接构建一个结构。

      这是一个比较时间的简单测试:

      function testArrayStruct()
          %# sample array of structures
          s = struct('data',[]);
          for i=5000:-1:1
              s(i).data = rand(randi(1000),2);
          end
      
          %# timing
          tic; v1 = func1(s); toc
          tic; v2 = func2(s); toc
          tic; v3 = func3(s); toc
      
          %# check all have the same output
          assert(isequal(v1,v2,v3))
      end
      

      结果:

      Elapsed time is 0.357796 seconds.         %# func1
      Elapsed time is 0.427568 seconds.         %# func2
      Elapsed time is 0.537971 seconds.         %# func3
      

      所以你可以看到基于循环的解决方案实际上是最快的..

      【讨论】:

        【解决方案3】:

        感谢 Amro 和 Pursuit 对我的问题的热情。

        我从 Jan Simon 获得了 Matlab 答案中的最佳解决方案:

        why arrayfun does NOT improve my struct array operation performance

        有一些点确实可以提高性能:

        1. 令人惊讶的是,SUM/LENGTH 比 MEAN 快
        2. timeit 可以给出更准确的结果。
        3. 最快的方法使用这样的技巧:

          m = sum(data, 1) / size(data, 1); 数据(:, 1) = 数据(:, 1) - m(1);

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2021-07-24
          • 2016-02-15
          • 2017-09-23
          • 1970-01-01
          • 1970-01-01
          • 2019-03-13
          • 2014-11-29
          • 2018-02-16
          相关资源
          最近更新 更多