読者です 読者をやめる 読者になる 読者になる

まんぼう日記

takataka's diary

Theano では allow_gc を False にしよう

Caffe を使ってみる - まんぼう日記 で Caffe と Theano で MNIST の学習をさせる実験をやってみましたが,両者でネットワーク構成が違ってたので,やり直すことにしました.その過程で,Theano で GPU を使うときは config.allow_gc を False にすると速くなる,っちうことがわかったのでメモ.

 

 

config.allow_gc

何かのついでに Theano のドキュメントを調べてたら,次の記述を見つけました.

 config – Theano Configuration — Theano 0.8.0 documentation

theano.config.allow_gc って変数に関するもの.デフォルトでは True です.で,

Disabling Theano garbage collection allows Theano to reuse buffers for intermediate results between function calls. This speeds up Theano by no longer spending time reallocating space. This gives significant speed up on functions with many ops that are fast to execute, but this increases Theano’s memory usage.

 だそうな.これはやってみる価値ありそうな気配....

 

実験条件

まずは,ちょうどよい機会だったので,Theano で書いた CNN のプログラムを書き直し.Batch Normalization を実装する - まんぼう日記 の時に作ったプログラム

https://gist.github.com/takatakamanbou/2471f7b4de908a601646#file-nnet151219-py

を利用するようにしました.できたプログラムはこちら

https://gist.github.com/takatakamanbou/b4eafa6a0d8c1a47857e#file-convnet160323-py

 

で,上記の CNN のプログラムを使った実験用プログラムがこちら

 https://gist.github.com/takatakamanbou/79a8ac7b760158501c7e

 

Caffe を使ってみる - まんぼう日記 のプログラムからの主な変更点は次の通り:

  • 従来は MNIST の学習データ6万個を5万個と1万個にわけて,前者で学習,後者で学習中の検査を行っていたが,Caffe のサンプルにあわせて,6万個全部学習に使い,学習中の検査はテストデータで行う.
  • 従来は,500個の学習用ミニバッチをランダムな順序で1回ずつ学習するのを1epochとして,20epochの学習を行うようにしていたが,Caffe のふるまいにあわせるため,600個のバッチからランダムに1つ選んで学習することを繰り返すことにした.
  • 2つ目の convolution 層の出力が 20 チャンネルだったが,Caffe の方は 50 だったので,50 にした.
  • convolution 層の出力活性化関数を ReLu にしていたが,Caffe にあわせて線形にした.Caffe の方では線形だけどしきい値は使ってるので,そこもあわせた. 

 

実験結果

やってみました.プログラム中に theano.config.allow_gc = False って書いてもいいけど,ここでは環境変数 THEANO_FLAGS を使ってます.

 

allow_gc の指定なし,つまりデフォルト値 True の場合
$ time THEANO_FLAGS='floatX=float32,device=gpu0' python ex160323.py
/usr/local/lib/python2.7/dist-packages/theano/tensor/signal/downsample.py:6: UserWarning: downsample module has been moved to the theano.tensor.signal.pool module.
  "downsample module has been moved to the theano.tensor.signal.pool module.")
Using gpu device 0: GeForce GTX TITAN X (CNMeM is disabled, CuDNN 4007)
### ID:  20160326-113657
### Conv-Pool-Conv-Pool-ReLu-Softmax
# T4InputLayer:  (1, 28, 28)  dropout =  1.0
# ConvLayer:     (20, 1, 5, 5) (20, 24, 24)  bmode =  valid
# PoolLayer:      ds =  (2, 2)  st =  None  dropout =  1.0 (20, 12, 12) 2880
# ConvLayer:     (50, 20, 5, 5) (50, 8, 8)  bmode =  valid
# PoolLayer:      ds =  (2, 2)  st =  None  dropout =  1.0 (50, 4, 4) 800
# FullLayer:     800 500 ReLu 1.0
# FullLayer:     500 10 linear 1.0
### training:   NL =  60000  batchsize =  100
#               eta =  0.01 mu =  0.9 lam =  0.0005
0 | 0.0230 92.10 | 0.0230 91.43
   :
10000 | 0.0001 0.33 | 0.0004 1.27
### ID:  20160326-113657

real    1m41.924s
user    1m9.144s
sys    0m32.244s

だいたい100秒です.GPUメモリの使用量の方は,nvidia-smi コマンドで観察したところ 240MiB あたりで数 MiB 上下してます.

 

allow_gc = False の場合
$ time THEANO_FLAGS='allow_gc=False,floatX=float32,device=gpu0' python ex160323.py
   :
10000 | 0.0001 0.19 | 0.0003 1.06
### ID:  20160326-113956

real    1m1.271s
user    0m55.176s
sys    0m5.932s

およそ60秒....大幅なスピードアップです.GPUメモリ使用量はずっと 259 MiB.

 

考察

というわけで,allow_gc = False の効果は抜群です.GPUメモリの使用量については,こんくらいの小規模なネットワークでは気にするほどではないようです.

 

ちなみに,Caffe で同じ構成のネットワークを学習させた場合は,実行時間が 25秒弱,GPUメモリ使用量は 228MiB でした.

 

これはたかたかの憶測ですが,今回の実験での Caffe と Theano での実行時間の違いは,主に次の二つに起因すると思われます.

  • Theano の方はたかたかが自分で書いたプログラムなので,最適化が十分でない
  • Caffe はデータ読み込みを学習本体と別スレッドにして,ひとつのミニバッチの学習と並行して次のミニバッチを読み込むようになっている

後者については,自力でなんとかする手があります.興味があれば 画像読み込みと学習を並列化するためのほげ ― Python で multi-threading - まんぼう日記 へどうぞ.