各スレッドが最小化プロセス全体を実行する必要があるという事実に関連する 3 つの主な問題が見られます (現在使用している Matlab の最小化ルーチンの種類はfminunc
? fminsearch
? minFunc
?)。
最小化は、必要な一時変数に関して要求が厳しい場合があります。もちろん、それをどのように実装するつもりかによっては、たとえばグローバルメモリを使用して、一時的なものを保存してそれらを処理する必要があるため、これによりアルゴリズムのパフォーマンスが制限される可能性があります。
最小化プロセスを完了するのに必要な時間はスレッドごとに異なる可能性があるため、スレッドの同期についても慎重に考慮する必要があります。
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);
}