矩阵点积

时间:2017-11-15 14:07:49

标签: c++ cuda

免责声明:我是初学者。

typedef struct
{
    int row_;
    int col_;
    float* element_;
    int step;
}Matrix_t;

#define BLOCK_SIZE 64

__device__ float getElement(const Matrix_t A, int row, int col);
__device__ Matrix_t getSubMat(Matrix_t A, int row, int col);
__device__ void setElement(Matrix_t A, int row, int col, float value);
__global__ void MatrixDot(Matrix_t A, Matrix_t B, float* dot_);
float  Matrix_dot_(float* M_dev_1, float* M_dev_2, int Number_of_cols, int Number_of_rows, int step);

Matrix_t用于通过ptr()运算符将cv :: cuda :: GpuMat链接到C接口,以获取指向元素的GPU指针。

__device__ float getElement(const Matrix_t A, int row, int col)
{
    return A.element_[row* A.step + col];
}

__device__ void setElement(Matrix_t A, int row, int col, float value)
{
    A.element_[row*A.step + col] = value;
}
__device__ Matrix_t getSubMat(Matrix_t A, int row, int col)
{
    Matrix_t A_sub;
    A_sub.row_ = BLOCK_SIZE;
    A_sub.col_ = BLOCK_SIZE;
    A_sub.step = A.step;
    A_sub.element_ = &A.element_[A.step * BLOCK_SIZE * row + BLOCK_SIZE * col];

    return A_sub;
}

这是内核:

__global__ void MatrixDot(Matrix_t A, Matrix_t B, float* dot_)
{
    int blockRow = blockIdx.y;
    int blockCol = blockIdx.x;


    float SubDotValue = 0.0f;


    int row = threadIdx.y;
    int col = threadIdx.x;



    for(int m = 0; m < (A.row_ / BLOCK_SIZE); ++m)
    {
        //get subA & subB
        Matrix_t A_sub = getSubMat(A, blockRow, m);
        Matrix_t B_sub = getSubMat(B, blockRow, m);

        //set Asub & Bsub to the  __shared__ memory

        __shared__ float ASub[BLOCK_SIZE][BLOCK_SIZE];
        __shared__ float BSub[BLOCK_SIZE][BLOCK_SIZE];

        ASub[row][col] = getElement(A_sub, row, col);
        BSub[row][col] = getElement(B_sub, row, col);

        //Synchronize before calculations:
        __syncthreads();

        //Get the dot product of the vector Asub[] Bsub[]
        for(int el_ = 0; el_ < BLOCK_SIZE; ++el_)
        {
            SubDotValue += ASub[row][el_] * BSub[row][el_];
        }
        __syncthreads();
    }

    dot_[row] = SubDotValue;

}

和包装器:

float  Matrix_dot_(float* M_dev_1,float* M_dev_2, int Number_of_cols, int Number_of_rows, int step)
{


    float retval = 0;
    float* retval_partial;
    float* retval_device;

    Matrix_t A;
    A.col_ = Number_of_cols;
    A.row_ = Number_of_rows;
    A.element_ = M_dev_1;
    A.step = step;
    Matrix_t B;
    B.col_ = Number_of_cols;
    B.row_ = Number_of_rows;
    B.element_ = M_dev_2;
    B.step = step;



    retval_partial = (float*)malloc( B.row_*sizeof(float) );

    cudaError_t err = cudaMalloc( (void**)&retval_device,B.row_/ BLOCK_SIZE *sizeof(float) );
    printf("\n Cuda malloc: %s", cudaGetErrorString(err));
    std::cout<<std::flush;
    dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE);
    dim3 dimGrid(B.row_ / BLOCK_SIZE, B.col_ / BLOCK_SIZE);

    MatrixDot<<<dimGrid, dimBlock>>>(A, B, retval_device);
    err = cudaThreadSynchronize();
    std::cout<<std::flush;

    printf("\n Cuda kernel run: %s", cudaGetErrorString(err));
    err = cudaMemcpy(retval_partial, retval_device, B.row_ / BLOCK_SIZE* sizeof(float), cudaMemcpyDeviceToHost);
    printf("\n Cuda cudaMemcpy: %s", cudaGetErrorString(err));
    err = cudaFree(retval_device);
    printf("\n Cuda cudaFree: %s", cudaGetErrorString(err));
    for(int i = 0; i<B.row_/ BLOCK_SIZE ; ++i)
    {
        retval+=retval_partial[i];
    }

    free(retval_partial);

    return retval;
}

