簡単なCNNによるディープラーニングライブラリ速度比較

##はじめに
おはようございます．みなさんディープラーニングはお好きですか．最近いくつかのライブラリで同じようなCNNを書いて動かして見たので，触った感触と簡単な速度比較結果を記事にしようかと思います．内容的には100番煎じくらいなわけですが興味があればご覧ください．ついでに「おまえは（任意の深層学習ライブラリ名）を何もわかっていない！」とか「こっちの書き方のが早いやろがい！」とかあれば遠慮なくご指摘ください．コードは[こちら](https://github.com/daigo0927/compare-deeplibs)

・やること：ライブラリごとのCNN構築・学習
・比較ライブラリ：TensorFlow，Keras，Sonnet，PyTorch，Chainer
・比較指標：画像データのforward&backwardにかかる時間

##Requirements
・python 3.5
・tensorflow 1.1.0
・keras 2.0.6
・dm-sonnet 1.13
・torch 0.2.0.post3
　・torchvision 0.1.9
・chainer 3.1.0
他に必要なライブラリはリポジトリ内の[requirements.txt](https://github.com/daigo0927/compare-deeplibs/blob/master/requirements.txt)をご覧ください．

##触った感触
今回は各ライブラリで簡単なCNNを組み，画像分類を行いました．ネットワークの構成としてはConv-BatchNorm-ReLU-MaxPool-Conv-BatchNorm-ReLU-MaxPool-FullConnectとなっています．
畳み込みのフィルタの数とかプーリング・バッチ正規化・ReLUの順番とかは特に意図はないです．

<img src="https://qiita-image-store.s3.amazonaws.com/0/152704/49423360-c332-8dc2-79c2-f54aa69fe8f8.png" width=40%>

リポジトリ内の各```train_(ライブラリ名).py```について，
1.ネットワークの定義
2.学習の流れの定義
3.学習実行
という順番で統一して書きました．

各ライブラリの簡単な説明と，触った感想を書いていこうと思います．


参考：[【PyTorch、Chainer、Keras、TensorFlow】ディープラーニングのフレームワークの利点・欠点【2017年10月更新】](http://s0sem0y.hatenablog.com/entry/2017/05/15/063753)

###[TensorFlow](https://www.tensorflow.org/api_docs/)
みなさんご存知Google製ライブラリ．
コミュニティの盛り上がりは深層学習ライブラリでも随一です．最新の研究も多く実装・公開されています．ラズパイにもインストールできるなど，研究以外にも広範な用途に使えるという強みがあります．

触った感触としてはまず名前空間（```tf.variable_scope()```とかで扱うやつ）が特徴的かつややとっつきづらいかと思います．RNNや，最近ではGANのdiscriminatorなどではネットワーク内の重みを使い回すことがあります．こうしたときTensorFlowでは名前空間を理解する必要があります．
詳しくはこちらの記事が非常に参考になります．
[TensorFlow の名前空間を理解して共有変数を使いこなす](https://qiita.com/TomokIshii/items/ffe999b3e1a506c396c8)

また，畳み込みなどといった各種レイヤーは```tf.layers```からも利用できますが個人的には```tf.contrib.layers```の物を使うのがおすすめです．
例えば```tf.layers.conv2d()```ではフィルタ（重み）の定義を自分で明示的に実装する必要がありますが，```tf.contrib.layers.conv2d```（コード内では```tcl.conv2d```と表記）では引数として出力フィルタの枚数やカーネルサイズを決めると自動的に重み変数を定義してくれます．らくちんですね．
ついでですが，```tf.contrib.layers.fully_connected```による全結合層では活性化関数がデフォルトでReLUになっているため，気づかずに使うと全く学習が進まないことがあります（[train_tf.py](https://github.com/daigo0927/compare-deeplibs/blob/master/train_tf.py)内41-2行）．私のように痛い目に合わないよう気をつけてください．

###[Keras](https://keras.io/ja/)
TensorFlowのラッパーライブラリ．Googleの[@fchollet](https://twitter.com/fchollet)さんが「より多くの人に深層学習に触れてもらいたい」という思いから開発し始めたそうです．
他のライブラリに比べて細かい設定が隠匿されているため，圧倒的にモデル構築が簡単です．私も初めはKerasから入りました．[train_keras.py](https://github.com/daigo0927/compare-deeplibs/blob/master/train_keras.py)では大まかな流れを統一して書きましたが，今回行うような簡単な画像分類タスクであればよりシンプルに書くことも可能かと思います．とはいえResNetやGANなどといったモデルも実装できるので侮ってはいけません．
さらに複雑なネットワークに関しては他のライブラリの方が柔軟に対応できるかもしれません．

###[Sonnet](https://deepmind.github.io/sonnet/)
DeepMind製ライブラリ．TensorFlowの関数とミックスしてモデルを定義できるのが面白くかつ便利なところかと思います．
今回触った限りではTensorFlow単体で書くのとそれほど違うようには感じませんでしたが，リカレント系の関数をいろいろ備えているなと思いました（```snt.DeepRNN```とか```snt.GRU```とか）．

参考
[DeepMind の深層学習ライブラリ Sonnet を早速試してみた](http://deeplearning.hatenablog.com/entry/sonnet)
[DeepMindのSonnetを触ったので、TensorFlowやKerasと比較しながら解説してみた](https://qiita.com/jinbeizame007/items/3661e067c8185bb9e87f)

###[Pytorch](http://pytorch.org/docs/0.3.1/)
facebookが主に開発するライブラリ．TensorFlowに匹敵する盛り上がりを見せており，最新の研究の追実装も多く公開されているように感じます．後述のChainerをフォークして開発されています．私の研究室でも最近流行りつつあります．
PyTorchによる実装に関しては研究室の後輩である[vwrs](https://github.com/vwrs?tab=repositories)くんにやってもらいました．そのため触った感想というほどのものはないのですが，コード内でのCPUとGPUの切り替えが非常にシームレスに実装できると感じました．

###[Chainer](https://docs.chainer.org/en/stable/)
日本の企業であるPreferred Networks社が開発する深層学習ライブラリ．今回の比較をするにあたって初めて触りましたが，わかりやすくネットワークを構築できると感じました．またPyTorchと同様にCPU・GPUの切り替えがスムーズに実装できるのも魅力に感じます．
余談ですが，先日Preferred Networksの方の話していた内容によると，自社ライブラリの存在は知名度をあげるだけでなく組織内での研究・開発の一貫性を持たせる意味でも有意義なのだそうです．確かに同じ組織内でバラバラのツールが使われていたら研究内容を報告したり知見を蓄積する上でも面倒だなと感じました．

##速度比較実験
各ライブラリによって構築したCNNを用いて画像分類の学習を行いました．
・データ：CIFAR10（10クラス，各5000枚，縦横32×32のRGB画像）
・学習設定
　・エポック数：20
　・バッチサイズ：128
・計算機：Tesla K80（シングルGPU）
どのライブラリも同じネットワークなので分類精度は同じ（だったはず）です．今回は画像データをforwardし，誤差勾配をbackwardするのに要する時間（厳密にはミニバッチの値をGPUに載せてからforwardし，backpropagationによってパラメータを更新するまで）のエポックごとの和を比較しました．

結果がこちら．単位は秒です．

|　　　|1エポック目[s]|2エポック目以降平均[s]|20エポック合計[s]|
|---|:-:|:-:|:-:|
|TensorFlow|69.01|19.90|447.06|
|Keras|69.60|19.00|430.58|
|Sonnet|68.50|19.56|440.10|
|Pytorch|244.93|1.77|278.47|
|Chainer|52.23|2.58|101.18|

PyTorchとChainer速い...！
TensorFlow, Keras, Sonnetはどれも大差ないのは納得できますが，PyTorch, Chainerとこれほど速度差が出るとは，私のコーディングのせいなのでしょうがややショックです．
今回知ったんですけど，どのライブラリも最初だけ時間かかるんですね．
TensorFlow, Keras, SonnetとPyTorch, Chainerの違いといえばやはりDefine-and-RunかDefine-by-Runかというところでしょうか．
最近1月26日にリリースされたTensorFlow-v1.5でもEagerExecutionなるDefine-by-Runのインターフェースが実装されたことを考えると，世の流れはDefine-by-Runなのでしょう．それが実行時間と関係あるのかは正直なところさっぱりなのですが，知ってる人はぜひコメントしてくださると嬉しいです．

参考
[ChainerのDefine by Runとは？](http://s0sem0y.hatenablog.com/entry/2017/01/14/060758)
[Tensorflow 1.5のEager Executionを触ってみた](https://qiita.com/hiroyuki827/items/730b4684d8e84760b5ea)
[Eager Execution: An imperative, define-by-run interface to TensorFlow](https://developers.googleblog.com/2017/10/eager-execution-imperative-define-by.html)

##まとめ
今回は5つの深層学習ライブラリについて同じようなCNNを記述，画像分類タスクの学習に要する時間を比較しました．
コーディングの感触としてはやはり初心者にもっとも優しいのはKerasかと思います．Sonnetに関してはまだ先行事例が少ないのでなんとも言えませんが，より高度なネットワークを実装する場合はTensorFlow, PyTorch, Chainerのどれかが使えるべきかと思います．個人的にはTensorFlow推しですが，これらに関しては実際にExamplesなどを見て（時間があればコードを写経して）自分の感覚にあったものを使えばいいと思います．

コードへのご指摘や各ライブラリについて見識をお持ちの方はぜひコメントしてくださると嬉しいです！
ご覧いただきありがとうございます．