SlideShare a Scribd company logo
第9回 行列計算(行列-行列積)
長岡技術科学大学 電気電子情報工学専攻 出川智啓
今回の内容
2015/06/10GPGPU実践プログラミング2
 行列-行列積
 CUDAによる行列-行列積の実装
 2次元的な並列化
 スレッド数の取り方による性能の変化
 共有メモリの利用
行列-行列積C=AB
 
k
jkkiji BAC ,,,
































NLL
N
LMM
L
NMM
N
BB
BB
AA
AA
CC
CC
,1,
,11,1
,1,
,11,1
,1,
,11,1









2015/06/10GPGPU実践プログラミング3
行列-行列積C=AB
2015/06/10GPGPU実践プログラミング4
 計算量は行列サイズの3乗に比例
 頻出しないが,出てくると確実にボトルネック化
 様々な高速化・並列化の方法が存在
 並列計算のテスト
 計算環境の評価
 アルゴリズムの評価
i
k
i
j
k
j
[A] [C]
[B]
配列アクセスのイメージ
2015/06/10GPGPU実践プログラミング5
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
C[i][j] = 0;
for(k=0;k<SIZE;k++){
C[i][j] += A[i][k]*B[k][j];
}
}
}
1次元配列での行列の表現
2015/06/10GPGPU実践プログラミング6
 1次元配列C[]を宣言し,整数型変数i,jを使って任意
の要素にアクセス
 行方向がi(第1次元),列方向がj(第2次元)
 画像処理など一般的な用途とは向きが異なる
 水平(x,行)方向がi,垂直(y,列)方向がj
 2次元配列の場合
 1次元配列の場合
C[1][2] = 9
C[_______] = 9
SIZE=6
1*6 + 2
C[i][j]  C[i*SIZE+j]
メモリアドレスが連続
i
j
1
7
2
8
3
9
4
10
5 6
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define SIZE 4096
#define Bytes (SIZE*SIZE*sizeof(float))
#define MILLISEC_PER_SEC 1000
#define FLOPS_TO_GFLOPS  1e‐9
void matmul(float *, float *, float *);
int main(void){
float *hA, *hB, *hC;
int i,j,k;
clock_t start_c, stop_c;
float time_s,time_ms;
float gflops;
hA = (float *)malloc(Bytes);
hB = (float *)malloc(Bytes);
hC = (float *)malloc(Bytes);
for(i=0;i<SIZE;i++){
for(k=0;k<SIZE;k++){
hA[i*SIZE + k]=(float)(i+1)*0.1f;
}
}
for(k=0;k<SIZE;k++){
for(j=0;j<SIZE;j++){
hB[k*SIZE + j]=(float)(j+1)*0.1f;
}
}
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
hC[i*SIZE + j] = 0.0f;
}
}
CPUプログラム
2015/06/10GPGPU実践プログラミング7
matmul.c
start_c = clock();
matmul(hA,hB,hC);
stop_c = clock();
time_s = (stop_c‐start_c)
/(float)CLOCKS_PER_SEC;
time_ms = time_s*MILLISEC_PER_SEC;
gflops = 2.0*SIZE*SIZE*SIZE/time_s
* FLOPS_TO_GFLOPS;
printf("%f ms¥n",time_ms);
printf("%f GFLOPS¥n",gflops);
return 0;
}
//行列-行列積
void matmul(float *A,float *B,float *C){
int i,j,k;
for(i=0; i<SIZE; i++){
for(j=0; j<SIZE; j++){
for(k=0; k<SIZE; k++){
C[i*SIZE+j] += 
A[i*SIZE+k]*B[k*SIZE+j];
}
}
}
}
CPUプログラム(続き)
2015/06/10GPGPU実践プログラミング8
matmul.c
行列-行列積の計算量
2015/06/10GPGPU実践プログラミング9
 計算能力FLOPS[flop/s]
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
C[i][j] = 0;
for(k=0;k<SIZE;k++){
C[i][j] += A[i][k]*B[k][j];
}
}
}
FLOPS=SIZE×SIZE×SIZE×2/実行時間
CPUプログラムの性能評価
 行列サイズ _____________2
 実行時間 _____________ ms
 実効性能 _____________ FLOPS
2015/06/10GPGPU実践プログラミング10
4096
≈600,000*
0.2G
*行列サイズを変えた時の実行時間の変化から推定
2562 30ms,1.2G
5122 350ms,0.77G
10242 8670ms,0.25G
20482 72680ms,0.24G
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
C[i*SIZE j] = 0;
for(k=0;k<SIZE;k++){
C[i*SIZE+j] 
+= A[i*SIZE+k]*B[k*SIZE+j];
}
}
}
GPUプログラム(1スレッド版)
i
k
i
j
k
j
[A] [C]
[B]
2015/06/10GPGPU実践プログラミング11
2次元的な配列アクセスの優先方向
2015/06/10GPGPU実践プログラミング12
 2次元配列の場合
in[][],out[][]
Ny
Nx
i
j
for(i=0;i<Nx;i++)
for(j=0;j<Ny;j++)
out[i][j]=in[i][j];
for(j=0;j<Ny;j++)
for(i=0;i<Nx;i++)
out[i][j]=in[i][j];
2次元的な配列アクセスの優先方向
2015/06/10GPGPU実践プログラミング13
 2次元配列の場合
