1

入力データは次のとおりです。

  % @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

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」を評判の新しいタグとして追加できません。

4

3 に答える 3

4

これまでに書かれたすべての Matlab パフォーマンス ブログ投稿で説明されているように、使用arrayfunは「コードのベクトル化」とは見なされません。

フィールドがランドマークのすべてのエントリに対して同じ長さである場合、.data最初にすべてのデータを 1 つの DATASIZE-BY-LANDMARKSIZE マーティクスに配置し、次にこのコマンドを実行することで、このコードをベクトル化できます。

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

しかし、そのようにすると、コードの明快さが大幅に失われます。(通常、ベクトル化のような速度の利点があると確信してbsxfunいますが、今朝はテストを行っていません。)


理由に関しては、私は本当に質問するのに適切な人ではありません。しかし、ベクトル化の利点の多くは、メモリの連続ブロックの単純な操作の実行に依存しています。構造体の配列に格納されたデータは、異なるメモリ位置へのポインターの配列として格納される (と私は信じています)。これが、Landmarks(i).data構造体配列全体を再割り当てせずにサイズまたはクラスを変更できる理由です。

于 2012-06-23T15:10:41.060 に答える
3

AmroとPursuitの私の質問に熱心に感謝します。

JanSimonからのMatlabの回答で最良の解決策が得られます。

arrayfunが構造体配列の操作パフォーマンスを改善しない理由

パフォーマンスを向上させるいくつかのポイントがあります。

  1. 驚くべきことに、SUM/LENGTHがMEANよりも高速です
  2. timeitはより正確な結果を与えることができます。
  3. 最速のアプローチは、次のようなトリックを使用します。

    m = sum(data、1)/ size(data、1); data(:、1)= data(:、1)-m(1);

于 2012-06-24T01:54:16.117 に答える
1

次の 3 つの実装を検討してください (すべて 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 ループを使用して、構造体の配列を反復処理します。
  • 2 番目は、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

したがって、ループベースのソリューションが実際に最速であることがわかります..

于 2012-06-23T22:47:18.687 に答える