0

ループを GPU スレッドに分割するだけで、Matlab で CUDA を使用してシミュレーションの速度を向上できるかどうか疑問に思っていました。

これまでのところ、R で mclapply を使用してループを実行しましたが、CUDA を使用して Matlab で高速化できるかどうか疑問に思っていました。(Nvidia Gtx 650 ti ブースト)

これが私がやっていることの簡単な例です: 私は薄暗い 2000x9 のデータセットを持っていて、移動するデータ ウィンドウ (約 1500 行) で少なくとも 250 のループを実行したいです。これらのループは独立しているため、並列計算に最適です。

ループの例:最初の 1500 行を取得します。データセット全体 (1500x9) でいくつかの魔法。各列で単変量関数を計算し (1500x1 で 9 回の操作を行います)、各列で特定の損失関数を使用して最小化問題を実行します (1500x1 で 9 回の操作を行います)。(途中ですべての列を操作しているため、異なるスレッドで列を分離することはできません)

私の考え: 各ループを異なる GPU スレッドで実行するとしたら? 単一の GPU コアでこのような難しい計算問題を処理することに意味はありますか? (例として、1 コアの i7 3770k で 1 ループに約 300 秒かかります)

単一の GPU スレッドが CPU に比べてはるかに遅いことは知っていますが、すべてのループが同時に実行されるとしたら? 特に、各ループにはデータが与えられると非常に時間がかかるため、データを GPU に供給するのにかかる時間は、全体の時間のわずかな部分にすぎません。

重要な注意: 私は非常にお粗末な「プログラマー」です。私が計画しているのは、変数 i の関数で for ループ (1:250 の i) を分割し、これを GPU に渡すことです。

4

2 に答える 2

2

各スレッドが最小化プロセス全体を実行する必要があるという事実に関連する 3 つの主な問題が見られます (現在使用している Matlab の最小化ルーチンの種類はfminunc? fminsearch? minFunc?)。

  1. 最小化は、必要な一時変数に関して要求が厳しい場合があります。もちろん、それをどのように実装するつもりかによっては、たとえばグローバルメモリを使用して、一時的なものを保存してそれらを処理する必要があるため、これによりアルゴリズムのパフォーマンスが制限される可能性があります。

  2. 最小化プロセスを完了するのに必要な時間はスレッドごとに異なる可能性があるため、スレッドの同期についても慎重に考慮する必要があります。

  3. Matlab には非常に効果的な最適化ルーチンがあり、そのパフォーマンスをカスタム実装で複製するのは一般的に困難です (もちろん不可能ではありません)。私の経験では、Matlab のfminuncルーチンは、NAG が提供する Broyden-Fletcher-Goldfarb-Shanno の同等のルーチンよりも効果的です。したがって、上記の最適化ルーチンのいずれかを変換しようとすると、満足のいく結果が得られない可能性があります。

私は CUDA で高速化された Matlab を使用して多くの最適化問題に直面してきました。私の「ゴールド ルール」は、Matlab の最適化ルーチンの 1 つを使用し、直接的な問題 (関数の計算) の解決と、意図的に記述された CUDA コードのインターフェイスによる関数勾配を加速することです。 mex-filesによるMatlabで。有限差分による関数導関数の計算は独立しており、最適化パラメーターの数と同じ数の関数計算ルーチンの呼び出しを必要とするため、特に勾配を加速する必要がある (そして加速できる) ことを考慮してください。

EDIT 目的関数を最適化する必要があるとしますobjfun。私がやっていることはobjfun、mex ファイル インターフェイスを使用して CUDA でコーディングし、nvccそれをコンパイルしてから Matlab でリンクすることです。

私はMatlab 2010を使用しているため、CUDA関数はnvccコマンドによってC++コードでコンパイルおよび変換されます

system(sprintf('nvcc -I"%s/extern/include" --cuda "mexfun.cu" --output-file "mexfun.cpp"', matlabroot));

次に、Matlab にリンクします。

mex -I/opt/cuda/include -L/opt/cuda/lib -lcudart mexfun.cpp

Compiling CUDA C/C++ mex code under linux で提案されているように。