for(i=0;i<Nx;i++)
for(j=0;j<Ny;j++)
out[i][j]=in[i][j];
in[][],out[][]
for(j=0;j<Ny;j++)
for(i=0;i<Nx;i++)
out[i][j]=in[i][j];
Ny
Nx
i
j
2次元的な配列アクセスの優先方向
2015/06/10GPGPU実践プログラミング14
 2次元配列の1次元配列的表現
for(i=0;i<Nx;i++)
for(j=0;j<Ny;j++)
out[i][j]=in[i][j];
in[],out[]
for(i=0;i<Nx;i++)
for(j=0;j<Ny;j++)
out[i*Ny+j]=
in[i*Ny+j];
Ny
Nx
i
j
2次元的な配列アクセスの優先方向
2015/06/10GPGPU実践プログラミング15
 CUDAで2次元的に並列化してアクセスする場合
i = blockIdx.x*blockDim.x
+ threadIdx.x;
j = blockIdx.y*blockDim.y
+ threadIdx.y;
out[j*Nx+i]=in[j*Nx+i];
in[],out[]
for(i=0;i<Nx;i++)
for(j=0;j<Ny;j++)
out[i*Ny+j]=
in[i*Ny+j];
threadIdx.y
threadIdx.x
Ny
Nx
i
j
for(j=0;j<SIZE;j++){     //ループを入れ替え
for(i=0;i<SIZE;i++){ //
C[i+SIZE*j] = 0;
for(k=0;k<SIZE;k++){
C[i+SIZE*j] 
+= A[i+SIZE*k]*B[k+SIZE*j];
}
}
}
GPUプログラム(1スレッド版)
i
k
i
j
k
j
[A] [C]
[B]
2015/06/10GPGPU実践プログラミング16
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define SIZE 4096
#define Bytes (SIZE*SIZE*sizeof(float))
#define MILLISEC_PER_SEC 1000
#define FLOPS_TO_GFLOPS  1e‐9
void matmul(float *, float *, float *);
int main(void){
float *hA, *hB, *hC;
int i,j,k;
clock_t start_c, stop_c;
float time_s,time_ms;
float gflops;
hA = (float *)malloc(Bytes);
hB = (float *)malloc(Bytes);
hC = (float *)malloc(Bytes);
for(k=0;k<SIZE;k++){  //ループを入れ替え
for(i=0;i<SIZE;i++){//
hA[i+SIZE*k]=(float)(k+1)*0.1f;
}
}
for(j=0;j<SIZE;j++){  //ループを入れ替え
for(k=0;k<SIZE;k++){//
hB[k+SIZE*j]=(float)(k+1)*0.1f;
}
}
for(j=0;j<SIZE;j++){  //ループを入れ替え
for(i=0;i<SIZE;i++){//
hC[i+SIZE*j] = 0.0f;
}
}
CPUプログラム(GPU移植用修正版)
2015/06/10GPGPU実践プログラミング17
matmul2.c
start_c = clock();
matmul(hA,hB,hC);
stop_c = clock();
time_s = (stop_c‐start_c)
/(float)CLOCKS_PER_SEC;
time_ms = time_s*MILLISEC_PER_SEC;
gflops = 2.0*SIZE*SIZE*SIZE/time_s
* FLOPS_TO_GFLOPS;
printf("%f ms¥n",time_ms);
printf("%f GFLOPS¥n",gflops);
return 0;
}
//行列-行列積
void matmul(float *A,float *B,float *C){
int i,j,k;
for(j=0;j<SIZE;j++){  //ループを入れ替え
for(i=0;i<SIZE;i++){//
for(k=0; k<SIZE; k++){
C[i+SIZE*j] += 
A[i+SIZE*k]*B[k+SIZE*j];
}
}
}
}
CPUプログラム(GPU移植用修正版)
2015/06/10GPGPU実践プログラミング18
matmul2.c
//#include, #defineは省略
#include "mm1.cu" //ここのファイル名(*.cu)を変更することで行列-行列積のKernelを切り替え
int main(void){
//CPU用の変数宣言などは省略
float *dA, *dB, *dC;
float *GPUresult; //GPUでの計算結果を受け取る用
cudaMalloc( (void**)&dA, Bytes );
cudaMalloc( (void**)&dB, Bytes );
cudaMalloc( (void**)&dC, Bytes );
GPUresult = (float *)malloc(Bytes);
cudaMemcpy( dA, hA, SIZE*SIZE*sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy( dB, hB, SIZE*SIZE*sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy( dC, hC, SIZE*SIZE*sizeof(float), cudaMemcpyHostToDevice);
dim3 Thread = dim3(THREADX,THREADY,1); //実行用パラメータの宣言と設定
dim3 Block  = dim3(BLOCKX ,BLOCKY, 1); //実行用パラメータの宣言と設定
matmulGPU<<<Block,Thread>>>(dA,dB,dC); //行列‐行列積の実行
cudaMemcpy(GPUresult, dC, SIZE*SIZE*sizeof(float), cudaMemcpyDeviceToHost);
//ここ以降で結果が正しいかチェック
return 0;
}
GPUプログラム(CPU処理用共通部分)
2015/06/10GPGPU実践プログラミング19
matmul.cu
2次元的な並列度の指定
2015/06/10GPGPU実践プログラミング20
 <<<ブロック数,1ブロックあたりのスレッド数>>>
 gridDim, blockDimを指定していることと同じ
 x,y,zをメンバに持つdim3構造体
 指定しないメンバは1で初期化される
 dim3型構造体変数の宣言と値の代入
 dim3 変数名 = dim3(xの値, yの値, zの値);
 dim3 変数名;でdim3型構造体変数を宣言
 変数名 = dim3(xの値, yの値, zの値);で値を代入
 dim3 Thread = dim3(THREADX,THREADY,1);
 dim3 Block  = dim3(BLOCKX ,BLOCKY, 1); 
2次元的な並列度の指定
2015/06/10GPGPU実践プログラミング21
#define THREADX ...
#define THREADY ...
#define BLOCKX  ...
#define BLOCKY  ...
int main(void){
dim3 block(2,2,1), thread(4,4,1);
matmul<<<block, thread>>>(...);
dim3 Thread = dim3(THREADX,THREADY,1);
dim3 Block  = dim3(BLOCKX ,BLOCKY, 1); 
matmul<<<Block, Thread>>>(...);
matmul<<<dim3(2,2,1), dim3(4,4,1)>>>(...);
}
dim3型変数block, 
threadを利用
・・・
あるいは直接dim3
型として記述
・・・
dim3型変数のもう
一つの宣言方法
・・・
//1スレッドが全ての要素を計算
#define THREADX 1
#define THREADY 1
#define BLOCKX  1
#define BLOCKY  1
__global__ void matmulGPU(float *A, float *B, float *C){
int i,j,k;
for(j=0; j<SIZE; j++){     //ループを入れ替え
for(i=0; i<SIZE; i++){ //
for(k=0; k<SIZE; k++){
//C[i*SIZE+j] += A[i*SIZE+k]*B[k*SIZE+j];
C[i+SIZE*j] += A[i+SIZE*k]*B[k+SIZE*j];
}
}
}
}
GPUプログラム(行列-行列積カーネル)
2015/06/10GPGPU実践プログラミング22
mm1.cu
GPUプログラムの性能評価
 行列サイズ _____________2
 実行時間 _____________ ms
 実効性能 _____________ FLOPS
1スレッド版は時間がかかりすぎるので
時間があるときにやりましょう
2015/06/10GPGPU実践プログラミング23
4096
≈20,000,000
6M
1282 328ms,0.013G
2562 5153ms,0.0065G
5122 42149ms,0.0064G
GPUへの移植
2015/06/10GPGPU実践プログラミング24
 2次元的に並列化し,1スレッドが1点の積を計算
 行列サイズ8x8, ブロックを各方向2,ブロック内のス
レッド数を4に設定
GPUへの移植
2015/06/10GPGPU実践プログラミング25
 2次元的に並列化し,1スレッドが1成分の積を計算
blockIdx.y=0 blockIdx.y=1
blockIdx.x=0blockIdx.x=1
gridDim.y=2
gridDim.x=2
blockDim.y=4
blockDim.x=4
threadIdx.x=
threadIdx.y=
1スレッドが読み込む配列要素の決定
2015/06/10GPGPU実践プログラミング26
 i = blockIdx.x*blockDim.x + threadIdx.x
 j = blockIdx.y*blockDim.y + threadIdx.y
(0,0)(0,1)(0,2)(0,3)(0,0)
(3,3) (3,3)
(1,0)(1,1)(1,2)(1,3)
(2,0)(2,1)(2,2)(2,3)
(3,0)(3,1)(3,2)(3,3) (3,3)
(0,0) (0,0)
block(0,0) block(0,1)
block(1,0) block(1,1)
threadIdx
threadIdx.x
threadIdx.y
j= 0 1 2 3 4 5 6 7
i=01234567
1スレッドが1要素の計算を担当
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
i
k
i
j
k
j
[A] [C]
[B]
THREADX
THREADY
2015/06/10GPGPU実践プログラミング27
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
for(k=0;k<SIZE;k++){
C[i+SIZE*j] 
+= A[i+SIZE*k]*B[k+SIZE*j];
}
}
}
1スレッドが1要素の計算を担当
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
i
k
i
j
k
j
[A] [C]
[B]
THREADX
THREADY
2015/06/10GPGPU実践プログラミング28
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
for(k=0;k<SIZE;k++){
C[i+SIZE*j] 
+= A[i+SIZE*k]*B[k+SIZE*j];
}
}
}
1スレッドが1要素の計算を担当
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
i
k
i
j
k
j
[A] [C]
[B]
THREADX
THREADY
2015/06/10GPGPU実践プログラミング29
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
for(k=0;k<SIZE;k++){
C[i+SIZE*j] 
+= A[i+SIZE*k]*B[k+SIZE*j];
}
}
}
1スレッドが1要素の計算を担当
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
i
k
i
j
k
j
[A] [C]
[B]
THREADX
THREADY
2015/06/10GPGPU実践プログラミング30
for(i=0;i<SIZE;i++){
for(j=0;j<SIZE;j++){
for(k=0;k<SIZE;k++){
C[i+SIZE*j] 
+= A[i+SIZE*k]*B[k+SIZE*j];
}
}
}
//1スレッド(i,j)がCijの計算を担当
#define THREADX 16
#define THREADY 16
#define BLOCKX  (SIZE/THREADX)
#define BLOCKY  (SIZE/THREADY)
__global__ void matmulGPU(float *A, float *B, float *C){
int i,j,k;
i = blockIdx.x*blockDim.x + threadIdx.x;
j = blockIdx.y*blockDim.y + threadIdx.y;
C[i*SIZE + j]=0.0f;
for(k=0; k<SIZE; k++){
C[i+SIZE*j] += A[i+SIZE*k] * B[k+SIZE*j];
}
}
GPUプログラム(行列-行列積カーネル)
2015/06/10GPGPU実践プログラミング31
mm2.cu
//1スレッド(i,j)がCijの計算を担当
#define THREADX 16
#define THREADY 16
#define BLOCKX  (SIZE/THREADX)
#define BLOCKY  (SIZE/THREADY)
__global__ void matmulGPU(float *A, float *B, float *C){
int i,j,k;
float sum = 0.0f; ・・・レジスタを使う
i = blockIdx.x*blockDim.x + threadIdx.x;
j = blockIdx.y*blockDim.y + threadIdx.y;
for(k=0; k<SIZE; k++){
sum += A[i+SIZE*k] * B[k+SIZE*j]; ・・・レジスタを使うことでグローバル
}                                        メモリへのアクセス回数を減らす
C[i+SIZE*j] = sum; ・・・レジスタからグローバルメモリへ
}                                            代入
GPUプログラム(行列-行列積カーネル)
2015/06/10GPGPU実践プログラミング32
mm2.cu
GPUプログラムの性能評価
 行列サイズ _____________2
 ブロック _____________
 スレッド _____________
 実行時間 _____________ ms
 実効性能 _____________ FLOPS
