メインコンテンツ

GPU を使用した相関の高速化

この例では、GPU を使用して相互相関を高速化する方法を示します。相関問題の多くは、大規模なデータセットを扱うことから、GPU の使用によりより高速な解決が可能です。この例では、Parallel Computing Toolbox™ のユーザー ライセンスが必要です。どの GPU がサポートされているかについては、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。

はじめに

まず、ご使用のマシンの GPU の基本的な情報を学習します。GPU にアクセスするには、Parallel Computing Toolbox を使用します。

if ~(parallel.gpu.GPUDevice.isAvailable)
    fprintf("\n\t**GPU not available. Stopping.**\n");
    return;
else
    dev = gpuDevice;
    fprintf(...
    "GPU detected (%s, %d multiprocessors, Compute Capability %s)", ...
    dev.Name, dev.MultiprocessorCount, dev.ComputeCapability);
end
GPU detected (NVIDIA RTX A5000, 64 multiprocessors, Compute Capability 8.6)

ベンチマーク機能

CPU 用に書かれたコードは GPU に移植して実行できるため、1 つの関数を CPU と GPU の両方のベンチマークに利用できます。ただし、GPU 上のコードは CPU とは非同期に実行されるため、性能測定には特別な注意が必要です。ある関数の実行に要した時間を測定する前に、すべての GPU 処理が終了しているか、デバイス上で 'wait' メソッドを実行して確認します。この追加の呼び出しは、CPU の性能には影響を与えません。

この例では、3 つの異なるタイプの相互相関のベンチマークを行います。

単純な相互相関のベンチマーク

最初の例として、同じサイズの 2 つのベクトルが構文 xcorr(u,v) を使用して相互相関されています。GPU 実行時間に対する CPU 実行時間の比は、ベクトルのサイズに対してプロットされています。

sizes = floor(logspace(5,7,10))';
tc = zeros(numel(sizes),1);
tg = zeros(numel(sizes),1);

for s = 1:numel(sizes)
    if s == 1
        fprintf("** Benchmarking vector-vector cross-correlation. **")
        fprintf("Running xcorr of N elements")
    end
    fprintf(".");
    a = single(rand(sizes(s),1));
    b = single(rand(sizes(s),1));
    tc(s) = timeit(@() xcorr(a,b),1);
    tg(s) = gputimeit(@() xcorr(gpuArray(a),gpuArray(b)),1);
    if s == numel(sizes)
        disp(table(sizes,1e3*tc,1e3*tg,VariableNames= ...
            ["Length (N)" "CPU time (ms)" "GPU time (ms)"]))
    end
end
** Benchmarking vector-vector cross-correlation. **
Running xcorr of N elements
..........
    Length (N)    CPU time (ms)    GPU time (ms)
    __________    _____________    _____________

         1e+05       3.2248           1.1345    
    1.6681e+05       6.0368           1.2935    
    2.7826e+05       9.0778           1.5205    
    4.6416e+05        16.32           1.9185    
    7.7426e+05       25.602           2.5235    
    1.2915e+06       56.349           3.7115    
    2.1544e+06       85.022           7.5365    
    3.5938e+06        143.4           13.051    
    5.9948e+06       285.56           20.219    
         1e+07       365.81           33.806    
% Plot the results
fig = figure;
ax = axes(Parent=fig);
semilogx(ax,sizes,tc./tg,"r*-");
ylabel(ax,"Speedup");
xlabel(ax,"Vector size");
title(ax,"GPU Acceleration of XCORR");

行列の列の相互相関のベンチマーク

2 番目の例として、行列 A の列が、構文 xcorr(A) を使用して対相互相関され、すべての相関からなる大きな行列出力が生成されています。CPU の実行時間と GPU の実行時間の比率は、行列 A のサイズに対してプロットされています。

