CUDA学習の二:shared_memory使用、マトリクス乗算
4689 ワード
CUDAでshared_を使用memoryは演算を加速することができ,行列乗算では体現される.
行列C=A*B,通常の演算ではC[i,j]=A[i,:*B[:,j]を用いて結果を算出する.しかし、CPU上でこの演算を完了するには、A[m,n],B[n,k]を設定すると、Cマトリクスはm*kであり、全体として、m*n*k乗算、m*(b-1)*k加算、シリアル実行が必要であり、全体の複雑度はO(m*n*k)である.
マトリックスクラス:
CPU上のプログラム、1つの3層の循環
GPUで加速し、CUDAで実現したいと思います.kernelと書きます.
この場合、計算プロセスは並列であるが、A、Bマトリクスにアクセスする場合、同時にアクセスできないため、主な時間はメモリ読み取りに費やされ、各スレッドはAの1行、Bの1列を読み取り、Cの対応値を計算する.したがってglobal memoryからn回A,m回Bを読む必要がある.時間複雑度はO(m+n)次メモリアクセスとk次乗算である.
実際にはshared memoryを使う方法もありますが、ここではA、Bマトリクスをblocksizeに従ってサブマトリクスsubA[blocksize][blocksize]、subB[blocksize][blocksize]に分けます.サブマトリクスを__に設定shared__. thread block内のすべてのthreadsはshared memoryを共用している(読み書き可能).するとAはglobal memoryからn/block_しか読まなかったsize回、Bはm/blockしか読めませんでした_size次;時間的複雑さは、O(m/block_size+n/block_size)二次メモリアクセス、およびk次乗算である.時間の複雑さをさらに減らす.コードは次のとおりです.
参照sample_6.5\0_SimplematrixMulプログラム.コメント詳細
Rachel zhangのブログCUDA学習シリーズの2つを参照してください.http://blog.csdn.net/abcjennifer/article/details/42528569
行列C=A*B,通常の演算ではC[i,j]=A[i,:*B[:,j]を用いて結果を算出する.しかし、CPU上でこの演算を完了するには、A[m,n],B[n,k]を設定すると、Cマトリクスはm*kであり、全体として、m*n*k乗算、m*(b-1)*k加算、シリアル実行が必要であり、全体の複雑度はO(m*n*k)である.
マトリックスクラス:
1 class Matrix
2 {
3 public:
4 int cols; // x
5 int rows; // y
6 float *data; // ,
7 }
CPU上のプログラム、1つの3層の循環
for(int i =0;i< C.rows;i++)
{
for(int j =0;j< C.cols;j++)
{
float *a = A.data;
float *b = B.data;
for(int k=0;k<A.cols;k++)
C.data[i*C.cols+j]+=a[i*A.cols+k] * b[k*B.cols+j];
}
}
}
GPUで加速し、CUDAで実現したいと思います.kernelと書きます.
__global__ void matrixMulKernel(const Matrix A, const Matrix B, Matrix C)
{
// Each thread computes one element of C
// by accumulating results into Cvalue
float Cvalue = 0;
int row = blockIdx.y * blockDim.y + threadIdx.y;
int col = blockIdx.x * blockDim.x + threadIdx.x;
for (int e = 0; e < A.cols; ++e)
Cvalue += A.data[row * A.cols + e]* B.data[e * B.cols + col];
C.data[row * C.cols + col] = Cvalue;
}
この場合、計算プロセスは並列であるが、A、Bマトリクスにアクセスする場合、同時にアクセスできないため、主な時間はメモリ読み取りに費やされ、各スレッドはAの1行、Bの1列を読み取り、Cの対応値を計算する.したがってglobal memoryからn回A,m回Bを読む必要がある.時間複雑度はO(m+n)次メモリアクセスとk次乗算である.
実際にはshared memoryを使う方法もありますが、ここではA、Bマトリクスをblocksizeに従ってサブマトリクスsubA[blocksize][blocksize]、subB[blocksize][blocksize]に分けます.サブマトリクスを__に設定shared__. thread block内のすべてのthreadsはshared memoryを共用している(読み書き可能).するとAはglobal memoryからn/block_しか読まなかったsize回、Bはm/blockしか読めませんでした_size次;時間的複雑さは、O(m/block_size+n/block_size)二次メモリアクセス、およびk次乗算である.時間の複雑さをさらに減らす.コードは次のとおりです.
__global__ void matrixMulKernel(const float *A, const float *B, float *C,int Aw ,int Bw)
{
const int bs = CUDA_LG::block_size;
int tx = threadIdx.x;
int ty = threadIdx.y;
int bx = blockIdx.x;
int by = blockIdx.y;
int aBlockFisrt = by * bs * Aw ;
int aBlockStep = bs ;
int aBlockLast = by * bs * Aw + Aw - 1 ;
int bBlockFisrt = bx * bs ;
int bBlockStep = bs * Bw ;
float subC=0;
for(int a = aBlockFisrt,int b = bBlockFisrt; a <= aBlockLast ;a+=aBlockStep,b+=bBlockStep )
{
// shared memory
__shared__ float subA[bs][bs];
__shared__ float subB[bs][bs];
subA[ty][tx] = A[a + ty * Aw + tx];
subB[ty][tx] = B[b + ty * Bw + tx];
__syncthreads();
for(int i = 0;i<bs;i++)
{
subC += subA[ty][i] * subB[i][tx];
}
__syncthreads();
}
C[ by*bs*Bw + bx*bs + ty * Bw +tx] = subC;
}
参照sample_6.5\0_SimplematrixMulプログラム.コメント詳細
Rachel zhangのブログCUDA学習シリーズの2つを参照してください.http://blog.csdn.net/abcjennifer/article/details/42528569