2015/06/10GPGPU実践プログラミング33
4096
2,600
53G
16×16
256×256
GPUプログラムのパラメータチューニング
2015/06/10GPGPU実践プログラミング34
 1スレッドが1点の計算を担当
 i行j列の計算を担当
 スレッドの割り当て方で性能が変化
 どのような割り当て方がいいのか?
 それはなぜか?
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロックTHREADX
THREADY
GPUプログラムのパラメータチューニング
2015/06/10GPGPU実践プログラミング35
 1スレッドが1点の計算を担当
 i行j列の計算を担当
 スレッドの割り当て方で性能が変化
 どのような割り当て方がいいのか?
 それはなぜか?
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロックTHREADX
THREADY
GPUプログラムの評価(FLOPS)
 行列サイズ _____________2
THREADY→
THREADX↓ 1 2 4 8 16 32 64 128 256 512 1024
1
2 ‐
4 ‐ ‐
8 ‐ ‐ ‐
16 ‐ ‐ ‐ ‐
32 ‐ ‐ ‐ ‐ ‐
64 ‐ ‐ ‐ ‐ ‐ ‐
128 ‐ ‐ ‐ ‐ ‐ ‐ ‐
256 ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐
512 ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐
1024 ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐
行列が大
きいとここ
が高速
CUDAの制限に
より実行不可能
2015/06/10GPGPU実践プログラミング36
4096
GPUプログラムの評価(FLOPS)
 行列サイズ _____________2