sizes = floor(logspace(2,2.5,10))';
tc = zeros(numel(sizes),1);
tg = zeros(numel(sizes),1);
for s = 1:numel(sizes)
    if s == 1
        fprintf("** Benchmarking matrix column cross-correlation. **")
        fprintf("Running xcorr (matrix) of an N-by-N matrix")
    end
    fprintf(".");
    a = single(rand(sizes(s)));
    tc(s) = timeit(@() xcorr(a),1);
    tg(s) = gputimeit(@() xcorr(gpuArray(a)),1);
    if s == numel(sizes)
        disp(table(sizes,1e3*tc,1e3*tg,VariableNames= ...
            ["Size (N)" "CPU time (ms)" "GPU time (ms)"]))
    end
end
** Benchmarking matrix column cross-correlation. **
Running xcorr (matrix) of an N-by-N matrix
..........
    Size (N)    CPU time (ms)    GPU time (ms)
    ________    _____________    _____________

      100          5.3818           0.80717   
      113          8.0898           0.88967   
      129          13.426            1.6885   
      146          18.493            2.0345   
      166            25.6            2.4435   
      189          36.405            3.1765   
      215          57.449            3.8975   
      244          81.755            4.7185   
      278          131.18            11.829   
      316          178.32            15.023   
% Plot the results
fig = figure;
ax = axes(Parent=fig);
semilogx(ax,sizes.^2,tc./tg,"r*-")
ylabel(ax,"Speedup")
xlabel(ax,"Matrix Elements")
title(ax,"GPU Acceleration of XCORR (Matrix)")

2 次元の相互相関のベンチマーク

最後の例として、X と Y の 2 つの行列が xcorr2(X,Y) を使用して相互相関されています。X のサイズは固定されており、Y のサイズは可変です。2 番目の行列のサイズに対する speedup の値がプロットされています。

sizes = floor(logspace(2.5,3.5,10))';
tc = zeros(numel(sizes),1);
tg = zeros(numel(sizes),1);
a = single(rand(100));

for s = 1:numel(sizes)
    if s == 1
        fprintf("** Benchmarking 2-D cross-correlation**")
        fprintf("Running xcorr2 of 100-by-100 and N-by-N matrices.")
    end
    fprintf(".");
    b = single(rand(sizes(s)));
    tc(s) = timeit(@() xcorr2(a,b),1);
    tg(s) = gputimeit(@() xcorr2(gpuArray(a),gpuArray(b)),1);
    if s == numel(sizes)
        disp(table(sizes,1e3*tc,1e3*tg,VariableNames= ...
            ["Size (N)" "CPU time (ms)" "GPU time (ms)"]))
    end
end
** Benchmarking 2-D cross-correlation**
Running xcorr2 of 100-by-100 and N-by-N matrices.
..........
    Size (N)    CPU time (ms)    GPU time (ms)
    ________    _____________    _____________

       316         3.9288           2.7275    
       408         6.0308           2.9065    
       527         9.4288           3.4885    
       681         15.166           5.8805    
       879         24.238           7.5805    
      1136         37.586           12.254    
      1467         65.472           18.775    
      1895         109.37           28.703    
      2448         171.28            42.79    
      3162          299.2           70.185    
% Plot the results
fig = figure;
ax =axes(Parent=fig);
semilogx(ax,sizes.^2,tc./tg,"r*-")
ylabel(ax,"Speedup")
xlabel(ax,"Matrix Elements")
title(ax,"GPU Acceleration of XCORR2")

GPU により高速化されたその他の信号処理関数

GPU 上で実行できるその他の信号処理関数がいくつかあります。これらの関数には、fftifftconvfilterfftfiltなどが含まれます。場合によっては、CPU に対しかなりの高速化が達成できます。GPU によって高速化された信号処理関数すべての一覧については、Signal Processing Toolbox™ ドキュメンテーションのGPU アルゴリズムの高速化の節を参照してください。

参考

(Parallel Computing Toolbox) | (Parallel Computing Toolbox) |