深層学習の並列化の仕組み・ボトルネックについて

深層学習の並列化について有識者の方にお話しを伺えたのでまとめておきます
6
リスのキング(ryo_grid) @ryo_grid

深層学習の大規模並列化について。 (機械学習とか使わないような、)科学計算プログラムの大規模並列もすごく難しいそうですが、深層学習は深層学習でまた別種の?難しさがあるんですねえ。 slideshare.net/iwiwi/nips17-8…   (続く)

2019-04-12 09:45:08
リスのキング(ryo_grid) @ryo_grid

(続き) しかし、こんな感じの話があるとすると、機械学習用スパコンとかで例えば1万GPU、NPUなり用意しても、MAXの台数まではスケール(と言うのかな)しないのだろうし、そうなると人間の脳をシミュレートして、とかってのも難しいのかな、と思ったり? slideは2017年の話だから、今は違うんかな?

2019-04-12 09:47:11
リスのキング(ryo_grid) @ryo_grid

ちなみにスパコン京とかはwikipediaによると、全体で88,128プロセッサで各プロセッサが8コア持ってたらしいので、MPIで全コア使ってアプリケーションを動かすと約70万プロセス並列、OpenMPでのスレッド並列も組み合わせるなら88,128プロセッサ並列(プロセス内で8並列) ja.wikipedia.org/wiki/%E4%BA%AC… (続く)

2019-04-12 09:59:15
リスのキング(ryo_grid) @ryo_grid