次に、たとえば を使用するとfminunc(@mexfun,...)、Matlab は目的汎関数を最適化し、その各評価が GPU で実行されます (したがって高速化されます)。勾配の評価に使用される有限差分は最適化プロセス全体を大幅に遅くする可能性があるため、分析的に利用可能な場合は、同じアプローチで勾配計算もコーディングしています。

Matlab 2013 および Windows システムについては、Creating mex files from CUDA code を参照してください。

編集mexfun.cu の構造 (目的関数)

// Do not change the function name (`mexFunction`) and the function arguments (`nlhs`, `plhs`, ...). 
void mexFunction(int nlhs, mxArray *plhs[],int nrhs, const mxArray *prhs[])

{
    /* Maps Matlab's pointers to the input variables to CUDA pointers */
    double* input_1     = mxGetPr(prhs[0]);
    double* input_2     = mxGetPr(prhs[1]);

    /* Recovers the size of the input matrices */
    int dimx = mxGetN(prhs[0]);
    ...         
    int dimu = mxGetM(prhs[3]);         

    /* Memory allocations on the host */
    cuDoubleComplex* hfoo = (cuDoubleComplex *)malloc(sizeof(cuDoubleComplex)*dimx);
    ...

   /* Memory allocations on the device */
   cuDoubleComplex* dfoo; cudaMalloc((void*)&d_Kernel_Matrix,dimx*sizeof(cuDoubleComplex));
   ...

  /* Memory transfer from host to device */
  cudaMemcpy(dfoo,hfoo,dimx*sizeof(cuDoubleComplex),cudaMemcpyHostToDevice);
  ....

  /* Kernel launch */
  dim3 dimBlock(BLOCK_SIZE_X,BLOCK_SIZE_Y);
  Kernel_To_Be_Launched <<<dimGrid,dimBlock >>>(hfoo,dfoo,dimx);

 /* Copy the results from device to host */ cudaMemcpy(hfoo,dfoo,dimx*sizeof(cuDoubleComplex),cudaMemcpyDeviceToHost);


 /* Passing the output matrices to MATLAB */
 plhs[0] = mxCreateDoubleMatrix(1,dimu,mxCOMPLEX);
 double* hfoo_re = mxGetPr(plhs[0]);
 double* hfoo_im = mxGetPi(plhs[0]);

 /* Freeing host memory */
 free(hfoo);
 ...

 /* Freeing device memory */
 cudaFree(dfoo);

}

于 2013-07-06T20:55:34.433 に答える
0

私は自分自身を CUDA の専門家とは (まったく) 考えていませんが、ここしばらくの間、CUDA を広範囲に使用してきました。私の推測では、確かにある程度のスピードアップが得られるかもしれませんが、問題についての詳細な知識がなければ、おそらくいくらかの努力がなければ、どれだけ高速化されるかを判断するのは難しいでしょう。つまり、いわば「壁を越えて投げる」ことはできず、CUDA コンパイラーがすべての断片をキャッチすることを期待することはできません。

CUDA にはメモリの使用に関する非常に厳格なルールがあるため、当面の懸念はメモリ管理とバス トラフィックに関連するものです。コンパイラは通常、可能な限り処理を続けますが、メモリとバスを非効率的に使用するとパフォーマンスが低下します。

具体的には、優れたパフォーマンスを得るために、問題の一部をさまざまなストリーミング マルチプロセッサの共有メモリにロードする必要があります。最新のカードの SM で使用できる共有メモリは 48K のみです。あなたの問題は、すでに 48K を超えている 1500 x 9 (floats だと思います) のチャンクで説明しています。さらに、SM 上の共有メモリは、SM 上のすべてのプロセッサによって使用されます。問題が SM の 48K をすべて占有する場合、その SM のほとんどはアイドル状態になります。

だから、それは悪いですね。しかし、これらの 1500 x 9 チャンクの答えを小さな断片に計算して再結合できる方法があれば、GPU アプローチの候補があるかもしれません。多くの場合、ある程度の創造性が必要です。

しかし、これは 1 つの懸念事項に過ぎないことを強調します。 これは、私が別のアプリケーションで取り組んでいる問題に似ているため、私に飛びついたものです。

JackOLantern は他にも上げていますし、読み書きパターンなどもあります。

于 2013-07-07T19:54:02.830 に答える