【问题标题】:error using cublasSgemmBatched in mex在 mex 中使用 cublasSgemmBatched 时出错
【发布时间】:2016-01-11 20:43:58
【问题描述】:

我正在尝试使用 mex 文件中的 cublasSgemmBatched 从 matlab 中乘以多个矩阵。

我的matlab代码很简单:

gpuDevice(1);
a = single(rand(400,10,1500,'gpuArray'));
b = single(rand(10,12,1500,'gpuArray'));
c = MatCuda(a,b)

我收到以下错误:

使用 gpuArray/subsref 时出错 CUDA 执行期间发生意外错误。 CUDA 错误是: 未知错误

这里是 mexFunction 代码:

void mexFunction( int nlhs, mxArray *plhs[],
              int nrhs, const mxArray *prhs[]){

char const * const errId = "parallel:gpu:mexGPUExample:InvalidInput";
char const * const errMsg = "Invalid input to MEX file.";

/* Declare all variables.*/
mxGPUArray const *A;
mxGPUArray const *B;
mxGPUArray *C;

/* Initialize the MathWorks GPU API. */
mxInitGPU();

/* Throw an error if the input is not a GPU array. */
if ((nrhs != 2) || !(mxIsGPUArray(prhs[0])) || !(mxIsGPUArray(prhs[1]))) {
    mexErrMsgIdAndTxt(errId, errMsg);
}

A = mxGPUCreateFromMxArray(prhs[0]);
B = mxGPUCreateFromMxArray(prhs[1]);

if ((mxGPUGetClassID(A) != mxSINGLE_CLASS) || (mxGPUGetClassID(B) != mxSINGLE_CLASS)) {
    mexErrMsgIdAndTxt(errId, errMsg);
}

float const *d_A;
float const *d_B;
d_A = (float const *)(mxGPUGetDataReadOnly(A));
d_B = (float const *)(mxGPUGetDataReadOnly(B));

const mwSize *dimsA = mxGPUGetDimensions(A);
size_t nrowsA = dimsA[0];
size_t ncolsA = dimsA[1];
size_t nMatricesA = dimsA[2];
mxFree((void*) dimsA);

const mwSize *dimsB = mxGPUGetDimensions(B);
size_t nrowsB = dimsB[0];
size_t ncolsB = dimsB[1];
size_t nMatricesB = dimsB[2];
mxFree((void*)dimsB);

size_t nrowsC = nrowsA;
size_t ncolsC = ncolsB;

mwSize dimsC[3] = { nrowsA, ncolsB, nMatricesB };
C = mxGPUCreateGPUArray(mxGPUGetNumberOfDimensions(A),
    dimsC,
    mxGPUGetClassID(A),
    mxGPUGetComplexity(A),
    MX_GPU_DO_NOT_INITIALIZE);

float *d_C;
d_C = (float *)(mxGPUGetData(C));

cublasHandle_t handle;
cublasStatus_t ret;
ret = cublasCreate(&handle);
if (ret != CUBLAS_STATUS_SUCCESS)
{
    printf("cublasCreate returned error code %d, line(%d)\n", ret, __LINE__);
    exit(EXIT_FAILURE);
}
const float alpha = 1.0f;
const float beta = 0.0f;
ret = cublasSgemmBatched(handle, CUBLAS_OP_N, CUBLAS_OP_N, nrowsA, ncolsB, ncolsA, &alpha, &d_A, nrowsA, &d_B, nrowsB, &beta, &d_C, nrowsC, nMatricesA);

if (ret != CUBLAS_STATUS_SUCCESS)
{
    printf("cublasSgemm returned error code %d, line(%d)\n", ret, __LINE__);
    exit(EXIT_FAILURE);
}

ret = cublasDestroy(handle);
if (ret != CUBLAS_STATUS_SUCCESS)
{
    printf("cublasCreate returned error code %d, line(%d)\n", ret, __LINE__);
    exit(EXIT_FAILURE);
}

plhs[0] = mxGPUCreateMxArrayOnGPU(C);
mxGPUDestroyGPUArray(A);
mxGPUDestroyGPUArray(B);
mxGPUDestroyGPUArray(C);
}

我怀疑它与函数 cublasSgemmBatched 有关,因为当我从代码中删除它时,我没有收到错误。