THREADY→
THREADX↓ 1 2 4 8 16 32 64 128 256 512 1024
1 0.5 0.9 1.8 3.7 4.8 3.8 3.2 1.9 1.6 1.5 1.5
2 0.9 1.9 3.7 7.3 9.5 7.5 6.3 4.5 4.1 5.4 ‐
4 1.8 3.7 7.4 15 19 14 12 12 13 ‐ ‐
8 3.7 7.4 15 29 31 27 28 32 ‐ ‐ ‐
16 7.3 15 29 55 53 53 54 ‐ ‐ ‐ ‐
32 15 29 57 69 60 53 ‐ ‐ ‐ ‐ ‐
64 29 57 71 67 53 ‐ ‐ ‐ ‐ ‐ ‐
128 47 79 70 54 ‐ ‐ ‐ ‐ ‐ ‐ ‐
256 49 78 58 ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐
512 48 57 ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐
1024 49 ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐
CUDAの制限に
より実行不可能
2015/06/10GPGPU実践プログラミング37
4096
GPUプログラムの評価(FLOPS)
(i*SIZE+jで配列へアクセス )
 行列サイズ _____________2
2015/06/10GPGPU実践プログラミング38
4096
THREADY→
THREADX↓
1 2 4 8 16 32 64 128 256 512
1 0.4 0.9 1.8 3.6 7.2 14.6 29.1 56.8 71.5 68.3
2 0.9 1.8 3.6 7.2 14.5 28.9 56.0 81.6 82.0 57.9
4 1.8 3.6 7.2 14.3 28.5 53.9 49.9 48.9 57.4 ‐
8 3.5 7.0 14.1 28.2 21.9 18.5 21.2 47.1 ‐ ‐
16 4.6 9.2 14.0 38.0 7.8 11.0 29.5 ‐ ‐ ‐
32 3.6 3.9 2.3 2.2 2.7 11.1 ‐ ‐ ‐ ‐
64 2.8 2.2 1.8 2.0 10.2 ‐ ‐ ‐ ‐ ‐
128 1.5 1.7 1.7 3.2 ‐ ‐ ‐ ‐ ‐ ‐
256 1.4 1.5 2.1 ‐ ‐ ‐ ‐ ‐ ‐ ‐
512 1.4 1.6 ‐ ‐ ‐ ‐ ‐ ‐ ‐ ‐
共有メモリによるデータ再利用
2015/06/10GPGPU実践プログラミング39
 各スレッドは異なる[A]の行(i)にアクセス
 [B]の列(j)は同じ
 列の読み込みはSIZE回(i=0,1,・・・,SIZE‐1)
 全てのスレッドが同じ列をSIZE回読込
 [B]の再利用で高速化できるのでは?
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロックTHREADX
THREADY
i
k
i
j
k
j
[A] [C]
[B]
共有メモリによるデータ再利用
2015/06/10GPGPU実践プログラミング40
 各スレッドは異なる[A]の行(i)にアクセス
 [B]の列(j)は同じ
 Bk,jだけでなくスレッド数分(Bk,j, Bk+1,j,・・・)
