1

128 枚の画像で 2D FFT に CUFFT を使用しています。各画像のサイズは 128 x 128 です。MATLAB では、1 つの 2D FFT を実行するのに 0.3 ミリ秒かかり、128 枚の画像すべてに対して FFT を実行するには、そのミリ秒数のほぼ 128 倍かかります。CUFFT を使用して、次のコードを実行すると、1 つの画像の FFT が計算されます。

cudaMalloc( (void**)idata, sizeof(cufftDoubleReal) * 128 * 128 );
cudaMalloc( (void**)odata, sizeof(cufftDoubleComplex) * 128 * 128 );
cudaMemcpy( *idata, in_real, 128 * 128 * sizeof(cufftDoubleReal), 
                                  cudaMemcpyHostToDevice );
cudaMemcpy( *idata, in_complex, 128 * 128 * sizeof(cufftDoubleComples), 
                                  cudaMemcpyHostToDevice );

cufftExecD2Z( plan, idata, odata );
cudaMemcpy( out_complex, *odata, 128 * 128 * sizeof(cufftDoubleComplex), cudaMemcpyDeviceToHost );

私のマシンでは約0.4msかかります。

複数の画像に対して同じコードを実行してみましたが、実行時間は基本的に画像数倍の0.4msです。私が行った方法は、基本的に上記のコードを何度もコピーして貼り付けることです。もちろん、対応する画像の変数を変更します。つまり、

// For image1
cudaMalloc( (void**)idata, sizeof(cufftDoubleReal) * 128 * 128 );
cudaMalloc( (void**)odata, sizeof(cufftDoubleComplex) * 128 * 128 );
cudaMemcpy( *idata, in_real, 128 * 128 * sizeof(cufftDoubleReal), 
                                  cudaMemcpyHostToDevice );
cudaMemcpy( *idata, in_complex, 128 * 128 * sizeof(cufftDoubleComples), 
                                  cudaMemcpyHostToDevice );
cufftExecD2Z( plan, idata, odata );
cudaMemcpy( out_complex, *odata, 128 * 128 * sizeof(cufftDoubleComplex), cudaMemcpyDeviceToHost );

// For image 2
cudaMalloc( (void**)idata2, sizeof(cufftDoubleReal) * 128 * 128 );
cudaMalloc( (void**)odata2, sizeof(cufftDoubleComplex) * 128 * 128 );
cudaMemcpy( *idata2, in_real2, 128 * 128 * sizeof(cufftDoubleReal), 
                                  cudaMemcpyHostToDevice );
cudaMemcpy( *idata2, in_complex2, 128 * 128 * sizeof(cufftDoubleComples), 
                                  cudaMemcpyHostToDevice );
cufftExecD2Z( plan, idata2, odata2 );
cudaMemcpy( out_complex, *odata2, 128 * 128 * sizeof(cufftDoubleComplex), cudaMemcpyDeviceToHost );
...
// For image N
...

したがって、128 個の画像すべてに 2D FFT を適用すると、実行時間は MATLAB の実行時間とほぼ同じになると予想できます。

だから私の質問: 実行を適用する方法は正しいですか? GPU の並列処理能力を十分に活用できていますか? コードの実行方法を変更する必要があります。たとえば、最初に 128 個のイメージすべてに対して cudaMemcpy を実行し、CPU と GPU の実行をオーバーラップさせるためにそれらを実行する必要がありますか?

4

1 に答える 1

4

まず、コードのプロファイリングをお勧めします。100 枚すべての画像をプロファイリングする必要はありませんが、2 ~ 5 枚の画像で十分です。

プロファイル データに基づいて、データの転送に費やされた時間と CUFFT 操作に費やされた時間を比較する必要があります。それらがほぼ等しい場合 (またはオーバーラップが有益であることが視覚的にわかる場合)、コピーと (CUFFT) 計算のオーバーラップを試してください。CUDA ストリームを使用してこれを達成します。CUDA ストリームの使用法に関する多くのチュートリアルと、CUDA タグ (CUFFT タグを含む) に関する質問の例があり、ストリームの使用と CUFFT でのストリームの使用について説明しています。

これとは別に、上記に関連して、CUFFT バッチ パラメーターを使用して、おそらく 2 ~ 5 個の画像変換をまとめてバッチ処理し、100 枚の画像の全体的な処理時間が短縮されるかどうかを確認することをお勧めします。

実際に 2 つのアイデアを組み合わせることができます。つまり、変換をバッチで実行し、CUDA ストリームを使用してコピー/計算オーバーラップを使用して、画像のバッチに関連付けられたコピー操作を前のバッチからの計算操作とオーバーラップさせることができます。

それとは別に、cudaMalloc操作には費用がかかります。パフォーマンス (計算) ループに含めないことが最善です。これは、可能であれば、コード内で最初に一度実行することを意味します。すべての画像に新しいスペースを割り当てるのではなく、必要なすべてのスペースを割り当て (たとえば、画像の 2 ~ 3 バッチの場合)、そのスペースを再利用することをお勧めします。

于 2016-04-06T02:00:43.090 に答える