質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

CUDA

CUDAは並列計算プラットフォームであり、Nvidia GPU(Graphics Processing Units)向けのプログラミングモデルです。CUDAは様々なプログラミング言語、ライブラリ、APIを通してNvidiaにインターフェイスを提供します。

Q&A

解決済

1回答

2845閲覧

CUDA 行列の内積での疑問点

退会済みユーザー

退会済みユーザー

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

CUDA

CUDAは並列計算プラットフォームであり、Nvidia GPU(Graphics Processing Units)向けのプログラミングモデルです。CUDAは様々なプログラミング言語、ライブラリ、APIを通してNvidiaにインターフェイスを提供します。

0グッド

0クリップ

投稿2019/02/27 05:30

疑問点のあるコード

c言語歴5ヶ月,cuda歴5日の初心者です。現在c++で多層パーセプトロンのライブラリを
作成中なのですがcpuで計算させるためのコードは完成し、GPUバージョンを作ろうと
cudaに手を出したのですが内積の処理を行うサンプルコードがわけわからなくて
大変苦しんでおります。
ある程度qiitaなどを参考に理解できましたがどうしてもわからない点が二点あるので
大変初歩的な質問では御座いますがどうかご教授よろしくお願いします。

c

1///////////////////////////////////////////////////////////////////////// 2// 3// このコードでは入力配列Adと入力配列Bdの内積を行い結果を配列Cdへ格納する 4// 5// Ad dot Bd = Cd 6// ↑ ↑ ↑ 7// (200,300)(300,500)(200,500) 8// 9////////////////////////////////////////////////////////////////////////// 10 11#include <stdio.h> 12#include <stdlib.h> 13#include <cuda.h> 14#include <cuda_runtime.h> 15#include <sys/time.h> 16 17////////////////////////////////////////////////////////// 18// ↓GPU側で内積を行う関数 19////////////////////////////////////////////////////////// 20 21__global__ 22void matmul(float *A, float *B, float *C, int l, int m, int n) 23{ 24 int i, j, k; 25 float sum; 26 27 i = blockIdx.y * blockDim.y + threadIdx.y; 28 j = blockIdx.x * blockDim.x + threadIdx.x; 29 30 sum = 0.0; 31 for (k = 0; k < m; k++) { 32 sum += A[i * m + k] * B[k * n + j]; 33 } 34 C[i*n+j] = sum; 35} 36 37////////////////////////////////////////////////////////// 38// ↓行列に乱数代入 39////////////////////////////////////////////////////////// 40 41void init_matrix(float *m, int h, int w) 42{ 43 int i, j; 44 for (i = 0; i < h; i++) 45 for (j = 0; j < w; j++) 46 m[i * w + j] = (float)random(); 47} 48 49////////////////////////////////////////////////////////// 50// ↓処理時間計算 51////////////////////////////////////////////////////////// 52double get_elapsed_time(struct timeval *begin, struct timeval *end) 53{ 54 return (end->tv_sec - begin->tv_sec) * 1000 55 + (end->tv_usec - begin->tv_usec) / 1000.0; 56} 57 58////////////////////////////////////////////////////////// 59// ↓メイン関数 60////////////////////////////////////////////////////////// 61int main(int argc, char *argv[]) 62{ 63 float *Ad, *Bd, *Cd;//GPU側のメモリ(配列) 64 float *Ah, *Bh, *Ch;//CPU側のメモリ(配列) 65 struct timeval t1, t2;//処理時間測定用変数 66 67 //配列Ad,Ahの形状定義 68 int a_col = 200;//行 69 int a_row = 300;//列 70 71 //配列Bd,Bhの形状定義 72 int b_col = 300;//行 73 int b_row = 500;//列 74 75 //配列Cd,Chの形状定義 76 int c_col = 200;//行 77 int c_row = 500;//列 78 79 //配列Ah,Adを動的確保し乱数を流し込む(CPU側GPU側共に) 80 Ah = (float *)malloc(sizeof(float) * a_col * a_row); 81 cudaMalloc((void **)&Ad, sizeof(float) * a_col * a_row); 82 init_matrix(Ah, a_col, a_row); 83 84 //乱数を流しこんだAhの内容をデバイス側のAdに代入? 85 cudaMemcpy(Ad, Ah, sizeof(float) * a_col * a_row,cudaMemcpyHostToDevice); 86 87 //配列Bh,Bdを動的確保し乱数を流し込む(CPU側GPU側共に) 88 Bh = (float *)malloc(sizeof(float) * b_col * b_row); 89 cudaMalloc((void **)&Bd, sizeof(float) * b_col * b_row); 90 init_matrix(Bh, b_col, b_row); 91 92 //乱数を流しこんだBhの内容をデバイス側のBdに代入? 93 cudaMemcpy(Bd, Bh, sizeof(float) * b_col * b_row,cudaMemcpyHostToDevice); 94 95 //配列Ch,Cdを動的確保(CPU側GPU側共に) 96 Ch = (float *)malloc(sizeof(float) * c_col * c_row); 97 cudaMalloc((void **)&Cd, sizeof(float) * c_col * c_row); 98 99 //スレッドの同期? 100 cudaDeviceSynchronize(); 101 102 //内積を開始した時間代入 103 gettimeofday(&t1, NULL); 104 105 // カーネル関数呼び出し 106 matmul<<<dim3(a_row / 16, b_row / 16),dim3(16, 16)>>>(Ad, Bd, Cd, b_row, a_col, a_row); 107 108 //スレッドの同期? 109 cudaDeviceSynchronize(); 110 111 //内積を終了した時間代入 112 gettimeofday(&t2, NULL); 113 114 //処理にかかった時間表示 115 printf("Elapsed time: %f msec\n", get_elapsed_time(&t1, &t2)); 116 117 // 計算結果をGPUからCPUのメモリに代入 118 cudaMemcpy(Ch, Cd, sizeof(float) * b_row * a_row, cudaMemcpyDeviceToHost); 119 120 //GPU側に確保したメモリ解放 121 cudaFree(Ad); 122 cudaFree(Bd); 123 cudaFree(Cd); 124 125 return 0; 126}

