MATLAB’da CUBLAS ile Matris Çarpma İşlemi Nasıl Yapılır?

MATLAB’da CUBLAS ile Matris Çarpma İşlemi Nasıl Yapılır?

C=AXB işlemi yapılacaktır.
A:MxN boyutlu matris,
B:NxP boyutlu matris,
C:MXP boyutlu matristir.

cublasDemo.cpp isimli bir dosya oluşturarak içeriğini:

#include “mex.h”
Void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
}

şu şekilde dolduruyoruz. Bu c-mex için standart ibarelerdir.

Giriş verilerinin tipini önceden belirlememiz gerekmektedir. Kolaylık olması açısından single seçilmiştir, double olarak veriler belirlenirse kullanılacak komutlar değişecektir.


#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs != 2)
mexErrMsgTxt("Invaid number of input arguments");
if (!mxIsSingle(prhs[0]) && !mxIsSingle(prhs[1]))
mexErrMsgTxt("input matrices must be single ");
float* A = (float*)mxGetData(prhs[0]);
float* B = (float*)mxGetData(prhs[1]);
int numARows = mxGetM(prhs[0]);
int numACols = mxGetN(prhs[0]);
int numBRows = mxGetM(prhs[1]);
int numBCols = mxGetN(prhs[1]);
If (numACols != numBRows)
mexErrMsgTxt("Invalid matrix dimension");
}

Çıkış matrisinin boyutları belirlenir:


#include "mex.h"
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs != 2)
mexErrMsgTxt("Invaid number of input arguments");
if (!mxIsSingle(prhs[0]) && !mxIsSingle(prhs[1]))
mexErrMsgTxt("input matrices must be single ");
float* A = (float*)mxGetData(prhs[0]);
float* B = (float*)mxGetData(prhs[1]);
int numARows = mxGetM(prhs[0]);
int numACols = mxGetN(prhs[0]);
int numBRows = mxGetM(prhs[1]);
int numBCols = mxGetN(prhs[1]);
int numCRows = numARows;
int numCCols = numBCols;
plhs[0] = mxCreateNumericMatrix(numCRows, numCCols, mxSINGLE_CLASS, mxREAL);
float* C = (float*)mxGetData(plhs[0]);
}

GPU’nun belleğinde matrisleri yerleştirmek için alan oluşturulmalıdır. Bunun için cudaMalloc ve cudaFree komutları kullanılır. Bu komutlar cuda_runtime.h dosyasında kayıtlı olduğundan ilk başta include edilmesi gerekmektedir.


#include "mex.h"
#include ,cuda_runtime.h.
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs != 2)
mexErrMsgTxt("Invaid number of input arguments");
if (!mxIsSingle(prhs[0]) && !mxIsSingle(prhs[1]))
mexErrMsgTxt("input matrices must be single ");
float* A = (float*)mxGetData(prhs[0]);
float* B = (float*)mxGetData(prhs[1]);
int numARows = mxGetM(prhs[0]);
int numACols = mxGetN(prhs[0]);
int numBRows = mxGetM(prhs[1]);
int numBCols = mxGetN(prhs[1]);
int numCRows = numARows;
int numCCols = numBCols;
plhs[0] = mxCreateNumericMatrix(numCRows, numCCols, mxSINGLE_CLASS, mxREAL);
float* C = (float*)mxGetData(plhs[0]);
float *deviceA, *deviceB, *deviceC;
cudaMalloc(&deviceA, sizeof(float) * numARows * numACols);
cudaMalloc(&deviceB, sizeof(float) * numBRows * numBCols);
cudaMalloc(&deviceC, sizeof(float) * numCRows * numCCols);
// insert cuBLAS function(s) here
cudaFree(deviceA);
cudaFree(deviceB);
cudaFree(deviceC);
}

CUBLAS işlemleri için cublas_v2.h dosyasını include etmemiz gerekmektedir.


#include "mex.h"
#include ,cuda_runtime.h.
#include ,cublas_v2.h.
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
{
if (nrhs != 2)
mexErrMsgTxt("Invaid number of input arguments");
if (!mxIsSingle(prhs[0]) && !mxIsSingle(prhs[1]))
mexErrMsgTxt("input matrices must be single ");
float* A = (float*)mxGetData(prhs[0]);
float* B = (float*)mxGetData(prhs[1]);
int numARows = mxGetM(prhs[0]);
int numACols = mxGetN(prhs[0]);
int numBRows = mxGetM(prhs[1]);
int numBCols = mxGetN(prhs[1]);
int numCRows = numARows;
int numCCols = numBCols;
plhs[0] = mxCreateNumericMatrix(numCRows, numCCols, mxSINGLE_CLASS, mxREAL);
float* C = (float*)mxGetData(plhs[0]);
float *deviceA, *deviceB, *deviceC;
cudaMalloc(&deviceA, sizeof(float) * numARows * numACols);
cudaMalloc(&deviceB, sizeof(float) * numBRows * numBCols);
cudaMalloc(&deviceC, sizeof(float) * numCRows * numCCols);
cublasHandle_t handle;
cublasCreate(&handle);
cublasSetMatrix(numARows,numACols,sizeof(float),A,numARows,deviceA,numARows);
cublasSetMatrix(numBRows,numBCols,sizeof(float),B,numBRows,deviceB,numBRows);
cublasDestroy(handle);
cudaFree(deviceA);
cudaFree(deviceB);
cudaFree(deviceC);
}

Başka bir CUBLAS fonksiyonu kullanılmadan cublasDestroy() ile yok etmemiz gerekmektedir.
Ayrıca cudaMemcpy() kullanmadan cublasSetMatrix ile veri GPU’nun belleğine çekilmektedir.

Matris çarpma işlemi için:

float alpha = 1.0f;
float beta = 0.0f;
cublasSgemm(handle,CUBLAS_OP_N,CUBLAS_OP_N,numARows,numBCols,numACols,&alpha,deviceA,numARows,deviceB,numBRows,&beta,deviceC,numCRows);
cublasGetMatrix(numCRows,numCCols,sizeof(float),deviceC,numCRows,C,numCRows);

CUBLAS kullanırken thread ve grid sayılarını belirlememize gerek yok, kendisi uygun olan değerleri duruma göre ayarlamaktadır.

Hazır olan c-mex kodumuzu derleyerek, çalışmaya hazır hale getirmeliyiz.


mex cublasDemo.cpp -lcudart -lcublas -L"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\lib\x64"
-v -I"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.0\include"

derlemeden sonra Windows 64 bit kullanıyorsak cublasDemo1.mexw64 dosyası oluşur.

Çalıştırmak için:

A = single(rand(200,300));
B = single(rand(300,400));
C = cublasDemo(A,B);

cublas

Yorum Yapın