cuda画像処理入門 - gpu technology...

23
CUDA画像処理入門 エヌビディアジャパン CUDAエンジニア 森野慎也 GTC Japan 2014

Upload: others

Post on 07-Nov-2019

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

CUDA画像処理入門

エヌビディアジャパン CUDAエンジニア 森野慎也

GTC Japan 2014

Page 2: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

CUDAを用いた画像処理

画像処理をCUDAで並列化

— 基本的な並列化の考え方

— 目標 : 妥当なNaïveコードが書ける

最適化の初歩がわかる

— ブロックサイズ

— メモリアクセスパターン

Page 3: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

RGB → Y(輝度) 変換

カラー画像から、グレイスケールへの変換

— Y = 0.299 × R + 0.587 × G + 0.114 × B

Page 4: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

CUDAにおける画像処理の基礎

2次元メモリ確保API

— Pitchを考慮

— cudaMallocPitch()、cudaMemcpy2D()

並列化

— CUDAの並列度 : 数万以上欲しい…

Keplerでの目安 : CUDA Core数 x 10 程度 (最低限)

Page 5: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

PITCHを考慮したメモリレイアウト

RGBA(8 bit, uchar4)の配列

index = x + y * pitchInPixel

width

pitchInPixel = pitchInByte / sizeof(uchar4)

(x, y)

Page 6: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

2次元メモリ 確保・転送

cudaError_t cudaMallocPitch ( void** devPtr, size_t* pitch, size_t width, size_t height )

— widthバイトのメモリを、height行分、取得する。

— 行は、pitchバイトで整列する。

cudaError_t cudaMemcpy2D ( void* dst, size_t dpitch, const void* src, size_t spitch, size_t width, size_t height,cudaMemcpyKind kind )

— dstで示されるメモリ (dpitchバイトで整列)に、srcで示されるメモリ (spitchバイトで整列) を、width (バイト) x height (行)、コピーする。

Page 7: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

サンプルコード

uchar4 *src, *dImage;

size_t spitch, dPitch, dPitchInPixel;

// ピッチつきで、メモリをアロケート

cudaMallocPitch(&dImage, *dPitch, width * sizeof(uchar4), height);

dPitchInPixel = dPitch / sizeof(uchar4);

// ピッチを変換しつつ、ホスト→デバイスへと、メモリ転送

cudaMemcpy2D(dImage, dPitch, src, sPitch, width * sizeof(uchar4), height,

cudaMemcpyHostToDevice);

Page 8: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

画像処理における並列化の基本

基本 : 1 ピクセルに対して、 1スレッドを対応させる

— ピクセル数分、スレッドが走る。例 : 262,144 (= 512 x 512) スレッド

スレッドは、処理対象のピクセルを持つ。

— 自分の位置 (x, y) を知ることが必要

Page 9: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

2DでのBLOCK・THREADの割り当て

Thread : 「2次元」でピクセルに対応。

Block : 「2次元」で定義。一定のサイズのタイル。

Grid : 必要数のBlockを「2次元」に敷き詰める。

1 Block

1 Pixel = 1 Thread

(x, y) =

(Global ID X, Global ID Y)

Page 10: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

2DでのBLOCK・THREADの割り当て

GlobalID は、(x, y, z)方向に計算できる

— GlobalID(x) = blockDim.x * blockIdx.x + threadIdx.x

— GlobalID(y) = blockDim.y * blockIdx.y + threadIdx.y

— GlobalID(z) = blockDim.z * blockIdx.z + threadIdx.z

blockDim.x * blockIdx.xthreadIdx.x

blockDim.y * blockIdx.y

threadIdx.y

Page 11: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

RGB → Y 変換 カーネル

__global__

void RGBToYKernel(uchar4 *dDst, const uchar4 *dSrc, int width, int height, int pitch){

int gidx = blockDim.x * blockIdx.x + threadIdx.x;

int gidy = blockDim.y * blockIdx.y + threadIdx.y;

if ((gidx < width) && (gidy < height)) {

int pos = gidx + gidy * pitch;

// Y = 0.299 R + 0.587 G + 0.114 B

uchar4 value = src[pos];

float Y = 0.299f * value.x + 0.587f * value.y + 0.114f * value.z;

unsigned char y = (unsigned char)min(255, (int)Y);

dDst[pos ] = pixel;

}

}

Page 12: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

カーネル呼び出し (GRIDサイズ指定)

/* value、radixで割って、切り上げる */

int divRoundUp(int value, int radix) {

return (value + radix – 1) / radix;

}

/* gridDim, blockDimを、2次元(x, y方向)に初期化 */

dim3 blockDim(64, 2);

/* divRoundUp()は、切り上げの割り算 */

dim3 gridDim(divRoundUp(width, blockDim.x), divRoundUp(height, blockDim.y));

RGBToYKernel<<<gridDim, blockDim>>>(dDst, dSrc, …);