(続き となって、PFNさんの1024GPUという実績も、まだ並列度で言えば遠いなーと思ったけど、GPUって演算器のお化けみたいなものなので、CPU数で比べてはいけないのかも。 (科学計算アプリケーションがどれも70万プロセス並列までスケールするかと言えば、そうでないというのは承知してます)

2019-04-12 10:05:25
リスのキング(ryo_grid) @ryo_grid

まあしかし、データ並列できるってことは、ネットワークの帯域やレイテンシはさほどネックにはならんのかな? GPU内のメモリバンド幅も(詳しくないけど、)太いと聞いたので大丈夫なのだろう。きっと。あとはCPU-GPU間のインターコネクトの帯域やレイテンシがネックになるか、か。 (続く

2019-04-12 10:09:55
リスのキング(ryo_grid) @ryo_grid

まあ、ここは一度GPUに計算を投げてから、GPU単体で処理が行える(CPUとやりとりしたり、ホストマシンのメモリの読み書きとかしない)割合がどんぐらいあるかによって変わるんだよなーきっと。なので、分からんな。GPUに渡す計算するためのデータ量と、それで行える?計算処理量の比もあるしな。

2019-04-12 10:15:05
Keisuke🦥 @keisukefukuda

@ryo_grid 論点はたくさんあるんですが、conventionalなHPCアプリとの一番の違い(というか難しさ)は、一言でいうと「並列化すると結果が変わる」(普通は悪くなる)ことにあって、「結果を一定以上の水準に保ったまま並列化する」のが一番難しいところですね。次に、

2019-04-12 10:36:20
Keisuke🦥 @keisukefukuda

@ryo_grid 演算、バス、IOのそれぞれがそれなりに重いので、ボトルネックがコロコロ移動するというのがあります。最後に、全域通信が頻発するので大変というのもあります(京とかで大規模スケールするようなアプリは、通信を局所的に抑える工夫をしますがそれができない)

2019-04-12 10:39:12
リスのキング(ryo_grid) @ryo_grid

@keisukefukuda なるほど。 ということは、バス(GPU内)、バス(GPU-CPU間)、バス(CPU-メモリ間)、ネットワークI/O、ストレージI/Oのどれもボトルネックになるときはなるし、ならないときはならない、って理解で合ってますか?

2019-04-12 11:17:23
リスのキング(ryo_grid) @ryo_grid

@keisukefukuda あと、深層学習に精通してないので、よく理解できなかったのですが、並列化すると結果が変わるってのは、並列化を行う過程で、1GPUの場合と処理内容が変わっているから、ということなんですよね、おそらく。 で、変わらない並列化も無くはないが、遅い、みたいな話なのかなーとか。

2019-04-12 11:20:07
Keisuke🦥 @keisukefukuda

@ryo_grid 基本的には、「変わらない並列化」は無いですね。なぜかというと、深層学習というのは本質的には関数の最小化問題で、逐次の勾配法で関数の最小値を探す(つまり、空間の中で勾配=微分係数を見ながら関数値が小さくなる方向へ1ステップずつ進む)方法なので、これを高速化する方法というのは(続

2019-04-12 12:57:49
Keisuke🦥 @keisukefukuda

@ryo_grid (1)ステップごとの計算時間を減らす(2)ステップ数を減らす(1ステップでより多くのデータを消費する)の2通りしか無いわけです。で、(1)は極端なStrong Scalingなのでほとんど無理で、(2)はステップ数を減らすので、少ない回数でゴールへ到達するためにがんばる必要が出てきます。

2019-04-12 13:01:52
リスのキング(ryo_grid) @ryo_grid

@keisukefukuda 回答ありがとうございます。 秋葉さんのスライドに書いてあったようにデータ並列で分割処理して、一度同期をとってAllReduceでデータを交換する、というのは(1)をやっているように思えるのですが、そうではない?

2019-04-12 13:20:00
Keisuke🦥 @keisukefukuda

@ryo_grid これは2をやっています。GPUあたりの処理データ数を変えずに、GPU数を増やしており、1ステップあたりの時間は維持したまま全体の繰り返し数を減らしています

2019-04-12 13:30:38
リスのキング(ryo_grid) @ryo_grid

@keisukefukuda 各1GPUがやっている計算は並列化する前と(本質的には)あまり変わらなくて、担当するデータ範囲を変えて各々が処理した結果を、適当なタイミングでがっちゃんこすると、全体の繰り返し数が減る、というアルゴリズム?がある、という認識で合ってますか? (ミニバッチのバッチ単位で分割していて(続

2019-04-12 13:48:09
リスのキング(ryo_grid) @ryo_grid

@keisukefukuda 続き) バッチ単位ではなくて、バッチ群単位、に訂正します。 で、処理するバッチ群は各々のGPU間で適当なタイミングで入れ換える? とかそんな感じですかね。

2019-04-12 13:50:01
Keisuke🦥 @keisukefukuda

@ryo_grid データを入れ替えるのは必須ではないですが、とにかくデータ全体がまんべんなく一巡するように処理します

2019-04-12 13:51:28
リスのキング(ryo_grid) @ryo_grid

@keisukefukuda ということは、イメージ的には、分割されたデータセットで学習したNN群をがっちゃんこすることで、全てのデータセットで普通に?学習したNNに近いNNが作り出せる、ということになるんですかね?

2019-04-12 13:57:51
Keisuke🦥 @keisukefukuda

@ryo_grid 実は、全体で共通のNNを維持しながら学習をしていきます。そのための通信がallreduceで、ステップごとに微分係数(勾配)を互いに交換/平均してから空間内を進むことによって、全員が協力して一つのモデルを更新していくことになります

2019-04-12 14:00:22
リスのキング(ryo_grid) @ryo_grid

@keisukefukuda データ分割で高速化っていう風な見方をすると、処理する学習データセットを複数GPUで分割することで、前の投稿で(1)と言っていた1ステップを高速化するということなのかな、と思ったりしますが、そうではなくて、各GPUは全データセットを持っていて、その中のミニバッチをシャッフルして入力として(続

2019-04-12 14:48:44
リスのキング(ryo_grid) @ryo_grid

@keisukefukuda 続き) 学習を行って、1ステップごとに全GPUが同期&allreduceする、って処理になるんですかね。

2019-04-12 14:50:24