和主要:

int main(int argc, const char * argv[])
{
    cv::cuda::DeviceInfo devInfo;
    cv::cuda::setDevice(devInfo.deviceID());

    cv::Mat cudatestA = cv::Mat(64*3, 64*3, CV_32FC1, 2);
    cv::Mat cudatestB = cv::Mat(64*3, 64*3, CV_32FC1, 2);


    double tr = (double) cv::getTickCount();
    double res = cudatestA.dot(cudatestB);

    tr = ((double)cv::getTickCount()-tr)/(double)cv::getTickFrequency();

    cv::cuda::GpuMat ctA(cudatestA);
    cv::cuda::GpuMat ctB(cudatestB);


    double tm_ = (double) cv::getTickCount();
    float res_m = 0;

    res_m = Matrix_dot_((float* )ctA.ptr(), (float*)ctB.ptr(), ctA.cols, ctA.rows, ctA.step);
    tm_ = ((double)cv::getTickCount()-tm_)/(double)cv::getTickFrequency();


    printf("\nCPU: %0.4fms, res: %0.4f\nGPU_M: %0.4fms, res: %0.4f\n", tr*1000.0f, res, tm_*1000.0f,res_m);
    return 0;
}

我目前陷入了各种各样的问题:

1)它总是输出0。

2)它只能用于矩阵M * N多个定义的BLOCK_SIZE(64)。

1)我无法确定我的逻辑中断的地方,我可以让dot产品在矢量上工作而没有任何麻烦但是每行之间的步幅引起的矩阵问题阻止我使用代码(代码删除为该网站告诉我代码太多了。)

1 个答案:

答案 0 :(得分:1)

部分答案:

在你的内核中,你并没有做好总和,也没有采取好的元素,你的暗淡似乎是倒置的

__global__ void MatrixDot(Matrix_t A, Matrix_t B, float* dot_)
{
//int blockRow = blockIdx.y;
//int blockCol = blockIdx.x;
int blockRow = blockIdx.x;
int blockCol = blockIdx.y;


float SubDotValue = 0.0f;


//int row = threadIdx.y;
//int col = threadIdx.x;
int row = threadIdx.x;
int col = threadIdx.y;




for(int m = 0; m < (A.row_ / BLOCK_SIZE); ++m)
    {
        //get subA & subB
        Matrix_t A_sub = getSubMat(A, m, blockCol);//getSubMat(A, blockRow, m)
        Matrix_t B_sub = getSubMat(B, m, blockCol);//getSubMat(B, blockRow, m)

        //set Asub & Bsub to the  __shared__ memory

        __shared__ float ASub[BLOCK_SIZE][BLOCK_SIZE];
        __shared__ float BSub[BLOCK_SIZE][BLOCK_SIZE];

        ASub[row][col] = getElement(A_sub, row, col);
        BSub[row][col] = getElement(B_sub, row, col);

        //Synchronize before calculations:
        __syncthreads();

        //Get the dot product of the vector Asub[] Bsub[]
        for(int el_ = 0; el_ < BLOCK_SIZE; ++el_)
        {
            SubDotValue += ASub[row][el_] * BSub[row][el_];
        }
        __syncthreads();
    }

dot_[blockRow*BLOCK_SIZE + row] = SubDotValue; //dot_[row] = SubDotValue;

}

你的包装器也没有分配你需要的尺寸:

cudaError_t err = cudaMalloc( (void**)&retval_device,B.row_/ BLOCK_SIZE *sizeof(float) );

应该是:

cudaError_t err = cudaMalloc( (void**)&retval_device,B.row_*sizeof(float) );

请注意,其他相关的分配也必须改变(懒惰我)。

你主要需要将GpuMat步骤除以GpuMat中一个元素的大小

res_m = Matrix_dot_((float* )ctA.ptr(), (float*)ctB.ptr(), ctA.cols, ctA.rows, ctA.step/ctA.elemsize1());

您可能还想更改Matrix_t结构以使用const float *而不是float来使用:

 GpuMat_.ptr<float>();

而不是:

(float*)GpuMat.ptr();

请注意,对于N行的矩阵,您开始N ^ 2个线程执行相同的操作。我对Cuda没有足够的知识来解决这个问题。