Page 13: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

悪い並列化の例

GPUの並列化としては、NG。非常に低速。

— 並列度が低い

— メモリアクセスパターンが悪い

ただし… CPU的発想としてはふつう。

Thread 0

Thread 1

Thread 2

Thread 3

Page 14: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

ここはポイント!コアレス(COALESCED)アクセス

連続するスレッドが、連続するメモリにアクセスする。— threadIdx.xに対して、連続。

Memory :

0 1 2 3 4 5 6 7 8 …

threadIdx.x

Thread :

Page 15: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

再掲 : 2DでのBLOCK・THREADの割り当て

GlobalID は、(x, y, z)方向に計算できる

— GlobalID(x) = blockDim.x * blockIdx.x + threadIdx.x

— GlobalID(y) = blockDim.y * blockIdx.y + threadIdx.y

— GlobalID(z) = blockDim.z * blockIdx.z + threadIdx.z

blockDim.x * blockIdx.xthreadIdx.x

blockDim.y * blockIdx.y

threadIdx.y

Page 16: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

動かしてみる

Page 17: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

FAQ : BLOCKDIMの決め方

1. Occupancy (占有率) を 100 %にする

2. Blockあたりのスレッド数は、なるべく小さく。

3. 横方向は、コアレスアクセス。なるべく、長くする。

Page 18: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

BLOCKDIMの決め方 (OCCUPANCY から)

SMXあたり、2048 Thread走らせたい。

— Occupancy (占有率) = 100 %

Occupancy = 100 % を満たす、Blockあたりのスレッド数は、

2048 Thread / 16 Block = 128 Thread / Block2048 Thread / 8 Block = 256 Thread / Block2048 Thread / 4 Block = 512 Thread / Block2048 Thread / 2 Block = 1024 Thread / Block

項目 値

最大のBlock数 / SMX 16

最大のThread数 / SMX 2048

最大のThread数 / Block 1024

Page 19: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

BLOCKDIMの決め方(BLOCKの粒度から)

Grid = 4096 Thread の実行例を考えてみる

— Block : 256 Thread、1024 Threadで比較

— 3 SMX / GPU、1 SMXあたり 1 Blockが実行可能とする

1024 Thread / Block

Block

Block

Block

BlockSMX 0

SMX 1

SMX 2

256 Thread / Block

SMX 0 Block

Block

Block

Block

Block

Block

Block

Block

Block

Block

Block

Block

Block

Block

Block

SMX 1

SMX 2

Block

t

t

Blockサイズは小さいほうが得 → 128 Threads / Block

Page 20: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

BLOCKDIMの決め方 (SMXの構造から)

Warp Scheduler x 4 :

— 1 clockあたり、4 Warpに対する命令発行

— Blockのサイズは、 128 Thread の倍数が望ましい。(128 Thread = 32 Thread/Warp x 4 Warp)

Page 21: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

タイルは横長がよい

タイルの横幅は、32(Warpの幅)の倍数がよい。

32より小さい場合、16、もしくは、8 を使う。

Memory :

threadIdx.x

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31Thread :

Page 22: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

RGB→Y変換時のバンド幅 : TESLA K20CblockDim.x

1 2 4 8 16 32 64 128 256 512 1024blo

ckD

im.y

1 1.4 2.8 5.6 11.2 22.1 43.9 78.5 119.8 119.3 115.4 87.7

2 2.6 5.2 10.4 20.6 40.7 77.9 119.8 119.4 115.3 87.4 -

4 4.8 9.6 19.2 37.8 74.0 119.4 118.2 114.2 87.3 - -

8 8.4 16.7 33.3 69.6 115.0 117.9 111.9 87.1 - - -

16 13.4 26.3 60.6 106.7 115.0 114.3 87.2 - - - -

32 17.7 40.4 81.1 103.9 110.9 86.9 - - - - -

64 20.7 41.7 79.8 99.0 83.5 - - - - - -

128 20.7 41.6 75.6 75.3 - - - - - - -

256 20.7 41.0 60.3 - - - - - - - -

512 20.5 37.6 - - - - - - - - -

1024 19.1 - - - - - - - - - -

値: バンド幅 (GB/sec)

Tesla K20c (ECC off)

Occupancy < 100 %

blockDim.x < 8

Page 23: CUDA画像処理入門 - GPU Technology Conferenceon-demand.gputechconf.com/gtc/2014/jp/sessions/4002.pdf · CUDA画像処理入門 エヌビディアジャパンCUDAエンジニア森野慎也

まとめ

画像処理におけるCUDA

— Pitchを考慮したメモリレイアウト

— 2次元のGridの呼び出し

正しいNaïveコード (カーネル) の書き方

— コアレスアクセス

— ピクセルごとに、スレッドを割り当てる

並列度は、数万以上。

— Blockサイズは、128が適当 (単純なカーネルの場合)