More  Modern  GPU
岡野原  ⼤大輔
hillbig@preferred.jp
Preferred  Networks,  Inc.
Preferred  Infrastructure,  Inc.
12/3 2015 PFI/PFN 全体セミナー
GPU/CUDAについて
l  GPU/CUDAは近年年⼤大きな成功を収めている
–  ディープラーニング、機械学習、シミュレーション、グラフィックス
l  GPUとCPUの差は急速に広がっている
–  クロック周波数が頭打ちになり、コアをたくさん並べることで⾼高速化
–  TitanX  6TFlops  (3092  cores),  Xeon  0.8TFlops  (18  cores)
–  CPUは2年年毎にコアが⼆二つずつ増え、4年年毎にSIMDの幅が倍になる
–  GPUは2年年毎にコアが⼆二倍になる
l  GPUはメモリバンド幅が⾮非常に⼤大きい  
–  メモリがGPUに組み込まれており、数百GB/s
l  なぜこのような差が⽣生まれているのか?
2
GPUが⼤大きな性能向上をはたした理理由
l  プログラムにおける明⽰示的な並列列処理理
–  従来のCPUは逐次的な処理理を書く。コア数が増えてもそれを利利⽤用することは困難
–  GPU/CUDAははじめからプログラマに並列列処理理を書かせる。プログラマはすごく⼤大
変だが、GPUのコアが増えると性能がスケールする(フリーランチagain)
l  仮想実⾏行行コード
–  仮想プログラムは実⾏行行時に実⾏行行コードにランタイムの中で変換される。
–  HWは互換性を切切った新しいアーキテクチャを積極的に採⽤用できる。
l  ⼤大量量のスレッドでレイテンシを隠す
–  CPUのようなキャッシュは持たず、分岐予測もしない
–  コア毎のキャッシュコヒーレンシは問題にならない
–  ⼤大量量のスレッドを同時に持てるようにし,データが揃ったスレッドから実⾏行行する
しかし我々はCUDAを書くのか
l  否!
–  素⼈人はCUDAを書いてはならない  [Okuta  2015]
l  cupy  (chainer)
–  殆どのnumpyで書く数値計算はそのままGPU化できる
–  ディープラーニングだけにつかうのは勿体無い
l  modern  gpu/thrust  (今回のメイン)
–  離離散的なアルゴリズムをSTLで書ける
–  CUDAを⼀一切切書かずにかなり汎⽤用的にアルゴリズムをかける
–  コンパイルが遅いのとエラー時に意味不不明
4
cupy  (chainer.cuda.cupy)
l  chainerの開発のために作られたnumpy互換ライブラリ
l  Numpyと同じように書きながら、gpuの性能をフルに活かせる!
l  今までCUDAを書くのがなんだったのかという衝撃の簡単さ
l  中の仕組み
–  実⾏行行時にcudaコードを動的に⽣生成し、コンパイルし、キャッシュ
–  関数ごとの⾮非常に細切切れのcudaライブラリが⼤大量量にできている
u  Chainerの規模だと数万個
–  Nvidiaの⼈人⽈曰く、直接kernelをloadする仕組みを利利⽤用したのを⾒見見たのは⼆二例例⽬目だと
l  きっとChainer  Meetupで詳しい話がされますので今⽇日は省省略略
5
ModernGPUの説明のまえに・・
並列列処理理の考え⽅方
l  並列列処理理の種類
–  MIMD(Multiple  Instruction,  Multiple  Data)
u  複数の命令令で、複数のデータを同時に処理理する
u  例例:PESY-‐‑‒SC(睡蓮)、datacenter  as  a  computer
–  SIMD(Single  Instruction,  Multiple  Data)
u  ⼀一つの命令令で、複数のデータを同時に処理理する
u  例例:SSE
l  GPUはMIMD  +  SIMD(彼らはSIMTと呼んでいる)
–  各ストリームプロセッサ(SM)は独⽴立立に動作し異異なるデータを扱う  MIMD
–  各SMはwarp単位(今は16〜~32)で同じ命令令でデータをまとめて処理理をするSIMD
u  全てのデータアクセスはgather/scatter
–  各SMは⼗十分な量量のスレッドを持ち、データが揃ったスレッドから
実⾏行行することでレイテンシを隠す 6
並列列処理理の困難さ
l  並列列処理理は逐次処理理とは考え⽅方を変えないといけない
–  ⼀一番遅い⼈人が⾜足を引っ張り、全体の性能を決める
–  すべてのリソースを使い切切るように⼼心がける
(例例、問題を100にしか分割できない場合,3000コア中2900コアは使われない)
–  問題は⼤大量量の全く同じ⼤大きさの独⽴立立に解ける問題に分解されるのが理理想
l  逐次処理理とは違うアルゴリズム、データ構造が必要
–  ⼩小⼿手先での並列列化は性能はでず,遅くなることも
7
代表的な並列列処理理  (Prefix-‐‑‒)Scan
l  配列列X[0…n)が与えられた時,Scanは次を求める
–  X[i]  :=  X[0]  +  X[1]  +  ...  +  X[i-‐‑‒1]      exclusive  scan
–  X[i]  :=  X[0]  +  X[1]  +  …  +  X[i]            inclusive  scan
l  Scanは次のように並列列に計算できる
–  各X[i]について,X[i]  +=  X[i-‐‑‒1]
–  各X[i]について,    X[i]  +=  X[i-‐‑‒2]
–  各X[i]について,X[i]  +=  X[i-‐‑‒4]
–  ...
l  例例:X[7]の時,
–  X[7]  +=  X[6]
–  X[7]  +=  X[5]  (=X[4]+X[5])  
l  これはO(log  n)時間で実⾏行行できる
8
Modern  GPU
l  GPUが有効なのは計算粒粒度度が同じような数値計算問題のみか?
→  通常の離離散的アルゴリズムでも有効
l  Modern  GPU
–  Nvidiaが2013年年に発表、ライブラリと、ドキュメントから構成される
–  http://nvlabs.github.io/moderngpu/
l  基本的な考え
–  1.  問題を処理理量量が全く同じ⼤大きさの⼩小さな問題に分割する
–  2.  各問題を独⽴立立に普通の逐次的なアルゴリズムで解く
–  3.  (必要に応じて)解をまとめる
l  重要なのは1の全く同じ⼤大きさに分割するところ
9
例例:マージソート  (1/2)
l  ⼆二つのソート済み配列列X,  Yが与えられた時,これらをあわせてソートせよ
l  X  =  {1,  3,  3,  5,  7,  9,  10,  10,  11,  13,  15}
l  Y  =  {0,  2,  3,  3,  7,  8,      8,      9,  10,  11,  14}
l  Z={0,  1,  2,  3,  3,  3,  3,  5,  7,  7  8,  8,  9,  9,  10,  10,  10,  11,  11,  13,  14,  15}
l  それぞれの配列列⻑⾧長をn=|X|,  m=|Y|とした時,計算量量はO(n+m)
10
例例:マージソート  (2/2)
逐次的なマージソート
X,  Y,  Z  
ix  =  0,  iy  =  0,  iz  =  0
while  (iz  <  n+m)  {
      if  (comp(X[ix],  Y[iy])  Z[iz++]  =  X[ix++]
      else                                                    Z[iz++]  =  Y[iy++]
}
//  境界条件はcompがうまいことやってくれてることにします
これをどのように分割するのか?
11
マージソートの解釈
0 1 3 5 6 6 7 9 10
1
2
2
4
7
8
9
9
10
12
行にA、列にBを並べた行列を考える。
マージソートにおけるZ[iz++] = X[ix++]は右に進む、Z[iz++] = Y[iy++]は下に

進むに対応する
このパスをマージパスと呼ぶ	
X[4]=6 < Y[4]=7
マージパスによる問題の分割
l  もし、マージパスが分かっていれば、問題は全く同じ⼤大きさに分割できる
13
0 1 3 5 6 6 7 9 10
1
2
2
4
7
8
9
9
10
Z[0…4)を計算する領域	
 Z[4…8)を計算する領域	
Z[8…12)を計算する領域	
Z[12…16)を計算する領域
マージパスによる問題の分割
l  X  =  0  1  3  5  6  6  7  9  10  
l  Y  =  1  2  2  4  7  8  9  9  10
l  それぞれの問題は、⻑⾧長さ4の結果を出⼒力力するマージソートに分割される
l  0  1  と  1  2  のマージソート
l  3  5  と  2  4  のマージソート
l  6  6  7  と  7  のマージソート
l  9  と  8  9  9  のマージソート
l  10  と  10  のマージソート(最後だけ⻑⾧長さは違う)
マージパスによる問題の分割
l  マージパスを使えば問題を正確に同じ⼤大きさの問題に分けられる
–  マージパスを得るにはマージソートが必要(循環・・)
→マージパスとの交差点は全体を⾒見見なくても求められる
15
0 1 3 5 6 6 7 9 10
1
2
2
4
7
8
9
9
10
この線上で二分探索
X[i] < Y[8 – i]
となる最大のiを求める
マージパスによる並列列マージソートまとめ
l  問題を分割する
–  ⼆二分探索索をブロック数だけやる(並列列)
l  分割された問題をそれぞれ独⽴立立に逐次的に解く
–  答えを書くZの位置も分かっている
–  固定⻑⾧長の問題なので、ループは展開しておける  #pragma  unroll
–  この場合、解はまとめる必要がない
l  ⾮非常に⾼高速
–  TitanXにおいて    288GB/秒(32ビット整数の場合,700億件/秒)
16
次のような問題も同様にして解ける
l  Bulk  Insert,  Bulk  Delete
–  まとめて挿⼊入、まとめて削除
l  Segmented  Vector  Reduction
–  ⻑⾧長さの異異なる配列列の集合に対し,各配列列毎にReductionをする
l  DBにおけるJoin
–  Outer,  Inner,  Left-‐‑‒,  Right-‐‑‒  Join
–  やっていることはマージソートとほぼ同じ
l  特に興味深いのがMapReduceができる点
l  これらは,Modern  GPU,Thrust,  Cubなどのライブラリで提供されている
17
GPUでMapReduce
l  Map+Shuffle(Sort)+ReduceはGPUで効率率率的に実現可能
l  MapReduceは最近、分散並列列処理理では⾮非効率率率的と廃れてきたが、扱える計算
クラスは⾮非常に広い
–  分散クラスタでは毎回ディスクに書き込む部分とShuffleがボトルネック
–  GPUの場合、⾼高帯域GPUメモリを介して処理理できる
l  Map:要素Dから可変⻑⾧長のキーKと値Vのタプルの集合を⽣生成する  D-‐‑‒>  [K,  V]
l  Shuffle:同じキーの要素をまとめる  [K,  V]  -‐‑‒>  [K,  [V]]
l  Reduce:値の集合を値に潰す  [V]  -‐‑‒>  Z
l  全体としては  [D]  -‐‑‒>  [K,  Z]
18
GPUで転置ファイルを作ってみよう
l  転置ファイル
–  各単語毎にその出現位置を記録
1.  ⽂文字列列中の単語数を数える
1.  単語境界の数を数える(!isAlpha(right)  &&  isAlpha(left))  
2.  各単語の出現位置と、そのハッシュ値を計算する
1.  これはSegmented  Reductionで解ける
2.  (ハッシュ値、位置、⻑⾧長さ)をReduceする
3.  KR法でハッシュ値を計算するのでReduceの順によらない
3.  ハッシュ値で単語をソートし集める
4.  ハッシュ値でSegmented  Reduction
1.  各単語毎の出現位置をまとめる
19
ソースコード例例
l  https://github.com/hillbig/gpuexperiments
20
実験
l  英⽂文700MB
l  マシン:Titan  X
l  総単語数  106,888,008
l  異異なり単語数  1,252,268
l  GPU実⾏行行時間:1.67秒
–  そのうち、CPU-‐‑‒>GPU  コピー時間:0.2秒
–  但し、キーの0.1%未満は衝突している
l  ⽐比較:CPU実⾏行行時間  14.80秒
l  約10倍弱は速くなった
21
22
input=300000000 wordCount=45788064
distinctWord=1129243 words=45788064
0 2528465 the
1 1564080 of
2 1219248 and
3 986168 in
4 862412 a
5 862356 to
6 507386 is
7 484451 The
8 445334 was
9 336005 for
10 334510 s
11 316207 as
12 295183 by
13 282728 with
14 281566 on
15 241960 that
16 235218 doc
17 221649 from
18 193797 at
19 189947 his
20 157175 an
コンパイル時間
l  nvcc  +  thrust  の組み合わせはコンパイル時間がやばい
–  全てtemplateでコンパイル時に展開されるだけでなく、nvcc側の最適化も
–  1分ぐらいかかる
l  お勧めは関数毎に別ソースファイルでコンパイル
–  10秒ぐらいなので,許容範囲・・
23
まとめ
l  GPUによる並列列処理理を紹介した
–  離離散的で⾮非均質な問題も効率率率的に解けるアルゴリズムが登場してきた
–  cupy,  thrust,  cub(未紹介)などを使えばCUDAを書かなくても並列列処理理できる
l  今後は⾮非同期,並列列処理理が重要になる
–  中央集権型,逐次型は性能⾯面,電⼒力力消費⾯面で競争⼒力力が落落ちていく
–  Goのchannel,  go  routineのような⾔言語によるネイティブサポートが必要
–  データの依存関係を⾃自然に表した,データフローモデル
l  昔のデータセンターが今は1チップで実現
–  Datacenter  as  a  computerの著者が予⾔言していたデータセンターが1チップに収
まる時代が到来しつつある  (数⼗十TFlops  in  1  chip)
–  通信はレイテンシ,スループット,電⼒力力量量が問題.狭い場所で処理理すれば全部解決
24
Copyright  ©  2015-‐‑‒
Preferred  Networks  All  Right  Reserved.

More modern gpu