:::: MENU ::::
MATLAB

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




MATLAB’da arrayfun nasıl kullanılır?

MATLAB’ın GPU hesaplamada önerdiği yöntemlerden birisi de arrayfun fonksiyonunun kullanılmasıdır.

sonuc = arrayfun(@Fonksiyonum, giris1, giris2,...); şeklinde bir yapı ile kullanılmaktadır.

Giriş parametreleri(giris1, giris2,…) gpuArray olarak tanımlanmak zorundadır.
Fonksiyonumuz sayılarla ifade edilebilen ve eleman bazlı (scalar/elementwise) olmalıdır. Yani vektör ve matris hesaplamaları yapılamamaktadır.
sonuc, Fonksiyonumuzun çıktısı olarak GPU belleğinde oluşur.

Örneğin 4 farklı diziyi giriş olarak alan basit bir hesaplamanın yapıldığı yapı aşağıdadır.


a = gpuArray(1:0.1:10);
b = gpuArray(2:0.1:11);
c = gpuArray(3:0.1:12);
d = gpuArray(4:0.1:13);
gpu_x = arrayfun(@Fonksiyonum,a,b,c,d);
x= gather(gpu_x);

Fonksiyonum.m dosyasının içeriği:
function out = Fonksiyonum(a, b, c, d)
out = b / (a * d * sin(c));

Burada işlemler eleman bazlı ve sayısal olduğu için Fonksiyonum fonksiyonu GPU’da paralel bir şekilde çalıştırılmaktadır.

arrayfun ile sadece basit sayısal işlemler değil kontrol parametreleri de kullanılabilir. for, while, break, if gibi ifadelerle de fonksiyonlar yazılabilir.

Örneğin:

myGoodFunc

Aşağıdaki örnekte matris indekslemesi olduğundan hata vermektedir.


Sayfalar:123456789