読み込んでどこかに保持
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロックTHREADX
THREADY
共有メモリによるデータ再利用
2015/06/10GPGPU実践プログラミング41
 各スレッドは異なる[A]の行(i)にアクセス
 [B]の列(j)は同じ
 Bk,jだけでなくスレッド数分(Bik,j, Bk+1,j,・・・)
読み込んでどこかに保持
 保持したデータから読み出し
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロックTHREADX
THREADY
L2キャッシュ
コンスタントメモリ
テクスチャメモリ
GPU
レジ
スタ
レジ
スタ
レジ
スタ
レジ
スタ
CUDA 
Core
CUDA 
Core
CUDA 
Core
CUDA 
Core
L1キャッ
シュ
共有
メモリ
SM
レジ
スタ
レジ
スタ
レジ
スタ
レジ
スタ
CUDA 
Core
CUDA 
Core
CUDA 
Core
CUDA 
Core
L1キャッ
シュ
共有
メモリ
SM
グローバルメモリ
ローカル
メモリ
ローカル
メモリ
ローカル
メモリ
ローカル
メモリ
・・・
・・・
Chip
共有(シェアード)メモリ
 ブロック内のスレッドが共通
のデータ(メモリアドレス)に
アクセス可能
 物理的にSMに近い
 遅延はグローバルメモリの
20~30分の1,帯域幅は10倍
2015/06/10GPGPU実践プログラミング42
 Fermi世代以前のGPUで
マネージドキャッシュとして
利用
 1ブロックあたり
16,32*,48kB
*Kepler世代から
ホスト
メモリ
//1スレッド(i,j)がCijの計算を担当
//共有メモリによるデータ再利用版
#define THREADX 256
#define THREADY 1
#define BLOCKX  (SIZE/THREADX)
#define BLOCKY  (SIZE/THREADY)
__global__ void matmulGPU
(float *A, float *B, float *C){
int i,j,k;
float sum=0.0f;
int tx;
__shared__ float sB[THREADX];
i = blockIdx.x*blockDim.x+threadIdx.x;
j = blockIdx.y*blockDim.y+threadIdx.y;
tx= threadIdx.x;
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j];
__syncthreads();
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();
}
C[i+SIZE*j] = sum;
}
GPUプログラム(行列-行列積カーネル)
2015/06/10GPGPU実践プログラミング43
mm3.cu
共有メモリの宣言
2015/06/10GPGPU実践プログラミング44
 1ブロック内でデータを共有
 スレッド(0,0)がBk,j,スレッド(1,0)が