疑問点その1:GPU側で内積を行う関数について。

・普通内積を計算するならこうなるはずです。

c

1for(int i=0;i<l;i++){ ←ない 2 for(int j=0;j<n;j++){ ←ない 3 sum = 0.0; 4 for (int k = 0; k < m; k++) { 5 sum += A[i * m + k] * B[k * n + j]; 6 } 7 C[i*n+j] = sum; 8 } 9}

しかし上2つのfor文が無く代わりに
i = blockIdx.y * blockDim.y + threadIdx.y;
j = blockIdx.x * blockDim.x + threadIdx.x;
が記述されています。
なぜこのような書き方ができるのでしょうか?

疑問点その2:カーネル関数呼び出し時のグリッド数とブロック数

今回のコードでは下記のように記述されています。

c

1matmul<<<dim3(a_row / 16, b_row / 16),dim3(16, 16)>>>(Ad, Bd, Cd, b_row, a_col, a_row);

カーネル関数を呼び出すときは下記のように呼びだせば良いと知っています。
しかし適切なグリッド数とブロック数はどのように求めればよいのでしょうか?

func<<<grid(dim3型), block(dim3型)>>>();

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

しかし上2つのfor文が無く代わりに
i = blockIdx.y * blockDim.y + threadIdx.y;
j = blockIdx.x * blockDim.x + threadIdx.x;
が記述されています。
なぜこのような書き方ができるのでしょうか?

大量のCUDA-coreが総数l*n個動くから。てかそうすることで高速に演算してる。

しかし適切なグリッド数とブロック数はどのように求めればよいのでしょうか?
func<<<grid(dim3型), block(dim3型)>>>();

両者のx,yごとの積が省略されたloopの繰り返し回数に相当する。
適切な数はcase-by-case。CUDAのドキュメントを読むがよい。

[追記]

グリッド数とブロック数は

正しくは「グリッドあたりのブロック数 と ブロックあたりのスレッド数」な。

投稿2019/02/27 06:05

編集2019/02/27 12:59
episteme

総合スコア16614

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/03/07 15:31

ご回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問