Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

20171128分散深層学習とChainerMNについて

6,497 views

Published on

ChainerMNによる機械学習の高速化勉強会での講演資料です。
PFN鈴木脩司「分散深層学習とChainerMNについて」

Published in: Technology

20171128分散深層学習とChainerMNについて

  1. 1. 分散深層学習とChainerMN について 鈴木 脩司 Preferred Networks, Inc. ChainerMNによる機械学習の高速化勉強会 2017/11/28
  2. 2. 自己紹介 名前:鈴木脩司 経歴  -2015 東京工業大学 大学院情報理工学科 計算工学専攻 – バイオインフォマティクス、特に配列相同性検索の高速化について研究  2015-2017 株式会社富士通研究所 – クラウドの運用管理について研究  2017- 株式会社Preferred Networks – Researcherとして、バイオヘルスケア分野、ChainerMNの研究開発 ちなみに、2011-2012の間、アルバイトとしてFixstarsでGPU等のアクセラレータ を使った高速化をやってました 2
  3. 3. 会社紹介:Preferred Networks, Inc. (PFN)  設立: 2014/3月(Preferred Infrastructureからの分社) – 出資者: NTT (2014), Fanuc (2015), TOYOTA (2015)  本社: 東京都千代田区大手町 支社:カルフォルニア、サンマテオ  従業員数: 約110名(殆どがEngineers & Researchers)  事業内容: Internet of Thing + 機械学習 – 交通 – 製造業 – バイオヘルスケア 3
  4. 4. 今日のお話  分散深層学習の基礎  ChainerMNについて  ChainerMNの使い方  高速化への道  ChainerMNの今後 4
  5. 5. 分散深層学習の基礎 5
  6. 6. 2つのアプローチ Data Parallel 6 Model Parallel
  7. 7. 分散深層学習のアプローチ データ並列  全ワーカーがモデルのレプリカを持つ  異なるデータを処理し協力してモデルを更新 モデル並列  レイヤーごとやレイヤー内で計算を分割  GPU メモリが足りなかった時代に行われていた 7
  8. 8. 8 同期型 非同期型 Computation Parameter Server Push grad Pull model データ並列の2つのアプローチ
  9. 9. 9 同期型 非同期型 Computation Parameter Server Push grad Pull modelどっちが良いのか? データ並列の2つのアプローチ
  10. 10. 10 同期型 非同期型 スループット低 スループット高 よくある誤解 スループット = NN にデータを食わせる速度
  11. 11. 11
  12. 12. 同期型 vs. 非同期型 12 同期型 非同期型 スループット低 スループット高 スループットのみを見るのは愚か!
  13. 13. [Figure 3, Chen+ 2016]
  14. 14. Gradient Staleness  Stale gradients = 古いパラメータに対して計算された勾 配  Staleness はモデルの改善に悪影響がある 14
  15. 15. ImageNet (ILSVRC’17) CLS 優勝チーム 17
  16. 16. 個人的見解  同期型じゃないとダメということは無いのではないか  非同期型でも上手くチューニングすれば同じ精度までいける場合は多いと予想  ただし同期型の方がチューニングがしやすいので実用的 18
  17. 17. ChainerMNについて 19
  18. 18. ChainerMN  Chainer の追加パッケージ  分散深層学習に必要な機能を追加 特徴  高速 NVIDIA NCCL, CUDA-Aware MPI 等の最新技術の活用により高い性能を実現  柔軟 Chainer の柔軟性を損なわず、動的なネットワークですら分散学習可能  簡単 既存のコードを少し変更すれば利用可能 20
  19. 19. ChainerMN  ChainerMN は MPI を利用、SPMD で動作 SPMD = single program, multiple data; 全プロセスは同じスクリプトで動作する  1 プロセス (ワーカー)で1 GPU sakura1 train_imagenet.py (GPU0) train_imagenet.py (GPU1) train_imagenet.py (GPU2) train_imagenet.py (GPU3) sakura2 train_imagenet.py (GPU0) train_imagenet.py (GPU1) train_imagenet.py (GPU2) train_imagenet.py (GPU3) $ mpiexec -n 8 -host sakura1,sakura2 python train_imagenet.py 21
  20. 20. 通常の学習イテレーション Forward Backward Optimize 62 Gradient 𝜹𝑬 𝜹𝒘 Gradient 𝜹𝑬 𝜹𝒘 22
  21. 21. 学習イテレーション 23 通常のChainerによる学習 Forward Backward Optimize All-Reduce Forward Forward Forward Backward Backward Backward Optimize Optimize Optimize ChainerMNによる分散学習
  22. 22. All-Reduce  各ワーカーが持つ値を集計し、集計した結果を全ワーカーに配る処理  ChainerMNでは全ワーカーが持つ勾配𝑔𝑖から平均 ҧ𝑔を計算して配る 24 All-Reduce 𝑔0 = 1 𝑔1 = 2 ҧ𝑔 = 1.5 ҧ𝑔 = 1.5
  23. 23. 25 詳細: https://chainer.org/general/2017/02/08/Performance-of-Distributed-Deep- Learning-Using-ChainerMN.html
  24. 24. Microsoft Azureを利用した実験 26
  25. 25. 27 最新のTOP500(2017年11月現在)で、 国内のIndustry segmentで1位
  26. 26. ImageNetを1024GPUを使って15分で学習 [Akiba+ 2017] 28 1024GPUでも、ほぼ線形にスケール 参考文献: https://arxiv.org/abs/1711.04325
  27. 27. ChainerMNの使い方
  28. 28. ChainerMNに必要なライブラリ (GPUを利用する場合) 1. Chainer – CuPyとcuDNN も含めてインストールする 2. MPI (OpenMPIなど) – CUDA-Awareのサポートを入れてコンパイルする 3. NCCL – githubにあるものはバージョンが古いので、NVIDIAのサイトからダウンロード 4. MPI4py 5. Cython – 事前にpipなどでインストールする必要がある 30 CPUのみの場合は以下を参照 http://chainermn.readthedocs.io/en/latest/installation/guide.html
  29. 29. ChainerMNのインストールとサンプル実行(GPUを利用する場合)  インストール方法 – $ pip install chainermn  MNISTのサンプルの実行 – $ git clone git@github.com:chainer/chainermn.git – $ cd chainermn – $ mpiexec -n 4 python examples/mnist/train_mnist.py –g  この例では1つのノードで4つのワーカーが起動して、4つのGPUを使って分散学 習が実行される 31
  30. 30. あれ、動かない?と思ったら・・・  ChainerMNドキュメントのStep-by-Step Troubleshootingを見る! – http://chainermn.readthedocs.io/en/latest/installation/troubleshooti ng.html  Step-by-Step TroubleshootingはChainerMNを使うときにハマりそう な部分を、1つ1つ問題がないか確認していく手順が書かれている – たとえば・・・  Check SSH connection 32 $ ssh host00 'hostname' host00 # without hitting the password $ ssh host01 'hostname' host01 # without hitting the password ...
  31. 31. Chainerのコードを改良してChainerMNを使う手順  説明にはMNISTのサンプルを利用  完成コード – https://github.com/chainer/chainermn/blob/master/examples/mnist /train_mnist.py  最低限必要な変更点 1. Communicatorの作成と使用するGPUの指定 2. マルチノード用のOptimizerの作成 3. データの分配 4. マルチノード用のEvaluatorの作成 33
  32. 32. 1. Communicatorの作成と使用するGPUの指定  Communicatorの作成 – 高い並列性能を実現するためには計算機環境に合わせてCommunicatorを 選択する必要がある。詳しくは以下を参照  https://chainermn.readthedocs.io/en/latest/reference/index.html#communicators  プロセスが使用するGPUを指定 – ChainerのMNISTのサンプル: – ChainerMNのMNISTのサンプル: 34 # args.gpu: 使用するGPUのID chainer.cuda.get_device(args.gpu).use() # comm.intra_rank:マシン内におけるワーカーの番号 device = comm.intra_rank chainer.cuda.get_device(device).use() comm = chainermn.create_communicator()
  33. 33. 2. マルチノード用のOptimizerの作成  マルチノード用のOptimizerを以下のようにして作成 – ChainerのMNISTのサンプル: – ChainerMNのMNISTのサンプル: 35 optimizer = chainer.optimizers.Adam() optimizer = chainermn.create_multi_node_optimizer( chainer.optimizers.Adam(), comm)
  34. 34. 3.データの分配  2.までの状態では、1つのワーカーだけで改良前と同じサイズのデータを学習 – このため、Chainerのサンプルよりも1エポックのバッチサイズが、ワーカー数倍増加  改良前とバッチサイズを同じ大きさにするために、1つのワーカーがデータの読 み込みを行い、全ワーカーに分割して配る – ChainerのMNISTのサンプル: – ChainerMNのMNISTのサンプル: 36 train, test = chainer.datasets.get_mnist() if comm.rank == 0: # rank 0 のワーカーが読み込み train, test = chainer.datasets.get_mnist() else: train, test = None, None # データを分割して配る train = chainermn.scatter_dataset(train, comm) test = chainermn.scatter_dataset(test, comm)
  35. 35. 4. マルチノード用のEvaluatorの作成  マルチノード用のEvaluatorを以下のように作成 – ChainerのMNISTのサンプル: – ChainerMNのMNISTのサンプル: – 注意  PrintReportなどのExtensionは1つのワーカーだけ実行するようする 37 trainer.extend(extensions.Evaluator(test_iter, model, device=args.gpu)) evaluator = extensions.Evaluator(test_iter, model, device=device) evaluator = chainermn.create_multi_node_evaluator(evaluator, comm) trainer.extend(evaluator)
  36. 36. 実行!  シングルノード実行 – $ mpiexec -n 4 python train_mnist.py –g  1つのノードで4つのワーカーを立ち上げ、4個のGPUを使って分散学習を行う  マルチノード実行 – $ mpiexec -n 8 -host host00,host01 python train_mnist.py –g  host00,host01 という2つのノードで、4つずつワーカーが立ち上げ、 合計8個のGPUを使って分散学習を行う 38
  37. 37. よくある質問その1 39 ChainerMN を使ったら遅くなりました 通信が遅いと速くなりません All-Reduceなど、逐次処理の部分の割合が多いと、 いくら並列化しても速くなりません。この後紹介する方法で高速化してみてください
  38. 38. よくある質問その2 40 MNISTが速くならないんですが・・・ データサイズが小さいMNISTは速くなり ません MNISTのexampleは動作確認するには十分ですが、速度を測定するには不適切です
  39. 39. 高速化への道 41
  40. 40. ChainerMNの高速化の流れ 1. まずはプロファイリング 2. バッチサイズを頑張ってあげる 3. 適切なcommunicatorを使う 42
  41. 41. アムダールの法則  計算機の並列度を上げた場合に、全体として期待できる全体の性能向上の程度 を数式として表現したもの (by Wikipedia先生)  期待できる並列化による性能向上は以下の通り 1 1 − 𝑃 + 𝑃 𝑁 ChainerMNでいえば、少なくともAll-Reduceの部分は逐次実行の部分になる ので、All-Reduceにかかる割合が全体の割合に比べて大きい場合、並列度をい くら上げても速くならない 43 𝑃: 並列化できる処理の割合 𝑁: 並列度 1 − 𝑃 の部分(逐次実行の部分)が大きいと 並列度を上げても速くならない
  42. 42. まずはプロファイル  高速化する前に必ずプロファイルを取る – どこが遅いのか定量的に把握するために重要 – All-Reduce以外でも逐次処理になっている部分があれば、その割合を見積もり、並列 化によって本当に速くなるのか確認 – 関数レベルの高速化で十分速くなる場合も多いので、そのようなものがないかこれで 確認  Chainer, ChainerMNで使える代表的なプロファイラ – cProfile (Python標準) – NVPROF (CUDA用のプロファイラ) 44
  43. 43. cProfile使ったプロファイルの取り方  Pythonに標準で入っているプロファイラ。基本的なことは大体できる。  ChainerMNの場合、以下のようにすれば、学習部分のプロファイルが取れる 45 import cProfile import pstats … pr = cProfile.Profile() pr.enable() # trainの実行部分 trainer.run() pr.disable() # 時間のかかっている関数が上にくるようにソート stats = pstats.Stats(pr) print(“sort by cumtime”) stats.sort_stats('cumtime') print(stats.print_stats())
  44. 44. NVPROFを使ったプロファイルの取り方  CUDA関係用のプロファイラ – 参考: http://docs.nvidia.com/cuda/profiler-users-guide/index.html#prepare- application  コードを変更しなくても以下のように実行するだけでプロファイルが取れる – $ mpiexec -n 2 nvprof -o ‘%h-%p.nvprof’ python examples/mnist/train_mnist.py –g  プロファイル結果はGUIのNVVPで見ると細かいところも見れてわかりやすいの でおすすめ – 参考: https://developer.nvidia.com/nvidia-visual-profiler – ただし、ChainerMNのプロファイル結果は重いことが多いので、数イテレーションで 止まるようにしたり、以下を参考にして、大きいファイルも読み込めるようにすると 良い http://docs.nvidia.com/cuda/profiler-users-guide/index.html#large-data 46
  45. 45. バッチサイズを頑張ってあげる  All-Reduceの割合が大きい場合、並列化によって速くするには1ノードあたりの バッチサイズを大きくする – 1ノードあたりのバッチサイズが大きくなると、1イテレーションあたりのAll- Reduce以外の処理でかかる時間が相対的に大きくなるので、並列化効率が上昇する  精度が落ちていないかを確認し、落ちている場合は学習率等のパラメータを調 整する必要がある 47 ただし、バッチサイズを大きくした場合、 精度が低下する可能性大! 参考: [Goyal+ 2017]
  46. 46. ImageNetの学習で最近注目な手法  Goyal, P et al. (2017). Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour. – http://arxiv.org/abs/1706.02677  Smith, S. L. et al. (2017). Don’t Decay the Learning Rate, Increase the Batch Size. – https://arxiv.org/abs/1711.00489 48
  47. 47. Goyal, P et al. (2017). Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour. 以下の手法により、精度を落とさずにバッチサイズを大きくすることに成功し、 256GPUを使って1時間でImageNetの学習を完了  学習率のLinear Scaling Rule – バッチサイズを𝑘倍したら、それに合わせて学習率𝜂を𝑘倍する  Gradual warmup – 学習のスタートは学習率を𝜂に設定し、各イテレーション毎に徐々に大きくし、 5epochのところで学習率を𝑘𝜂になるように調整 49
  48. 48. Smith, S. L. et al. (2017). Don’t Decay the Learning Rate, Increase the Batch Size.  良く使われるDecaying learning rateの代わりに、バッチサイズを大きくする 50
  49. 49. 適切なcommunicatorを使う  使っているシステムによってはCommunicatorを変えることで、All-Reduceが 速くなる場合がある  2017年11月現在のおすすめはPureNcclCommunicator – All-ReduceをNCCLに丸投げするCommunicator – NCCLがネットワーク構成を自動で判定し、ネットワーク構成に適したAll-Reduceを 勝手にやってくれる 51
  50. 50. 高速化の具体例紹介:ImageNetを1024GPUで学習する際に何をしたのか? Goyal+ 2017の論文からバッチサイズを大きくするために、以下の部分を改良 1. RMSprop Warm-up  SGDの代わりに最初はRMSpropを使って最適化 2. Slow-Start Learning Rate Schedule  学習率を下げるタイミングを変更 3. Batch Normalization without Moving Averages  移動平均を使わないようにパラメータを設定 また、以下のように学習の高速化を実施 今回はここを詳しく紹介 1. PureNcclCommunicatorで1024GPUを利用 2. Convolutionのauto tuneを活用 3. FLOAT16を使ったAll-Reduce 4. NCCLパラメータのチューニング 52
  51. 51. PureNcclCommunicatorで1024GPUを利用 一見、簡単に動きそうな気がするが、1024 GPUの規模でNCCLを使う場合 様々な問題が発生するので、以下のように対処  NCCLの大量file descripter open問題 – 解決方法: ulimit -n unlimited  NCCLのスタックの大量使用 – 解決方法: ulimit -s unlimited  NCCLの謎‘unhandled system error’ – 解決方法:全ノードのreboot 53
  52. 52. Convolutionのauto tuneを活用  cuDNNが実装しているConvolution用の関数のうち、もっとも高速なも のを自動で選択 – Chainer 3.1(2017/11/17にリリース)からの追加機能 – これによって数%の速度が向上  Auto tuneを使う場合は以下のようにすればよい 54 chainer.global_config.autotune = True
  53. 53. FLOAT16を使ったAll-Reduce  Forward, Backward等の計算ではFLOAT32を使い、All-Reduceの時のみ、 FLOAT16で実行  これにより、通信するデータ量が半分になり、All-Reduceにかかる時間も短縮 – ResNet-50の場合、100MB→50MBに削減 – 今回の場合、ほとんど精度に影響がないことは一応確認  現在は、ChainerMNで未実装だが、今後サポートする予定 55 All-ReduceForward Backward Optimize… … All-ReduceForward Backward Optimize… …FP32→FP16 FP16→FP32
  54. 54. NCCLのパラメータチューニング  NCCLの以下のようなパラメータを変更 – NCCL_BUFFSIZE:通信の際のバッファサイズ – NCCL_RINGS:通信を行う際のリングの指定  特に、NCCLで使っているリングがどうなっているのか確認することは重要 – 環境変数で以下のようにすると、どのGPU間で通信するのか確認できる (NCCLのド キュメントにはINFOがないが、NCCL 2.0.5ではまだ使える)  $ export NCCL_DEBUG=INFO  ネットワーク構成によっては、ちゃんと最適化すると数%~十数%は速度が改 善 56
  55. 55. ChainerMNの今後 57
  56. 56. ChainerMNの今後  ChainerMNでは今後以下のような機能を追加予定 – モデル並列用の機能の拡充  実験的に追加されているモデル並列用の機能をもっと使いやすくする – Double bufferingを活用したAll-Reduceの隠ぺい  All-Reduceとその他の処理をオーバーラップさせることで、全体に占めるAll- Reduceの処理時間の割合を削減 – フォールトトレランス機能の拡充 – FLOAT16対応 58
  57. 57. まとめ  ChainerMNとは – Chainerによる学習を、分散処理によって高速化するための追加パッケージ – 特徴  高速、柔軟、簡単 – GitHubリポジトリ  https://github.com/chainer/chainermn  ChainerMNの使い方 – Communicatorの作成と使用するGPUの指定、マルチノード用のOptimizer の作成だけで簡単にChainerMN対応可能  高速化への道 – 1. プロファイリング取る、2. バッチサイズを頑張ってあげる、3. 適切な communicatorを使う 59

×