非常感谢您的帮助! 谢谢!

【问题讨论】:

  • gemmBatched 比大多数 cublas 函数使用起来更复杂。您不仅必须复制要相乘的矩阵数组,还必须复制指向这些矩阵的指针数组。您可以通过编写正确使用该函数的普通 C/C++ 代码来测试您的理解,或者查看this
  • 你没有掌握gemmBatched函数的要求,所以你的调用肯定是不正确的。我们不会为您拥有d_Ad_Bd_C 的参数传递设备指针的(主机)地址。这些是指针对指针的参数,必须将它们正确设置为设备指针数组,然后将其复制到设备。我认为您的方法完全忽略了这一点。

标签: matlab cuda mex cublas


【解决方案1】:

这里不需要 MEX 文件,您可以使用 pagefun 来执行此操作。另外,我建议直接在single 精度中构建ab 而不是强制转换。换句话说,

a = rand(400,10,1500,'single','gpuArray');
b = rand(10,12,1500,'single','gpuArray');
c = pagefun(@mtimes, a, b);

【讨论】:

    【解决方案2】:

    cublasDgemm 为我工作。我只是将常规数组传递给 mexfunction。这是我的示例代码。

    #include <cuda_runtime.h>
    #include <cublas_v2.h>
    #include <time.h>
    #include "mex.h"
    #include "mxGPUArray.h"
    
    typedef struct _matrixSize
    {
        unsigned int uiWA, uiHA, uiWB, uiHB, uiWC, uiHC;
    } sMatrixSize;
    
    void matrixMultiply(double const* d_A, double const* d_B, double* d_C, sMatrixSize &matrix_size);
    
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray const *prhs[])
    {
        mxGPUArray const *A;
        mxGPUArray const *B;
        mxGPUArray *C;
        _matrixSize matrix_size;
        mwSize const *A_sz;
        mwSize const *B_sz;
    
        double const *d_A;
        double const *d_B;
        double *d_C;
    
        char const * const errId = "parallel:gpu:mexGPUExample:InvalidInput";
        char const * const errMsg = "Invalid input to MEX file.";
    
        if (nrhs != 2) {
            mexErrMsgTxt("Need two inputs");
        }
    
        A = mxGPUCreateFromMxArray(prhs[0]);
        B = mxGPUCreateFromMxArray(prhs[1]);
    
        A_sz=mxGPUGetDimensions(A);
        B_sz = mxGPUGetDimensions(B);
    
        matrix_size.uiWA = (unsigned int)A_sz[0]; matrix_size.uiHA = (unsigned int)A_sz[1];
        matrix_size.uiWB = (unsigned int)B_sz[0]; matrix_size.uiHB = (unsigned int)B_sz[1];
        mwSize C_sz[3] = { matrix_size.uiWA, matrix_size.uiHB, 1 };
    
        d_A = (double const *)(mxGPUGetDataReadOnly(A));
        d_B = (double const *)(mxGPUGetDataReadOnly(B));
    
        C = mxGPUCreateGPUArray(mxGPUGetNumberOfDimensions(A),
            C_sz,
            mxGPUGetClassID(A),
            mxGPUGetComplexity(A),
            MX_GPU_DO_NOT_INITIALIZE);
    
        d_C = (double *)(mxGPUGetData(C));
    
        matrixMultiply(d_A, d_B, d_C, matrix_size);
        plhs[0] = mxGPUCreateMxArrayOnGPU(C);
    
        mxFree((void*)A_sz);
        mxFree((void*)B_sz);
        mxGPUDestroyGPUArray(A);
        mxGPUDestroyGPUArray(B);
        mxGPUDestroyGPUArray(C);
    }
    
    void matrixMultiply(double const* d_A, double const* d_B, double* d_C, sMatrixSize &matrix_size)
    {
        cublasStatus_t status;
        cublasHandle_t handle;
        status=cublasCreate(&handle);
        if (status != CUBLAS_STATUS_SUCCESS)
        {
            if (status == CUBLAS_STATUS_NOT_INITIALIZED) {
                mexPrintf("CUBLAS initializing error");
            }
            getchar();
            return;
        }
        const double alpha = 1.0f;
        const double beta = 0.0f;
        cublasDgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, matrix_size.uiWB, matrix_size.uiHA, matrix_size.uiWA, &alpha, d_B, matrix_size.uiWB, d_A, matrix_size.uiWA, &beta, d_C, matrix_size.uiWB);
        cudaThreadSynchronize();
        cublasDestroy(handle);
    }
    

    还有更原生的 cuda 风格。两者都适合我。

    #include <cuda_runtime.h>
    #include <cublas_v2.h>
    #include <time.h>
    #include "mex.h"
    #include "mxGPUArray.h"
    
    typedef struct _matrixSize
    {
        unsigned int uiWA, uiHA, uiWB, uiHB, uiWC, uiHC;
    } sMatrixSize;
    
    void matrixMultiply(double const* d_A, double const* d_B, double* d_C, sMatrixSize &matrix_size);
    
    void mexFunction(int nlhs, mxArray *plhs[], int nrhs, mxArray const *prhs[])
    {
        mxArray const *mA;
        mxArray const *mB;
    
        _matrixSize matrix_size;
        size_t A_w, A_h, B_w, B_h;
    
        double *d_A;
        double *d_B;
        double *d_C;
    
        double *h_A;
        double *h_B;
        double *h_C;
    
        char const * const errId = "parallel:gpu:mexGPUExample:InvalidInput";
        char const * const errMsg = "Invalid input to MEX file.";
    
        if (nrhs != 2) {
            mexErrMsgTxt("Need two inputs");
        }
    
        mA = prhs[0]; mB = prhs[1];
        A_w = mxGetM(mA);A_h = mxGetN(mA);B_w = mxGetM(mB);B_h = mxGetN(mB);
    
        matrix_size.uiWA = (unsigned int)A_w; matrix_size.uiHA = (unsigned int)A_h;
        matrix_size.uiWB = (unsigned int)B_w; matrix_size.uiHB = (unsigned int)B_h;
        matrix_size.uiWC = (unsigned int)A_w; matrix_size.uiHC = (unsigned int)B_h;
    
        mwSize const C_sz[3] = { matrix_size.uiWA, matrix_size.uiHB, 1 };
    
        unsigned int size_A = matrix_size.uiWA * matrix_size.uiHA;
        unsigned int mem_size_A = sizeof(double) * size_A;
        h_A = (double*)mxGetData(mA);
    
        unsigned int size_B = matrix_size.uiWB * matrix_size.uiHB;
        unsigned int mem_size_B = sizeof(double) * size_B;
        h_B = (double*)mxGetData(mB);
    
        unsigned int size_C = matrix_size.uiWC * matrix_size.uiHC;
        unsigned int mem_size_C = sizeof(double) * size_C;
    
        plhs[0] = mxCreateNumericArray(3, C_sz, mxDOUBLE_CLASS, mxREAL);
        h_C = (double*)mxGetData(plhs[0]);
    
        cudaMalloc((void **)&d_A, mem_size_A);
        cudaMalloc((void **)&d_B, mem_size_B);
        cudaMemcpy(d_A, h_A, mem_size_A, cudaMemcpyHostToDevice);
        cudaMemcpy(d_B, h_B, mem_size_B, cudaMemcpyHostToDevice);
        cudaMalloc((void **)&d_C, mem_size_C);
    
        matrixMultiply(d_A, d_B, d_C, matrix_size);
        cudaMemcpy(h_C, d_C, mem_size_C, cudaMemcpyDeviceToHost);
        cudaThreadSynchronize();
    
        cudaFree(d_A);
        cudaFree(d_B);
        cudaFree(d_C);      
    }
    
    
    void matrixMultiply(double const* d_A, double const* d_B, double* d_C, sMatrixSize &matrix_size)
    {
        cublasHandle_t handle;
        cublasCreate(&handle);
        const double alpha = 1.0f;
        const double beta = 0.0f;
        cublasDgemm(handle, CUBLAS_OP_N, CUBLAS_OP_N, matrix_size.uiWB, matrix_size.uiHA, matrix_size.uiWA, &alpha, d_B, matrix_size.uiWB, d_A, matrix_size.uiWA, &beta, d_C, matrix_size.uiWB);
        cublasDestroy(handle);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-30
      • 2014-01-31
      相关资源
      最近更新 更多