我看到三个主要问题与每个线程应该执行整个最小化过程(您当前使用哪种 Matlab 最小化例程fminunc
????)fminsearch
。minFunc
就所需的临时变量而言,最小化可能要求很高。这可能会限制您的算法的性能,因为需要存储临时数据并处理它们,例如使用全局内存,这当然取决于您打算如何实现它。
您还应该仔细考虑线程同步,因为完成最小化过程所需的时间可能会因线程而异。
Matlab 具有非常有效的优化例程,其性能通常很难(但当然,并非不可能)通过自定义实现来复制。根据我的经验,Matlabfminunc
比 NAG 提供的 Broyden-Fletcher-Goldfarb-Shanno 等效例程更有效。因此,如果您尝试翻译上述优化例程之一,那么您最终可能会得到不太令人满意的结果。
我使用 CUDA 加速的 Matlab 遇到了许多优化问题,我的“黄金法则”是使用 Matlab 的优化例程之一,并通过特意编写的 CUDA 代码接口加速直接问题(函数的计算)和函数梯度的解决方案通过 mex 文件使用 Matlab。考虑到梯度需要(并且可以)加速,因为通过有限差分计算的泛函导数是独立的,并且需要调用与优化参数数量一样多的泛函计算例程。
编辑
假设我必须优化目标函数objfun
。我正在做的是objfun
在 CUDA 中使用 mex 文件接口编写代码,通过编译它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
正如在 linux 下编译 CUDA C/C++ mex 代码中所建议的那样。
然后,例如,当使用 时fminunc(@mexfun,...)
,Matlab 将优化目标函数,并且对它的每次评估都将在 GPU 上执行(并因此加速)。当分析可用时,我还通过相同的方法对梯度计算进行编码,因为用于评估梯度的有限差分会显着减慢整个优化过程。
对于 Matlab 2013 和 Windows 系统,请参阅从 CUDA 代码创建 mex 文件。
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);
}