Bk+1,j,・・・にアクセス
 必要な要素数は行方向のスレッド分
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロックTHREADX
THREADY
THREADX
THREADX
THREADX
__shared__ float sB[THREADX];
共有メモリへ代入
2015/06/10GPGPU実践プログラミング45
i
k
i
j
k
j
[A] [C]
[B]
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j]; //k=0
__syncthreads(); //同期を取る
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();
}
C[i+SIZE*j] = sum;
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
共有メモリ
tx=
0
1
2
THREADX
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j]; //k=0
__syncthreads();
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();
}
C[i+SIZE*j] = sum;
共有メモリから読込
2015/06/10GPGPU実践プログラミング46
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
共有メモリ
w
w
00+0
THREADX
共有メモリから読込
2015/06/10GPGPU実践プログラミング47
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
共有メモリ
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j]; //k=0
__syncthreads();
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();
}
C[i+SIZE*j] = sum; w
w
THREADX
10+1
共有メモリから読込
2015/06/10GPGPU実践プログラミング48
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
共有メモリ
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j]; //k=0
__syncthreads(); 
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();//同期を取る
}
C[i+SIZE*j] = sum; w
w
THREADX
20+2
共有メモリへ代入
2015/06/10GPGPU実践プログラミング49
i
k
i
j
k
j
[A] [C]
[B]
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j]; //k=3
__syncthreads(); //同期を取る
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();
}
C[i+SIZE*j] = sum;
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
共有メモリ
tx=
0
1
2
THREADX
共有メモリから読込
2015/06/10GPGPU実践プログラミング50
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
共有メモリ
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j]; //k=3
__syncthreads(); 
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();
}
C[i+SIZE*j] = sum;
w
w
THREADX
03+0
共有メモリから読込
2015/06/10GPGPU実践プログラミング51
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
共有メモリ
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j]; //k=3
__syncthreads(); 
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();
}
C[i+SIZE*j] = sum; w
w
THREADX
13+1
共有メモリから読込
2015/06/10GPGPU実践プログラミング52
i
k
i
j
k
j
[A] [C]
[B]
1スレッドの計算担当
1スレッドのメモリ
アクセス範囲
1ブロック
共有メモリ
for(k=0; k<SIZE; k+=THREADX){
sB[tx] = B[(k+tx)+SIZE*j]; //k=3
__syncthreads(); 
for(int w = 0;w<THREADX;w++){
sum += A[i+SIZE*(k+w)]*sB[w];
}
__syncthreads();//同期を取る
}
C[i+SIZE*j] = sum; w
w
THREADX
23+2
GPUプログラムの性能評価
 行列サイズ _____________2
 ブロック _____________
 スレッド _____________
 実行時間 _____________ ms
 実効性能 _____________ FLOPS
2015/06/10GPGPU実践プログラミング53
4096
2,600
49G‐>52G
256×1
16×4096
128×1 2841ms,48G
256×1 2631ms,52G
512×1 2748ms,50G
1024×1 2876ms,48G

More Related Content

PDF
2015年度GPGPU実践プログラミング 第10回 行列計算(行列-行列積の高度な最適化)
PDF
2015年度GPGPU実践プログラミング 第7回 総和計算
PDF
2015年度GPGPU実践プログラミング 第5回 GPUのメモリ階層
PDF
いまさら聞けない!CUDA高速化入門
PPTX
強化学習 DQNからPPOまで
PDF
CUDAプログラミング入門
PDF
第1回 配信講義 計算科学技術特論A (2021)
PDF
2015年度先端GPGPUシミュレーション工学特論 第7回 総和計算(Atomic演算)
2015年度GPGPU実践プログラミング 第10回 行列計算(行列-行列積の高度な最適化)
2015年度GPGPU実践プログラミング 第7回 総和計算
2015年度GPGPU実践プログラミング 第5回 GPUのメモリ階層
いまさら聞けない!CUDA高速化入門
強化学習 DQNからPPOまで
CUDAプログラミング入門
第1回 配信講義 計算科学技術特論A (2021)
2015年度先端GPGPUシミュレーション工学特論 第7回 総和計算(Atomic演算)

What's hot (20)

