6

誰でも助けることができますか?私はかなり経験豊富な Matlab ユーザーですが、以下のコードの高速化に問題があります。

12 個のコアを使用して、3 つのループすべてを 1 回実行して達成できた最速の時間は、約 200 秒です。実際の関数は最大 720 回呼び出され、このレートでは実行に 40 時間以上かかります。Matlab プロファイラーによると、CPU 時間の大部分は指数関数呼び出しに費やされます。gpuArray を使用してこれを大幅に高速化し、Quadro 4000 グラフィック カードで exp 呼び出しを実行しましたが、ワークステーションにはグラフィック カードが 1 つしかないため、parfor ループが使用されなくなります。誰か助けてもらえますか、またはこのコードは Matlab を使用して達成できる最適に近いですか? 私は openMP を使用して非常に粗雑な C++ 実装を作成しましたが、ほとんど効果がありませんでした。

よろしくお願いします

function SPEEDtest_CPU

% Variable setup:
% - For testing I'll use random variables. These will actually be fed into 
%   the function for the real version of this code.
sy    = 320;
sx    = 100;
sz    = 32;
A     = complex(rand(sy,sx,sz),rand(sy,sx,sz));
B     = complex(rand(sy,sx,sz),rand(sy,sx,sz));
C     = rand(sy,sx);
D     = rand(sy*sx,1);
F     = zeros(sy,sx,sz);
x     = rand(sy*sx,1);  
y     = rand(sy*sx,1);
x_ind = (1:sx) - (sx / 2) - 1;
y_ind = (1:sy) - (sy / 2) - 1;


% MAIN LOOPS 
%  - In the real code this set of three loops will be called ~720 times!
%  - Using 12 cores, the fastest I have managed is ~200 seconds for one
%    call of this function.
tic
for z = 1 : sz
    A_slice = A(:,:,z);
    A_slice = A_slice(:);
    parfor cx = 1 : sx       
        for cy = 1 : sy       
            E = ( x .* x_ind(cx) ) + ( y .* y_ind(cy) ) + ( C(cy,cx) .* D );                                                          

            F(cy,cx,z) = (B(cy,cx,z) .* exp(-1i .* E))' * A_slice; 
        end       
    end   
end
toc

end
4

8 に答える 8

2

例のように、データが実際の (複雑ではない) 場合は、置き換える時間を節約できます。

(B(cy,cx,z) .* exp(-1i .* E))'

(B(cy,cx,z) .* (cos(E)+1i*sin(E))).'

具体的には、私のマシンではよりも19%(cos(x)+1i*sin(x)).'時間がかかりません。exp(-1i .* x)'


ABが複雑な場合:Eはまだ実数であるため、ループの外側で事前計算を行うことができBconj = conj(B)ます (これにはデータ サイズで約 10 ミリ秒かかり、1 回だけ実行されます)。

(B(cy,cx,z) .* exp(-1i .* E))'

(Bconj(cy,cx,z) .* (cos(E)+1i*sin(E))).'

同様の利益を得るために。

于 2013-10-04T10:28:35.687 に答える
1

MATLAB コードを高速化するには、主に 2 つの方法があります。事前割り当てベクトル化

十分に事前割り当てされていますが、ベクトル化はありません。これを行う方法を最もよく学ぶには、線形代数をよく理解し、 を使用しrepmatてベクトルを多次元に展開する必要があります。

ベクトル化は数桁のスピードアップをもたらし、コアを最適に使用します (フラグが立っている場合)。

あなたが計算している数式は何ですか?私は手を貸すことができるかもしれません?

于 2013-10-04T10:21:56.790 に答える
0

ここで他の人が与えた他の良いアドバイスに加えて、乗算 byはループとA_sliceは独立しており、両方のループが終了したらcx,cy乗算してループの外に出すことができます。F

同様に、 の共役は、による乗算の前に、ループB*exp(...)の外側でまとめて行うこともできます。cx,cyA_slice

于 2013-10-10T08:14:48.427 に答える
0

それが速度に役立つかどうかはわかりませんが、E は基本的に合計であるため、それを使用してexp (i cx(A+1)x) = exp(i cx(A) x) * exp(i x)事前exp(i x)に計算することができます。

そうすれば、反復ごとに exp を評価する必要はありませんが、乗算するだけで済み、高速になるはずです。

于 2013-10-04T10:57:27.300 に答える
0

この行: ( x .* x_ind(cx) ) + ( y .* y_ind(cy) ) + ( C(cy,cx) .* D );

ある種の畳み込みですよね?循環畳み込みは周波数領域ではるかに高速であり、周波数領域との間の変換は FTT を使用して最適化されます。

于 2017-02-04T17:03:22.587 に答える