先日このグラフで世界を驚かせたchainerMNの中身の話をchainerMNによる分散学習 - YouTubeでやっています。
chainerは分散ディープラーニングフレームワークとして現在世界最速だそうです。
視聴したのでメモ。おもしろかったです。
語り手はchainerMNの作者秋葉さん(iwiwi)
Top coderで四位、数々のプログラミングコンテストで受賞歴を持つすごい人。
動画を見る限り今までchainerで作っていたモデルをchainerMNに移し替えるのも簡単そうです。
chainerMNの思想
chainerMNの高速化は王道である、と繰り返されていた。凄まじい新テクニックとかを使っているわけではない。
まず、分散deep learningにはモデルパラレルとデータパラレルという方式があるが、chainerはデータパラレルである。
データパラレルでは、各GPUで同一のモデルを使い、異なる入力データに対して計算をさせる。具体的には、chainerMNではバッチセットの異なる部分を担当させている。
一方、モデルパラレルでは各GPUに対してモデルの異なる部分(例えばGPUごとに別のレイヤー)を担当させるが、高速化の点で課題があり、現在はポピュラーではない。
データパラレルにはさらに、syncとasync、2つの方式があり、chainerMNではsync方式を使っている。
asyncとは各GPUを同期させずに勝手にforward(予測)→backward(勾配算出)→optimize(ニューラルネットの重み更新)をさせて勝手に各々のタイミングで重みを更新させていく方法。
asyncは同期する(計算が遅いGPUを待つ)必要がなくスループット(単位時間あたりの計算量)は出るが、あるGPUでforwardした後に重みを更新した時に、すでに他のGPUが重みを更新した後でモデルが古くなっていることがある。(stale gradientsと呼ばれる現象。)
このため重みの更新が効果的でなかったり、時には悪影響だったりする。
googleのチームがsyncとasyncの方式を比較した結果が以下で、asyncは正解率が低い。
以上が、chainerMNがsync方式である理由である。
chainerはMPIという並列コンピューティング規格を使っており、MPIでは、Single program multiple dataの考え方を取り入れている。つまり、各GPUで同じ学習スクリプトtrain_mnist.pyを実行させるだけ。
通常のchainerではforward(予測)、backward(勾配算出)、optimize(重み更新)を行うが、chainerMNではbackwardとoptimizeの間にallreduceが挟まれるのが、普通のchainerとの違い。
allreduceとは、各GPUで算出された勾配を平均化すること。chainerMNとは、実態は allreduceの提供であり、その他forwardとbackwardとoptimizeは普通のchainerでやっていることと変わらない。
なので、いままでchainerで作っていたモデルをchainerMNで使う場合、変更点はかなり少ない。すばらしい。
chainerの提供の形
chainerMNは、今後ユーザーに対しoptimizerのラッパーとして提供する予定。
例えばユーザーはいままで、optimizerを
"chainer.optimizers.MometumSGD()"と書いていたところを"chainermn.DistributedOptimizer(chainer.optimizers.MometumSGD())"
とするだけ。これだけ。驚き。
ただし、現実装では各GPUへのデータセットの分配など、いくつかの下準備が必要で、改善中であるとのこと。
ベンチマークの見方
分散ディープラーニングのベンチマークを見るには注意が必要。
asyncにして分散しまくりにすればスループットならいくらでも上げられるが、学習モデルの劣化が起こる。Learning curveを公開していないベンチマーク結果には注意。
chainerMNではきちんとLearning Curveを公開しています。
chainerでは、きちんとLearning curveが128GPUでも上昇している。
(多少飽和点が8GPUと比べ落ちているのはバッチを大きくしたことの影響。バッチサイズが減ると、局所解にはまりやすくなる。)
パフォーマンスは思ったより出たというか、tensorflowやMXnetはC++なのに対して、そもそもchainerはPythonで書かれていることもあり、他のフレームワークに勝てると思っていなかったのだそう。
勝った要因として、MPI,Infinibandが有利、さらにCUDA MPIを使うことによりメモリの転送を高速化していることが効いてるらしく、GPU数が多いほど相対的にchainerが強い。
また、tensorflowが遅い、というか分散学習をオンにすると遅い原因は、tensorflowがパラメータサーバーというアーキテクチャを使っており、パラメーターサーバーとのモデルや重みとのやりとりの通信がボトルネックになっているようだ。
現状のtensorflowはパラメーターサーバーが偶数だと遅い、など分散学習ではいろいろな課題を抱えている。
感想
PFNは前から凄いと思っていたけど、本当にすごい。
Googleがガチで取り組んでるdeep learningにパフォーマンスで勝つなんてかっこよすぎでしょう。
PFNは「この計算をやるにはこう設計すべきなんだ」といわんばかりに、複雑な計算を美しく実装するのが上手いという印象です。chainerも最高にいいので使いましょう。