5

私は、matlab で分散配列と対話分散配列を使用するのが初めてです。私が作成した並列コードは機能しますが、シリアル バージョンよりもはるかに遅く、その理由がわかりません。以下のコード例は、ボリューム データからヘッセ行列の固有値を計算します。

シリアル版:

S = size(D);
Dsmt=imgaussian(D,2,20);
[fx, fy, fz] = gradient(Dsmt);
DHess = zeros([3 3 S(1) S(2) S(3)]);
[DHess(1,1,:,:,:), DHess(1,2,:,:,:), DHess(1,3,:,:,:)] = gradient(fx);
[DHess(2,1,:,:,:), DHess(2,2,:,:,:), DHess(2,3,:,:,:)] = gradient(fy);
[DHess(3,1,:,:,:), DHess(3,2,:,:,:), DHess(3,3,:,:,:)] = gradient(fz);

d = zeros([3 S(1) S(2) S(3)]);
for i = 1 : S(1)
    fprintf('Slice %d out of %d\n', i, S(1));
    for ii = 1 : S(2)
        for iii = 1 : S(3)
            d(:,i,ii,iii) = eig(squeeze(DHess(:,:,i,ii,iii)));
        end
    end
end

パラレルバージョン:

S = size(D);
Dsmt=imgaussian(D,2,20);
[fx, fy, fz] = gradient(Dsmt);
DHess = zeros([3 3 S(1) S(2) S(3)]);
[DHess(1,1,:,:,:), DHess(1,2,:,:,:), DHess(1,3,:,:,:)] = gradient(fx);
[DHess(2,1,:,:,:), DHess(2,2,:,:,:), DHess(2,3,:,:,:)] = gradient(fy);
[DHess(3,1,:,:,:), DHess(3,2,:,:,:), DHess(3,3,:,:,:)] = gradient(fz);
CDHess = distributed(DHess);
spmd  
    d = zeros([3 S(1) S(2) S(3)], codistributor('1d',4));
    for i = 1 : S(1)
        fprintf('Slice %d out of %d\n', i, S(1));
        for ii = 1 : S(2)
            for iii = drange(1 : S(3))
                d(:,i,ii,iii) = eig(squeeze(CDHess(:,:,i,ii,iii)));
            end
        end
    end
end

誰かがこの問題に光を当てることができれば、私はとても感謝しています

4

2 に答える 2

2

これがあなたのコードの書き直されたバージョンです。私はあなたの場合のようにではなく、最も外側のループ、つまり最も内側のループに作業を分割しました。dまた、結果ベクトルのローカル部分とヘッセ行列のローカル部分を明示的に割り当てました。

コードでは、作業を分割することに依存しdrangeており、ローカル部分の抽出を回避するために分散配列に直接アクセスします。確かに、MATLABがすべてを正しく実行した場合、このような大幅な速度低下は発生しないはずです。結論として、コードが非常に遅い理由はわかりません。おそらく、行列を分散しているにもかかわらず、MATLABがリモートデータアクセスを行っているためです。

とにかく、以下のコードは実行され、4つのラボを使用して私のコンピューターでかなり良いスピードアップを提供します。何か作業するために、合成ランダム入力データを生成しました。コメントをご覧ください。不明な点がある場合は、後で詳しく説明します。

clear all;

D = rand(512, 512, 3);
S = size(D);
[fx, fy, fz] = gradient(D);

% this part could also be parallelized - at least a bit.
tic;
DHess = zeros([3 3 S(1) S(2) S(3)]);
[DHess(1,1,:,:,:), DHess(1,2,:,:,:), DHess(1,3,:,:,:)] = gradient(fx);
[DHess(2,1,:,:,:), DHess(2,2,:,:,:), DHess(2,3,:,:,:)] = gradient(fy);
[DHess(3,1,:,:,:), DHess(3,2,:,:,:), DHess(3,3,:,:,:)] = gradient(fz);
toc

% your sequential implementation
d = zeros([3, S(1) S(2) S(3)]);
disp('sequential')
tic
for i = 1 : S(1)
    for ii = 1 : S(2)
        for iii = 1 : S(3)
            d(:,i,ii,iii) = eig(squeeze(DHess(:,:,i,ii,iii)));
        end
    end
end
toc

% my parallel implementation
disp('parallel')
tic
spmd
    % just for information
    disp(['lab ' num2str(labindex)]);

    % distribute the input data along the third dimension
    % This is the dimension of the outer-most loop, hence this is where we
    % want to parallelize!
    DHess_dist  = codistributed(DHess, codistributor1d(3));
    DHess_local = getLocalPart(DHess_dist);

    % create an output data distribution - 
    % note that this time we split along the second dimension
    codist = codistributor1d(2, codistributor1d.unsetPartition, [3, S(1) S(2) S(3)]);
    localSize = [3 codist.Partition(labindex) S(2) S(3)];

    % allocate local part of the output array d
    d_local = zeros(localSize);

    % your ordinary loop, BUT! the outermost loop is split amongst the
    % threads explicitly, using local indexing. In the loop only local parts
    % of matrix d and DHess are accessed
    for i = 1:size(d_local,2)
        for ii = 1 : S(2)
            for iii = 1 : S(3)
                d_local(:,i,ii,iii) = eig(squeeze(DHess_local(:,:,i,ii,iii)));
            end
        end
    end

    % assemble local results to a codistributed matrix
    d_dist = codistributed.build(d_local, codist);
end
toc

isequal(d, d_dist)

そして出力

Elapsed time is 0.364255 seconds.
sequential
Elapsed time is 33.498985 seconds.
parallel
Lab 1: 
  lab 1
Lab 2: 
  lab 2
Lab 3: 
  lab 3
Lab 4: 
  lab 4
Elapsed time is 9.445856 seconds.

ans =

     1

編集私は再形成されたマトリックスのパフォーマンスをチェックしましたDHess=[3x3xN]。パフォーマンスはそれほど良くない(10%)ので、実質的ではありません。eigしかし、多分あなたは少し異なって実装することができますか?結局のところ、それらは3x3あなたが扱っている行列です。

于 2012-10-26T13:12:22.213 に答える
1

matlabpool を開いた場所を指定していませんでした。これが、得られる高速化を決定する主な要因になります。

「ローカル」スケジューラを使用している場合、分散配列を使用してもメリットがないことがよくあります。特に、時間のかかる操作が既に MATLAB でマルチスレッド化されている場合、ローカル スケジューラを使用すると、matlabpool ワーカーがシングルスレッド モードで実行されるため、ほぼ確実に速度が低下します。

別のマシンのワーカーで他のスケジューラを使用している場合は、高速化できる可能性がありますが、それは何をしているかによって異なります。ここに例がありますhttp://www.mathworks.com/products/parallel-computing/examples.html?file=/products/demos/shipping/distcomp/paralleldemo_backslash_bench.html\ MATLABの演算子のいくつかのベンチマークを示しています。

最後に、特に MATLAB の組み込みのインデックス付けと比較すると、分散配列のインデックス付けは残念ながらかなり遅いことに注意してください。spmd ブロック内の対話型分散配列の「ローカル部分」を抽出し、それらを排他的に操作できる場合、それも役立つ場合があります。

于 2012-10-26T09:24:33.153 に答える