PDF
プログラムを高速化する話Ⅱ 〜GPGPU編〜
PDF
GPGPU Seminar (GPU Accelerated Libraries, 3 of 3, Thrust)
PDF
Optimizer入門&最新動向
PDF
(文献紹介)Deep Unrolling: Learned ISTA (LISTA)
PDF
POMDP下での強化学習の基礎と応用
PDF
【DL輪読会】Domain Generalization by Learning and Removing Domainspecific Features
PPTX
【DL輪読会】Scaling Laws for Neural Language Models
PDF
CUDAメモ
PPTX
[DL輪読会]World Models
PDF
GPGPU Seminar (GPGPU and CUDA Fortran)
PDF
[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介
PDF
プログラムを高速化する話
PDF
SSII2021 [TS2] 深層強化学習 〜 強化学習の基礎から応用まで 〜
PDF
SLAMチュートリアル大会資料(ORB-SLAM)
PPTX
分散深層学習 @ NIPS'17
PDF
CUDAのアセンブリ言語基礎のまとめ PTXとSASSの概説
PDF
グラフニューラルネットワーク入門
PDF
TVM の紹介
PDF
C++による数値解析の並列化手法
プログラムを高速化する話Ⅱ 〜GPGPU編〜
GPGPU Seminar (GPU Accelerated Libraries, 3 of 3, Thrust)
Optimizer入門&最新動向
(文献紹介)Deep Unrolling: Learned ISTA (LISTA)
POMDP下での強化学習の基礎と応用
【DL輪読会】Domain Generalization by Learning and Removing Domainspecific Features
【DL輪読会】Scaling Laws for Neural Language Models
CUDAメモ
[DL輪読会]World Models
GPGPU Seminar (GPGPU and CUDA Fortran)
[GTCJ2018]CuPy -NumPy互換GPUライブラリによるPythonでの高速計算- PFN奥田遼介
プログラムを高速化する話
SSII2021 [TS2] 深層強化学習 〜 強化学習の基礎から応用まで 〜
SLAMチュートリアル大会資料(ORB-SLAM)
分散深層学習 @ NIPS'17
CUDAのアセンブリ言語基礎のまとめ PTXとSASSの概説
グラフニューラルネットワーク入門
TVM の紹介
C++による数値解析の並列化手法
Ad

Viewers also liked (20)

PDF
2015年度GPGPU実践基礎工学 第4回 CPUのアーキテクチャ
PDF
2015年度GPGPU実践プログラミング 第11回 画像処理
PDF
2015年度GPGPU実践基礎工学 第1回 学際的分野における先端シミュレーション技術の歴史
PDF
2015年度GPGPU実践プログラミング 第14回 N体問題
PDF
2015年度GPGPU実践プログラミング 第13回 多粒子の運動
PDF
2015年度GPGPU実践プログラミング 第2回 GPUのアーキテクチャとプログラム構造
PDF
2015年度GPGPU実践基礎工学 第3回 GPUクラスタ上でのプログラミング(CUDA)
PDF
2015年度GPGPU実践プログラミング 第1回 GPGPUの歴史と応用例
PDF
2015年度GPGPU実践プログラミング 第8回 総和計算(高度な最適化)
PDF
2015年度GPGPU実践プログラミング 第4回 GPUでの並列プログラミング(ベクトル和,移動平均,差分法)
PDF
2015年度GPGPU実践プログラミング 第6回 パフォーマンス解析ツール
PDF
2015年度GPGPU実践プログラミング 第12回 偏微分方程式の差分計算
PDF
2015年度GPGPU実践基礎工学 第9回補足 GROUSEの利用方法
PDF
2015年度GPGPU実践基礎工学 第7回 シングルコアとマルチコア
PDF
2015年度GPGPU実践基礎工学 第12回 GPUによる画像処理
PDF
2015年度GPGPU実践基礎工学 第6回 ソフトウェアによるCPUの高速化技術
PDF
2015年度GPGPU実践基礎工学 第13回 GPUのメモリ階層
PDF
2015年度GPGPU実践基礎工学 第5回 ハードウェアによるCPUの高速化技術
PDF
2015年度GPGPU実践基礎工学 第8回 並列計算の概念 (プロセスとスレッド)
PDF
2015年度GPGPU実践プログラミング 第15回 GPU最適化ライブラリ
2015年度GPGPU実践基礎工学 第4回 CPUのアーキテクチャ
2015年度GPGPU実践プログラミング 第11回 画像処理
2015年度GPGPU実践基礎工学 第1回 学際的分野における先端シミュレーション技術の歴史
2015年度GPGPU実践プログラミング 第14回 N体問題
2015年度GPGPU実践プログラミング 第13回 多粒子の運動
2015年度GPGPU実践プログラミング 第2回 GPUのアーキテクチャとプログラム構造
2015年度GPGPU実践基礎工学 第3回 GPUクラスタ上でのプログラミング(CUDA)
2015年度GPGPU実践プログラミング 第1回 GPGPUの歴史と応用例
2015年度GPGPU実践プログラミング 第8回 総和計算(高度な最適化)
2015年度GPGPU実践プログラミング 第4回 GPUでの並列プログラミング(ベクトル和,移動平均,差分法)
2015年度GPGPU実践プログラミング 第6回 パフォーマンス解析ツール
2015年度GPGPU実践プログラミング 第12回 偏微分方程式の差分計算
2015年度GPGPU実践基礎工学 第9回補足 GROUSEの利用方法
2015年度GPGPU実践基礎工学 第7回 シングルコアとマルチコア
2015年度GPGPU実践基礎工学 第12回 GPUによる画像処理
2015年度GPGPU実践基礎工学 第6回 ソフトウェアによるCPUの高速化技術
2015年度GPGPU実践基礎工学 第13回 GPUのメモリ階層
2015年度GPGPU実践基礎工学 第5回 ハードウェアによるCPUの高速化技術
2015年度GPGPU実践基礎工学 第8回 並列計算の概念 (プロセスとスレッド)
2015年度GPGPU実践プログラミング 第15回 GPU最適化ライブラリ
Ad

Similar to 2015年度GPGPU実践プログラミング 第9回 行列計算(行列-行列積) (20)

PDF
GPGPU Education at Nagaoka University of Technology: A Trial Run
PDF
2015年度GPGPU実践基礎工学 第11回 GPUでの並列 プログラミング(ベクトル和)
PPTX
GPUによる多倍長整数乗算の高速化手法の提案
PDF
GPGPU Seminar (GPU Accelerated Libraries, 2 of 3, cuSPARSE)
PDF
技術系大学におけるGPU教育の一試行
PDF
[関東GPGPU勉強会#2] ライブラリを使って大規模疎行列線形方程式を解いてみよう
PDF
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
PDF
動的計画法の並列化
PDF
CUDA1日(?)体験会
PDF
2015年度GPGPU実践プログラミング 第3回 GPGPUプログラミング環境
PDF
CUDA1日(?)体験会 (再アップロード)
PDF
GPGPU Seminar (GPU Accelerated Libraries, 1 of 3, cuBLAS)
KEY
NVIDIA Japan Seminar 2012
PDF
1072: アプリケーション開発を加速するCUDAライブラリ
PDF
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
PDF
Hello, DirectCompute
PDF
第11回 配信講義 計算科学技術特論B(2022)
PDF
2015年度先端GPGPUシミュレーション工学特論 第15回 CPUとGPUの協調
PDF
200625material naruse
GPGPU Education at Nagaoka University of Technology: A Trial Run
2015年度GPGPU実践基礎工学 第11回 GPUでの並列 プログラミング(ベクトル和)
GPUによる多倍長整数乗算の高速化手法の提案
GPGPU Seminar (GPU Accelerated Libraries, 2 of 3, cuSPARSE)
技術系大学におけるGPU教育の一試行
[関東GPGPU勉強会#2] ライブラリを使って大規模疎行列線形方程式を解いてみよう
CMSI計算科学技術特論B(14) OpenACC・CUDAによるGPUコンピューティング
動的計画法の並列化
CUDA1日(?)体験会
2015年度GPGPU実践プログラミング 第3回 GPGPUプログラミング環境
CUDA1日(?)体験会 (再アップロード)
GPGPU Seminar (GPU Accelerated Libraries, 1 of 3, cuBLAS)
NVIDIA Japan Seminar 2012
1072: アプリケーション開発を加速するCUDAライブラリ
GPU-FPGA 協調計算を記述するためのプログラミング環境に関する研究(HPC169 No.10)
Hello, DirectCompute
第11回 配信講義 計算科学技術特論B(2022)
2015年度先端GPGPUシミュレーション工学特論 第15回 CPUとGPUの協調
200625material naruse

More from 智啓 出川 (20)

PDF
Fortranが拓く世界、VSCodeが架ける橋
PDF
Very helpful python code to find coefficients of the finite difference method
PDF
Why do we confuse String and Array of Characters in Fortran?
PDF
Pythonによる累乗近似
PDF
数値計算結果のPythonによる後処理について(1次元データのピーク値およびその位置の推定)
PDF
オブジェクト指向Fortranが拓く(はずだった)新しい世界
PPTX
Schematic diagrams of GPUs' architecture and Time evolution of theoretical FL...
PDF
Cuda fortranの利便性を高めるfortran言語の機能
PDF
PGI CUDA FortranとGPU最適化ライブラリの一連携法
PPTX
教育機関でのJetsonの活用の可能性
PDF
GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)
PDF
GPGPU Seminar (PyCUDA)
PDF
2015年度先端GPGPUシミュレーション工学特論 第14回 複数GPUの利用
PDF
2015年度先端GPGPUシミュレーション工学特論 第13回 数値流体力学への応用 (高度な最適化)
PDF
2015年度先端GPGPUシミュレーション工学特論 第11回 数値流体力学への応用 (支配方程式,CPUプログラム)
PDF
2015年度先端GPGPUシミュレーション工学特論 第10回 Poisson方程式の求解 (線形連立一次方程式)
PDF
2015年度先端GPGPUシミュレーション工学特論 第9回 偏微分方程式の差分計算 (移流方程式)
PDF
2015年度先端GPGPUシミュレーション工学特論 第8回 偏微分方程式の差分計算 (拡散方程式)
PDF
2015年度先端GPGPUシミュレーション工学特論 第6回 プログラムの性能評価指針 (Flop/Byte,計算律速,メモリ律速)
PDF
2015年度先端GPGPUシミュレーション工学特論 第5回 GPUのメモリ階層の詳細 (様々なメモリの利用)
Fortranが拓く世界、VSCodeが架ける橋
Very helpful python code to find coefficients of the finite difference method
Why do we confuse String and Array of Characters in Fortran?
Pythonによる累乗近似
数値計算結果のPythonによる後処理について(1次元データのピーク値およびその位置の推定)
オブジェクト指向Fortranが拓く(はずだった)新しい世界
Schematic diagrams of GPUs' architecture and Time evolution of theoretical FL...
Cuda fortranの利便性を高めるfortran言語の機能
PGI CUDA FortranとGPU最適化ライブラリの一連携法
教育機関でのJetsonの活用の可能性
GPGPU Seminar (Accelerataion of Lattice Boltzmann Method using CUDA Fortran)
GPGPU Seminar (PyCUDA)
2015年度先端GPGPUシミュレーション工学特論 第14回 複数GPUの利用
2015年度先端GPGPUシミュレーション工学特論 第13回 数値流体力学への応用 (高度な最適化)
2015年度先端GPGPUシミュレーション工学特論 第11回 数値流体力学への応用 (支配方程式,CPUプログラム)
2015年度先端GPGPUシミュレーション工学特論 第10回 Poisson方程式の求解 (線形連立一次方程式)
2015年度先端GPGPUシミュレーション工学特論 第9回 偏微分方程式の差分計算 (移流方程式)
2015年度先端GPGPUシミュレーション工学特論 第8回 偏微分方程式の差分計算 (拡散方程式)
2015年度先端GPGPUシミュレーション工学特論 第6回 プログラムの性能評価指針 (Flop/Byte,計算律速,メモリ律速)
2015年度先端GPGPUシミュレーション工学特論 第5回 GPUのメモリ階層の詳細 (様々なメモリの利用)

2015年度GPGPU実践プログラミング 第9回 行列計算(行列-行列積)